0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 #include <termios.h>
0107 #include <unistd.h>
0108 #include <stdlib.h>
0109 #include <stdio.h>
0110 #include <errno.h>
0111 #include <string.h>
0112 #include <stdlib.h>
0113 #include <ctype.h>
0114 #include <sys/stat.h>
0115 #include <sys/types.h>
0116 #include <sys/ioctl.h>
0117 #include <unistd.h>
0118 #include "linenoise.h"
0119
0120 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
0121 #define LINENOISE_MAX_LINE 4096
0122 static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
0123 static linenoiseCompletionCallback *completionCallback = NULL;
0124 static linenoiseHintsCallback *hintsCallback = NULL;
0125 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
0126
0127 static struct termios orig_termios;
0128 static int rawmode = 0;
0129 static int mlmode = 0;
0130 static int atexit_registered = 0;
0131 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
0132 static int history_len = 0;
0133 static char **history = NULL;
0134
0135 int ndrx_G_ctrl_d = 0;
0136
0137
0138
0139
0140 struct linenoiseState {
0141 int ifd;
0142 int ofd;
0143 char *buf;
0144 size_t buflen;
0145 const char *prompt;
0146 size_t plen;
0147 size_t pos;
0148 size_t oldpos;
0149 size_t len;
0150 size_t cols;
0151 size_t maxrows;
0152 int history_index;
0153 };
0154
0155 enum KEY_ACTION{
0156 KEY_NULL = 0,
0157 CTRL_A = 1,
0158 CTRL_B = 2,
0159 CTRL_C = 3,
0160 CTRL_D = 4,
0161 CTRL_E = 5,
0162 CTRL_F = 6,
0163 CTRL_H = 8,
0164 TAB = 9,
0165 CTRL_K = 11,
0166 CTRL_L = 12,
0167 ENTER = 13,
0168 CTRL_N = 14,
0169 CTRL_P = 16,
0170 CTRL_T = 20,
0171 CTRL_U = 21,
0172 CTRL_W = 23,
0173 ESC = 27,
0174 BACKSPACE = 127
0175 };
0176
0177 static void linenoiseAtExit(void);
0178 int linenoiseHistoryAdd(const char *line);
0179 static void refreshLine(struct linenoiseState *l);
0180
0181
0182 #if 0
0183 FILE *lndebug_fp = NULL;
0184 #define lndebug(...) \
0185 do { \
0186 if (lndebug_fp == NULL) { \
0187 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
0188 fprintf(lndebug_fp, \
0189 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
0190 (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
0191 (int)l->maxrows,old_rows); \
0192 } \
0193 fprintf(lndebug_fp, ", " __VA_ARGS__); \
0194 fflush(lndebug_fp); \
0195 } while (0)
0196 #else
0197 #define lndebug(fmt, ...)
0198 #endif
0199
0200
0201
0202
0203 void linenoiseSetMultiLine(int ml) {
0204 mlmode = ml;
0205 }
0206
0207
0208
0209 static int isUnsupportedTerm(void) {
0210 char *term = getenv("TERM");
0211 int j;
0212
0213 if (term == NULL) return 0;
0214 for (j = 0; unsupported_term[j]; j++)
0215 if (!strcasecmp(term,unsupported_term[j])) return 1;
0216 return 0;
0217 }
0218
0219
0220 static int enableRawMode(int fd) {
0221 struct termios raw;
0222
0223 if (!isatty(STDIN_FILENO)) goto fatal;
0224 if (!atexit_registered) {
0225 atexit(linenoiseAtExit);
0226 atexit_registered = 1;
0227 }
0228 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
0229
0230 raw = orig_termios;
0231
0232
0233 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
0234
0235 raw.c_oflag &= ~(OPOST);
0236
0237 raw.c_cflag |= (CS8);
0238
0239
0240 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
0241
0242
0243 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;
0244
0245
0246 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
0247 rawmode = 1;
0248 return 0;
0249
0250 fatal:
0251 errno = ENOTTY;
0252 return -1;
0253 }
0254
0255 static void disableRawMode(int fd) {
0256
0257 if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
0258 rawmode = 0;
0259 }
0260
0261
0262
0263
0264 static int getCursorPosition(int ifd, int ofd) {
0265 char buf[32];
0266 int cols, rows;
0267 unsigned int i = 0;
0268
0269
0270 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
0271
0272
0273 while (i < sizeof(buf)-1) {
0274 if (read(ifd,buf+i,1) != 1) break;
0275 if (buf[i] == 'R') break;
0276 i++;
0277 }
0278 buf[i] = '\0';
0279
0280
0281 if (buf[0] != ESC || buf[1] != '[') return -1;
0282 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
0283 return cols;
0284 }
0285
0286
0287
0288 static int getColumns(int ifd, int ofd) {
0289 struct winsize ws;
0290
0291 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
0292
0293 int start, cols;
0294
0295
0296 start = getCursorPosition(ifd,ofd);
0297 if (start == -1) goto failed;
0298
0299
0300 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
0301 cols = getCursorPosition(ifd,ofd);
0302 if (cols == -1) goto failed;
0303
0304
0305 if (cols > start) {
0306 char seq[32];
0307 snprintf(seq,32,"\x1b[%dD",cols-start);
0308 if (write(ofd,seq,strlen(seq)) == -1) {
0309
0310 }
0311 }
0312 return cols;
0313 } else {
0314 return ws.ws_col;
0315 }
0316
0317 failed:
0318 return 80;
0319 }
0320
0321
0322 void linenoiseClearScreen(void) {
0323 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
0324
0325 }
0326 }
0327
0328
0329
0330 static void linenoiseBeep(void) {
0331 fprintf(stderr, "\x7");
0332 fflush(stderr);
0333 }
0334
0335
0336
0337
0338 static void freeCompletions(linenoiseCompletions *lc) {
0339 size_t i;
0340 for (i = 0; i < lc->len; i++)
0341 free(lc->cvec[i]);
0342 if (lc->cvec != NULL)
0343 free(lc->cvec);
0344 }
0345
0346
0347
0348
0349
0350
0351
0352 static int completeLine(struct linenoiseState *ls) {
0353 linenoiseCompletions lc = { 0, NULL };
0354 int nread, nwritten;
0355 char c = 0;
0356
0357 completionCallback(ls->buf,&lc);
0358 if (lc.len == 0) {
0359 linenoiseBeep();
0360 } else {
0361 size_t stop = 0, i = 0;
0362
0363 while(!stop) {
0364
0365 if (i < lc.len) {
0366 struct linenoiseState saved = *ls;
0367
0368 ls->len = ls->pos = strlen(lc.cvec[i]);
0369 ls->buf = lc.cvec[i];
0370 refreshLine(ls);
0371 ls->len = saved.len;
0372 ls->pos = saved.pos;
0373 ls->buf = saved.buf;
0374 } else {
0375 refreshLine(ls);
0376 }
0377
0378 nread = read(ls->ifd,&c,1);
0379 if (nread <= 0) {
0380 freeCompletions(&lc);
0381 return -1;
0382 }
0383
0384 switch(c) {
0385 case 9:
0386 i = (i+1) % (lc.len+1);
0387 if (i == lc.len) linenoiseBeep();
0388 break;
0389 case 27:
0390
0391 if (i < lc.len) refreshLine(ls);
0392 stop = 1;
0393 break;
0394 default:
0395
0396 if (i < lc.len) {
0397 nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
0398 ls->len = ls->pos = nwritten;
0399 }
0400 stop = 1;
0401 break;
0402 }
0403 }
0404 }
0405
0406 freeCompletions(&lc);
0407 return c;
0408 }
0409
0410
0411 void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
0412 completionCallback = fn;
0413 }
0414
0415
0416
0417 void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
0418 hintsCallback = fn;
0419 }
0420
0421
0422
0423 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
0424 freeHintsCallback = fn;
0425 }
0426
0427
0428
0429
0430
0431 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
0432 size_t len = strlen(str);
0433 char *copy, **cvec;
0434
0435 copy = malloc(len+1);
0436 if (copy == NULL) return;
0437 memcpy(copy,str,len+1);
0438 cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
0439 if (cvec == NULL) {
0440 free(copy);
0441 return;
0442 }
0443 lc->cvec = cvec;
0444 lc->cvec[lc->len++] = copy;
0445 }
0446
0447
0448
0449
0450
0451
0452
0453 struct abuf {
0454 char *b;
0455 int len;
0456 };
0457
0458 static void abInit(struct abuf *ab) {
0459 ab->b = NULL;
0460 ab->len = 0;
0461 }
0462
0463 static void abAppend(struct abuf *ab, const char *s, int len) {
0464 char *new = realloc(ab->b,ab->len+len);
0465
0466 if (new == NULL) return;
0467 memcpy(new+ab->len,s,len);
0468 ab->b = new;
0469 ab->len += len;
0470 }
0471
0472 static void abFree(struct abuf *ab) {
0473 free(ab->b);
0474 }
0475
0476
0477
0478 void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
0479 char seq[64];
0480 if (hintsCallback && plen+l->len < l->cols) {
0481 int color = -1, bold = 0;
0482 char *hint = hintsCallback(l->buf,&color,&bold);
0483 if (hint) {
0484 int hintlen = strlen(hint);
0485 int hintmaxlen = l->cols-(plen+l->len);
0486 if (hintlen > hintmaxlen) hintlen = hintmaxlen;
0487 if (bold == 1 && color == -1) color = 37;
0488 if (color != -1 || bold != 0)
0489 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
0490 else
0491 seq[0] = '\0';
0492 abAppend(ab,seq,strlen(seq));
0493 abAppend(ab,hint,hintlen);
0494 if (color != -1 || bold != 0)
0495 abAppend(ab,"\033[0m",4);
0496
0497 if (freeHintsCallback) freeHintsCallback(hint);
0498 }
0499 }
0500 }
0501
0502
0503
0504
0505
0506 static void refreshSingleLine(struct linenoiseState *l) {
0507 char seq[64];
0508 size_t plen = strlen(l->prompt);
0509 int fd = l->ofd;
0510 char *buf = l->buf;
0511 size_t len = l->len;
0512 size_t pos = l->pos;
0513 struct abuf ab;
0514
0515 while((plen+pos) >= l->cols) {
0516 buf++;
0517 len--;
0518 pos--;
0519 }
0520 while (plen+len > l->cols) {
0521 len--;
0522 }
0523
0524 abInit(&ab);
0525
0526 snprintf(seq,64,"\r");
0527 abAppend(&ab,seq,strlen(seq));
0528
0529 abAppend(&ab,l->prompt,strlen(l->prompt));
0530 abAppend(&ab,buf,len);
0531
0532 refreshShowHints(&ab,l,plen);
0533
0534 snprintf(seq,64,"\x1b[0K");
0535 abAppend(&ab,seq,strlen(seq));
0536
0537 snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
0538 abAppend(&ab,seq,strlen(seq));
0539 if (write(fd,ab.b,ab.len) == -1) {}
0540 abFree(&ab);
0541 }
0542
0543
0544
0545
0546
0547 static void refreshMultiLine(struct linenoiseState *l) {
0548 char seq[64];
0549 int plen = strlen(l->prompt);
0550 int rows = (plen+l->len+l->cols-1)/l->cols;
0551 int rpos = (plen+l->oldpos+l->cols)/l->cols;
0552 int rpos2;
0553 int col;
0554 int old_rows = l->maxrows;
0555 int fd = l->ofd, j;
0556 struct abuf ab;
0557
0558
0559 if (rows > (int)l->maxrows) l->maxrows = rows;
0560
0561
0562
0563 abInit(&ab);
0564 if (old_rows-rpos > 0) {
0565 lndebug("go down %d", old_rows-rpos);
0566 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
0567 abAppend(&ab,seq,strlen(seq));
0568 }
0569
0570
0571 for (j = 0; j < old_rows-1; j++) {
0572 lndebug("clear+up");
0573 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
0574 abAppend(&ab,seq,strlen(seq));
0575 }
0576
0577
0578 lndebug("clear");
0579 snprintf(seq,64,"\r\x1b[0K");
0580 abAppend(&ab,seq,strlen(seq));
0581
0582
0583 abAppend(&ab,l->prompt,strlen(l->prompt));
0584 abAppend(&ab,l->buf,l->len);
0585
0586
0587 refreshShowHints(&ab,l,plen);
0588
0589
0590
0591 if (l->pos &&
0592 l->pos == l->len &&
0593 (l->pos+plen) % l->cols == 0)
0594 {
0595 lndebug("<newline>");
0596 abAppend(&ab,"\n",1);
0597 snprintf(seq,64,"\r");
0598 abAppend(&ab,seq,strlen(seq));
0599 rows++;
0600 if (rows > (int)l->maxrows) l->maxrows = rows;
0601 }
0602
0603
0604 rpos2 = (plen+l->pos+l->cols)/l->cols;
0605 lndebug("rpos2 %d", rpos2);
0606
0607
0608 if (rows-rpos2 > 0) {
0609 lndebug("go-up %d", rows-rpos2);
0610 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
0611 abAppend(&ab,seq,strlen(seq));
0612 }
0613
0614
0615 col = (plen+(int)l->pos) % (int)l->cols;
0616 lndebug("set col %d", 1+col);
0617 if (col)
0618 snprintf(seq,64,"\r\x1b[%dC", col);
0619 else
0620 snprintf(seq,64,"\r");
0621 abAppend(&ab,seq,strlen(seq));
0622
0623 lndebug("\n");
0624 l->oldpos = l->pos;
0625
0626 if (write(fd,ab.b,ab.len) == -1) {}
0627 abFree(&ab);
0628 }
0629
0630
0631
0632 static void refreshLine(struct linenoiseState *l) {
0633 if (mlmode)
0634 refreshMultiLine(l);
0635 else
0636 refreshSingleLine(l);
0637 }
0638
0639
0640
0641
0642 int linenoiseEditInsert(struct linenoiseState *l, char c) {
0643 if (l->len < l->buflen) {
0644 if (l->len == l->pos) {
0645 l->buf[l->pos] = c;
0646 l->pos++;
0647 l->len++;
0648 l->buf[l->len] = '\0';
0649 if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
0650
0651
0652 if (write(l->ofd,&c,1) == -1) return -1;
0653 } else {
0654 refreshLine(l);
0655 }
0656 } else {
0657 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
0658 l->buf[l->pos] = c;
0659 l->len++;
0660 l->pos++;
0661 l->buf[l->len] = '\0';
0662 refreshLine(l);
0663 }
0664 }
0665 return 0;
0666 }
0667
0668
0669 void linenoiseEditMoveLeft(struct linenoiseState *l) {
0670 if (l->pos > 0) {
0671 l->pos--;
0672 refreshLine(l);
0673 }
0674 }
0675
0676
0677 void linenoiseEditMoveRight(struct linenoiseState *l) {
0678 if (l->pos != l->len) {
0679 l->pos++;
0680 refreshLine(l);
0681 }
0682 }
0683
0684
0685 void linenoiseEditMoveHome(struct linenoiseState *l) {
0686 if (l->pos != 0) {
0687 l->pos = 0;
0688 refreshLine(l);
0689 }
0690 }
0691
0692
0693 void linenoiseEditMoveEnd(struct linenoiseState *l) {
0694 if (l->pos != l->len) {
0695 l->pos = l->len;
0696 refreshLine(l);
0697 }
0698 }
0699
0700
0701
0702 #define LINENOISE_HISTORY_NEXT 0
0703 #define LINENOISE_HISTORY_PREV 1
0704 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
0705 if (history_len > 1) {
0706
0707
0708 free(history[history_len - 1 - l->history_index]);
0709 history[history_len - 1 - l->history_index] = strdup(l->buf);
0710
0711 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
0712 if (l->history_index < 0) {
0713 l->history_index = 0;
0714 return;
0715 } else if (l->history_index >= history_len) {
0716 l->history_index = history_len-1;
0717 return;
0718 }
0719 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
0720 l->buf[l->buflen-1] = '\0';
0721 l->len = l->pos = strlen(l->buf);
0722 refreshLine(l);
0723 }
0724 }
0725
0726
0727
0728 void linenoiseEditDelete(struct linenoiseState *l) {
0729 if (l->len > 0 && l->pos < l->len) {
0730 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
0731 l->len--;
0732 l->buf[l->len] = '\0';
0733 refreshLine(l);
0734 }
0735 }
0736
0737
0738 void linenoiseEditBackspace(struct linenoiseState *l) {
0739 if (l->pos > 0 && l->len > 0) {
0740 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
0741 l->pos--;
0742 l->len--;
0743 l->buf[l->len] = '\0';
0744 refreshLine(l);
0745 }
0746 }
0747
0748
0749
0750 void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
0751 size_t old_pos = l->pos;
0752 size_t diff;
0753
0754 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
0755 l->pos--;
0756 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
0757 l->pos--;
0758 diff = old_pos - l->pos;
0759 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
0760 l->len -= diff;
0761 refreshLine(l);
0762 }
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772 static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
0773 {
0774 struct linenoiseState l;
0775
0776
0777
0778 l.ifd = stdin_fd;
0779 l.ofd = stdout_fd;
0780 l.buf = buf;
0781 l.buflen = buflen;
0782 l.prompt = prompt;
0783 l.plen = strlen(prompt);
0784 l.oldpos = l.pos = 0;
0785 l.len = 0;
0786 l.cols = getColumns(stdin_fd, stdout_fd);
0787 l.maxrows = 0;
0788 l.history_index = 0;
0789
0790
0791 l.buf[0] = '\0';
0792 l.buflen--;
0793
0794
0795
0796 linenoiseHistoryAdd("");
0797
0798 if (write(l.ofd,prompt,l.plen) == -1) return -1;
0799 while(1) {
0800 char c;
0801 int nread;
0802 char seq[3];
0803
0804 nread = read(l.ifd,&c,1);
0805 if (nread <= 0) return l.len;
0806
0807
0808
0809
0810 if (c == 9 && completionCallback != NULL) {
0811 c = completeLine(&l);
0812
0813 if (c < 0) return l.len;
0814
0815 if (c == 0) continue;
0816 }
0817
0818 switch(c) {
0819 case ENTER:
0820 history_len--;
0821 free(history[history_len]);
0822 if (mlmode) linenoiseEditMoveEnd(&l);
0823 if (hintsCallback) {
0824
0825
0826 linenoiseHintsCallback *hc = hintsCallback;
0827 hintsCallback = NULL;
0828 refreshLine(&l);
0829 hintsCallback = hc;
0830 }
0831 return (int)l.len;
0832 case CTRL_C:
0833 errno = EAGAIN;
0834 return -1;
0835 case BACKSPACE:
0836 case 8:
0837 linenoiseEditBackspace(&l);
0838 break;
0839 case CTRL_D:
0840
0841 if (l.len > 0) {
0842 linenoiseEditDelete(&l);
0843 } else {
0844 history_len--;
0845 free(history[history_len]);
0846 ndrx_G_ctrl_d=1;
0847 return -1;
0848 }
0849 break;
0850 case CTRL_T:
0851 if (l.pos > 0 && l.pos < l.len) {
0852 int aux = buf[l.pos-1];
0853 buf[l.pos-1] = buf[l.pos];
0854 buf[l.pos] = aux;
0855 if (l.pos != l.len-1) l.pos++;
0856 refreshLine(&l);
0857 }
0858 break;
0859 case CTRL_B:
0860 linenoiseEditMoveLeft(&l);
0861 break;
0862 case CTRL_F:
0863 linenoiseEditMoveRight(&l);
0864 break;
0865 case CTRL_P:
0866 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
0867 break;
0868 case CTRL_N:
0869 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
0870 break;
0871 case ESC:
0872
0873
0874
0875 if (read(l.ifd,seq,1) == -1) break;
0876 if (read(l.ifd,seq+1,1) == -1) break;
0877
0878
0879 if (seq[0] == '[') {
0880 if (seq[1] >= '0' && seq[1] <= '9') {
0881
0882 if (read(l.ifd,seq+2,1) == -1) break;
0883 if (seq[2] == '~') {
0884 switch(seq[1]) {
0885 case '3':
0886 linenoiseEditDelete(&l);
0887 break;
0888 }
0889 }
0890 } else {
0891 switch(seq[1]) {
0892 case 'A':
0893 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
0894 break;
0895 case 'B':
0896 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
0897 break;
0898 case 'C':
0899 linenoiseEditMoveRight(&l);
0900 break;
0901 case 'D':
0902 linenoiseEditMoveLeft(&l);
0903 break;
0904 case 'H':
0905 linenoiseEditMoveHome(&l);
0906 break;
0907 case 'F':
0908 linenoiseEditMoveEnd(&l);
0909 break;
0910 }
0911 }
0912 }
0913
0914
0915 else if (seq[0] == 'O') {
0916 switch(seq[1]) {
0917 case 'H':
0918 linenoiseEditMoveHome(&l);
0919 break;
0920 case 'F':
0921 linenoiseEditMoveEnd(&l);
0922 break;
0923 }
0924 }
0925 break;
0926 default:
0927 if (linenoiseEditInsert(&l,c)) return -1;
0928 break;
0929 case CTRL_U:
0930 buf[0] = '\0';
0931 l.pos = l.len = 0;
0932 refreshLine(&l);
0933 break;
0934 case CTRL_K:
0935 buf[l.pos] = '\0';
0936 l.len = l.pos;
0937 refreshLine(&l);
0938 break;
0939 case CTRL_A:
0940 linenoiseEditMoveHome(&l);
0941 break;
0942 case CTRL_E:
0943 linenoiseEditMoveEnd(&l);
0944 break;
0945 case CTRL_L:
0946 linenoiseClearScreen();
0947 refreshLine(&l);
0948 break;
0949 case CTRL_W:
0950 linenoiseEditDeletePrevWord(&l);
0951 break;
0952 }
0953 }
0954 return l.len;
0955 }
0956
0957
0958
0959
0960 void linenoisePrintKeyCodes(void) {
0961 char quit[4];
0962
0963 printf("Linenoise key codes debugging mode.\n"
0964 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
0965 if (enableRawMode(STDIN_FILENO) == -1) return;
0966 memset(quit,' ',4);
0967 while(1) {
0968 char c;
0969 int nread;
0970
0971 nread = read(STDIN_FILENO,&c,1);
0972 if (nread <= 0) continue;
0973 memmove(quit,quit+1,sizeof(quit)-1);
0974 quit[sizeof(quit)-1] = c;
0975 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
0976
0977 printf("'%c' %02x (%d) (type quit to exit)\n",
0978 isprint(c) ? c : '?', (int)c, (int)c);
0979 printf("\r");
0980 fflush(stdout);
0981 }
0982 disableRawMode(STDIN_FILENO);
0983 }
0984
0985
0986
0987 static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
0988 int count;
0989
0990 if (buflen == 0) {
0991 errno = EINVAL;
0992 return -1;
0993 }
0994
0995 if (enableRawMode(STDIN_FILENO) == -1) return -1;
0996 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
0997 disableRawMode(STDIN_FILENO);
0998 printf("\n");
0999 return count;
1000 }
1001
1002
1003
1004
1005
1006
1007 static char *linenoiseNoTTY(void) {
1008 char *line = NULL;
1009 size_t len = 0, maxlen = 0;
1010
1011 while(1) {
1012 if (len == maxlen) {
1013 if (maxlen == 0) maxlen = 16;
1014 maxlen *= 2;
1015 char *oldval = line;
1016 line = realloc(line,maxlen);
1017 if (line == NULL) {
1018 if (oldval) free(oldval);
1019 return NULL;
1020 }
1021 }
1022 int c = fgetc(stdin);
1023 if (c == EOF || c == '\n') {
1024 if (c == EOF && len == 0) {
1025 free(line);
1026 return NULL;
1027 } else {
1028 line[len] = '\0';
1029 return line;
1030 }
1031 } else {
1032 line[len] = c;
1033 len++;
1034 }
1035 }
1036 }
1037
1038
1039
1040
1041
1042
1043 char *linenoise(const char *prompt) {
1044 char buf[LINENOISE_MAX_LINE];
1045 int count;
1046
1047 if (!isatty(STDIN_FILENO)) {
1048
1049
1050 return linenoiseNoTTY();
1051 } else if (isUnsupportedTerm()) {
1052 size_t len;
1053
1054 printf("%s",prompt);
1055 fflush(stdout);
1056 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1057 len = strlen(buf);
1058 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1059 len--;
1060 buf[len] = '\0';
1061 }
1062 return strdup(buf);
1063 } else {
1064 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1065 if (count == -1) return NULL;
1066 return strdup(buf);
1067 }
1068 }
1069
1070
1071
1072
1073
1074 void linenoiseFree(void *ptr) {
1075 free(ptr);
1076 }
1077
1078
1079
1080
1081
1082 static void freeHistory(void) {
1083 if (history) {
1084 int j;
1085
1086 for (j = 0; j < history_len; j++)
1087 free(history[j]);
1088 free(history);
1089 }
1090 }
1091
1092
1093 static void linenoiseAtExit(void) {
1094 disableRawMode(STDIN_FILENO);
1095 freeHistory();
1096 }
1097
1098
1099
1100
1101
1102
1103
1104
1105 int linenoiseHistoryAdd(const char *line) {
1106 char *linecopy;
1107
1108 if (history_max_len == 0) return 0;
1109
1110
1111 if (history == NULL) {
1112 history = malloc(sizeof(char*)*history_max_len);
1113 if (history == NULL) return 0;
1114 memset(history,0,(sizeof(char*)*history_max_len));
1115 }
1116
1117
1118 if (history_len && !strcmp(history[history_len-1], line)) return 0;
1119
1120
1121
1122 linecopy = strdup(line);
1123 if (!linecopy) return 0;
1124 if (history_len == history_max_len) {
1125 free(history[0]);
1126 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1127 history_len--;
1128 }
1129 history[history_len] = linecopy;
1130 history_len++;
1131 return 1;
1132 }
1133
1134
1135
1136
1137
1138 int linenoiseHistorySetMaxLen(int len) {
1139 char **new;
1140
1141 if (len < 1) return 0;
1142 if (history) {
1143 int tocopy = history_len;
1144
1145 new = malloc(sizeof(char*)*len);
1146 if (new == NULL) return 0;
1147
1148
1149 if (len < tocopy) {
1150 int j;
1151
1152 for (j = 0; j < tocopy-len; j++) free(history[j]);
1153 tocopy = len;
1154 }
1155 memset(new,0,sizeof(char*)*len);
1156 memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1157 free(history);
1158 history = new;
1159 }
1160 history_max_len = len;
1161 if (history_len > history_max_len)
1162 history_len = history_max_len;
1163 return 1;
1164 }
1165
1166
1167
1168 int linenoiseHistorySave(const char *filename) {
1169 mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1170 FILE *fp;
1171 int j;
1172
1173 fp = fopen(filename,"w");
1174 umask(old_umask);
1175 if (fp == NULL) return -1;
1176 chmod(filename,S_IRUSR|S_IWUSR);
1177 for (j = 0; j < history_len; j++)
1178 fprintf(fp,"%s\n",history[j]);
1179 fclose(fp);
1180 return 0;
1181 }
1182
1183
1184
1185
1186
1187
1188 int linenoiseHistoryLoad(const char *filename) {
1189 FILE *fp = fopen(filename,"r");
1190 char buf[LINENOISE_MAX_LINE];
1191
1192 if (fp == NULL) return -1;
1193
1194 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1195 char *p;
1196
1197 p = strchr(buf,'\r');
1198 if (!p) p = strchr(buf,'\n');
1199 if (p) *p = '\0';
1200 linenoiseHistoryAdd(buf);
1201 }
1202 fclose(fp);
1203 return 0;
1204 }