linenoise.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. *
  8. * Does a number of crazy assumptions that happen to be true in 99.9999% of
  9. * the 2010 UNIX computers around.
  10. *
  11. * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
  12. * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
  13. *
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or without
  17. * modification, are permitted provided that the following conditions are met:
  18. *
  19. * * Redistributions of source code must retain the above copyright notice,
  20. * this list of conditions and the following disclaimer.
  21. * * Redistributions in binary form must reproduce the above copyright
  22. * notice, this list of conditions and the following disclaimer in the
  23. * documentation and/or other materials provided with the distribution.
  24. * * Neither the name of Redis nor the names of its contributors may be used
  25. * to endorse or promote products derived from this software without
  26. * specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  29. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  34. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  35. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * References:
  41. * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
  42. * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
  43. *
  44. * Todo list:
  45. * - Switch to gets() if $TERM is something we can't support.
  46. * - Filter bogus Ctrl+<char> combinations.
  47. * - Win32 support
  48. *
  49. * Bloat:
  50. * - Completion?
  51. * - History search like Ctrl+r in readline?
  52. *
  53. * List of escape sequences used by this program, we do everything just
  54. * with three sequences. In order to be so cheap we may have some
  55. * flickering effect with some slow terminal, but the lesser sequences
  56. * the more compatible.
  57. *
  58. * CHA (Cursor Horizontal Absolute)
  59. * Sequence: ESC [ n G
  60. * Effect: moves cursor to column n
  61. *
  62. * EL (Erase Line)
  63. * Sequence: ESC [ n K
  64. * Effect: if n is 0 or missing, clear from cursor to end of line
  65. * Effect: if n is 1, clear from beginning of line to cursor
  66. * Effect: if n is 2, clear entire line
  67. *
  68. * CUF (CUrsor Forward)
  69. * Sequence: ESC [ n C
  70. * Effect: moves cursor forward of n chars
  71. *
  72. * The following are used to clear the screen: ESC [ H ESC [ 2 J
  73. * This is actually composed of two sequences:
  74. *
  75. * cursorhome
  76. * Sequence: ESC [ H
  77. * Effect: moves the cursor to upper left corner
  78. *
  79. * ED2 (Clear entire screen)
  80. * Sequence: ESC [ 2 J
  81. * Effect: clear the whole screen
  82. *
  83. */
  84. #include <termios.h>
  85. #include <unistd.h>
  86. #include <stdlib.h>
  87. #include <stdio.h>
  88. #include <errno.h>
  89. #include <string.h>
  90. #include <stdlib.h>
  91. #include <sys/types.h>
  92. #include <sys/ioctl.h>
  93. #include <unistd.h>
  94. #include "linenoise.h"
  95. #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
  96. #define LINENOISE_MAX_LINE 4096
  97. static char *unsupported_term[] = {"dumb","cons25",NULL};
  98. static linenoiseCompletionCallback *completionCallback = NULL;
  99. static struct termios orig_termios; /* in order to restore at exit */
  100. static int rawmode = 0; /* for atexit() function to check if restore is needed*/
  101. static int atexit_registered = 0; /* register atexit just 1 time */
  102. static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
  103. static int history_len = 0;
  104. char **history = NULL;
  105. static void linenoiseAtExit(void);
  106. int linenoiseHistoryAdd(const char *line);
  107. static int isUnsupportedTerm(void) {
  108. char *term = getenv("TERM");
  109. int j;
  110. if (term == NULL) return 0;
  111. for (j = 0; unsupported_term[j]; j++)
  112. if (!strcasecmp(term,unsupported_term[j])) return 1;
  113. return 0;
  114. }
  115. static void freeHistory(void) {
  116. if (history) {
  117. int j;
  118. for (j = 0; j < history_len; j++)
  119. free(history[j]);
  120. free(history);
  121. }
  122. }
  123. static int enableRawMode(int fd) {
  124. struct termios raw;
  125. if (!isatty(STDIN_FILENO)) goto fatal;
  126. if (!atexit_registered) {
  127. atexit(linenoiseAtExit);
  128. atexit_registered = 1;
  129. }
  130. if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
  131. raw = orig_termios; /* modify the original mode */
  132. /* input modes: no break, no CR to NL, no parity check, no strip char,
  133. * no start/stop output control. */
  134. raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  135. /* output modes - disable post processing */
  136. raw.c_oflag &= ~(OPOST);
  137. /* control modes - set 8 bit chars */
  138. raw.c_cflag |= (CS8);
  139. /* local modes - choing off, canonical off, no extended functions,
  140. * no signal chars (^Z,^C) */
  141. raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
  142. /* control chars - set return condition: min number of bytes and timer.
  143. * We want read to return every single byte, without timeout. */
  144. raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
  145. /* put terminal in raw mode after flushing */
  146. if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
  147. rawmode = 1;
  148. return 0;
  149. fatal:
  150. errno = ENOTTY;
  151. return -1;
  152. }
  153. static void disableRawMode(int fd) {
  154. /* Don't even check the return value as it's too late. */
  155. if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
  156. rawmode = 0;
  157. }
  158. /* At exit we'll try to fix the terminal to the initial conditions. */
  159. static void linenoiseAtExit(void) {
  160. disableRawMode(STDIN_FILENO);
  161. freeHistory();
  162. }
  163. static int getColumns(void) {
  164. struct winsize ws;
  165. if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80;
  166. return ws.ws_col;
  167. }
  168. static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) {
  169. char seq[64];
  170. size_t plen = strlen(prompt);
  171. while((plen+pos) >= cols) {
  172. buf++;
  173. len--;
  174. pos--;
  175. }
  176. while (plen+len > cols) {
  177. len--;
  178. }
  179. /* Cursor to left edge */
  180. snprintf(seq,64,"\x1b[0G");
  181. if (write(fd,seq,strlen(seq)) == -1) return;
  182. /* Write the prompt and the current buffer content */
  183. if (write(fd,prompt,strlen(prompt)) == -1) return;
  184. if (write(fd,buf,len) == -1) return;
  185. /* Erase to right */
  186. snprintf(seq,64,"\x1b[0K");
  187. if (write(fd,seq,strlen(seq)) == -1) return;
  188. /* Move cursor to original position. */
  189. snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
  190. if (write(fd,seq,strlen(seq)) == -1) return;
  191. }
  192. static void beep() {
  193. fprintf(stderr, "\x7");
  194. fflush(stderr);
  195. }
  196. static void freeCompletions(linenoiseCompletions *lc) {
  197. size_t i;
  198. for (i = 0; i < lc->len; i++)
  199. free(lc->cvec[i]);
  200. if (lc->cvec != NULL)
  201. free(lc->cvec);
  202. }
  203. static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) {
  204. linenoiseCompletions lc = { 0, NULL };
  205. int nread, nwritten;
  206. char c = 0;
  207. completionCallback(buf,&lc);
  208. if (lc.len == 0) {
  209. beep();
  210. } else {
  211. size_t stop = 0, i = 0;
  212. size_t clen;
  213. while(!stop) {
  214. /* Show completion or original buffer */
  215. if (i < lc.len) {
  216. clen = strlen(lc.cvec[i]);
  217. refreshLine(fd,prompt,lc.cvec[i],clen,clen,cols);
  218. } else {
  219. refreshLine(fd,prompt,buf,*len,*pos,cols);
  220. }
  221. nread = read(fd,&c,1);
  222. if (nread <= 0) {
  223. freeCompletions(&lc);
  224. return -1;
  225. }
  226. switch(c) {
  227. case 9: /* tab */
  228. i = (i+1) % (lc.len+1);
  229. if (i == lc.len) beep();
  230. break;
  231. case 27: /* escape */
  232. /* Re-show original buffer */
  233. if (i < lc.len) {
  234. refreshLine(fd,prompt,buf,*len,*pos,cols);
  235. }
  236. stop = 1;
  237. break;
  238. default:
  239. /* Update buffer and return */
  240. if (i < lc.len) {
  241. nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]);
  242. *len = *pos = nwritten;
  243. }
  244. stop = 1;
  245. break;
  246. }
  247. }
  248. }
  249. freeCompletions(&lc);
  250. return c; /* Return last read character */
  251. }
  252. void linenoiseClearScreen(void) {
  253. if (write(STDIN_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
  254. /* nothing to do, just to avoid warning. */
  255. }
  256. }
  257. static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) {
  258. size_t plen = strlen(prompt);
  259. size_t pos = 0;
  260. size_t len = 0;
  261. size_t cols = getColumns();
  262. int history_index = 0;
  263. buf[0] = '\0';
  264. buflen--; /* Make sure there is always space for the nulterm */
  265. /* The latest history entry is always our current buffer, that
  266. * initially is just an empty string. */
  267. linenoiseHistoryAdd("");
  268. if (write(fd,prompt,plen) == -1) return -1;
  269. while(1) {
  270. char c;
  271. int nread;
  272. char seq[2], seq2[2];
  273. nread = read(fd,&c,1);
  274. if (nread <= 0) return len;
  275. /* Only autocomplete when the callback is set. It returns < 0 when
  276. * there was an error reading from fd. Otherwise it will return the
  277. * character that should be handled next. */
  278. if (c == 9 && completionCallback != NULL) {
  279. c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
  280. /* Return on errors */
  281. if (c < 0) return len;
  282. /* Read next character when 0 */
  283. if (c == 0) continue;
  284. }
  285. switch(c) {
  286. case 13: /* enter */
  287. history_len--;
  288. free(history[history_len]);
  289. return (int)len;
  290. case 3: /* ctrl-c */
  291. errno = EAGAIN;
  292. return -1;
  293. case 127: /* backspace */
  294. case 8: /* ctrl-h */
  295. if (pos > 0 && len > 0) {
  296. memmove(buf+pos-1,buf+pos,len-pos);
  297. pos--;
  298. len--;
  299. buf[len] = '\0';
  300. refreshLine(fd,prompt,buf,len,pos,cols);
  301. }
  302. break;
  303. case 4: /* ctrl-d, remove char at right of cursor */
  304. if (len > 1 && pos < (len-1)) {
  305. memmove(buf+pos,buf+pos+1,len-pos);
  306. len--;
  307. buf[len] = '\0';
  308. refreshLine(fd,prompt,buf,len,pos,cols);
  309. } else if (len == 0) {
  310. history_len--;
  311. free(history[history_len]);
  312. return -1;
  313. }
  314. break;
  315. case 20: /* ctrl-t */
  316. if (pos > 0 && pos < len) {
  317. int aux = buf[pos-1];
  318. buf[pos-1] = buf[pos];
  319. buf[pos] = aux;
  320. if (pos != len-1) pos++;
  321. refreshLine(fd,prompt,buf,len,pos,cols);
  322. }
  323. break;
  324. case 2: /* ctrl-b */
  325. goto left_arrow;
  326. case 6: /* ctrl-f */
  327. goto right_arrow;
  328. case 16: /* ctrl-p */
  329. seq[1] = 65;
  330. goto up_down_arrow;
  331. case 14: /* ctrl-n */
  332. seq[1] = 66;
  333. goto up_down_arrow;
  334. break;
  335. case 27: /* escape sequence */
  336. if (read(fd,seq,2) == -1) break;
  337. if (seq[0] == 91 && seq[1] == 68) {
  338. left_arrow:
  339. /* left arrow */
  340. if (pos > 0) {
  341. pos--;
  342. refreshLine(fd,prompt,buf,len,pos,cols);
  343. }
  344. } else if (seq[0] == 91 && seq[1] == 67) {
  345. right_arrow:
  346. /* right arrow */
  347. if (pos != len) {
  348. pos++;
  349. refreshLine(fd,prompt,buf,len,pos,cols);
  350. }
  351. } else if (seq[0] == 91 && (seq[1] == 65 || seq[1] == 66)) {
  352. up_down_arrow:
  353. /* up and down arrow: history */
  354. if (history_len > 1) {
  355. /* Update the current history entry before to
  356. * overwrite it with tne next one. */
  357. free(history[history_len-1-history_index]);
  358. history[history_len-1-history_index] = strdup(buf);
  359. /* Show the new entry */
  360. history_index += (seq[1] == 65) ? 1 : -1;
  361. if (history_index < 0) {
  362. history_index = 0;
  363. break;
  364. } else if (history_index >= history_len) {
  365. history_index = history_len-1;
  366. break;
  367. }
  368. strncpy(buf,history[history_len-1-history_index],buflen);
  369. buf[buflen] = '\0';
  370. len = pos = strlen(buf);
  371. refreshLine(fd,prompt,buf,len,pos,cols);
  372. }
  373. } else if (seq[0] == 91 && seq[1] > 48 && seq[1] < 55) {
  374. /* extended escape */
  375. if (read(fd,seq2,2) == -1) break;
  376. if (seq[1] == 51 && seq2[0] == 126) {
  377. /* delete */
  378. if (len > 0 && pos < len) {
  379. memmove(buf+pos,buf+pos+1,len-pos-1);
  380. len--;
  381. buf[len] = '\0';
  382. refreshLine(fd,prompt,buf,len,pos,cols);
  383. }
  384. }
  385. }
  386. break;
  387. default:
  388. if (len < buflen) {
  389. if (len == pos) {
  390. buf[pos] = c;
  391. pos++;
  392. len++;
  393. buf[len] = '\0';
  394. if (plen+len < cols) {
  395. /* Avoid a full update of the line in the
  396. * trivial case. */
  397. if (write(fd,&c,1) == -1) return -1;
  398. } else {
  399. refreshLine(fd,prompt,buf,len,pos,cols);
  400. }
  401. } else {
  402. memmove(buf+pos+1,buf+pos,len-pos);
  403. buf[pos] = c;
  404. len++;
  405. pos++;
  406. buf[len] = '\0';
  407. refreshLine(fd,prompt,buf,len,pos,cols);
  408. }
  409. }
  410. break;
  411. case 21: /* Ctrl+u, delete the whole line. */
  412. buf[0] = '\0';
  413. pos = len = 0;
  414. refreshLine(fd,prompt,buf,len,pos,cols);
  415. break;
  416. case 11: /* Ctrl+k, delete from current to end of line. */
  417. buf[pos] = '\0';
  418. len = pos;
  419. refreshLine(fd,prompt,buf,len,pos,cols);
  420. break;
  421. case 1: /* Ctrl+a, go to the start of the line */
  422. pos = 0;
  423. refreshLine(fd,prompt,buf,len,pos,cols);
  424. break;
  425. case 5: /* ctrl+e, go to the end of the line */
  426. pos = len;
  427. refreshLine(fd,prompt,buf,len,pos,cols);
  428. break;
  429. case 12: /* ctrl+l, clear screen */
  430. linenoiseClearScreen();
  431. refreshLine(fd,prompt,buf,len,pos,cols);
  432. }
  433. }
  434. return len;
  435. }
  436. static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
  437. int fd = STDIN_FILENO;
  438. int count;
  439. if (buflen == 0) {
  440. errno = EINVAL;
  441. return -1;
  442. }
  443. if (!isatty(STDIN_FILENO)) {
  444. if (fgets(buf, buflen, stdin) == NULL) return -1;
  445. count = strlen(buf);
  446. if (count && buf[count-1] == '\n') {
  447. count--;
  448. buf[count] = '\0';
  449. }
  450. } else {
  451. if (enableRawMode(fd) == -1) return -1;
  452. count = linenoisePrompt(fd, buf, buflen, prompt);
  453. disableRawMode(fd);
  454. printf("\n");
  455. }
  456. return count;
  457. }
  458. char *linenoise(const char *prompt) {
  459. char buf[LINENOISE_MAX_LINE];
  460. int count;
  461. if (isUnsupportedTerm()) {
  462. size_t len;
  463. printf("%s",prompt);
  464. fflush(stdout);
  465. if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
  466. len = strlen(buf);
  467. while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
  468. len--;
  469. buf[len] = '\0';
  470. }
  471. return strdup(buf);
  472. } else {
  473. count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
  474. if (count == -1) return NULL;
  475. return strdup(buf);
  476. }
  477. }
  478. /* Register a callback function to be called for tab-completion. */
  479. void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
  480. completionCallback = fn;
  481. }
  482. void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
  483. size_t len = strlen(str);
  484. char *copy = malloc(len+1);
  485. memcpy(copy,str,len+1);
  486. lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
  487. lc->cvec[lc->len++] = copy;
  488. }
  489. /* Using a circular buffer is smarter, but a bit more complex to handle. */
  490. int linenoiseHistoryAdd(const char *line) {
  491. char *linecopy;
  492. if (history_max_len == 0) return 0;
  493. if (history == NULL) {
  494. history = malloc(sizeof(char*)*history_max_len);
  495. if (history == NULL) return 0;
  496. memset(history,0,(sizeof(char*)*history_max_len));
  497. }
  498. linecopy = strdup(line);
  499. if (!linecopy) return 0;
  500. if (history_len == history_max_len) {
  501. free(history[0]);
  502. memmove(history,history+1,sizeof(char*)*(history_max_len-1));
  503. history_len--;
  504. }
  505. history[history_len] = linecopy;
  506. history_len++;
  507. return 1;
  508. }
  509. int linenoiseHistorySetMaxLen(int len) {
  510. char **new;
  511. if (len < 1) return 0;
  512. if (history) {
  513. int tocopy = history_len;
  514. new = malloc(sizeof(char*)*len);
  515. if (new == NULL) return 0;
  516. if (len < tocopy) tocopy = len;
  517. memcpy(new,history+(history_max_len-tocopy), sizeof(char*)*tocopy);
  518. free(history);
  519. history = new;
  520. }
  521. history_max_len = len;
  522. if (history_len > history_max_len)
  523. history_len = history_max_len;
  524. return 1;
  525. }
  526. /* Save the history in the specified file. On success 0 is returned
  527. * otherwise -1 is returned. */
  528. int linenoiseHistorySave(char *filename) {
  529. FILE *fp = fopen(filename,"w");
  530. int j;
  531. if (fp == NULL) return -1;
  532. for (j = 0; j < history_len; j++)
  533. fprintf(fp,"%s\n",history[j]);
  534. fclose(fp);
  535. return 0;
  536. }
  537. /* Load the history from the specified file. If the file does not exist
  538. * zero is returned and no operation is performed.
  539. *
  540. * If the file exists and the operation succeeded 0 is returned, otherwise
  541. * on error -1 is returned. */
  542. int linenoiseHistoryLoad(char *filename) {
  543. FILE *fp = fopen(filename,"r");
  544. char buf[LINENOISE_MAX_LINE];
  545. if (fp == NULL) return -1;
  546. while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
  547. char *p;
  548. p = strchr(buf,'\r');
  549. if (!p) p = strchr(buf,'\n');
  550. if (p) *p = '\0';
  551. linenoiseHistoryAdd(buf);
  552. }
  553. fclose(fp);
  554. return 0;
  555. }