Multiplexing: API refactoring.

from orig commit c9d36d0, partial changes only, didn't include NoTTY
 support
This commit is contained in:
Данила Горнушко 2023-11-23 01:07:52 +03:00
parent 73645ef92d
commit 16bcf3d8ad
2 changed files with 34 additions and 43 deletions

View file

@ -760,31 +760,33 @@ int linenoiseEditStart(struct linenoiseState *l, char *buf, size_t buflen, const
return 0; return 0;
} }
char *linenoiseEditMore = "If you see this, you are misusing the API: when linenoiseEditFeed() is called, if it returns linenoiseEditMore the user is yet editing the line. See the README file for more information.";
/* This function is part of the multiplexed API of linenoise, see the top /* This function is part of the multiplexed API of linenoise, see the top
* comment on linenoiseEditStart() for more information. Call this function * comment on linenoiseEditStart() for more information. Call this function
* each time there is some data to read from the standard input file * each time there is some data to read from the standard input file
* descriptor. In the case of blocking operations, this function can just be * descriptor. In the case of blocking operations, this function can just be
* called in a loop, and block. * called in a loop, and block.
* *
* The function returns NULL to signal that line editing is still in progress, * The function returns linenoiseEditMore to signal that line editing is still
* that is, the user didn't yet pressed enter / CTRL-D. Otherwise the function * in progress, that is, the user didn't yet pressed enter / CTRL-D. Otherwise
* returns the pointer to the buffer and populates '*len' with the current * the function returns the pointer to the heap-allocated buffer with the
* buffer length. If '*len' is set to -1, some special condition occurred, and * edited line, that the user should free with linenoiseFree().
* the caller may want to check 'errno': *
* On special conditions, NULL is returned and errno is populated:
* *
* EAGAIN if the user pressed Ctrl-C * EAGAIN if the user pressed Ctrl-C
* ENOENT if the user pressed Ctrl-D * ENOENT if the user pressed Ctrl-D
*
* Some other errno: I/O error.
*/ */
char *linenoiseEditFeed(struct linenoiseState *l, int *len) { char *linenoiseEditFeed(struct linenoiseState *l) {
char c; char c;
int nread; int nread;
char seq[3]; char seq[3];
nread = fread(&c, 1, 1, stdin); nread = fread(&c, 1, 1, stdin);
if (nread <= 0) { if (nread <= 0) return NULL;
if (len) *len = l->len;
return l->buf;
}
/* Only autocomplete when the callback is set. It returns < 0 when /* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the * there was an error reading from fd. Otherwise it will return the
@ -792,12 +794,9 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
if (c == 9 && completionCallback != NULL) { if (c == 9 && completionCallback != NULL) {
c = completeLine(l); c = completeLine(l);
/* Return on errors */ /* Return on errors */
if (c < 0) { if (c < 0) return NULL;
if (len) *len = -1;
return l->buf;
}
/* Read next character when 0 */ /* Read next character when 0 */
if (c == 0) return NULL; if (c == 0) return linenoiseEditMore;
} }
switch(c) { switch(c) {
@ -813,12 +812,10 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
refreshLine(l); refreshLine(l);
hintsCallback = hc; hintsCallback = hc;
} }
if (len) *len = l->len; return strdup(l->buf);
return l->buf;
case CTRL_C: /* ctrl-c */ case CTRL_C: /* ctrl-c */
errno = EAGAIN; errno = EAGAIN;
if (len) *len = -1; return NULL;
return l->buf;
case BACKSPACE: /* backspace */ case BACKSPACE: /* backspace */
case 8: /* ctrl-h */ case 8: /* ctrl-h */
linenoiseEditBackspace(l); linenoiseEditBackspace(l);
@ -830,9 +827,8 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
} else { } else {
history_len--; history_len--;
free(history[history_len]); free(history[history_len]);
if (len) *len = -1;
errno = ENOENT; errno = ENOENT;
return l->buf; return NULL;
} }
break; break;
case CTRL_T: /* ctrl-t, swaps current character with previous. */ case CTRL_T: /* ctrl-t, swaps current character with previous. */
@ -912,10 +908,7 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
} }
break; break;
default: default:
if (linenoiseEditInsert(l,c)) { if (linenoiseEditInsert(l,c)) return NULL;
if (len) *len = -1;
return l->buf;
}
break; break;
case CTRL_U: /* Ctrl+u, delete the whole line. */ case CTRL_U: /* Ctrl+u, delete the whole line. */
l->buf[0] = '\0'; l->buf[0] = '\0';
@ -941,7 +934,7 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
linenoiseEditDeletePrevWord(l); linenoiseEditDeletePrevWord(l);
break; break;
} }
return NULL; return linenoiseEditMore;
} }
@ -957,33 +950,28 @@ void linenoiseEditStop(struct linenoiseState *l) {
* In many applications that are not event-drivern, we can just call * In many applications that are not event-drivern, we can just call
* the blocking linenoise API, wait for the user to complete the editing * the blocking linenoise API, wait for the user to complete the editing
* and return the buffer. */ * and return the buffer. */
static int linenoiseBlockingEdit(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) static char *linenoiseBlockingEdit(char *buf, size_t buflen, const char *prompt)
{ {
struct linenoiseState l;
/* Editing without a buffer is invalid. */ /* Editing without a buffer is invalid. */
if (buflen == 0) { if (buflen == 0) {
errno = EINVAL; errno = EINVAL;
return -1; return NULL;
} }
linenoiseEditStart(l,buf,buflen,prompt); linenoiseEditStart(&l,buf,buflen,prompt);
int len; char *res;
while(1) { while((res = linenoiseEditFeed(&l)) == linenoiseEditMore);
char *res = linenoiseEditFeed(l,&len); linenoiseEditStop(&l);
if (res != NULL) break; return res;
}
linenoiseEditStop(l);
return len;
} }
/* The high level function that is the main API of the linenoise library. */ /* The high level function that is the main API of the linenoise library. */
char *linenoise(const char *prompt) { char *linenoise(const char *prompt) {
char buf[LINENOISE_MAX_LINE]; char buf[LINENOISE_MAX_LINE];
int count;
struct linenoiseState l; char *retval = linenoiseBlockingEdit(buf,LINENOISE_MAX_LINE,prompt);
count = linenoiseBlockingEdit(&l,-1,-1,buf,LINENOISE_MAX_LINE,prompt); return retval;
if (count == -1) return NULL;
return strdup(buf);
} }
/* This is just a wrapper the user may want to call in order to make sure /* This is just a wrapper the user may want to call in order to make sure
@ -991,6 +979,7 @@ char *linenoise(const char *prompt) {
* created with. Useful when the main program is using an alternative * created with. Useful when the main program is using an alternative
* allocator. */ * allocator. */
void linenoiseFree(void *ptr) { void linenoiseFree(void *ptr) {
if (ptr == linenoiseEditMore) return; // Protect from API misuse.
free(ptr); free(ptr);
} }

View file

@ -46,6 +46,8 @@ extern "C" {
#include <stddef.h> /* For size_t. */ #include <stddef.h> /* For size_t. */
extern char *linenoiseEditMore;
/* The linenoiseState structure represents the state during line editing. /* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing * We pass this state to functions implementing specific editing
* functionalities. */ * functionalities. */
@ -71,7 +73,7 @@ typedef struct linenoiseCompletions {
/* Non blocking API. */ /* Non blocking API. */
int linenoiseEditStart(struct linenoiseState *l, char *buf, size_t buflen, const char *prompt); int linenoiseEditStart(struct linenoiseState *l, char *buf, size_t buflen, const char *prompt);
char *linenoiseEditFeed(struct linenoiseState *l, int *len); char *linenoiseEditFeed(struct linenoiseState *l);
void linenoiseEditStop(struct linenoiseState *l); void linenoiseEditStop(struct linenoiseState *l);
void linenoiseHide(struct linenoiseState *l); void linenoiseHide(struct linenoiseState *l);
void linenoiseShow(struct linenoiseState *l); void linenoiseShow(struct linenoiseState *l);