Fossil SCM
Update the built-in copy of linenoise to the latest from the GitHub repository ([https://github.com/antirez/linenoise])
Commit
6cf508f6a3835d9d89599b0271ec0589c3040e80ed2e719296ddae861b938178
Parent
09e5d8d9c033c24…
2 files changed
+125
-69
+5
+125
-69
| --- src/linenoise.c | ||
| +++ src/linenoise.c | ||
| @@ -1,9 +1,7 @@ | ||
| 1 | -/* linenoise.c -- VERSION 1.0 | |
| 2 | - * | |
| 3 | - * Guerrilla line editing library against the idea that a line editing lib | |
| 4 | - * needs to be 20,000 lines of C code. | |
| 1 | +/* linenoise.c -- guerrilla line editing library against the idea that a | |
| 2 | + * line editing lib needs to be 20,000 lines of C code. | |
| 5 | 3 | * |
| 6 | 4 | * You can find the latest source code at: |
| 7 | 5 | * |
| 8 | 6 | * http://github.com/antirez/linenoise |
| 9 | 7 | * |
| @@ -10,11 +8,11 @@ | ||
| 10 | 8 | * Does a number of crazy assumptions that happen to be true in 99.9999% of |
| 11 | 9 | * the 2010 UNIX computers around. |
| 12 | 10 | * |
| 13 | 11 | * ------------------------------------------------------------------------ |
| 14 | 12 | * |
| 15 | - * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com> | |
| 13 | + * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> | |
| 16 | 14 | * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> |
| 17 | 15 | * |
| 18 | 16 | * All rights reserved. |
| 19 | 17 | * |
| 20 | 18 | * Redistribution and use in source and binary forms, with or without |
| @@ -105,27 +103,28 @@ | ||
| 105 | 103 | * |
| 106 | 104 | */ |
| 107 | 105 | |
| 108 | 106 | #include <termios.h> |
| 109 | 107 | #include <unistd.h> |
| 110 | -#include <stdarg.h> | |
| 111 | 108 | #include <stdlib.h> |
| 112 | 109 | #include <stdio.h> |
| 113 | 110 | #include <errno.h> |
| 114 | 111 | #include <string.h> |
| 115 | 112 | #include <stdlib.h> |
| 116 | 113 | #include <ctype.h> |
| 114 | +#include <sys/stat.h> | |
| 117 | 115 | #include <sys/types.h> |
| 118 | 116 | #include <sys/ioctl.h> |
| 119 | 117 | #include <unistd.h> |
| 120 | 118 | #include "linenoise.h" |
| 121 | -#include "sqlite3.h" | |
| 122 | 119 | |
| 123 | 120 | #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 |
| 124 | 121 | #define LINENOISE_MAX_LINE 4096 |
| 125 | -static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; | |
| 122 | +static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; | |
| 126 | 123 | static linenoiseCompletionCallback *completionCallback = NULL; |
| 124 | +static linenoiseHintsCallback *hintsCallback = NULL; | |
| 125 | +static linenoiseFreeHintsCallback *freeHintsCallback = NULL; | |
| 127 | 126 | |
| 128 | 127 | static struct termios orig_termios; /* In order to restore at exit.*/ |
| 129 | 128 | static int rawmode = 0; /* For atexit() function to check if restore is needed*/ |
| 130 | 129 | static int mlmode = 0; /* Multi line mode. Default is single line. */ |
| 131 | 130 | static int atexit_registered = 0; /* Register atexit just 1 time. */ |
| @@ -178,58 +177,26 @@ | ||
| 178 | 177 | static void refreshLine(struct linenoiseState *l); |
| 179 | 178 | |
| 180 | 179 | /* Debugging macro. */ |
| 181 | 180 | #if 0 |
| 182 | 181 | FILE *lndebug_fp = NULL; |
| 183 | -#define lndebug(fmt, arg1) \ | |
| 182 | +#define lndebug(...) \ | |
| 184 | 183 | do { \ |
| 185 | 184 | if (lndebug_fp == NULL) { \ |
| 186 | 185 | lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ |
| 187 | 186 | fprintf(lndebug_fp, \ |
| 188 | 187 | "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ |
| 189 | 188 | (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ |
| 190 | 189 | (int)l->maxrows,old_rows); \ |
| 191 | 190 | } \ |
| 192 | - fprintf(lndebug_fp, ", " fmt, arg1); \ | |
| 191 | + fprintf(lndebug_fp, ", " __VA_ARGS__); \ | |
| 193 | 192 | fflush(lndebug_fp); \ |
| 194 | 193 | } while (0) |
| 195 | 194 | #else |
| 196 | -#define lndebug(fmt, arg1) | |
| 195 | +#define lndebug(fmt, ...) | |
| 197 | 196 | #endif |
| 198 | 197 | |
| 199 | -/* =========================== C89 compatibility ============================ */ | |
| 200 | - | |
| 201 | -/* snprintf() is not C89, but sqlite3_vsnprintf() can be adapted. */ | |
| 202 | -static int linenoiseSnprintf(char *str, size_t size, const char *format, ...) { | |
| 203 | - va_list ap; | |
| 204 | - int result; | |
| 205 | - | |
| 206 | - va_start(ap,format); | |
| 207 | - result = (int)strlen(sqlite3_vsnprintf((int)size,str,format,ap)); | |
| 208 | - va_end(ap); | |
| 209 | - | |
| 210 | - return result; | |
| 211 | -} | |
| 212 | -#undef snprintf | |
| 213 | -#define snprintf linenoiseSnprintf | |
| 214 | - | |
| 215 | -/* strdup() is technically not standard C89 despite being in POSIX. */ | |
| 216 | -static char *linenoiseStrdup(const char *s) { | |
| 217 | - size_t size = strlen(s)+1; | |
| 218 | - char *result = malloc(size); | |
| 219 | - | |
| 220 | - if (result) memcpy(result,s,size); | |
| 221 | - | |
| 222 | - return result; | |
| 223 | -} | |
| 224 | -#undef strdup | |
| 225 | -#define strdup linenoiseStrdup | |
| 226 | - | |
| 227 | -/* strcasecmp() is not standard C89. SQLite offers a direct replacement. */ | |
| 228 | -#undef strcasecmp | |
| 229 | -#define strcasecmp sqlite3_stricmp | |
| 230 | - | |
| 231 | 198 | /* ======================= Low level terminal handling ====================== */ |
| 232 | 199 | |
| 233 | 200 | /* Set if to use or not the multi line mode. */ |
| 234 | 201 | void linenoiseSetMultiLine(int ml) { |
| 235 | 202 | mlmode = ml; |
| @@ -245,11 +212,11 @@ | ||
| 245 | 212 | for (j = 0; unsupported_term[j]; j++) |
| 246 | 213 | if (!strcasecmp(term,unsupported_term[j])) return 1; |
| 247 | 214 | return 0; |
| 248 | 215 | } |
| 249 | 216 | |
| 250 | -/* Raw mode */ | |
| 217 | +/* Raw mode: 1960 magic shit. */ | |
| 251 | 218 | static int enableRawMode(int fd) { |
| 252 | 219 | struct termios raw; |
| 253 | 220 | |
| 254 | 221 | if (!isatty(STDIN_FILENO)) goto fatal; |
| 255 | 222 | if (!atexit_registered) { |
| @@ -315,11 +282,10 @@ | ||
| 315 | 282 | } |
| 316 | 283 | |
| 317 | 284 | /* Try to get the number of columns in the current terminal, or assume 80 |
| 318 | 285 | * if it fails. */ |
| 319 | 286 | static int getColumns(int ifd, int ofd) { |
| 320 | -#if !defined(__sun__) | |
| 321 | 287 | struct winsize ws; |
| 322 | 288 | |
| 323 | 289 | if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { |
| 324 | 290 | /* ioctl() failed. Try to query the terminal itself. */ |
| 325 | 291 | int start, cols; |
| @@ -345,11 +311,10 @@ | ||
| 345 | 311 | } else { |
| 346 | 312 | return ws.ws_col; |
| 347 | 313 | } |
| 348 | 314 | |
| 349 | 315 | failed: |
| 350 | -#endif | |
| 351 | 316 | return 80; |
| 352 | 317 | } |
| 353 | 318 | |
| 354 | 319 | /* Clear the screen. Used to handle ctrl+l */ |
| 355 | 320 | void linenoiseClearScreen(void) { |
| @@ -442,10 +407,22 @@ | ||
| 442 | 407 | |
| 443 | 408 | /* Register a callback function to be called for tab-completion. */ |
| 444 | 409 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { |
| 445 | 410 | completionCallback = fn; |
| 446 | 411 | } |
| 412 | + | |
| 413 | +/* Register a hits function to be called to show hits to the user at the | |
| 414 | + * right of the prompt. */ | |
| 415 | +void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) { | |
| 416 | + hintsCallback = fn; | |
| 417 | +} | |
| 418 | + | |
| 419 | +/* Register a function to free the hints returned by the hints callback | |
| 420 | + * registered with linenoiseSetHintsCallback(). */ | |
| 421 | +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) { | |
| 422 | + freeHintsCallback = fn; | |
| 423 | +} | |
| 447 | 424 | |
| 448 | 425 | /* This function is used by the callback function registered by the user |
| 449 | 426 | * in order to add completion options given the input string when the |
| 450 | 427 | * user typed <tab>. See the example.c source code for a very easy to |
| 451 | 428 | * understand example. */ |
| @@ -491,10 +468,34 @@ | ||
| 491 | 468 | } |
| 492 | 469 | |
| 493 | 470 | static void abFree(struct abuf *ab) { |
| 494 | 471 | free(ab->b); |
| 495 | 472 | } |
| 473 | + | |
| 474 | +/* Helper of refreshSingleLine() and refreshMultiLine() to show hints | |
| 475 | + * to the right of the prompt. */ | |
| 476 | +void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { | |
| 477 | + char seq[64]; | |
| 478 | + if (hintsCallback && plen+l->len < l->cols) { | |
| 479 | + int color = -1, bold = 0; | |
| 480 | + char *hint = hintsCallback(l->buf,&color,&bold); | |
| 481 | + if (hint) { | |
| 482 | + int hintlen = strlen(hint); | |
| 483 | + int hintmaxlen = l->cols-(plen+l->len); | |
| 484 | + if (hintlen > hintmaxlen) hintlen = hintmaxlen; | |
| 485 | + if (bold == 1 && color == -1) color = 37; | |
| 486 | + if (color != -1 || bold != 0) | |
| 487 | + snprintf(seq,64,"\033[%d;%d;49m",bold,color); | |
| 488 | + abAppend(ab,seq,strlen(seq)); | |
| 489 | + abAppend(ab,hint,hintlen); | |
| 490 | + if (color != -1 || bold != 0) | |
| 491 | + abAppend(ab,"\033[0m",4); | |
| 492 | + /* Call the function to free the hint returned. */ | |
| 493 | + if (freeHintsCallback) freeHintsCallback(hint); | |
| 494 | + } | |
| 495 | + } | |
| 496 | +} | |
| 496 | 497 | |
| 497 | 498 | /* Single line low level line refresh. |
| 498 | 499 | * |
| 499 | 500 | * Rewrite the currently edited line accordingly to the buffer content, |
| 500 | 501 | * cursor position, and number of columns of the terminal. */ |
| @@ -521,10 +522,12 @@ | ||
| 521 | 522 | snprintf(seq,64,"\r"); |
| 522 | 523 | abAppend(&ab,seq,strlen(seq)); |
| 523 | 524 | /* Write the prompt and the current buffer content */ |
| 524 | 525 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 525 | 526 | abAppend(&ab,buf,len); |
| 527 | + /* Show hits if any. */ | |
| 528 | + refreshShowHints(&ab,l,plen); | |
| 526 | 529 | /* Erase to right */ |
| 527 | 530 | snprintf(seq,64,"\x1b[0K"); |
| 528 | 531 | abAppend(&ab,seq,strlen(seq)); |
| 529 | 532 | /* Move cursor to original position. */ |
| 530 | 533 | snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); |
| @@ -560,31 +563,34 @@ | ||
| 560 | 563 | abAppend(&ab,seq,strlen(seq)); |
| 561 | 564 | } |
| 562 | 565 | |
| 563 | 566 | /* Now for every row clear it, go up. */ |
| 564 | 567 | for (j = 0; j < old_rows-1; j++) { |
| 565 | - lndebug("clear+up", 0); | |
| 568 | + lndebug("clear+up"); | |
| 566 | 569 | snprintf(seq,64,"\r\x1b[0K\x1b[1A"); |
| 567 | 570 | abAppend(&ab,seq,strlen(seq)); |
| 568 | 571 | } |
| 569 | 572 | |
| 570 | 573 | /* Clean the top line. */ |
| 571 | - lndebug("clear", 0); | |
| 574 | + lndebug("clear"); | |
| 572 | 575 | snprintf(seq,64,"\r\x1b[0K"); |
| 573 | 576 | abAppend(&ab,seq,strlen(seq)); |
| 574 | 577 | |
| 575 | 578 | /* Write the prompt and the current buffer content */ |
| 576 | 579 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 577 | 580 | abAppend(&ab,l->buf,l->len); |
| 578 | 581 | |
| 582 | + /* Show hits if any. */ | |
| 583 | + refreshShowHints(&ab,l,plen); | |
| 584 | + | |
| 579 | 585 | /* If we are at the very end of the screen with our prompt, we need to |
| 580 | 586 | * emit a newline and move the prompt to the first column. */ |
| 581 | 587 | if (l->pos && |
| 582 | 588 | l->pos == l->len && |
| 583 | 589 | (l->pos+plen) % l->cols == 0) |
| 584 | 590 | { |
| 585 | - lndebug("<newline>", 0); | |
| 591 | + lndebug("<newline>"); | |
| 586 | 592 | abAppend(&ab,"\n",1); |
| 587 | 593 | snprintf(seq,64,"\r"); |
| 588 | 594 | abAppend(&ab,seq,strlen(seq)); |
| 589 | 595 | rows++; |
| 590 | 596 | if (rows > (int)l->maxrows) l->maxrows = rows; |
| @@ -608,11 +614,11 @@ | ||
| 608 | 614 | snprintf(seq,64,"\r\x1b[%dC", col); |
| 609 | 615 | else |
| 610 | 616 | snprintf(seq,64,"\r"); |
| 611 | 617 | abAppend(&ab,seq,strlen(seq)); |
| 612 | 618 | |
| 613 | - lndebug("\n", 0); | |
| 619 | + lndebug("\n"); | |
| 614 | 620 | l->oldpos = l->pos; |
| 615 | 621 | |
| 616 | 622 | if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ |
| 617 | 623 | abFree(&ab); |
| 618 | 624 | } |
| @@ -634,11 +640,11 @@ | ||
| 634 | 640 | if (l->len == l->pos) { |
| 635 | 641 | l->buf[l->pos] = c; |
| 636 | 642 | l->pos++; |
| 637 | 643 | l->len++; |
| 638 | 644 | l->buf[l->len] = '\0'; |
| 639 | - if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) { | |
| 645 | + if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { | |
| 640 | 646 | /* Avoid a full update of the line in the |
| 641 | 647 | * trivial case. */ |
| 642 | 648 | if (write(l->ofd,&c,1) == -1) return -1; |
| 643 | 649 | } else { |
| 644 | 650 | refreshLine(l); |
| @@ -808,10 +814,18 @@ | ||
| 808 | 814 | switch(c) { |
| 809 | 815 | case ENTER: /* enter */ |
| 810 | 816 | history_len--; |
| 811 | 817 | free(history[history_len]); |
| 812 | 818 | if (mlmode) linenoiseEditMoveEnd(&l); |
| 819 | + if (hintsCallback) { | |
| 820 | + /* Force a refresh without hints to leave the previous | |
| 821 | + * line as the user typed it after a newline. */ | |
| 822 | + linenoiseHintsCallback *hc = hintsCallback; | |
| 823 | + hintsCallback = NULL; | |
| 824 | + refreshLine(&l); | |
| 825 | + hintsCallback = hc; | |
| 826 | + } | |
| 813 | 827 | return (int)l.len; |
| 814 | 828 | case CTRL_C: /* ctrl-c */ |
| 815 | 829 | errno = EAGAIN; |
| 816 | 830 | return -1; |
| 817 | 831 | case BACKSPACE: /* backspace */ |
| @@ -954,11 +968,11 @@ | ||
| 954 | 968 | memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ |
| 955 | 969 | quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ |
| 956 | 970 | if (memcmp(quit,"quit",sizeof(quit)) == 0) break; |
| 957 | 971 | |
| 958 | 972 | printf("'%c' %02x (%d) (type quit to exit)\n", |
| 959 | - isprint((int)c) ? c : '?', (int)c, (int)c); | |
| 973 | + isprint(c) ? c : '?', (int)c, (int)c); | |
| 960 | 974 | printf("\r"); /* Go left edge manually, we are in raw mode. */ |
| 961 | 975 | fflush(stdout); |
| 962 | 976 | } |
| 963 | 977 | disableRawMode(STDIN_FILENO); |
| 964 | 978 | } |
| @@ -970,27 +984,53 @@ | ||
| 970 | 984 | |
| 971 | 985 | if (buflen == 0) { |
| 972 | 986 | errno = EINVAL; |
| 973 | 987 | return -1; |
| 974 | 988 | } |
| 975 | - if (!isatty(STDIN_FILENO)) { | |
| 976 | - /* Not a tty: read from file / pipe. */ | |
| 977 | - if (fgets(buf, buflen, stdin) == NULL) return -1; | |
| 978 | - count = strlen(buf); | |
| 979 | - if (count && buf[count-1] == '\n') { | |
| 980 | - count--; | |
| 981 | - buf[count] = '\0'; | |
| 982 | - } | |
| 983 | - } else { | |
| 984 | - /* Interactive editing. */ | |
| 985 | - if (enableRawMode(STDIN_FILENO) == -1) return -1; | |
| 986 | - count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); | |
| 987 | - disableRawMode(STDIN_FILENO); | |
| 988 | - printf("\n"); | |
| 989 | - } | |
| 989 | + | |
| 990 | + if (enableRawMode(STDIN_FILENO) == -1) return -1; | |
| 991 | + count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); | |
| 992 | + disableRawMode(STDIN_FILENO); | |
| 993 | + printf("\n"); | |
| 990 | 994 | return count; |
| 991 | 995 | } |
| 996 | + | |
| 997 | +/* This function is called when linenoise() is called with the standard | |
| 998 | + * input file descriptor not attached to a TTY. So for example when the | |
| 999 | + * program using linenoise is called in pipe or with a file redirected | |
| 1000 | + * to its standard input. In this case, we want to be able to return the | |
| 1001 | + * line regardless of its length (by default we are limited to 4k). */ | |
| 1002 | +static char *linenoiseNoTTY(void) { | |
| 1003 | + char *line = NULL; | |
| 1004 | + size_t len = 0, maxlen = 0; | |
| 1005 | + | |
| 1006 | + while(1) { | |
| 1007 | + if (len == maxlen) { | |
| 1008 | + if (maxlen == 0) maxlen = 16; | |
| 1009 | + maxlen *= 2; | |
| 1010 | + char *oldval = line; | |
| 1011 | + line = realloc(line,maxlen); | |
| 1012 | + if (line == NULL) { | |
| 1013 | + if (oldval) free(oldval); | |
| 1014 | + return NULL; | |
| 1015 | + } | |
| 1016 | + } | |
| 1017 | + int c = fgetc(stdin); | |
| 1018 | + if (c == EOF || c == '\n') { | |
| 1019 | + if (c == EOF && len == 0) { | |
| 1020 | + free(line); | |
| 1021 | + return NULL; | |
| 1022 | + } else { | |
| 1023 | + line[len] = '\0'; | |
| 1024 | + return line; | |
| 1025 | + } | |
| 1026 | + } else { | |
| 1027 | + line[len] = c; | |
| 1028 | + len++; | |
| 1029 | + } | |
| 1030 | + } | |
| 1031 | +} | |
| 992 | 1032 | |
| 993 | 1033 | /* The high level function that is the main API of the linenoise library. |
| 994 | 1034 | * This function checks if the terminal has basic capabilities, just checking |
| 995 | 1035 | * for a blacklist of stupid terminals, and later either calls the line |
| 996 | 1036 | * editing function or uses dummy fgets() so that you will be able to type |
| @@ -997,11 +1037,15 @@ | ||
| 997 | 1037 | * something even in the most desperate of the conditions. */ |
| 998 | 1038 | char *linenoise(const char *prompt) { |
| 999 | 1039 | char buf[LINENOISE_MAX_LINE]; |
| 1000 | 1040 | int count; |
| 1001 | 1041 | |
| 1002 | - if (isUnsupportedTerm()) { | |
| 1042 | + if (!isatty(STDIN_FILENO)) { | |
| 1043 | + /* Not a tty: read from file / pipe. In this mode we don't want any | |
| 1044 | + * limit to the line size, so we call a function to handle that. */ | |
| 1045 | + return linenoiseNoTTY(); | |
| 1046 | + } else if (isUnsupportedTerm()) { | |
| 1003 | 1047 | size_t len; |
| 1004 | 1048 | |
| 1005 | 1049 | printf("%s",prompt); |
| 1006 | 1050 | fflush(stdout); |
| 1007 | 1051 | if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; |
| @@ -1015,10 +1059,18 @@ | ||
| 1015 | 1059 | count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); |
| 1016 | 1060 | if (count == -1) return NULL; |
| 1017 | 1061 | return strdup(buf); |
| 1018 | 1062 | } |
| 1019 | 1063 | } |
| 1064 | + | |
| 1065 | +/* This is just a wrapper the user may want to call in order to make sure | |
| 1066 | + * the linenoise returned buffer is freed with the same allocator it was | |
| 1067 | + * created with. Useful when the main program is using an alternative | |
| 1068 | + * allocator. */ | |
| 1069 | +void linenoiseFree(void *ptr) { | |
| 1070 | + free(ptr); | |
| 1071 | +} | |
| 1020 | 1072 | |
| 1021 | 1073 | /* ================================ History ================================= */ |
| 1022 | 1074 | |
| 1023 | 1075 | /* Free the history, but does not reset it. Only used when we have to |
| 1024 | 1076 | * exit() to avoid memory leaks are reported by valgrind & co. */ |
| @@ -1107,14 +1159,18 @@ | ||
| 1107 | 1159 | } |
| 1108 | 1160 | |
| 1109 | 1161 | /* Save the history in the specified file. On success 0 is returned |
| 1110 | 1162 | * otherwise -1 is returned. */ |
| 1111 | 1163 | int linenoiseHistorySave(const char *filename) { |
| 1112 | - FILE *fp = fopen(filename,"w"); | |
| 1164 | + mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO); | |
| 1165 | + FILE *fp; | |
| 1113 | 1166 | int j; |
| 1114 | 1167 | |
| 1168 | + fp = fopen(filename,"w"); | |
| 1169 | + umask(old_umask); | |
| 1115 | 1170 | if (fp == NULL) return -1; |
| 1171 | + chmod(filename,S_IRUSR|S_IWUSR); | |
| 1116 | 1172 | for (j = 0; j < history_len; j++) |
| 1117 | 1173 | fprintf(fp,"%s\n",history[j]); |
| 1118 | 1174 | fclose(fp); |
| 1119 | 1175 | return 0; |
| 1120 | 1176 | } |
| 1121 | 1177 |
| --- src/linenoise.c | |
| +++ src/linenoise.c | |
| @@ -1,9 +1,7 @@ | |
| 1 | /* linenoise.c -- VERSION 1.0 |
| 2 | * |
| 3 | * Guerrilla line editing library against the idea that a line editing lib |
| 4 | * needs to be 20,000 lines of C code. |
| 5 | * |
| 6 | * You can find the latest source code at: |
| 7 | * |
| 8 | * http://github.com/antirez/linenoise |
| 9 | * |
| @@ -10,11 +8,11 @@ | |
| 10 | * Does a number of crazy assumptions that happen to be true in 99.9999% of |
| 11 | * the 2010 UNIX computers around. |
| 12 | * |
| 13 | * ------------------------------------------------------------------------ |
| 14 | * |
| 15 | * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com> |
| 16 | * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> |
| 17 | * |
| 18 | * All rights reserved. |
| 19 | * |
| 20 | * Redistribution and use in source and binary forms, with or without |
| @@ -105,27 +103,28 @@ | |
| 105 | * |
| 106 | */ |
| 107 | |
| 108 | #include <termios.h> |
| 109 | #include <unistd.h> |
| 110 | #include <stdarg.h> |
| 111 | #include <stdlib.h> |
| 112 | #include <stdio.h> |
| 113 | #include <errno.h> |
| 114 | #include <string.h> |
| 115 | #include <stdlib.h> |
| 116 | #include <ctype.h> |
| 117 | #include <sys/types.h> |
| 118 | #include <sys/ioctl.h> |
| 119 | #include <unistd.h> |
| 120 | #include "linenoise.h" |
| 121 | #include "sqlite3.h" |
| 122 | |
| 123 | #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 |
| 124 | #define LINENOISE_MAX_LINE 4096 |
| 125 | static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; |
| 126 | static linenoiseCompletionCallback *completionCallback = NULL; |
| 127 | |
| 128 | static struct termios orig_termios; /* In order to restore at exit.*/ |
| 129 | static int rawmode = 0; /* For atexit() function to check if restore is needed*/ |
| 130 | static int mlmode = 0; /* Multi line mode. Default is single line. */ |
| 131 | static int atexit_registered = 0; /* Register atexit just 1 time. */ |
| @@ -178,58 +177,26 @@ | |
| 178 | static void refreshLine(struct linenoiseState *l); |
| 179 | |
| 180 | /* Debugging macro. */ |
| 181 | #if 0 |
| 182 | FILE *lndebug_fp = NULL; |
| 183 | #define lndebug(fmt, arg1) \ |
| 184 | do { \ |
| 185 | if (lndebug_fp == NULL) { \ |
| 186 | lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ |
| 187 | fprintf(lndebug_fp, \ |
| 188 | "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ |
| 189 | (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ |
| 190 | (int)l->maxrows,old_rows); \ |
| 191 | } \ |
| 192 | fprintf(lndebug_fp, ", " fmt, arg1); \ |
| 193 | fflush(lndebug_fp); \ |
| 194 | } while (0) |
| 195 | #else |
| 196 | #define lndebug(fmt, arg1) |
| 197 | #endif |
| 198 | |
| 199 | /* =========================== C89 compatibility ============================ */ |
| 200 | |
| 201 | /* snprintf() is not C89, but sqlite3_vsnprintf() can be adapted. */ |
| 202 | static int linenoiseSnprintf(char *str, size_t size, const char *format, ...) { |
| 203 | va_list ap; |
| 204 | int result; |
| 205 | |
| 206 | va_start(ap,format); |
| 207 | result = (int)strlen(sqlite3_vsnprintf((int)size,str,format,ap)); |
| 208 | va_end(ap); |
| 209 | |
| 210 | return result; |
| 211 | } |
| 212 | #undef snprintf |
| 213 | #define snprintf linenoiseSnprintf |
| 214 | |
| 215 | /* strdup() is technically not standard C89 despite being in POSIX. */ |
| 216 | static char *linenoiseStrdup(const char *s) { |
| 217 | size_t size = strlen(s)+1; |
| 218 | char *result = malloc(size); |
| 219 | |
| 220 | if (result) memcpy(result,s,size); |
| 221 | |
| 222 | return result; |
| 223 | } |
| 224 | #undef strdup |
| 225 | #define strdup linenoiseStrdup |
| 226 | |
| 227 | /* strcasecmp() is not standard C89. SQLite offers a direct replacement. */ |
| 228 | #undef strcasecmp |
| 229 | #define strcasecmp sqlite3_stricmp |
| 230 | |
| 231 | /* ======================= Low level terminal handling ====================== */ |
| 232 | |
| 233 | /* Set if to use or not the multi line mode. */ |
| 234 | void linenoiseSetMultiLine(int ml) { |
| 235 | mlmode = ml; |
| @@ -245,11 +212,11 @@ | |
| 245 | for (j = 0; unsupported_term[j]; j++) |
| 246 | if (!strcasecmp(term,unsupported_term[j])) return 1; |
| 247 | return 0; |
| 248 | } |
| 249 | |
| 250 | /* Raw mode */ |
| 251 | static int enableRawMode(int fd) { |
| 252 | struct termios raw; |
| 253 | |
| 254 | if (!isatty(STDIN_FILENO)) goto fatal; |
| 255 | if (!atexit_registered) { |
| @@ -315,11 +282,10 @@ | |
| 315 | } |
| 316 | |
| 317 | /* Try to get the number of columns in the current terminal, or assume 80 |
| 318 | * if it fails. */ |
| 319 | static int getColumns(int ifd, int ofd) { |
| 320 | #if !defined(__sun__) |
| 321 | struct winsize ws; |
| 322 | |
| 323 | if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { |
| 324 | /* ioctl() failed. Try to query the terminal itself. */ |
| 325 | int start, cols; |
| @@ -345,11 +311,10 @@ | |
| 345 | } else { |
| 346 | return ws.ws_col; |
| 347 | } |
| 348 | |
| 349 | failed: |
| 350 | #endif |
| 351 | return 80; |
| 352 | } |
| 353 | |
| 354 | /* Clear the screen. Used to handle ctrl+l */ |
| 355 | void linenoiseClearScreen(void) { |
| @@ -442,10 +407,22 @@ | |
| 442 | |
| 443 | /* Register a callback function to be called for tab-completion. */ |
| 444 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { |
| 445 | completionCallback = fn; |
| 446 | } |
| 447 | |
| 448 | /* This function is used by the callback function registered by the user |
| 449 | * in order to add completion options given the input string when the |
| 450 | * user typed <tab>. See the example.c source code for a very easy to |
| 451 | * understand example. */ |
| @@ -491,10 +468,34 @@ | |
| 491 | } |
| 492 | |
| 493 | static void abFree(struct abuf *ab) { |
| 494 | free(ab->b); |
| 495 | } |
| 496 | |
| 497 | /* Single line low level line refresh. |
| 498 | * |
| 499 | * Rewrite the currently edited line accordingly to the buffer content, |
| 500 | * cursor position, and number of columns of the terminal. */ |
| @@ -521,10 +522,12 @@ | |
| 521 | snprintf(seq,64,"\r"); |
| 522 | abAppend(&ab,seq,strlen(seq)); |
| 523 | /* Write the prompt and the current buffer content */ |
| 524 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 525 | abAppend(&ab,buf,len); |
| 526 | /* Erase to right */ |
| 527 | snprintf(seq,64,"\x1b[0K"); |
| 528 | abAppend(&ab,seq,strlen(seq)); |
| 529 | /* Move cursor to original position. */ |
| 530 | snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); |
| @@ -560,31 +563,34 @@ | |
| 560 | abAppend(&ab,seq,strlen(seq)); |
| 561 | } |
| 562 | |
| 563 | /* Now for every row clear it, go up. */ |
| 564 | for (j = 0; j < old_rows-1; j++) { |
| 565 | lndebug("clear+up", 0); |
| 566 | snprintf(seq,64,"\r\x1b[0K\x1b[1A"); |
| 567 | abAppend(&ab,seq,strlen(seq)); |
| 568 | } |
| 569 | |
| 570 | /* Clean the top line. */ |
| 571 | lndebug("clear", 0); |
| 572 | snprintf(seq,64,"\r\x1b[0K"); |
| 573 | abAppend(&ab,seq,strlen(seq)); |
| 574 | |
| 575 | /* Write the prompt and the current buffer content */ |
| 576 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 577 | abAppend(&ab,l->buf,l->len); |
| 578 | |
| 579 | /* If we are at the very end of the screen with our prompt, we need to |
| 580 | * emit a newline and move the prompt to the first column. */ |
| 581 | if (l->pos && |
| 582 | l->pos == l->len && |
| 583 | (l->pos+plen) % l->cols == 0) |
| 584 | { |
| 585 | lndebug("<newline>", 0); |
| 586 | abAppend(&ab,"\n",1); |
| 587 | snprintf(seq,64,"\r"); |
| 588 | abAppend(&ab,seq,strlen(seq)); |
| 589 | rows++; |
| 590 | if (rows > (int)l->maxrows) l->maxrows = rows; |
| @@ -608,11 +614,11 @@ | |
| 608 | snprintf(seq,64,"\r\x1b[%dC", col); |
| 609 | else |
| 610 | snprintf(seq,64,"\r"); |
| 611 | abAppend(&ab,seq,strlen(seq)); |
| 612 | |
| 613 | lndebug("\n", 0); |
| 614 | l->oldpos = l->pos; |
| 615 | |
| 616 | if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ |
| 617 | abFree(&ab); |
| 618 | } |
| @@ -634,11 +640,11 @@ | |
| 634 | if (l->len == l->pos) { |
| 635 | l->buf[l->pos] = c; |
| 636 | l->pos++; |
| 637 | l->len++; |
| 638 | l->buf[l->len] = '\0'; |
| 639 | if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) { |
| 640 | /* Avoid a full update of the line in the |
| 641 | * trivial case. */ |
| 642 | if (write(l->ofd,&c,1) == -1) return -1; |
| 643 | } else { |
| 644 | refreshLine(l); |
| @@ -808,10 +814,18 @@ | |
| 808 | switch(c) { |
| 809 | case ENTER: /* enter */ |
| 810 | history_len--; |
| 811 | free(history[history_len]); |
| 812 | if (mlmode) linenoiseEditMoveEnd(&l); |
| 813 | return (int)l.len; |
| 814 | case CTRL_C: /* ctrl-c */ |
| 815 | errno = EAGAIN; |
| 816 | return -1; |
| 817 | case BACKSPACE: /* backspace */ |
| @@ -954,11 +968,11 @@ | |
| 954 | memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ |
| 955 | quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ |
| 956 | if (memcmp(quit,"quit",sizeof(quit)) == 0) break; |
| 957 | |
| 958 | printf("'%c' %02x (%d) (type quit to exit)\n", |
| 959 | isprint((int)c) ? c : '?', (int)c, (int)c); |
| 960 | printf("\r"); /* Go left edge manually, we are in raw mode. */ |
| 961 | fflush(stdout); |
| 962 | } |
| 963 | disableRawMode(STDIN_FILENO); |
| 964 | } |
| @@ -970,27 +984,53 @@ | |
| 970 | |
| 971 | if (buflen == 0) { |
| 972 | errno = EINVAL; |
| 973 | return -1; |
| 974 | } |
| 975 | if (!isatty(STDIN_FILENO)) { |
| 976 | /* Not a tty: read from file / pipe. */ |
| 977 | if (fgets(buf, buflen, stdin) == NULL) return -1; |
| 978 | count = strlen(buf); |
| 979 | if (count && buf[count-1] == '\n') { |
| 980 | count--; |
| 981 | buf[count] = '\0'; |
| 982 | } |
| 983 | } else { |
| 984 | /* Interactive editing. */ |
| 985 | if (enableRawMode(STDIN_FILENO) == -1) return -1; |
| 986 | count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); |
| 987 | disableRawMode(STDIN_FILENO); |
| 988 | printf("\n"); |
| 989 | } |
| 990 | return count; |
| 991 | } |
| 992 | |
| 993 | /* The high level function that is the main API of the linenoise library. |
| 994 | * This function checks if the terminal has basic capabilities, just checking |
| 995 | * for a blacklist of stupid terminals, and later either calls the line |
| 996 | * editing function or uses dummy fgets() so that you will be able to type |
| @@ -997,11 +1037,15 @@ | |
| 997 | * something even in the most desperate of the conditions. */ |
| 998 | char *linenoise(const char *prompt) { |
| 999 | char buf[LINENOISE_MAX_LINE]; |
| 1000 | int count; |
| 1001 | |
| 1002 | if (isUnsupportedTerm()) { |
| 1003 | size_t len; |
| 1004 | |
| 1005 | printf("%s",prompt); |
| 1006 | fflush(stdout); |
| 1007 | if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; |
| @@ -1015,10 +1059,18 @@ | |
| 1015 | count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); |
| 1016 | if (count == -1) return NULL; |
| 1017 | return strdup(buf); |
| 1018 | } |
| 1019 | } |
| 1020 | |
| 1021 | /* ================================ History ================================= */ |
| 1022 | |
| 1023 | /* Free the history, but does not reset it. Only used when we have to |
| 1024 | * exit() to avoid memory leaks are reported by valgrind & co. */ |
| @@ -1107,14 +1159,18 @@ | |
| 1107 | } |
| 1108 | |
| 1109 | /* Save the history in the specified file. On success 0 is returned |
| 1110 | * otherwise -1 is returned. */ |
| 1111 | int linenoiseHistorySave(const char *filename) { |
| 1112 | FILE *fp = fopen(filename,"w"); |
| 1113 | int j; |
| 1114 | |
| 1115 | if (fp == NULL) return -1; |
| 1116 | for (j = 0; j < history_len; j++) |
| 1117 | fprintf(fp,"%s\n",history[j]); |
| 1118 | fclose(fp); |
| 1119 | return 0; |
| 1120 | } |
| 1121 |
| --- src/linenoise.c | |
| +++ src/linenoise.c | |
| @@ -1,9 +1,7 @@ | |
| 1 | /* linenoise.c -- guerrilla line editing library against the idea that a |
| 2 | * line editing lib needs to be 20,000 lines of C code. |
| 3 | * |
| 4 | * You can find the latest source code at: |
| 5 | * |
| 6 | * http://github.com/antirez/linenoise |
| 7 | * |
| @@ -10,11 +8,11 @@ | |
| 8 | * Does a number of crazy assumptions that happen to be true in 99.9999% of |
| 9 | * the 2010 UNIX computers around. |
| 10 | * |
| 11 | * ------------------------------------------------------------------------ |
| 12 | * |
| 13 | * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> |
| 14 | * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> |
| 15 | * |
| 16 | * All rights reserved. |
| 17 | * |
| 18 | * Redistribution and use in source and binary forms, with or without |
| @@ -105,27 +103,28 @@ | |
| 103 | * |
| 104 | */ |
| 105 | |
| 106 | #include <termios.h> |
| 107 | #include <unistd.h> |
| 108 | #include <stdlib.h> |
| 109 | #include <stdio.h> |
| 110 | #include <errno.h> |
| 111 | #include <string.h> |
| 112 | #include <stdlib.h> |
| 113 | #include <ctype.h> |
| 114 | #include <sys/stat.h> |
| 115 | #include <sys/types.h> |
| 116 | #include <sys/ioctl.h> |
| 117 | #include <unistd.h> |
| 118 | #include "linenoise.h" |
| 119 | |
| 120 | #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 |
| 121 | #define LINENOISE_MAX_LINE 4096 |
| 122 | static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; |
| 123 | static linenoiseCompletionCallback *completionCallback = NULL; |
| 124 | static linenoiseHintsCallback *hintsCallback = NULL; |
| 125 | static linenoiseFreeHintsCallback *freeHintsCallback = NULL; |
| 126 | |
| 127 | static struct termios orig_termios; /* In order to restore at exit.*/ |
| 128 | static int rawmode = 0; /* For atexit() function to check if restore is needed*/ |
| 129 | static int mlmode = 0; /* Multi line mode. Default is single line. */ |
| 130 | static int atexit_registered = 0; /* Register atexit just 1 time. */ |
| @@ -178,58 +177,26 @@ | |
| 177 | static void refreshLine(struct linenoiseState *l); |
| 178 | |
| 179 | /* Debugging macro. */ |
| 180 | #if 0 |
| 181 | FILE *lndebug_fp = NULL; |
| 182 | #define lndebug(...) \ |
| 183 | do { \ |
| 184 | if (lndebug_fp == NULL) { \ |
| 185 | lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ |
| 186 | fprintf(lndebug_fp, \ |
| 187 | "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ |
| 188 | (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ |
| 189 | (int)l->maxrows,old_rows); \ |
| 190 | } \ |
| 191 | fprintf(lndebug_fp, ", " __VA_ARGS__); \ |
| 192 | fflush(lndebug_fp); \ |
| 193 | } while (0) |
| 194 | #else |
| 195 | #define lndebug(fmt, ...) |
| 196 | #endif |
| 197 | |
| 198 | /* ======================= Low level terminal handling ====================== */ |
| 199 | |
| 200 | /* Set if to use or not the multi line mode. */ |
| 201 | void linenoiseSetMultiLine(int ml) { |
| 202 | mlmode = ml; |
| @@ -245,11 +212,11 @@ | |
| 212 | for (j = 0; unsupported_term[j]; j++) |
| 213 | if (!strcasecmp(term,unsupported_term[j])) return 1; |
| 214 | return 0; |
| 215 | } |
| 216 | |
| 217 | /* Raw mode: 1960 magic shit. */ |
| 218 | static int enableRawMode(int fd) { |
| 219 | struct termios raw; |
| 220 | |
| 221 | if (!isatty(STDIN_FILENO)) goto fatal; |
| 222 | if (!atexit_registered) { |
| @@ -315,11 +282,10 @@ | |
| 282 | } |
| 283 | |
| 284 | /* Try to get the number of columns in the current terminal, or assume 80 |
| 285 | * if it fails. */ |
| 286 | static int getColumns(int ifd, int ofd) { |
| 287 | struct winsize ws; |
| 288 | |
| 289 | if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { |
| 290 | /* ioctl() failed. Try to query the terminal itself. */ |
| 291 | int start, cols; |
| @@ -345,11 +311,10 @@ | |
| 311 | } else { |
| 312 | return ws.ws_col; |
| 313 | } |
| 314 | |
| 315 | failed: |
| 316 | return 80; |
| 317 | } |
| 318 | |
| 319 | /* Clear the screen. Used to handle ctrl+l */ |
| 320 | void linenoiseClearScreen(void) { |
| @@ -442,10 +407,22 @@ | |
| 407 | |
| 408 | /* Register a callback function to be called for tab-completion. */ |
| 409 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { |
| 410 | completionCallback = fn; |
| 411 | } |
| 412 | |
| 413 | /* Register a hits function to be called to show hits to the user at the |
| 414 | * right of the prompt. */ |
| 415 | void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) { |
| 416 | hintsCallback = fn; |
| 417 | } |
| 418 | |
| 419 | /* Register a function to free the hints returned by the hints callback |
| 420 | * registered with linenoiseSetHintsCallback(). */ |
| 421 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) { |
| 422 | freeHintsCallback = fn; |
| 423 | } |
| 424 | |
| 425 | /* This function is used by the callback function registered by the user |
| 426 | * in order to add completion options given the input string when the |
| 427 | * user typed <tab>. See the example.c source code for a very easy to |
| 428 | * understand example. */ |
| @@ -491,10 +468,34 @@ | |
| 468 | } |
| 469 | |
| 470 | static void abFree(struct abuf *ab) { |
| 471 | free(ab->b); |
| 472 | } |
| 473 | |
| 474 | /* Helper of refreshSingleLine() and refreshMultiLine() to show hints |
| 475 | * to the right of the prompt. */ |
| 476 | void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { |
| 477 | char seq[64]; |
| 478 | if (hintsCallback && plen+l->len < l->cols) { |
| 479 | int color = -1, bold = 0; |
| 480 | char *hint = hintsCallback(l->buf,&color,&bold); |
| 481 | if (hint) { |
| 482 | int hintlen = strlen(hint); |
| 483 | int hintmaxlen = l->cols-(plen+l->len); |
| 484 | if (hintlen > hintmaxlen) hintlen = hintmaxlen; |
| 485 | if (bold == 1 && color == -1) color = 37; |
| 486 | if (color != -1 || bold != 0) |
| 487 | snprintf(seq,64,"\033[%d;%d;49m",bold,color); |
| 488 | abAppend(ab,seq,strlen(seq)); |
| 489 | abAppend(ab,hint,hintlen); |
| 490 | if (color != -1 || bold != 0) |
| 491 | abAppend(ab,"\033[0m",4); |
| 492 | /* Call the function to free the hint returned. */ |
| 493 | if (freeHintsCallback) freeHintsCallback(hint); |
| 494 | } |
| 495 | } |
| 496 | } |
| 497 | |
| 498 | /* Single line low level line refresh. |
| 499 | * |
| 500 | * Rewrite the currently edited line accordingly to the buffer content, |
| 501 | * cursor position, and number of columns of the terminal. */ |
| @@ -521,10 +522,12 @@ | |
| 522 | snprintf(seq,64,"\r"); |
| 523 | abAppend(&ab,seq,strlen(seq)); |
| 524 | /* Write the prompt and the current buffer content */ |
| 525 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 526 | abAppend(&ab,buf,len); |
| 527 | /* Show hits if any. */ |
| 528 | refreshShowHints(&ab,l,plen); |
| 529 | /* Erase to right */ |
| 530 | snprintf(seq,64,"\x1b[0K"); |
| 531 | abAppend(&ab,seq,strlen(seq)); |
| 532 | /* Move cursor to original position. */ |
| 533 | snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); |
| @@ -560,31 +563,34 @@ | |
| 563 | abAppend(&ab,seq,strlen(seq)); |
| 564 | } |
| 565 | |
| 566 | /* Now for every row clear it, go up. */ |
| 567 | for (j = 0; j < old_rows-1; j++) { |
| 568 | lndebug("clear+up"); |
| 569 | snprintf(seq,64,"\r\x1b[0K\x1b[1A"); |
| 570 | abAppend(&ab,seq,strlen(seq)); |
| 571 | } |
| 572 | |
| 573 | /* Clean the top line. */ |
| 574 | lndebug("clear"); |
| 575 | snprintf(seq,64,"\r\x1b[0K"); |
| 576 | abAppend(&ab,seq,strlen(seq)); |
| 577 | |
| 578 | /* Write the prompt and the current buffer content */ |
| 579 | abAppend(&ab,l->prompt,strlen(l->prompt)); |
| 580 | abAppend(&ab,l->buf,l->len); |
| 581 | |
| 582 | /* Show hits if any. */ |
| 583 | refreshShowHints(&ab,l,plen); |
| 584 | |
| 585 | /* If we are at the very end of the screen with our prompt, we need to |
| 586 | * emit a newline and move the prompt to the first column. */ |
| 587 | if (l->pos && |
| 588 | l->pos == l->len && |
| 589 | (l->pos+plen) % l->cols == 0) |
| 590 | { |
| 591 | lndebug("<newline>"); |
| 592 | abAppend(&ab,"\n",1); |
| 593 | snprintf(seq,64,"\r"); |
| 594 | abAppend(&ab,seq,strlen(seq)); |
| 595 | rows++; |
| 596 | if (rows > (int)l->maxrows) l->maxrows = rows; |
| @@ -608,11 +614,11 @@ | |
| 614 | snprintf(seq,64,"\r\x1b[%dC", col); |
| 615 | else |
| 616 | snprintf(seq,64,"\r"); |
| 617 | abAppend(&ab,seq,strlen(seq)); |
| 618 | |
| 619 | lndebug("\n"); |
| 620 | l->oldpos = l->pos; |
| 621 | |
| 622 | if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ |
| 623 | abFree(&ab); |
| 624 | } |
| @@ -634,11 +640,11 @@ | |
| 640 | if (l->len == l->pos) { |
| 641 | l->buf[l->pos] = c; |
| 642 | l->pos++; |
| 643 | l->len++; |
| 644 | l->buf[l->len] = '\0'; |
| 645 | if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { |
| 646 | /* Avoid a full update of the line in the |
| 647 | * trivial case. */ |
| 648 | if (write(l->ofd,&c,1) == -1) return -1; |
| 649 | } else { |
| 650 | refreshLine(l); |
| @@ -808,10 +814,18 @@ | |
| 814 | switch(c) { |
| 815 | case ENTER: /* enter */ |
| 816 | history_len--; |
| 817 | free(history[history_len]); |
| 818 | if (mlmode) linenoiseEditMoveEnd(&l); |
| 819 | if (hintsCallback) { |
| 820 | /* Force a refresh without hints to leave the previous |
| 821 | * line as the user typed it after a newline. */ |
| 822 | linenoiseHintsCallback *hc = hintsCallback; |
| 823 | hintsCallback = NULL; |
| 824 | refreshLine(&l); |
| 825 | hintsCallback = hc; |
| 826 | } |
| 827 | return (int)l.len; |
| 828 | case CTRL_C: /* ctrl-c */ |
| 829 | errno = EAGAIN; |
| 830 | return -1; |
| 831 | case BACKSPACE: /* backspace */ |
| @@ -954,11 +968,11 @@ | |
| 968 | memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ |
| 969 | quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ |
| 970 | if (memcmp(quit,"quit",sizeof(quit)) == 0) break; |
| 971 | |
| 972 | printf("'%c' %02x (%d) (type quit to exit)\n", |
| 973 | isprint(c) ? c : '?', (int)c, (int)c); |
| 974 | printf("\r"); /* Go left edge manually, we are in raw mode. */ |
| 975 | fflush(stdout); |
| 976 | } |
| 977 | disableRawMode(STDIN_FILENO); |
| 978 | } |
| @@ -970,27 +984,53 @@ | |
| 984 | |
| 985 | if (buflen == 0) { |
| 986 | errno = EINVAL; |
| 987 | return -1; |
| 988 | } |
| 989 | |
| 990 | if (enableRawMode(STDIN_FILENO) == -1) return -1; |
| 991 | count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); |
| 992 | disableRawMode(STDIN_FILENO); |
| 993 | printf("\n"); |
| 994 | return count; |
| 995 | } |
| 996 | |
| 997 | /* This function is called when linenoise() is called with the standard |
| 998 | * input file descriptor not attached to a TTY. So for example when the |
| 999 | * program using linenoise is called in pipe or with a file redirected |
| 1000 | * to its standard input. In this case, we want to be able to return the |
| 1001 | * line regardless of its length (by default we are limited to 4k). */ |
| 1002 | static char *linenoiseNoTTY(void) { |
| 1003 | char *line = NULL; |
| 1004 | size_t len = 0, maxlen = 0; |
| 1005 | |
| 1006 | while(1) { |
| 1007 | if (len == maxlen) { |
| 1008 | if (maxlen == 0) maxlen = 16; |
| 1009 | maxlen *= 2; |
| 1010 | char *oldval = line; |
| 1011 | line = realloc(line,maxlen); |
| 1012 | if (line == NULL) { |
| 1013 | if (oldval) free(oldval); |
| 1014 | return NULL; |
| 1015 | } |
| 1016 | } |
| 1017 | int c = fgetc(stdin); |
| 1018 | if (c == EOF || c == '\n') { |
| 1019 | if (c == EOF && len == 0) { |
| 1020 | free(line); |
| 1021 | return NULL; |
| 1022 | } else { |
| 1023 | line[len] = '\0'; |
| 1024 | return line; |
| 1025 | } |
| 1026 | } else { |
| 1027 | line[len] = c; |
| 1028 | len++; |
| 1029 | } |
| 1030 | } |
| 1031 | } |
| 1032 | |
| 1033 | /* The high level function that is the main API of the linenoise library. |
| 1034 | * This function checks if the terminal has basic capabilities, just checking |
| 1035 | * for a blacklist of stupid terminals, and later either calls the line |
| 1036 | * editing function or uses dummy fgets() so that you will be able to type |
| @@ -997,11 +1037,15 @@ | |
| 1037 | * something even in the most desperate of the conditions. */ |
| 1038 | char *linenoise(const char *prompt) { |
| 1039 | char buf[LINENOISE_MAX_LINE]; |
| 1040 | int count; |
| 1041 | |
| 1042 | if (!isatty(STDIN_FILENO)) { |
| 1043 | /* Not a tty: read from file / pipe. In this mode we don't want any |
| 1044 | * limit to the line size, so we call a function to handle that. */ |
| 1045 | return linenoiseNoTTY(); |
| 1046 | } else if (isUnsupportedTerm()) { |
| 1047 | size_t len; |
| 1048 | |
| 1049 | printf("%s",prompt); |
| 1050 | fflush(stdout); |
| 1051 | if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; |
| @@ -1015,10 +1059,18 @@ | |
| 1059 | count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); |
| 1060 | if (count == -1) return NULL; |
| 1061 | return strdup(buf); |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | /* This is just a wrapper the user may want to call in order to make sure |
| 1066 | * the linenoise returned buffer is freed with the same allocator it was |
| 1067 | * created with. Useful when the main program is using an alternative |
| 1068 | * allocator. */ |
| 1069 | void linenoiseFree(void *ptr) { |
| 1070 | free(ptr); |
| 1071 | } |
| 1072 | |
| 1073 | /* ================================ History ================================= */ |
| 1074 | |
| 1075 | /* Free the history, but does not reset it. Only used when we have to |
| 1076 | * exit() to avoid memory leaks are reported by valgrind & co. */ |
| @@ -1107,14 +1159,18 @@ | |
| 1159 | } |
| 1160 | |
| 1161 | /* Save the history in the specified file. On success 0 is returned |
| 1162 | * otherwise -1 is returned. */ |
| 1163 | int linenoiseHistorySave(const char *filename) { |
| 1164 | mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO); |
| 1165 | FILE *fp; |
| 1166 | int j; |
| 1167 | |
| 1168 | fp = fopen(filename,"w"); |
| 1169 | umask(old_umask); |
| 1170 | if (fp == NULL) return -1; |
| 1171 | chmod(filename,S_IRUSR|S_IWUSR); |
| 1172 | for (j = 0; j < history_len; j++) |
| 1173 | fprintf(fp,"%s\n",history[j]); |
| 1174 | fclose(fp); |
| 1175 | return 0; |
| 1176 | } |
| 1177 |
+5
| --- src/linenoise.h | ||
| +++ src/linenoise.h | ||
| @@ -47,14 +47,19 @@ | ||
| 47 | 47 | size_t len; |
| 48 | 48 | char **cvec; |
| 49 | 49 | } linenoiseCompletions; |
| 50 | 50 | |
| 51 | 51 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); |
| 52 | +typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); | |
| 53 | +typedef void(linenoiseFreeHintsCallback)(void *); | |
| 52 | 54 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); |
| 55 | +void linenoiseSetHintsCallback(linenoiseHintsCallback *); | |
| 56 | +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); | |
| 53 | 57 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); |
| 54 | 58 | |
| 55 | 59 | char *linenoise(const char *prompt); |
| 60 | +void linenoiseFree(void *ptr); | |
| 56 | 61 | int linenoiseHistoryAdd(const char *line); |
| 57 | 62 | int linenoiseHistorySetMaxLen(int len); |
| 58 | 63 | int linenoiseHistorySave(const char *filename); |
| 59 | 64 | int linenoiseHistoryLoad(const char *filename); |
| 60 | 65 | void linenoiseClearScreen(void); |
| 61 | 66 |
| --- src/linenoise.h | |
| +++ src/linenoise.h | |
| @@ -47,14 +47,19 @@ | |
| 47 | size_t len; |
| 48 | char **cvec; |
| 49 | } linenoiseCompletions; |
| 50 | |
| 51 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); |
| 52 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); |
| 53 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); |
| 54 | |
| 55 | char *linenoise(const char *prompt); |
| 56 | int linenoiseHistoryAdd(const char *line); |
| 57 | int linenoiseHistorySetMaxLen(int len); |
| 58 | int linenoiseHistorySave(const char *filename); |
| 59 | int linenoiseHistoryLoad(const char *filename); |
| 60 | void linenoiseClearScreen(void); |
| 61 |
| --- src/linenoise.h | |
| +++ src/linenoise.h | |
| @@ -47,14 +47,19 @@ | |
| 47 | size_t len; |
| 48 | char **cvec; |
| 49 | } linenoiseCompletions; |
| 50 | |
| 51 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); |
| 52 | typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); |
| 53 | typedef void(linenoiseFreeHintsCallback)(void *); |
| 54 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); |
| 55 | void linenoiseSetHintsCallback(linenoiseHintsCallback *); |
| 56 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); |
| 57 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); |
| 58 | |
| 59 | char *linenoise(const char *prompt); |
| 60 | void linenoiseFree(void *ptr); |
| 61 | int linenoiseHistoryAdd(const char *line); |
| 62 | int linenoiseHistorySetMaxLen(int len); |
| 63 | int linenoiseHistorySave(const char *filename); |
| 64 | int linenoiseHistoryLoad(const char *filename); |
| 65 | void linenoiseClearScreen(void); |
| 66 |