00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 #include <termios.h>
00127 #include <unistd.h>
00128 #include <stdlib.h>
00129 #include <stdio.h>
00130 #include <errno.h>
00131 #include <string.h>
00132 #include <stdlib.h>
00133 #include <ctype.h>
00134 #include <sys/stat.h>
00135 #include <sys/types.h>
00136 #include <sys/ioctl.h>
00137 #include <unistd.h>
00138 #include "linenoise.h"
00139
00140 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
00141 #define LINENOISE_MAX_LINE 4096
00142 static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
00143 static linenoiseCompletionCallback *completionCallback = NULL;
00144 static void * completionCallbackCtx = NULL;
00145 static linenoiseHintsCallback *hintsCallback = NULL;
00146 static void * hintsCallbackCtx = NULL;
00147 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
00148 static void * freeHintsCallbackCtx = NULL;
00149
00150 static struct termios orig_termios;
00151 static int maskmode = 0;
00152 static int rawmode = 0;
00153 static int mlmode = 0;
00154 static int atexit_registered = 0;
00155 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
00156 static int history_len = 0;
00157 static char **history = NULL;
00158
00159
00160
00161
00162 struct linenoiseState {
00163 int ifd;
00164 int ofd;
00165 char *buf;
00166 size_t buflen;
00167 const char *prompt;
00168 size_t plen;
00169 size_t pos;
00170 size_t oldpos;
00171 size_t len;
00172 size_t cols;
00173 size_t maxrows;
00174 int history_index;
00175 };
00176
00177 enum KEY_ACTION{
00178 KEY_NULL = 0,
00179 CTRL_A = 1,
00180 CTRL_B = 2,
00181 CTRL_C = 3,
00182 CTRL_D = 4,
00183 CTRL_E = 5,
00184 CTRL_F = 6,
00185 CTRL_H = 8,
00186 TAB = 9,
00187 CTRL_K = 11,
00188 CTRL_L = 12,
00189 ENTER = 13,
00190 CTRL_N = 14,
00191 CTRL_P = 16,
00192 CTRL_T = 20,
00193 CTRL_U = 21,
00194 CTRL_W = 23,
00195 ESC = 27,
00196 BACKSPACE = 127
00197 };
00198
00199 static void linenoiseAtExit(void);
00200 int linenoiseHistoryAdd(const char *line);
00201 static void refreshLine(struct linenoiseState *l);
00202
00203
00204 #if 0
00205 FILE *lndebug_fp = NULL;
00206 #define lndebug(...) \
00207 do { \
00208 if (lndebug_fp == NULL) { \
00209 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
00210 fprintf(lndebug_fp, \
00211 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
00212 (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
00213 (int)l->maxrows,old_rows); \
00214 } \
00215 fprintf(lndebug_fp, ", " __VA_ARGS__); \
00216 fflush(lndebug_fp); \
00217 } while (0)
00218 #else
00219 #define lndebug(fmt, ...)
00220 #endif
00221
00222
00223
00224
00225
00226
00227
00228 void linenoiseMaskModeEnable(void) {
00229 maskmode = 1;
00230 }
00231
00232
00233 void linenoiseMaskModeDisable(void) {
00234 maskmode = 0;
00235 }
00236
00237
00238 void linenoiseSetMultiLine(int ml) {
00239 mlmode = ml;
00240 }
00241
00242
00243
00244 static int isUnsupportedTerm(void) {
00245 char *term = getenv("TERM");
00246 int j;
00247
00248 if (term == NULL) return 0;
00249 for (j = 0; unsupported_term[j]; j++)
00250 if (!strcasecmp(term,unsupported_term[j])) return 1;
00251 return 0;
00252 }
00253
00254
00255 int enableRawMode(int fd, int flush) {
00256 struct termios raw;
00257
00258 if (!isatty(STDIN_FILENO)) goto fatal;
00259 if (!atexit_registered) {
00260 atexit(linenoiseAtExit);
00261 atexit_registered = 1;
00262 }
00263 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
00264
00265 raw = orig_termios;
00266
00267
00268 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
00269
00270 raw.c_oflag &= ~(OPOST);
00271
00272 raw.c_cflag |= (CS8);
00273
00274
00275 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
00276
00277
00278 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;
00279
00280
00281 if (tcsetattr(fd,(flush) ? TCSAFLUSH : TCSANOW, &raw) < 0) goto fatal;
00282 rawmode = 1;
00283 return 0;
00284
00285 fatal:
00286 errno = ENOTTY;
00287 return -1;
00288 }
00289
00290 void disableRawMode(int fd, int flush) {
00291
00292 if (rawmode && tcsetattr(fd,(flush) ? TCSAFLUSH : TCSANOW,&orig_termios) != -1)
00293 rawmode = 0;
00294 }
00295
00296
00297
00298
00299 static int getCursorPosition(int ifd, int ofd) {
00300 char buf[32];
00301 int cols, rows;
00302 unsigned int i = 0;
00303
00304
00305 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
00306
00307
00308 while (i < sizeof(buf)-1) {
00309 if (read(ifd,buf+i,1) != 1) break;
00310 if (buf[i] == 'R') break;
00311 i++;
00312 }
00313 buf[i] = '\0';
00314
00315
00316 if (buf[0] != ESC || buf[1] != '[') return -1;
00317 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
00318 return cols;
00319 }
00320
00321
00322
00323 static int getColumns(int ifd, int ofd) {
00324 struct winsize ws;
00325
00326 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
00327
00328 int start, cols;
00329
00330
00331 start = getCursorPosition(ifd,ofd);
00332 if (start == -1) goto failed;
00333
00334
00335 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
00336 cols = getCursorPosition(ifd,ofd);
00337 if (cols == -1) goto failed;
00338
00339
00340 if (cols > start) {
00341 char seq[32];
00342 snprintf(seq,32,"\x1b[%dD",cols-start);
00343 if (write(ofd,seq,strlen(seq)) == -1) {
00344
00345 }
00346 }
00347 return cols;
00348 } else {
00349 return ws.ws_col;
00350 }
00351
00352 failed:
00353 return 80;
00354 }
00355
00356
00357 void linenoiseClearScreen(void) {
00358 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
00359
00360 }
00361 }
00362
00363
00364
00365 static void linenoiseBeep(void) {
00366 fprintf(stderr, "\x7");
00367 fflush(stderr);
00368 }
00369
00370
00371
00372
00373 static void freeCompletions(linenoiseCompletions *lc) {
00374 size_t i;
00375 for (i = 0; i < lc->len; i++)
00376 free(lc->cvec[i]);
00377 if (lc->cvec != NULL)
00378 free(lc->cvec);
00379 }
00380
00381
00382
00383
00384
00385
00386
00387 static int completeLine(struct linenoiseState *ls) {
00388 linenoiseCompletions lc = { 0, NULL };
00389 int nread, nwritten;
00390 char c = 0;
00391
00392 completionCallback(completionCallbackCtx,ls->buf,&lc);
00393 if (lc.len == 0) {
00394 linenoiseBeep();
00395 } else {
00396 size_t stop = 0, i = 0;
00397
00398 while(!stop) {
00399
00400 if (i < lc.len) {
00401 struct linenoiseState saved = *ls;
00402
00403 ls->len = ls->pos = strlen(lc.cvec[i]);
00404 ls->buf = lc.cvec[i];
00405 refreshLine(ls);
00406 ls->len = saved.len;
00407 ls->pos = saved.pos;
00408 ls->buf = saved.buf;
00409 } else {
00410 refreshLine(ls);
00411 }
00412
00413 nread = read(ls->ifd,&c,1);
00414 if (nread <= 0) {
00415 freeCompletions(&lc);
00416 return -1;
00417 }
00418
00419 switch(c) {
00420 case 9:
00421 i = (i+1) % (lc.len+1);
00422 if (i == lc.len) linenoiseBeep();
00423 break;
00424 case 27:
00425
00426 if (i < lc.len) refreshLine(ls);
00427 stop = 1;
00428 break;
00429 default:
00430
00431 if (i < lc.len) {
00432 nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
00433 ls->len = ls->pos = nwritten;
00434 }
00435 stop = 1;
00436 break;
00437 }
00438 }
00439 }
00440
00441 freeCompletions(&lc);
00442 return c;
00443 }
00444
00445
00446 void linenoiseSetCompletionCallback(void *uctx, linenoiseCompletionCallback *fn) {
00447 completionCallbackCtx = uctx;
00448 completionCallback = fn;
00449 }
00450
00451
00452
00453 void linenoiseSetHintsCallback(void *uctx, linenoiseHintsCallback *fn) {
00454 hintsCallbackCtx = uctx;
00455 hintsCallback = fn;
00456 }
00457
00458
00459
00460 void linenoiseSetFreeHintsCallback(void *uctx, linenoiseFreeHintsCallback *fn) {
00461 freeHintsCallbackCtx = uctx;
00462 freeHintsCallback = fn;
00463 }
00464
00465
00466
00467
00468
00469 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
00470 size_t len = strlen(str);
00471 char *copy, **cvec;
00472
00473 copy = malloc(len+1);
00474 if (copy == NULL) return;
00475 memcpy(copy,str,len+1);
00476 cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
00477 if (cvec == NULL) {
00478 free(copy);
00479 return;
00480 }
00481 lc->cvec = cvec;
00482 lc->cvec[lc->len++] = copy;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491 struct abuf {
00492 char *b;
00493 int len;
00494 };
00495
00496 static void abInit(struct abuf *ab) {
00497 ab->b = NULL;
00498 ab->len = 0;
00499 }
00500
00501 static void abAppend(struct abuf *ab, const char *s, int len) {
00502 char *new = realloc(ab->b,ab->len+len);
00503
00504 if (new == NULL) return;
00505 memcpy(new+ab->len,s,len);
00506 ab->b = new;
00507 ab->len += len;
00508 }
00509
00510 static void abFree(struct abuf *ab) {
00511 free(ab->b);
00512 }
00513
00514
00515
00516 void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
00517 char seq[64];
00518 if (hintsCallback && plen+l->len < l->cols) {
00519 int color = -1, bold = 0;
00520 char *hint = hintsCallback(hintsCallbackCtx, l->buf,&color,&bold);
00521 if (hint) {
00522 int hintlen = strlen(hint);
00523 int hintmaxlen = l->cols-(plen+l->len);
00524 if (hintlen > hintmaxlen) hintlen = hintmaxlen;
00525 if (bold == 1 && color == -1) color = 37;
00526 if (color != -1 || bold != 0)
00527 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
00528 else
00529 seq[0] = '\0';
00530 abAppend(ab,seq,strlen(seq));
00531 abAppend(ab,hint,hintlen);
00532 if (color != -1 || bold != 0)
00533 abAppend(ab,"\033[0m",4);
00534
00535 if (freeHintsCallback) freeHintsCallback(freeHintsCallbackCtx, hint);
00536 }
00537 }
00538 }
00539
00540
00541
00542
00543
00544 static void refreshSingleLine(struct linenoiseState *l) {
00545 char seq[64];
00546 size_t plen = strlen(l->prompt);
00547 int fd = l->ofd;
00548 char *buf = l->buf;
00549 size_t len = l->len;
00550 size_t pos = l->pos;
00551 struct abuf ab;
00552
00553 while((plen+pos) >= l->cols) {
00554 buf++;
00555 len--;
00556 pos--;
00557 }
00558 while (plen+len > l->cols) {
00559 len--;
00560 }
00561
00562 abInit(&ab);
00563
00564 snprintf(seq,64,"\r");
00565 abAppend(&ab,seq,strlen(seq));
00566
00567 abAppend(&ab,l->prompt,strlen(l->prompt));
00568 if (maskmode == 1) {
00569 while (len--) abAppend(&ab,"*",1);
00570 } else {
00571 abAppend(&ab,buf,len);
00572 }
00573
00574 refreshShowHints(&ab,l,plen);
00575
00576 snprintf(seq,64,"\x1b[0K");
00577 abAppend(&ab,seq,strlen(seq));
00578
00579 snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
00580 abAppend(&ab,seq,strlen(seq));
00581 if (write(fd,ab.b,ab.len) == -1) {}
00582 abFree(&ab);
00583 }
00584
00585
00586
00587
00588
00589 static void refreshMultiLine(struct linenoiseState *l) {
00590 char seq[64];
00591 int plen = strlen(l->prompt);
00592 int rows = (plen+l->len+l->cols-1)/l->cols;
00593 int rpos = (plen+l->oldpos+l->cols)/l->cols;
00594 int rpos2;
00595 int col;
00596 int old_rows = l->maxrows;
00597 int fd = l->ofd, j;
00598 struct abuf ab;
00599
00600
00601 if (rows > (int)l->maxrows) l->maxrows = rows;
00602
00603
00604
00605 abInit(&ab);
00606 if (old_rows-rpos > 0) {
00607 lndebug("go down %d", old_rows-rpos);
00608 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
00609 abAppend(&ab,seq,strlen(seq));
00610 }
00611
00612
00613 for (j = 0; j < old_rows-1; j++) {
00614 lndebug("clear+up");
00615 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
00616 abAppend(&ab,seq,strlen(seq));
00617 }
00618
00619
00620 lndebug("clear");
00621 snprintf(seq,64,"\r\x1b[0K");
00622 abAppend(&ab,seq,strlen(seq));
00623
00624
00625 abAppend(&ab,l->prompt,strlen(l->prompt));
00626 if (maskmode == 1) {
00627 unsigned int i;
00628 for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
00629 } else {
00630 abAppend(&ab,l->buf,l->len);
00631 }
00632
00633
00634 refreshShowHints(&ab,l,plen);
00635
00636
00637
00638 if (l->pos &&
00639 l->pos == l->len &&
00640 (l->pos+plen) % l->cols == 0)
00641 {
00642 lndebug("<newline>");
00643 abAppend(&ab,"\n",1);
00644 snprintf(seq,64,"\r");
00645 abAppend(&ab,seq,strlen(seq));
00646 rows++;
00647 if (rows > (int)l->maxrows) l->maxrows = rows;
00648 }
00649
00650
00651 rpos2 = (plen+l->pos+l->cols)/l->cols;
00652 lndebug("rpos2 %d", rpos2);
00653
00654
00655 if (rows-rpos2 > 0) {
00656 lndebug("go-up %d", rows-rpos2);
00657 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
00658 abAppend(&ab,seq,strlen(seq));
00659 }
00660
00661
00662 col = (plen+(int)l->pos) % (int)l->cols;
00663 lndebug("set col %d", 1+col);
00664 if (col)
00665 snprintf(seq,64,"\r\x1b[%dC", col);
00666 else
00667 snprintf(seq,64,"\r");
00668 abAppend(&ab,seq,strlen(seq));
00669
00670 lndebug("\n");
00671 l->oldpos = l->pos;
00672
00673 if (write(fd,ab.b,ab.len) == -1) {}
00674 abFree(&ab);
00675 }
00676
00677
00678
00679 static void refreshLine(struct linenoiseState *l) {
00680 if (mlmode)
00681 refreshMultiLine(l);
00682 else
00683 refreshSingleLine(l);
00684 }
00685
00686
00687
00688
00689 int linenoiseEditInsert(struct linenoiseState *l, char c) {
00690 if (l->len < l->buflen) {
00691 if (l->len == l->pos) {
00692 l->buf[l->pos] = c;
00693 l->pos++;
00694 l->len++;
00695 l->buf[l->len] = '\0';
00696 if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
00697
00698
00699 char d = (maskmode==1) ? '*' : c;
00700 if (write(l->ofd,&d,1) == -1) return -1;
00701 } else {
00702 refreshLine(l);
00703 }
00704 } else {
00705 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
00706 l->buf[l->pos] = c;
00707 l->len++;
00708 l->pos++;
00709 l->buf[l->len] = '\0';
00710 refreshLine(l);
00711 }
00712 }
00713 return 0;
00714 }
00715
00716
00717 void linenoiseEditMoveLeft(struct linenoiseState *l) {
00718 if (l->pos > 0) {
00719 l->pos--;
00720 refreshLine(l);
00721 }
00722 }
00723
00724
00725 void linenoiseEditMoveRight(struct linenoiseState *l) {
00726 if (l->pos != l->len) {
00727 l->pos++;
00728 refreshLine(l);
00729 }
00730 }
00731
00732
00733 void linenoiseEditMoveHome(struct linenoiseState *l) {
00734 if (l->pos != 0) {
00735 l->pos = 0;
00736 refreshLine(l);
00737 }
00738 }
00739
00740
00741 void linenoiseEditMoveEnd(struct linenoiseState *l) {
00742 if (l->pos != l->len) {
00743 l->pos = l->len;
00744 refreshLine(l);
00745 }
00746 }
00747
00748
00749
00750 #define LINENOISE_HISTORY_NEXT 0
00751 #define LINENOISE_HISTORY_PREV 1
00752 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
00753 if (history_len > 1) {
00754
00755
00756 free(history[history_len - 1 - l->history_index]);
00757 history[history_len - 1 - l->history_index] = strdup(l->buf);
00758
00759 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
00760 if (l->history_index < 0) {
00761 l->history_index = 0;
00762 return;
00763 } else if (l->history_index >= history_len) {
00764 l->history_index = history_len-1;
00765 return;
00766 }
00767 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
00768 l->buf[l->buflen-1] = '\0';
00769 l->len = l->pos = strlen(l->buf);
00770 refreshLine(l);
00771 }
00772 }
00773
00774
00775
00776 void linenoiseEditDelete(struct linenoiseState *l) {
00777 if (l->len > 0 && l->pos < l->len) {
00778 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
00779 l->len--;
00780 l->buf[l->len] = '\0';
00781 refreshLine(l);
00782 }
00783 }
00784
00785
00786 void linenoiseEditBackspace(struct linenoiseState *l) {
00787 if (l->pos > 0 && l->len > 0) {
00788 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
00789 l->pos--;
00790 l->len--;
00791 l->buf[l->len] = '\0';
00792 refreshLine(l);
00793 }
00794 }
00795
00796
00797
00798 void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
00799 size_t old_pos = l->pos;
00800 size_t diff;
00801
00802 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
00803 l->pos--;
00804 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
00805 l->pos--;
00806 diff = old_pos - l->pos;
00807 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
00808 l->len -= diff;
00809 refreshLine(l);
00810 }
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820 static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
00821 {
00822 struct linenoiseState l;
00823
00824
00825
00826 l.ifd = stdin_fd;
00827 l.ofd = stdout_fd;
00828 l.buf = buf;
00829 l.buflen = buflen;
00830 l.prompt = prompt;
00831 l.plen = strlen(prompt);
00832 l.oldpos = l.pos = 0;
00833 l.len = 0;
00834 l.cols = getColumns(stdin_fd, stdout_fd);
00835 l.maxrows = 0;
00836 l.history_index = 0;
00837
00838
00839 l.buf[0] = '\0';
00840 l.buflen--;
00841
00842
00843
00844 linenoiseHistoryAdd("");
00845
00846 if (write(l.ofd,prompt,l.plen) == -1) return -1;
00847 while(1) {
00848 char c;
00849 int nread;
00850 char seq[3];
00851
00852 nread = read(l.ifd,&c,1);
00853 if (nread <= 0) return l.len;
00854
00855
00856
00857
00858 if (c == 9 && completionCallback != NULL) {
00859 c = completeLine(&l);
00860
00861 if (c < 0) return l.len;
00862
00863 if (c == 0) continue;
00864 }
00865
00866 switch(c) {
00867 case ENTER:
00868 history_len--;
00869 free(history[history_len]);
00870 if (mlmode) linenoiseEditMoveEnd(&l);
00871 if (hintsCallback) {
00872
00873
00874 linenoiseHintsCallback *hc = hintsCallback;
00875 hintsCallback = NULL;
00876 refreshLine(&l);
00877 hintsCallback = hc;
00878 }
00879 return (int)l.len;
00880 case CTRL_C:
00881 errno = EAGAIN;
00882 return -1;
00883 case BACKSPACE:
00884 case 8:
00885 linenoiseEditBackspace(&l);
00886 break;
00887 case CTRL_D:
00888
00889 if (l.len > 0) {
00890 linenoiseEditDelete(&l);
00891 } else {
00892 history_len--;
00893 free(history[history_len]);
00894 return -1;
00895 }
00896 break;
00897 case CTRL_T:
00898 if (l.pos > 0 && l.pos < l.len) {
00899 int aux = buf[l.pos-1];
00900 buf[l.pos-1] = buf[l.pos];
00901 buf[l.pos] = aux;
00902 if (l.pos != l.len-1) l.pos++;
00903 refreshLine(&l);
00904 }
00905 break;
00906 case CTRL_B:
00907 linenoiseEditMoveLeft(&l);
00908 break;
00909 case CTRL_F:
00910 linenoiseEditMoveRight(&l);
00911 break;
00912 case CTRL_P:
00913 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
00914 break;
00915 case CTRL_N:
00916 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
00917 break;
00918 case ESC:
00919
00920
00921
00922 if (read(l.ifd,seq,1) == -1) break;
00923 if (read(l.ifd,seq+1,1) == -1) break;
00924
00925
00926 if (seq[0] == '[') {
00927 if (seq[1] >= '0' && seq[1] <= '9') {
00928
00929 if (read(l.ifd,seq+2,1) == -1) break;
00930 if (seq[2] == '~') {
00931 switch(seq[1]) {
00932 case '3':
00933 linenoiseEditDelete(&l);
00934 break;
00935 }
00936 }
00937 } else {
00938 switch(seq[1]) {
00939 case 'A':
00940 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
00941 break;
00942 case 'B':
00943 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
00944 break;
00945 case 'C':
00946 linenoiseEditMoveRight(&l);
00947 break;
00948 case 'D':
00949 linenoiseEditMoveLeft(&l);
00950 break;
00951 case 'H':
00952 linenoiseEditMoveHome(&l);
00953 break;
00954 case 'F':
00955 linenoiseEditMoveEnd(&l);
00956 break;
00957 }
00958 }
00959 }
00960
00961
00962 else if (seq[0] == 'O') {
00963 switch(seq[1]) {
00964 case 'H':
00965 linenoiseEditMoveHome(&l);
00966 break;
00967 case 'F':
00968 linenoiseEditMoveEnd(&l);
00969 break;
00970 }
00971 }
00972 break;
00973 default:
00974 if (linenoiseEditInsert(&l,c)) return -1;
00975 break;
00976 case CTRL_U:
00977 buf[0] = '\0';
00978 l.pos = l.len = 0;
00979 refreshLine(&l);
00980 break;
00981 case CTRL_K:
00982 buf[l.pos] = '\0';
00983 l.len = l.pos;
00984 refreshLine(&l);
00985 break;
00986 case CTRL_A:
00987 linenoiseEditMoveHome(&l);
00988 break;
00989 case CTRL_E:
00990 linenoiseEditMoveEnd(&l);
00991 break;
00992 case CTRL_L:
00993 linenoiseClearScreen();
00994 refreshLine(&l);
00995 break;
00996 case CTRL_W:
00997 linenoiseEditDeletePrevWord(&l);
00998 break;
00999 }
01000 }
01001 return l.len;
01002 }
01003
01004
01005
01006
01007 void linenoisePrintKeyCodes(void) {
01008 char quit[4];
01009
01010 printf("Linenoise key codes debugging mode.\n"
01011 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
01012 if (enableRawMode(STDIN_FILENO, 1) == -1) return;
01013 memset(quit,' ',4);
01014 while(1) {
01015 char c;
01016 int nread;
01017
01018 nread = read(STDIN_FILENO,&c,1);
01019 if (nread <= 0) continue;
01020 memmove(quit,quit+1,sizeof(quit)-1);
01021 quit[sizeof(quit)-1] = c;
01022 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
01023
01024 printf("'%c' %02x (%d) (type quit to exit)\n",
01025 isprint(c) ? c : '?', (int)c, (int)c);
01026 printf("\r");
01027 fflush(stdout);
01028 }
01029 disableRawMode(STDIN_FILENO, 1);
01030 }
01031
01032
01033
01034 static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
01035 int count;
01036
01037 if (buflen == 0) {
01038 errno = EINVAL;
01039 return -1;
01040 }
01041
01042 if (enableRawMode(STDIN_FILENO, 0) == -1) return -1;
01043 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
01044 disableRawMode(STDIN_FILENO, 1);
01045 printf("\n");
01046 return count;
01047 }
01048
01049
01050
01051
01052
01053
01054 static char *linenoiseNoTTY(void) {
01055 char *line = NULL;
01056 size_t len = 0, maxlen = 0;
01057
01058 while(1) {
01059 if (len == maxlen) {
01060 if (maxlen == 0) maxlen = 16;
01061 maxlen *= 2;
01062 char *oldval = line;
01063 line = realloc(line,maxlen);
01064 if (line == NULL) {
01065 if (oldval) free(oldval);
01066 return NULL;
01067 }
01068 }
01069 int c = fgetc(stdin);
01070 if (c == EOF || c == '\n') {
01071 if (c == EOF && len == 0) {
01072 free(line);
01073 return NULL;
01074 } else {
01075 line[len] = '\0';
01076 return line;
01077 }
01078 } else {
01079 line[len] = c;
01080 len++;
01081 }
01082 }
01083 }
01084
01085
01086
01087
01088
01089
01090 char *linenoise(const char *prompt) {
01091 char buf[LINENOISE_MAX_LINE];
01092 int count;
01093
01094 if (!isatty(STDIN_FILENO)) {
01095
01096
01097 return linenoiseNoTTY();
01098 } else if (isUnsupportedTerm()) {
01099 size_t len;
01100
01101 printf("%s",prompt);
01102 fflush(stdout);
01103 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
01104 len = strlen(buf);
01105 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
01106 len--;
01107 buf[len] = '\0';
01108 }
01109 return strdup(buf);
01110 } else {
01111 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
01112 if (count == -1) return NULL;
01113 return strdup(buf);
01114 }
01115 }
01116
01117
01118
01119
01120
01121 void linenoiseFree(void *ptr) {
01122 free(ptr);
01123 }
01124
01125
01126
01127
01128
01129 static void freeHistory(void) {
01130 if (history) {
01131 int j;
01132
01133 for (j = 0; j < history_len; j++)
01134 free(history[j]);
01135 free(history);
01136 }
01137 }
01138
01139
01140 static void linenoiseAtExit(void) {
01141 disableRawMode(STDIN_FILENO, 1);
01142 freeHistory();
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152 int linenoiseHistoryAdd(const char *line) {
01153 char *linecopy;
01154
01155 if (history_max_len == 0) return 0;
01156
01157
01158 if (history == NULL) {
01159 history = malloc(sizeof(char*)*history_max_len);
01160 if (history == NULL) return 0;
01161 memset(history,0,(sizeof(char*)*history_max_len));
01162 }
01163
01164
01165 if (history_len && !strcmp(history[history_len-1], line)) return 0;
01166
01167
01168
01169 linecopy = strdup(line);
01170 if (!linecopy) return 0;
01171 if (history_len == history_max_len) {
01172 free(history[0]);
01173 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
01174 history_len--;
01175 }
01176 history[history_len] = linecopy;
01177 history_len++;
01178 return 1;
01179 }
01180
01181
01182
01183
01184
01185 int linenoiseHistorySetMaxLen(int len) {
01186 char **new;
01187
01188 if (len < 1) return 0;
01189 if (history) {
01190 int tocopy = history_len;
01191
01192 new = malloc(sizeof(char*)*len);
01193 if (new == NULL) return 0;
01194
01195
01196 if (len < tocopy) {
01197 int j;
01198
01199 for (j = 0; j < tocopy-len; j++) free(history[j]);
01200 tocopy = len;
01201 }
01202 memset(new,0,sizeof(char*)*len);
01203 memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
01204 free(history);
01205 history = new;
01206 }
01207 history_max_len = len;
01208 if (history_len > history_max_len)
01209 history_len = history_max_len;
01210 return 1;
01211 }
01212
01213
01214
01215 int linenoiseHistorySave(const char *filename) {
01216 mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
01217 FILE *fp;
01218 int j;
01219
01220 fp = fopen(filename,"w");
01221 umask(old_umask);
01222 if (fp == NULL) return -1;
01223 chmod(filename,S_IRUSR|S_IWUSR);
01224 for (j = 0; j < history_len; j++)
01225 fprintf(fp,"%s\n",history[j]);
01226 fclose(fp);
01227 return 0;
01228 }
01229
01230
01231
01232
01233
01234
01235 int linenoiseHistoryLoad(const char *filename) {
01236 FILE *fp = fopen(filename,"r");
01237 char buf[LINENOISE_MAX_LINE];
01238
01239 if (fp == NULL) return -1;
01240
01241 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
01242 char *p;
01243
01244 p = strchr(buf,'\r');
01245 if (!p) p = strchr(buf,'\n');
01246 if (p) *p = '\0';
01247 linenoiseHistoryAdd(buf);
01248 }
01249 fclose(fp);
01250 return 0;
01251 }