mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-08 20:28:30 +00:00
Improve ZIP filesystem and change its prefix
The ZIP filesystem has a breaking change. You now need to use /zip/ to open() / opendir() / etc. assets within the ZIP structure of your APE binary, instead of the previous convention of using zip: or zip! URIs. This is needed because Python likes to use absolute paths, and having ZIP paths encoded like URIs simply broke too many things. Many more system calls have been updated to be able to operate on ZIP files and file descriptors. In particular fcntl() and ioctl() since Python would do things like ask if a ZIP file is a terminal and get confused when the old implementation mistakenly said yes, because the fastest way to guarantee native file descriptors is to dup(2). This change also improves the async signal safety of zipos and ensures it doesn't maintain any open file descriptors beyond that which the user has opened. This change makes a lot of progress towards adding magic numbers that are specific to platforms other than Linux. The philosophy here is that, if you use an operating system like FreeBSD, then you should be able to take advantage of FreeBSD exclusive features, even if we don't polyfill them on other platforms. For example, you can now open() a file with the O_VERIFY flag. If your program runs on other platforms, then Cosmo will automatically set O_VERIFY to zero. This lets you safely use it without the need for #ifdef or ifstatements which detract from readability. One of the blindspots of the ASAN memory hardening we use to offer Rust like assurances has always been that memory passed to the kernel via system calls (e.g. writev) can't be checked automatically since the kernel wasn't built with MODE=asan. This change makes more progress ensuring that each system call will verify the soundness of memory before it's passed to the kernel. The code for doing these checks is fast, particularly for buffers, where it can verify 64 bytes a cycle. - Correct O_LOOP definition on NT - Introduce program_executable_name - Add ASAN guards to more system calls - Improve termios compatibility with BSDs - Fix bug in Windows auxiliary value encoding - Add BSD and XNU specific errnos and open flags - Add check to ensure build doesn't talk to internet
This commit is contained in:
parent
2730c66f4a
commit
00611e9b06
319 changed files with 4418 additions and 2599 deletions
284
third_party/linenoise/linenoise.c
vendored
284
third_party/linenoise/linenoise.c
vendored
|
@ -182,7 +182,10 @@
|
|||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -198,9 +201,9 @@
|
|||
#define LINENOISE_HISTORY_PREV 1
|
||||
|
||||
static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
|
||||
static linenoiseCompletionCallback *completionCallback = NULL;
|
||||
static linenoiseHintsCallback *hintsCallback = NULL;
|
||||
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||
static linenoiseCompletionCallback *completionCallback;
|
||||
static linenoiseHintsCallback *hintsCallback;
|
||||
static linenoiseFreeHintsCallback *freeHintsCallback;
|
||||
|
||||
static struct termios orig_termios; /* In order to restore at exit.*/
|
||||
static int maskmode; /* Show "***" instead of input. For passwords. */
|
||||
|
@ -329,21 +332,23 @@ void linenoiseDisableRawMode(int fd) {
|
|||
* and return it. On error -1 is returned, on success the position of the
|
||||
* cursor. */
|
||||
static int getCursorPosition(int ifd, int ofd) {
|
||||
char buf[32];
|
||||
int cols, rows;
|
||||
char buf[16], *p;
|
||||
unsigned int i = 0;
|
||||
/* Report cursor location */
|
||||
if (write(ofd, "\e[6n", 4) != 4) return -1;
|
||||
if (xwrite(ofd, "\e[6n", 4) == -1) return -1;
|
||||
/* Read the response: ESC [ rows ; cols R */
|
||||
while (i < sizeof(buf)-1) {
|
||||
if (read(ifd,buf+i,1) != 1) break;
|
||||
if (buf[i] == 'R') break;
|
||||
i++;
|
||||
if (buf[i++] == 'R') break;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
/* Parse it. */
|
||||
if (buf[0] != '\e' || buf[1] != '[') return -1;
|
||||
if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
|
||||
p = buf+2;
|
||||
if (*p++ != '\e' || *p++ != '[') return -1;
|
||||
rows = strtol(p,&p,10);
|
||||
if (*p==';') ++p;
|
||||
cols = strtol(p,&p,10);
|
||||
return cols;
|
||||
}
|
||||
|
||||
|
@ -358,16 +363,15 @@ static int getColumns(int ifd, int ofd) {
|
|||
start = getCursorPosition(ifd,ofd);
|
||||
if (start == -1) goto failed;
|
||||
/* Go to right margin and get position. */
|
||||
if (write(ofd,"\e[999C",6) != 6) goto failed;
|
||||
if (xwrite(ofd,"\e[999C",6) == -1) goto failed;
|
||||
cols = getCursorPosition(ifd,ofd);
|
||||
if (cols == -1) goto failed;
|
||||
/* Restore position. */
|
||||
if (cols > start) {
|
||||
char seq[32];
|
||||
snprintf(seq,32,"\e[%dD",cols-start);
|
||||
if (write(ofd,seq,strlen(seq)) == -1) {
|
||||
/* Can't recover... */
|
||||
}
|
||||
char seq[26], *p;
|
||||
p=stpcpy(seq,"\e[");
|
||||
p+=int64toarray_radix10(cols-start,p),*p++='D';
|
||||
xwrite(ofd,seq,p-seq);
|
||||
}
|
||||
return cols;
|
||||
} else {
|
||||
|
@ -379,9 +383,7 @@ failed:
|
|||
|
||||
/* Clear the screen. Used to handle ctrl+l */
|
||||
void linenoiseClearScreen(void) {
|
||||
if (write(fileno(stdout),"\e[H\e[2J",7) <= 0) {
|
||||
/* nothing to do, just to avoid warning. */
|
||||
}
|
||||
xwrite(fileno(stdout),"\e[H\e[2J",7);
|
||||
}
|
||||
|
||||
/* Beep, used for completion when there is nothing to complete or when all
|
||||
|
@ -389,17 +391,17 @@ void linenoiseClearScreen(void) {
|
|||
static void linenoiseBeep(void) {
|
||||
/* NOOOO */
|
||||
/* fprintf(stderr, "\x7"); */
|
||||
fflush(stderr);
|
||||
/* fflush(stderr); */
|
||||
}
|
||||
|
||||
/* ============================== Completion ================================ */
|
||||
|
||||
/* Free a list of completion option populated by linenoiseAddCompletion(). */
|
||||
static void freeCompletions(linenoiseCompletions *lc) {
|
||||
void linenoiseFreeCompletions(linenoiseCompletions *lc) {
|
||||
size_t i;
|
||||
for (i = 0; i < lc->len; i++)
|
||||
free(lc->cvec[i]);
|
||||
if (lc->cvec != NULL)
|
||||
if (lc->cvec)
|
||||
free(lc->cvec);
|
||||
}
|
||||
|
||||
|
@ -432,10 +434,10 @@ static int completeLine(struct linenoiseState *ls, char *seq, int size) {
|
|||
}
|
||||
nread = readansi(ls->ifd,seq,size);
|
||||
if (nread <= 0) {
|
||||
freeCompletions(&lc);
|
||||
linenoiseFreeCompletions(&lc);
|
||||
return -1;
|
||||
}
|
||||
switch (seq[0]) {
|
||||
switch(seq[0]) {
|
||||
case '\t':
|
||||
i = (i+1) % (lc.len+1);
|
||||
if (i == lc.len) linenoiseBeep();
|
||||
|
@ -443,7 +445,9 @@ static int completeLine(struct linenoiseState *ls, char *seq, int size) {
|
|||
default:
|
||||
/* Update buffer and return */
|
||||
if (i < lc.len) {
|
||||
nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
|
||||
size_t n = strlen(lc.cvec[i]);
|
||||
nwritten = MIN(n,ls->buflen);
|
||||
memcpy(ls->buf,lc.cvec[i],nwritten+1);
|
||||
ls->len = ls->pos = nwritten;
|
||||
}
|
||||
stop = 1;
|
||||
|
@ -451,7 +455,7 @@ static int completeLine(struct linenoiseState *ls, char *seq, int size) {
|
|||
}
|
||||
}
|
||||
}
|
||||
freeCompletions(&lc);
|
||||
linenoiseFreeCompletions(&lc);
|
||||
return nread;
|
||||
}
|
||||
|
||||
|
@ -508,8 +512,8 @@ static void abInit(struct abuf *ab) {
|
|||
}
|
||||
|
||||
static void abAppend(struct abuf *ab, const char *s, int len) {
|
||||
char *new = realloc(ab->b,ab->len+len);
|
||||
if (new == NULL) return;
|
||||
char *new;
|
||||
if (!(new = realloc(ab->b,ab->len+len))) return;
|
||||
memcpy(new+ab->len,s,len);
|
||||
ab->b = new;
|
||||
ab->len += len;
|
||||
|
@ -522,25 +526,29 @@ static void abFree(struct abuf *ab) {
|
|||
/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
|
||||
* to the right of the prompt. */
|
||||
static void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
|
||||
char seq[64];
|
||||
char seq[26], *p;
|
||||
if (hintsCallback && plen+l->len < l->cols) {
|
||||
int color = -1, bold = 0;
|
||||
int color = 0, bold = 0;
|
||||
char *hint = hintsCallback(l->buf,&color,&bold);
|
||||
if (hint) {
|
||||
int hintlen = strlen(hint);
|
||||
int hintmaxlen = l->cols-(plen+l->len);
|
||||
if (hintlen > hintmaxlen) hintlen = hintmaxlen;
|
||||
if (bold == 1 && color == -1) color = 37;
|
||||
if (color != -1 || bold != 0)
|
||||
snprintf(seq,64,"\e[%d;%d;49m",bold,color);
|
||||
else
|
||||
seq[0] = '\0';
|
||||
abAppend(ab,seq,strlen(seq));
|
||||
if (bold && !color) color = 37;
|
||||
if (color || bold) {
|
||||
p=stpcpy(seq,"\e[");
|
||||
p+=int64toarray_radix10(bold&255,p),*p++=';';
|
||||
p+=int64toarray_radix10(color&255,p);
|
||||
p=stpcpy(p,";49m");
|
||||
abAppend(ab,seq,p-seq);
|
||||
}
|
||||
abAppend(ab,hint,hintlen);
|
||||
if (color != -1 || bold != 0)
|
||||
if (color != -1 || bold)
|
||||
abAppend(ab,"\e[0m",4);
|
||||
/* Call the function to free the hint returned. */
|
||||
if (freeHintsCallback) freeHintsCallback(hint);
|
||||
if (freeHintsCallback) {
|
||||
freeHintsCallback(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -550,12 +558,12 @@ static void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen
|
|||
* Rewrite the currently edited line accordingly to the buffer content,
|
||||
* cursor position, and number of columns of the terminal. */
|
||||
static void refreshSingleLine(struct linenoiseState *l) {
|
||||
char seq[64];
|
||||
size_t plen = strlen(l->prompt);
|
||||
char seq[26], *p;
|
||||
int plen = strlen(l->prompt);
|
||||
int fd = l->ofd;
|
||||
char *buf = l->buf;
|
||||
size_t len = l->len;
|
||||
size_t pos = l->pos;
|
||||
int len = l->len;
|
||||
int pos = l->pos;
|
||||
struct abuf ab;
|
||||
while((plen+pos) >= l->cols) {
|
||||
buf++;
|
||||
|
@ -567,24 +575,25 @@ static void refreshSingleLine(struct linenoiseState *l) {
|
|||
}
|
||||
abInit(&ab);
|
||||
/* Cursor to left edge */
|
||||
snprintf(seq,64,"\r");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
abAppend(&ab,"\r",1);
|
||||
/* Write the prompt and the current buffer content */
|
||||
abAppend(&ab,l->prompt,strlen(l->prompt));
|
||||
if (maskmode == 1) {
|
||||
while (len--) abAppend(&ab,"*",1);
|
||||
while (len--) {
|
||||
abAppend(&ab,"*",1);
|
||||
}
|
||||
} else {
|
||||
abAppend(&ab,buf,len);
|
||||
}
|
||||
/* Show hits if any. */
|
||||
refreshShowHints(&ab,l,plen);
|
||||
/* Erase to right */
|
||||
snprintf(seq,64,"\e[0K");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
abAppend(&ab,"\e[K",3);
|
||||
/* Move cursor to original position. */
|
||||
snprintf(seq,64,"\r\e[%dC", (int)(pos+plen));
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
|
||||
p=stpcpy(seq,"\r\e[");
|
||||
p+=int64toarray_radix10(pos+plen,p),*p++='C';
|
||||
abAppend(&ab,seq,p-seq);
|
||||
xwrite(fd,ab.b,ab.len);
|
||||
abFree(&ab);
|
||||
}
|
||||
|
||||
|
@ -593,15 +602,15 @@ static void refreshSingleLine(struct linenoiseState *l) {
|
|||
* Rewrite the currently edited line accordingly to the buffer content,
|
||||
* cursor position, and number of columns of the terminal. */
|
||||
static void refreshMultiLine(struct linenoiseState *l) {
|
||||
char seq[64];
|
||||
struct abuf ab;
|
||||
char seq[26], *p;
|
||||
int plen = strlen(l->prompt);
|
||||
int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
|
||||
int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
|
||||
int rpos2; /* rpos after refresh. */
|
||||
int col; /* colum position, zero-based. */
|
||||
int old_rows = l->maxrows;
|
||||
int fd = l->ofd, j;
|
||||
struct abuf ab;
|
||||
int fd = l->ofd, i, j;
|
||||
/* Update maxrows if needed. */
|
||||
if (rows > (int)l->maxrows) l->maxrows = rows;
|
||||
/* First step: clear all the lines used before. To do so start by
|
||||
|
@ -609,24 +618,24 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
|||
abInit(&ab);
|
||||
if (old_rows-rpos > 0) {
|
||||
lndebug("go down %d", old_rows-rpos);
|
||||
snprintf(seq,64,"\e[%dB", old_rows-rpos);
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
p=stpcpy(seq,"\e[");
|
||||
p+=int64toarray_radix10(old_rows-rpos,p),*p++='B';
|
||||
abAppend(&ab,seq,p-seq);
|
||||
}
|
||||
/* Now for every row clear it, go up. */
|
||||
for (j = 0; j < old_rows-1; j++) {
|
||||
lndebug("clear+up");
|
||||
snprintf(seq,64,"\r\e[0K\e[1A");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
abAppend(&ab,"\r\e[K\e[1A",8);
|
||||
}
|
||||
/* Clean the top line. */
|
||||
lndebug("clear");
|
||||
snprintf(seq,64,"\r\e[0K");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
abAppend(&ab,"\r\e[K",4);
|
||||
/* Write the prompt and the current buffer content */
|
||||
abAppend(&ab,l->prompt,strlen(l->prompt));
|
||||
if (maskmode == 1) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
|
||||
for (i = 0; i < l->len; i++) {
|
||||
abAppend(&ab,"*",1);
|
||||
}
|
||||
} else {
|
||||
abAppend(&ab,l->buf,l->len);
|
||||
}
|
||||
|
@ -639,9 +648,7 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
|||
(l->pos+plen) % l->cols == 0)
|
||||
{
|
||||
lndebug("<newline>");
|
||||
abAppend(&ab,"\n",1);
|
||||
snprintf(seq,64,"\r");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
abAppend(&ab,"\n\r",2);
|
||||
rows++;
|
||||
if (rows > (int)l->maxrows) l->maxrows = rows;
|
||||
}
|
||||
|
@ -651,20 +658,23 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
|||
/* Go up till we reach the expected positon. */
|
||||
if (rows-rpos2 > 0) {
|
||||
lndebug("go-up %d", rows-rpos2);
|
||||
snprintf(seq,64,"\e[%dA", rows-rpos2);
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
p=stpcpy(seq,"\e[");
|
||||
p+=int64toarray_radix10(rows-rpos2,p),*p++='A';
|
||||
abAppend(&ab,seq,p-seq);
|
||||
}
|
||||
/* Set column. */
|
||||
col = (plen+(int)l->pos) % (int)l->cols;
|
||||
lndebug("set col %d", 1+col);
|
||||
if (col)
|
||||
snprintf(seq,64,"\r\e[%dC", col);
|
||||
else
|
||||
snprintf(seq,64,"\r");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
if (col) {
|
||||
p=stpcpy(seq,"\r\e[");
|
||||
p+=int64toarray_radix10(col,p),*p++='C';
|
||||
abAppend(&ab,seq,p-seq);
|
||||
} else {
|
||||
abAppend(&ab,"\r",1);
|
||||
}
|
||||
lndebug("\n");
|
||||
l->oldpos = l->pos;
|
||||
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
|
||||
xwrite(fd,ab.b,ab.len);
|
||||
abFree(&ab);
|
||||
}
|
||||
|
||||
|
@ -681,6 +691,7 @@ static void refreshLine(struct linenoiseState *l) {
|
|||
*
|
||||
* On error writing to the terminal -1 is returned, otherwise 0. */
|
||||
static int linenoiseEditInsert(struct linenoiseState *l, char c) {
|
||||
char d;
|
||||
if (l->len < l->buflen) {
|
||||
if (l->len == l->pos) {
|
||||
l->buf[l->pos] = c;
|
||||
|
@ -690,8 +701,8 @@ static int linenoiseEditInsert(struct linenoiseState *l, char c) {
|
|||
if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
|
||||
/* Avoid a full update of the line in the
|
||||
* trivial case. */
|
||||
char d = (maskmode==1) ? '*' : c;
|
||||
if (write(l->ofd,&d,1) == -1) return -1;
|
||||
d = (maskmode==1) ? '*' : c;
|
||||
if (xwrite(l->ofd,&d,1) == -1) return -1;
|
||||
} else {
|
||||
refreshLine(l);
|
||||
}
|
||||
|
@ -716,13 +727,13 @@ static void linenoiseEditMoveLeft(struct linenoiseState *l) {
|
|||
}
|
||||
|
||||
static bool IsSeparator(int c) {
|
||||
return !(isalnum(c) || c >= 128);
|
||||
return !(isalnum(c) || c > 127);
|
||||
}
|
||||
|
||||
/* Move cursor on the left. */
|
||||
static void linenoiseEditMoveLeftWord(struct linenoiseState *l) {
|
||||
if (l->pos > 0) {
|
||||
while (l->pos > 0 && IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
while (l->pos > 0 && IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
while (l->pos > 0 && !IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
refreshLine(l);
|
||||
}
|
||||
|
@ -731,7 +742,7 @@ static void linenoiseEditMoveLeftWord(struct linenoiseState *l) {
|
|||
/* Move cursor on the right. */
|
||||
static void linenoiseEditMoveRightWord(struct linenoiseState *l) {
|
||||
if (l->pos != l->len) {
|
||||
while (l->pos < l->len && IsSeparator(l->buf[l->pos])) l->pos++;
|
||||
while (l->pos < l->len && IsSeparator(l->buf[l->pos])) l->pos++;
|
||||
while (l->pos < l->len && !IsSeparator(l->buf[l->pos])) l->pos++;
|
||||
refreshLine(l);
|
||||
}
|
||||
|
@ -747,7 +758,7 @@ static void linenoiseEditMoveRight(struct linenoiseState *l) {
|
|||
|
||||
/* Move cursor to the start of the line. */
|
||||
static void linenoiseEditMoveHome(struct linenoiseState *l) {
|
||||
if (l->pos != 0) {
|
||||
if (l->pos) {
|
||||
l->pos = 0;
|
||||
refreshLine(l);
|
||||
}
|
||||
|
@ -809,7 +820,7 @@ static void linenoiseEditBackspace(struct linenoiseState *l) {
|
|||
|
||||
static void linenoiseEditDeleteNextWord(struct linenoiseState *l) {
|
||||
size_t i = l->pos;
|
||||
while (i != l->len && IsSeparator(l->buf[i])) i++;
|
||||
while (i != l->len && IsSeparator(l->buf[i])) i++;
|
||||
while (i != l->len && !IsSeparator(l->buf[i])) i++;
|
||||
memmove(l->buf+l->pos,l->buf+i,l->len-i);
|
||||
l->len -= i - l->pos;
|
||||
|
@ -819,9 +830,9 @@ static void linenoiseEditDeleteNextWord(struct linenoiseState *l) {
|
|||
/* Delete the previous word, maintaining the cursor at the start of the
|
||||
* current word. */
|
||||
static void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
|
||||
size_t diff;
|
||||
size_t old_pos = l->pos;
|
||||
while (l->pos > 0 && IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
size_t diff, old_pos;
|
||||
old_pos = l->pos;
|
||||
while (l->pos > 0 && IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
while (l->pos > 0 && !IsSeparator(l->buf[l->pos-1])) l->pos--;
|
||||
diff = old_pos - l->pos;
|
||||
memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
|
||||
|
@ -836,8 +847,8 @@ static void linenoiseKill(struct linenoiseState *l, size_t i, size_t n) {
|
|||
}
|
||||
|
||||
static void linenoiseEditKillLeft(struct linenoiseState *l) {
|
||||
size_t diff;
|
||||
size_t old_pos = l->pos;
|
||||
size_t diff, old_pos;
|
||||
old_pos = l->pos;
|
||||
l->pos = 0;
|
||||
diff = old_pos - l->pos;
|
||||
memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
|
||||
|
@ -851,6 +862,17 @@ static void linenoiseEditKillRight(struct linenoiseState *l) {
|
|||
refreshLine(l);
|
||||
}
|
||||
|
||||
static void linenoiseEditTransposeCharacters(struct linenoiseState *l) {
|
||||
int t;
|
||||
if (l->pos > 0 && l->pos < l->len) {
|
||||
t = l->buf[l->pos-1];
|
||||
l->buf[l->pos-1] = l->buf[l->pos];
|
||||
l->buf[l->pos] = t;
|
||||
if (l->pos < l->len) l->pos++;
|
||||
refreshLine(l);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is the core of the line editing capability of linenoise.
|
||||
* It expects 'fd' to be already in "raw mode" so that every key pressed
|
||||
* will be returned ASAP to read().
|
||||
|
@ -880,11 +902,11 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
/* The latest history entry is always our current buffer, that
|
||||
* initially is just an empty string. */
|
||||
linenoiseHistoryAdd("");
|
||||
if (write(l.ofd,prompt,l.plen) == -1) return -1;
|
||||
if (xwrite(l.ofd,prompt,l.plen) == -1) return -1;
|
||||
while(1) {
|
||||
int i;
|
||||
int nread;
|
||||
char seq[32];
|
||||
char seq[16];
|
||||
nread = readansi(l.ifd,seq,sizeof(seq));
|
||||
if (nread <= 0) return l.len;
|
||||
/* Only autocomplete when the callback is set. It returns < 0 when
|
||||
|
@ -926,14 +948,8 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
case CTRL('T'): /* swaps current character with previous. */
|
||||
if (l.pos > 0 && l.pos < l.len) {
|
||||
int aux = buf[l.pos-1];
|
||||
buf[l.pos-1] = buf[l.pos];
|
||||
buf[l.pos] = aux;
|
||||
if (l.pos != l.len-1) l.pos++;
|
||||
refreshLine(&l);
|
||||
}
|
||||
case CTRL('T'): /* swaps current character with previous. */
|
||||
linenoiseEditTransposeCharacters(&l);
|
||||
break;
|
||||
case CTRL('B'):
|
||||
linenoiseEditMoveLeft(&l);
|
||||
|
@ -947,12 +963,32 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
case CTRL('N'):
|
||||
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
|
||||
break;
|
||||
case CTRL('U'): /* delete the line backwards */
|
||||
linenoiseEditKillLeft(&l);
|
||||
break;
|
||||
case CTRL('K'): /* delete from current to end of line */
|
||||
linenoiseEditKillRight(&l);
|
||||
break;
|
||||
case CTRL('A'): /* go to the start of the line */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case CTRL('E'): /* go to the end of the line */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
case CTRL('L'): /* clear screen */
|
||||
linenoiseClearScreen();
|
||||
refreshLine(&l);
|
||||
break;
|
||||
case CTRL('W'): /* delete previous word */
|
||||
linenoiseEditDeletePrevWord(&l);
|
||||
break;
|
||||
case '\e': /* escape sequence */
|
||||
/* Read the next two bytes representing the escape sequence.
|
||||
* Use two calls to handle slow terminals returning the two
|
||||
* chars at different times. */
|
||||
if (nread < 2) break;
|
||||
if (seq[1] == '[') {
|
||||
switch(seq[1]) {
|
||||
case '[':
|
||||
if (nread < 3) break;
|
||||
if (seq[2] >= '0' && seq[2] <= '9') {
|
||||
if (nread < 4) break;
|
||||
|
@ -967,6 +1003,8 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
case '4': /* "\e[4~" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -989,10 +1027,12 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
case 'F': /* "\e[F" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (seq[1] == 'O') {
|
||||
break;
|
||||
case 'O':
|
||||
if (nread < 3) break;
|
||||
switch(seq[2]) {
|
||||
case 'H': /* "\eOH" is home */
|
||||
|
@ -1001,19 +1041,24 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
case 'F': /* "\eOF" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (seq[1] == 'b') { /* "\eb" is alt-b */
|
||||
break;
|
||||
case 'b': /* "\eb" is alt-b */
|
||||
linenoiseEditMoveLeftWord(&l);
|
||||
}
|
||||
else if (seq[1] == 'f') { /* "\ef" is alt-f */
|
||||
break;
|
||||
case 'f': /* "\ef" is alt-f */
|
||||
linenoiseEditMoveRightWord(&l);
|
||||
}
|
||||
else if (seq[1] == 'd') { /* "\ed" is alt-d */
|
||||
break;
|
||||
case 'd': /* "\ed" is alt-d */
|
||||
linenoiseEditDeleteNextWord(&l);
|
||||
}
|
||||
else if (seq[1] == CTRL('H')) { /* "\e\b" is ctrl-alt-h */
|
||||
break;
|
||||
case CTRL('H'): /* "\e\b" is ctrl-alt-h */
|
||||
linenoiseEditDeletePrevWord(&l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1023,25 +1068,6 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
}
|
||||
}
|
||||
break;
|
||||
case CTRL('U'): /* delete the line backwards */
|
||||
linenoiseEditKillLeft(&l);
|
||||
break;
|
||||
case CTRL('K'): /* delete from current to end of line */
|
||||
linenoiseEditKillRight(&l);
|
||||
break;
|
||||
case CTRL('A'): /* go to the start of the line */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case CTRL('E'): /* go to the end of the line */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
case CTRL('L'): /* clear screen */
|
||||
linenoiseClearScreen();
|
||||
refreshLine(&l);
|
||||
break;
|
||||
case CTRL('W'): /* delete previous word */
|
||||
linenoiseEditDeletePrevWord(&l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return l.len;
|
||||
|
@ -1051,14 +1077,14 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
* the STDIN file descriptor set in raw mode. */
|
||||
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
||||
int count;
|
||||
if (buflen == 0) {
|
||||
if (!buflen) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (enableRawMode(fileno(stdin)) == -1) return -1;
|
||||
count = linenoiseEdit(fileno(stdin), fileno(stdout), buf, buflen, prompt);
|
||||
linenoiseDisableRawMode(fileno(stdin));
|
||||
if (count != -1) printf("\n");
|
||||
if (count != -1) fputc('\n',stdout);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1110,7 +1136,7 @@ char *linenoise(const char *prompt) {
|
|||
* limit to the line size, so we call a function to handle that. */
|
||||
return linenoiseNoTTY();
|
||||
} else if (isUnsupportedTerm()) {
|
||||
printf("%s",prompt);
|
||||
fputs(prompt,stdout);
|
||||
fflush(stdout);
|
||||
return chomp(xgetline(stdin));
|
||||
} else {
|
||||
|
@ -1218,8 +1244,10 @@ int linenoiseHistorySave(const char *filename) {
|
|||
umask(old_umask);
|
||||
if (fp == NULL) return -1;
|
||||
chmod(filename,S_IRUSR|S_IWUSR);
|
||||
for (j = 0; j < history_len; j++)
|
||||
fprintf(fp,"%s\n",history[j]);
|
||||
for (j = 0; j < history_len; j++) {
|
||||
fputs(history[j],fp);
|
||||
fputc('\n',fp);
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue