root/src/simh/linehistory.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. linenoiseMaskModeEnable
  2. linenoiseMaskModeDisable
  3. linenoiseSetMultiLine
  4. isUnsupportedTerm
  5. enableRawMode
  6. disableRawMode
  7. getCursorPosition
  8. getColumns
  9. linenoiseClearScreen
  10. linenoiseBeep
  11. freeCompletions
  12. completeLine
  13. linenoiseSetCompletionCallback
  14. linenoiseSetHintsCallback
  15. linenoiseSetFreeHintsCallback
  16. linenoiseAddCompletion
  17. abInit
  18. abAppend
  19. abFree
  20. refreshShowHints
  21. refreshSingleLine
  22. refreshMultiLine
  23. refreshLine
  24. linenoiseEditInsert
  25. linenoiseEditMoveLeft
  26. linenoiseEditMoveRight
  27. linenoiseEditMoveWordEnd
  28. linenoiseEditMoveWordStart
  29. linenoiseEditMoveHome
  30. linenoiseEditMoveEnd
  31. linenoiseEditHistoryNext
  32. linenoiseSearchInHistory
  33. linenoiseEditDelete
  34. linenoiseEditBackspace
  35. linenoiseEditDeletePrevWord
  36. linenoiseEditDeleteNextWord
  37. linenoiseEdit
  38. linenoiseRaw
  39. linenoiseNoTTY
  40. linenoise
  41. linenoiseFree
  42. freeHistory
  43. linenoiseAtExit
  44. linenoiseHistoryAdd
  45. linenoiseHistorySetMaxLen
  46. pstrlen

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: BSD-2-Clause
   4  * scspell-id: 676f2224-f62a-11ec-baf3-80ee73e9b8e7
   5  *
   6  * -------------------------------------------------------------------------
   7  *
   8  * linehistory.c
   9  *
  10  * linehistory is forked from linenoise; the original version
  11  * is available from https://github.com/antirez/linenoise
  12  *
  13  * ------------------------------------------------------------------------
  14  *
  15  * Copyright (c) 2010-2014 Salvatore Sanfilippo <antirez@gmail.com>
  16  * Copyright (c) 2010-2013 Pieter Noordhuis <pcnoordhuis@gmail.com>
  17  * Copyright (c) 2020-2021 Jeffrey H. Johnson <trnsz@pobox.com>
  18  * Copyright (c) 2021-2022 The DPS8M Development Team
  19  *
  20  * All rights reserved.
  21  *
  22  * Redistribution and use in source and binary forms, with or without
  23  * modification, are permitted provided that the following conditions are
  24  * met:
  25  *
  26  *  *  Redistributions of source code must retain the above copyright
  27  *     notice, this list of conditions and the following disclaimer.
  28  *
  29  *  *  Redistributions in binary form must reproduce the above copyright
  30  *     notice, this list of conditions and the following disclaimer in the
  31  *     documentation and/or other materials provided with the distribution.
  32  *
  33  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  34  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  35  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  36  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  37  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  40  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  41  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  43  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44  *
  45  * -------------------------------------------------------------------------
  46  */
  47 
  48 #ifndef _POSIX_C_SOURCE
  49 # define _POSIX_C_SOURCE 200809L
  50 #endif /* ifndef _POSIX_C_SOURCE */
  51 
  52 #if !defined  ( __MINGW32__ )    \
  53   && !defined ( CROSS_MINGW32 )  \
  54   && !defined ( CROSS_MINGW64 )  \
  55   && !defined ( __MINGW64__ )    \
  56   && !defined ( _MSC_VER )       \
  57   && !defined ( _MSC_BUILD )
  58 
  59 # if defined( __sun ) && defined( __SVR4 )
  60 #  ifndef __EXTENSIONS__
  61 #   define __EXTENSIONS__ 1
  62 #  endif /* ifndef __EXTENSIONS__ */
  63 # endif /* if defined( __sun ) && defined( __SVR4 ) */
  64 # include <termios.h>
  65 # if defined( __sun ) && defined( __SVR4 )
  66 #  include <sys/termiox.h>
  67 # endif /* if defined( __sun ) && defined( __SVR4 ) */
  68 # include "linehistory.h"
  69 # ifndef __NetBSD__
  70 #  include "../dps8/dps8.h"
  71 # endif /* ifndef __NetBSD__ */
  72 # include <ctype.h>
  73 # include <errno.h>
  74 # include <stdio.h>
  75 # include <stdlib.h>
  76 # include <string.h>
  77 # include <strings.h>
  78 # include <sys/ioctl.h>
  79 # include <sys/stat.h>
  80 # include <sys/types.h>
  81 # include <unistd.h>
  82 
  83 # undef FREE
  84 # define FREE(p) do  \
  85   {                  \
  86     free((p));       \
  87     (p) = NULL;      \
  88   } while(0)
  89 
  90 # ifdef TESTING
  91 #  undef realloc
  92 #  undef FREE
  93 #  define FREE(p) free(p)
  94 #  define realloc trealloc
  95 # endif /* ifdef TESTING */
  96 
  97 # define LINENOISE_DEFAULT_HISTORY_MAX_LEN  100
  98 # define LINENOISE_MAX_LINE                4096
  99 
 100 static char *unsupported_term[] = {
 101   "dumb", "cons25", "emacs", NULL
 102 };
 103 
 104 # ifdef LH_COMPLETION
 105 static linenoiseCompletionCallback *completionCallback = NULL;
 106 # endif /* ifdef LH_COMPLETION */
 107 
 108 # ifdef LH_HINTS
 109 static linenoiseHintsCallback *hintsCallback           = NULL;
 110 static linenoiseFreeHintsCallback *freeHintsCallback   = NULL;
 111 # endif /* ifdef LH_HINTS */
 112 
 113 static struct termios orig_termios; /* In order to restore at exit.*/
 114 
 115 # ifdef LH_MASKMODE
 116 static int maskmode          = 0;   /* Show "**" instead of input for passwords */
 117 # endif /* ifdef LH_MASKMODE */
 118 
 119 static int rawmode           = 0;
 120 static int mlmode            = 0;   /* Multi line mode. Default is single line. */
 121 static int atexit_registered = 0;   /* Register atexit just 1 time.             */
 122 static int history_max_len   = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
 123 static int history_len       = 0;
 124 static char **history        = NULL;
 125 
 126 /*
 127  * The linenoiseState structure represents the state during line editing.
 128  * We pass this state to functions implementing specific editing
 129  * functionalities.
 130  */
 131 
 132 struct linenoiseState
 133 {
 134   int    ifd;            /* Terminal stdin file descriptor.                  */
 135   int    ofd;            /* Terminal stdout file descriptor.                 */
 136   char   *buf;           /* Edited line buffer.                              */
 137   size_t buflen;         /* Edited line buffer size.                         */
 138   const  char *prompt;   /* Prompt to display.                               */
 139   size_t plen;           /* Prompt length.                                   */
 140   size_t pos;            /* Current cursor position.                         */
 141   size_t oldpos;         /* Previous refresh cursor position.                */
 142   size_t len;            /* Current edited line length.                      */
 143   size_t cols;           /* Number of columns in terminal.                   */
 144   size_t maxrows;        /* Maximum num of rows used so far (multiline mode) */
 145   int    history_index;  /* The history index we are currently editing.      */
 146 };
 147 
 148 enum KEY_ACTION
 149 {
 150   KEY_NULL  = 0,  /* NULL      */
 151   CTRL_A    = 1,  /* Ctrl-A    */
 152   CTRL_B    = 2,  /* Ctrl-B    */
 153   CTRL_C    = 3,  /* Ctrl-C    */
 154   CTRL_D    = 4,  /* Ctrl-D    */
 155   CTRL_E    = 5,  /* Ctrl-E    */
 156   CTRL_F    = 6,  /* Ctrl-F    */
 157   CTRL_H    = 8,  /* Ctrl-H    */
 158   TAB       = 9,  /* Tab       */
 159   CTRL_K    = 11, /* Ctrl-K    */
 160   CTRL_L    = 12, /* Ctrl-L    */
 161   ENTER     = 13, /* Enter     */
 162   CTRL_N    = 14, /* Ctrl-N    */
 163   CTRL_P    = 16, /* Ctrl-P    */
 164   CTRL_T    = 20, /* Ctrl-T    */
 165   CTRL_U    = 21, /* Ctrl-U    */
 166   CTRL_W    = 23, /* Ctrl-W    */
 167   ESC       = 27, /* Escape    */
 168   BACKSPACE = 127 /* Backspace */
 169 };
 170 
 171 static void linenoiseAtExit(void);
 172 static void refreshLine(struct linenoiseState *l);
 173 size_t pstrlen(const char *s);
 174 
 175 # ifdef LH_MASKMODE
 176 
 177 /*
 178  * Enable "mask mode". When it is enabled, instead of the input that
 179  * the user is typing, the terminal will just display a corresponding
 180  * number of asterisks, like "****". This is useful for passwords and other
 181  * secrets that should not be displayed.
 182  */
 183 
 184 void
 185 linenoiseMaskModeEnable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187   maskmode = 1;
 188 }
 189 
 190 /* Disable mask mode. */
 191 void
 192 linenoiseMaskModeDisable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194   maskmode = 0;
 195 }
 196 # endif /* ifdef LH_MASKMODE */
 197 
 198 /* Set if to use or not the multi line mode. */
 199 void
 200 linenoiseSetMultiLine(int ml)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202   mlmode = ml;
 203 }
 204 
 205 /*
 206  * Return true if the terminal name is in the list of terminals we know are
 207  * not able to understand basic escape sequences.
 208  */
 209 
 210 static int
 211 isUnsupportedTerm(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213   char *term = getenv("TERM");
 214   int j;
 215 
 216   if (term == NULL)
 217   {
 218     return ( 0 );
 219   }
 220 
 221   for (j = 0; unsupported_term[j]; j++)
 222   {
 223     if (!strcasecmp(term, unsupported_term[j]))
 224     {
 225       return ( 1 );
 226     }
 227   }
 228 
 229   return ( 0 );
 230 }
 231 
 232 /* Raw mode */
 233 static int
 234 enableRawMode(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236   struct termios raw;
 237 
 238   if (!isatty(STDIN_FILENO))
 239   {
 240     goto fatal;
 241   }
 242 
 243   if (!atexit_registered)
 244   {
 245     atexit(linenoiseAtExit);
 246     atexit_registered = 1;
 247   }
 248 
 249   if (tcgetattr(fd, &orig_termios) == -1)
 250   {
 251     goto fatal;
 252   }
 253 
 254   raw = orig_termios; /* modify the original mode */
 255   /* input modes: no break, no CR to NL, no parity check, no strip char,
 256    * no start/stop output control. */
 257   raw.c_iflag &= ~( BRKINT | ICRNL | INPCK | ISTRIP | IXON );
 258   /* control modes - set 8 bit chars */
 259   raw.c_cflag |= ( CS8 );
 260   /* local modes - echoing off, canonical off, no extended functions,
 261    * no signal chars (^Z,^C) */
 262   raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
 263   /* control chars - set return condition: min number of bytes and timer.
 264    * We want read to return every single byte, without timeout. */
 265   raw.c_cc[VMIN]  = 1;
 266   raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
 267 
 268   /* put terminal in raw mode after flushing */
 269   if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
 270   {
 271     goto fatal;
 272   }
 273 
 274   rawmode = 1;
 275   return ( 0 );
 276 
 277 fatal:
 278   errno = ENOTTY;
 279   return ( -1 );
 280 }
 281 
 282 static void
 283 disableRawMode(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285   /* Don't even check the return value as it's too late. */
 286   if (rawmode && tcsetattr(fd, TCSAFLUSH, &orig_termios) != -1)
 287   {
 288     rawmode = 0;
 289   }
 290 }
 291 
 292 /*
 293  * Use the ESC [6n escape sequence to query the horizontal cursor position
 294  * and return it. On error -1 is returned, on success the position of the
 295  * cursor.
 296  */
 297 
 298 static int
 299 getCursorPosition(int ifd, int ofd)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301   char     buf[32];
 302   int      cols, rows;
 303   unsigned int i = 0;
 304 
 305   /* Report cursor location */
 306   if (write(ofd, "\x1b[6n", 4) != 4)
 307   {
 308     return ( -1 );
 309   }
 310 
 311   /* Read the response: ESC [ rows ; cols R */
 312   while (i < sizeof ( buf ) - 1)
 313   {
 314     if (read(ifd, buf + i, 1) != 1)
 315     {
 316       break;
 317     }
 318 
 319     if (buf[i] == 'R')
 320     {
 321       break;
 322     }
 323 
 324     i++;
 325   }
 326   buf[i] = '\0';
 327 
 328   /* Parse it. */
 329   if (buf[0] != ESC || buf[1] != '[')
 330   {
 331     return ( -1 );
 332   }
 333 
 334   if (sscanf(buf + 2, "%d;%d", &rows, &cols) != 2)
 335   {
 336     return ( -1 );
 337   }
 338 
 339   return ( cols );
 340 }
 341 
 342 /* Try to get the number of columns in terminal, or assume 80 */
 343 static int
 344 getColumns(int ifd, int ofd)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346   struct winsize ws;
 347 
 348   if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0)
 349   {
 350     /* ioctl() failed. Try to query the terminal itself. */
 351     int start, cols;
 352 
 353     /* Get the initial position so we can restore it later. */
 354     start = getCursorPosition(ifd, ofd);
 355     if (start == -1)
 356     {
 357       goto failed;
 358     }
 359 
 360     /* Go to right margin and get position. */
 361     if (write(ofd, "\x1b[999C", 6) != 6)
 362     {
 363       goto failed;
 364     }
 365 
 366     cols = getCursorPosition(ifd, ofd);
 367     if (cols == -1)
 368     {
 369       goto failed;
 370     }
 371 
 372     /* Restore position. */
 373     if (cols > start)
 374     {
 375       char seq[32];
 376       snprintf(seq, sizeof ( seq ), "\x1b[%dD", cols - start);
 377       if (write(ofd, seq, strlen(seq)) == -1)
 378       { /* Can't recover... */
 379       }
 380     }
 381 
 382     return ( cols );
 383   }
 384   else
 385   {
 386     return ( ws.ws_col );
 387   }
 388 
 389 failed:
 390   return ( 80 );
 391 }
 392 
 393 /* Clear the screen. Used to handle ctrl+l */
 394 void
 395 linenoiseClearScreen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397   if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0)
 398   { /* nothing to do, just to avoid warning. */
 399   }
 400 }
 401 
 402 # ifdef LH_COMPLETION
 403 
 404 /*
 405  * Beep, used for completion when there is nothing to complete or when all
 406  * the choices were already shown.
 407  */
 408 
 409 static void
 410 linenoiseBeep(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412   fprintf(stderr, "\x7");
 413   fflush(stderr);
 414 }
 415 
 416 /* Free a list of completion option populated by linenoiseAddCompletion(). */
 417 static void
 418 freeCompletions(const linenoiseCompletions *lc)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420   size_t i;
 421 
 422   for (i = 0; i < lc->len; i++)
 423   {
 424     FREE(lc->cvec[i]);
 425   }
 426 
 427   if (lc->cvec != NULL)
 428   {
 429     FREE(lc->cvec);
 430   }
 431 }
 432 
 433 /*
 434  * This is an helper function for linenoiseEdit() and is called when the
 435  * user types the <tab> key in order to complete the string currently in the
 436  * input.
 437  *
 438  * The state of the editing is encapsulated into the pointed linenoiseState
 439  * structure as described in the structure definition.
 440  */
 441 
 442 static int
 443 completeLine(struct linenoiseState *ls)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445   linenoiseCompletions lc = {
 446     0, NULL
 447   };
 448   int nread, nwritten;
 449   char c = 0;
 450 
 451   completionCallback(ls->buf, &lc);
 452   if (lc.len == 0)
 453   {
 454     linenoiseBeep();
 455   }
 456   else
 457   {
 458     size_t stop = 0, i = 0;
 459 
 460     while (!stop)
 461     {
 462       /* Show completion or original buffer */
 463       if (i < lc.len)
 464       {
 465         struct linenoiseState saved = *ls;
 466 
 467         ls->len = ls->pos = strlen(lc.cvec[i]);
 468         ls->buf = lc.cvec[i];
 469         refreshLine(ls);
 470         ls->len = saved.len;
 471         ls->pos = saved.pos;
 472         ls->buf = saved.buf;
 473       }
 474       else
 475       {
 476         refreshLine(ls);
 477       }
 478 
 479       nread = read(ls->ifd, &c, 1);
 480       if (nread <= 0)
 481       {
 482         freeCompletions(&lc);
 483         return ( -1 );
 484       }
 485 
 486       switch (c)
 487       {
 488       case 9: /* Tab */
 489         i = ( i + 1 ) % ( lc.len + 1 );
 490         if (i == lc.len)
 491         {
 492           linenoiseBeep();
 493         }
 494 
 495         stop = 1;
 496         break;
 497 
 498       default:
 499         /* Update buffer and return */
 500         if (i < lc.len)
 501         {
 502           nwritten = snprintf(ls->buf, ls->buflen, "%s", lc.cvec[i]);
 503           ls->len  = ls->pos = nwritten;
 504         }
 505 
 506         stop = 1;
 507         break;
 508       }
 509     }
 510   }
 511 
 512   freeCompletions(&lc);
 513   return ( c ); /* Return last read character */
 514 }
 515 
 516 /* Register a callback function to be called for tab-completion. */
 517 void
 518 linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 519 {
 520   completionCallback = fn;
 521 }
 522 
 523 # endif /* ifdef LH_COMPLETION */
 524 
 525 # ifdef LH_HINTS
 526 
 527 /*
 528  * Register a hits function to be called to show hits to the user at the
 529  * right of the prompt.
 530  */
 531 
 532 void
 533 linenoiseSetHintsCallback(linenoiseHintsCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 534 {
 535   hintsCallback = fn;
 536 }
 537 
 538 /*
 539  * Register a function to free the hints returned by the hints callback
 540  * registered with linenoiseSetHintsCallback().
 541  */
 542 
 543 void
 544 linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 545 {
 546   freeHintsCallback = fn;
 547 }
 548 
 549 # endif /* ifdef LH_HINTS */
 550 
 551 # ifdef LH_COMPLETION
 552 
 553 /*
 554  * This function is used by the callback function registered by the user
 555  * in order to add completion options given the input string when the
 556  * user typed <tab>.
 557  */
 558 
 559 void
 560 linenoiseAddCompletion(linenoiseCompletions *lc, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
 561 {
 562   size_t len = strlen(str);
 563   char *copy, **cvec;
 564 
 565   copy = malloc(len + 1);
 566   if (copy == NULL)
 567   {
 568     return;
 569   }
 570 
 571   memcpy(copy, str, len + 1);
 572   cvec = realloc(lc->cvec, sizeof ( char * ) * ( lc->len + 1 ));
 573   if (cvec == NULL)
 574   {
 575     FREE(copy);
 576     return;
 577   }
 578 
 579   lc->cvec            = cvec;
 580   lc->cvec[lc->len++] = copy;
 581 }
 582 
 583 # endif /* ifdef LH_COMPLETION */
 584 
 585 /*
 586  * We define a very simple "append buffer" structure, that is an heap
 587  * allocated string where we can append to. This is useful in order to
 588  * write all the escape sequences in a buffer and flush them to the standard
 589  * output in a single call, to avoid flickering effects.
 590  */
 591 
 592 struct abuf
 593 {
 594   char *b;
 595   int len;
 596 };
 597 
 598 static void
 599 abInit(struct abuf *ab)
     /* [previous][next][first][last][top][bottom][index][help] */
 600 {
 601   ab->b = NULL;
 602   ab->len = 0;
 603 }
 604 
 605 static void
 606 abAppend(struct abuf *ab, const char *s, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 607 {
 608   if (len <= 0)
 609   {
 610     return;
 611   }
 612 
 613   char *new = realloc(ab->b, 1 + ab->len + len);
 614 
 615   if (new == NULL)
 616   {
 617     return;
 618   }
 619 
 620   memcpy(new + ab->len, s, len);
 621   ab->b    = new;
 622   ab->len += len;
 623 }
 624 
 625 static void
 626 abFree(const struct abuf *ab)
     /* [previous][next][first][last][top][bottom][index][help] */
 627 {
 628   free(ab->b);
 629 }
 630 
 631 # ifdef LH_HINTS
 632 
 633 /*
 634  * Helper of refreshSingleLine() and refreshMultiLine() to show hints
 635  * to the right of the prompt.
 636  */
 637 
 638 static void
 639 refreshShowHints(struct abuf *ab, const struct linenoiseState *l, int plen)
     /* [previous][next][first][last][top][bottom][index][help] */
 640 {
 641   char seq[64];
 642 
 643   seq[0] = '\0';
 644   if (hintsCallback && plen + l->len < l->cols)
 645   {
 646     int color = -1, bold = 0;
 647     char *hint = hintsCallback(l->buf, &color, &bold);
 648     if (hint)
 649     {
 650       int hintlen    = strlen(hint);
 651       int hintmaxlen = l->cols - ( plen + l->len );
 652       if (hintlen > hintmaxlen)
 653       {
 654         hintlen = hintmaxlen;
 655       }
 656 
 657       if (bold == 1 && color == -1)
 658       {
 659         color = 37;
 660       }
 661 
 662       if (color != -1 || bold != 0)
 663       {
 664         snprintf(seq, sizeof ( seq ), "\033[%d;%d;49m", bold, color);
 665       }
 666       else
 667       {
 668         seq[0] = '\0';
 669       }
 670 
 671       abAppend(ab, seq, strlen(seq));
 672       abAppend(ab, hint, hintlen);
 673       if (color != -1 || bold != 0)
 674       {
 675         abAppend(ab, "\033[0m", 4);
 676       }
 677 
 678       /* Call the function to free the hint returned. */
 679       if (freeHintsCallback)
 680       {
 681         freeHintsCallback(hint);
 682       }
 683     }
 684   }
 685 }
 686 
 687 # endif /* ifdef LH_HINTS */
 688 
 689 /*
 690  * Single line low level line refresh.
 691  *
 692  * Rewrite the currently edited line accordingly to the buffer content,
 693  * cursor position, and number of columns of the terminal.
 694  */
 695 
 696 static void
 697 refreshSingleLine(const struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 698 {
 699   char   seq[64];
 700   size_t plen = pstrlen(l->prompt);
 701   int    fd   = l->ofd;
 702   char   *buf = l->buf;
 703   size_t len  = l->len;
 704   size_t pos  = l->pos;
 705   struct abuf ab;
 706 
 707   while (( plen + pos ) >= l->cols)
 708   {
 709     buf++;
 710     len--;
 711     pos--;
 712   }
 713   while (plen + len > l->cols)
 714   {
 715     len--;
 716   }
 717 
 718   abInit(&ab);
 719   /* Cursor to left edge */
 720   snprintf(seq, sizeof ( seq ), "\r");
 721   abAppend(&ab, seq, strlen(seq));
 722   /* Write the prompt and the current buffer content */
 723   abAppend(&ab, l->prompt, strlen(l->prompt));
 724 # ifdef LH_MASKMODE
 725   if (maskmode == 1)
 726   {
 727     while (len--)
 728     {
 729       abAppend(&ab, "*", 1);
 730     }
 731   }
 732   else
 733   {
 734 # endif /* ifdef LH_MASKMODE */
 735   abAppend(&ab, buf, len);
 736 # ifdef LH_MASKMODE
 737 }
 738 # endif /* ifdef LH_MASKMODE */
 739 # ifdef LH_HINTS
 740   /* Show hits if any. */
 741   refreshShowHints(&ab, l, plen);
 742 # endif /* ifdef LH_HINTS */
 743   /* Erase to right */
 744   snprintf(seq, sizeof ( seq ), "\x1b[0K");
 745   abAppend(&ab, seq, strlen(seq));
 746   /* Move cursor to original position. */
 747   snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", (int)( pos + plen ));
 748   abAppend(&ab, seq, strlen(seq));
 749   if (write(fd, ab.b, ab.len) == -1)
 750   { /* Can't recover from write error. */
 751   }
 752 
 753   abFree(&ab);
 754 }
 755 
 756 /*
 757  * Multi line low level line refresh.
 758  *
 759  * Rewrite the currently edited line accordingly to the buffer content,
 760  * cursor position, and number of columns of the terminal.
 761  */
 762 
 763 static void
 764 refreshMultiLine(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 765 {
 766   char seq[64];
 767   int plen = strlen(l->prompt);
 768   int rows = ( plen + l->len + l->cols - 1 )
 769              / l->cols; /* rows used by current buf. */
 770   int rpos = ( plen + l->oldpos + l->cols ) / l->cols; /* cursor relative row. */
 771   int rpos2; /* rpos after refresh. */
 772   int col; /* colum position, zero-based. */
 773   int old_rows = l->maxrows;
 774   int fd = l->ofd, j;
 775   struct abuf ab;
 776 
 777   /* Update maxrows if needed. */
 778   if (rows > (int)l->maxrows)
 779   {
 780     l->maxrows = rows;
 781   }
 782 
 783   /*
 784    * First step: clear all the lines used before. To do so start by
 785    * going to the last row.
 786    */
 787 
 788   abInit(&ab);
 789   if (old_rows - rpos > 0)
 790   {
 791     snprintf(seq, sizeof ( seq ), "\x1b[%dB", old_rows - rpos);
 792     abAppend(&ab, seq, strlen(seq));
 793   }
 794 
 795   /* Now for every row clear it, go up. */
 796   for (j = 0; j < old_rows - 1; j++)
 797   {
 798     snprintf(seq, sizeof ( seq ), "\r\x1b[0K\x1b[1A");
 799     abAppend(&ab, seq, strlen(seq));
 800   }
 801 
 802   /* Clean the top line. */
 803   snprintf(seq, sizeof ( seq ), "\r\x1b[0K");
 804   abAppend(&ab, seq, strlen(seq));
 805 
 806   /* Write the prompt and the current buffer content */
 807   abAppend(&ab, l->prompt, strlen(l->prompt));
 808 # ifdef LH_MASKMODE
 809   if (maskmode == 1)
 810   {
 811     unsigned int i;
 812     for (i = 0; i < l->len; i++)
 813     {
 814       abAppend(&ab, "*", 1);
 815     }
 816   }
 817   else
 818   {
 819 # endif /* ifdef LH_MASKMODE */
 820   abAppend(&ab, l->buf, l->len);
 821 # ifdef LH_MASKMODE
 822 }
 823 # endif /* ifdef LH_MASKMODE */
 824 
 825 # ifdef LH_HINTS
 826   /* Show hits if any. */
 827   refreshShowHints(&ab, l, plen);
 828 # endif /* ifdef LH_HINTS */
 829 
 830   /*
 831    * If we are at the very end of the screen with our prompt, we need to
 832    * emit a newline and move the prompt to the first column.
 833    */
 834 
 835   if (l->pos && l->pos == l->len && ( l->pos + plen ) % l->cols == 0)
 836   {
 837     abAppend(&ab, "\n", 1);
 838     snprintf(seq, sizeof ( seq ), "\r");
 839     abAppend(&ab, seq, strlen(seq));
 840     rows++;
 841     if (rows > (int)l->maxrows)
 842     {
 843       l->maxrows = rows;
 844     }
 845   }
 846 
 847   /* Move cursor to right position. */
 848   rpos2 = ( plen + l->pos + l->cols ) / l->cols;
 849 
 850   /* Go up till we reach the expected positon. */
 851   if (rows - rpos2 > 0)
 852   {
 853     snprintf(seq, sizeof ( seq ), "\x1b[%dA", rows - rpos2);
 854     abAppend(&ab, seq, strlen(seq));
 855   }
 856 
 857   /* Set column. */
 858   col = ( plen + (int)l->pos ) % (int)l->cols;
 859   if (col)
 860   {
 861     snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", col);
 862   }
 863   else
 864   {
 865     snprintf(seq, sizeof ( seq ), "\r");
 866   }
 867 
 868   abAppend(&ab, seq, strlen(seq));
 869 
 870   l->oldpos = l->pos;
 871 
 872   if (write(fd, ab.b, ab.len) == -1)
 873   { /* Can't recover from write error. */
 874   }
 875 
 876   abFree(&ab);
 877 }
 878 
 879 /*
 880  * Calls the two low level functions refreshSingleLine() or
 881  * refreshMultiLine() according to the selected mode.
 882  */
 883 
 884 static void
 885 refreshLine(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 886 {
 887   l->cols = getColumns(STDIN_FILENO, STDOUT_FILENO);
 888   if (mlmode)
 889   {
 890     refreshMultiLine(l);
 891   }
 892   else
 893   {
 894     refreshSingleLine(l);
 895   }
 896 }
 897 
 898 /*
 899  * Insert the character 'c' at cursor current position.
 900  * On error writing to the terminal -1 is returned, otherwise 0.
 901  */
 902 
 903 int
 904 linenoiseEditInsert(struct linenoiseState *l, char c)
     /* [previous][next][first][last][top][bottom][index][help] */
 905 {
 906   if (l->len < l->buflen)
 907   {
 908     if (l->len == l->pos)
 909     {
 910       l->buf[l->pos] = c;
 911       l->pos++;
 912       l->len++;
 913       l->buf[l->len] = '\0';
 914 # if defined( LH_MASKMODE ) && defined( LH_HINTS )
 915       if (( !mlmode && l->plen + l->len < l->cols && !hintsCallback ))
 916       {
 917         /* Avoid a full update of the line in the trivial case. */
 918         char d = ( maskmode == 1 ) ? '*' : (char)c;
 919         if (write(l->ofd, &d, 1) == -1)
 920         {
 921           return ( -1 );
 922         }
 923       }
 924       else
 925       {
 926 # endif /* if defined( LH_MASKMODE ) && defined( LH_HINTS ) */
 927       refreshLine(l);
 928 # if defined( LH_MASKMODE ) && defined( LH_HINTS )
 929       }
 930 # endif /* if defined( LH_MASKMODE ) && defined( LH_HINTS ) */
 931     }
 932     else
 933     {
 934       memmove(l->buf + l->pos + 1, l->buf + l->pos, l->len - l->pos);
 935       l->buf[l->pos] = c;
 936       l->len++;
 937       l->pos++;
 938       l->buf[l->len] = '\0';
 939       refreshLine(l);
 940     }
 941   }
 942 
 943   return ( 0 );
 944 }
 945 
 946 /* Move cursor on the left. */
 947 void
 948 linenoiseEditMoveLeft(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 949 {
 950   if (l->pos > 0)
 951   {
 952     l->pos--;
 953     refreshLine(l);
 954   }
 955 }
 956 
 957 /* Move cursor on the right. */
 958 void
 959 linenoiseEditMoveRight(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 960 {
 961   if (l->pos != l->len)
 962   {
 963     l->pos++;
 964     refreshLine(l);
 965   }
 966 }
 967 
 968 /* Move cursor to the end of the current word. */
 969 void
 970 linenoiseEditMoveWordEnd(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 971 {
 972   if (l->len == 0 || l->pos >= l->len)
 973   {
 974     return;
 975   }
 976 
 977   if (l->buf[l->pos] == ' ')
 978   {
 979     while (l->pos < l->len && l->buf[l->pos] == ' ')
 980     {
 981       ++l->pos;
 982     }
 983   }
 984 
 985   while (l->pos < l->len && l->buf[l->pos] != ' ')
 986   {
 987     ++l->pos;
 988   }
 989   refreshLine(l);
 990 }
 991 
 992 /* Move cursor to the start of the current word. */
 993 void
 994 linenoiseEditMoveWordStart(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 995 {
 996   if (l->len == 0)
 997   {
 998     return;
 999   }
1000 
1001   if (l->buf[l->pos - 1] == ' ')
1002   {
1003     --l->pos;
1004   }
1005 
1006   if (l->buf[l->pos] == ' ')
1007   {
1008     while (l->pos > 0 && l->buf[l->pos] == ' ')
1009     {
1010       --l->pos;
1011     }
1012   }
1013 
1014   while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
1015   {
1016     --l->pos;
1017   }
1018   refreshLine(l);
1019 }
1020 
1021 /* Move cursor to the start of the line. */
1022 void
1023 linenoiseEditMoveHome(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1024 {
1025   if (l->pos != 0)
1026   {
1027     l->pos = 0;
1028     refreshLine(l);
1029   }
1030 }
1031 
1032 /* Move cursor to the end of the line. */
1033 void
1034 linenoiseEditMoveEnd(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1035 {
1036   if (l->pos != l->len)
1037   {
1038     l->pos = l->len;
1039     refreshLine(l);
1040   }
1041 }
1042 
1043 /*
1044  * Substitute the currently edited line with the next
1045  * or previous history entry as specified by 'dir'.
1046  */
1047 
1048 # define LINENOISE_HISTORY_NEXT 0
1049 # define LINENOISE_HISTORY_PREV 1
1050 void
1051 linenoiseEditHistoryNext(struct linenoiseState *l, int dir)
     /* [previous][next][first][last][top][bottom][index][help] */
1052 {
1053   if (history_len > 1)
1054   {
1055 
1056     /*
1057      * Update the current history entry before to
1058      * overwrite it with the next one.
1059      */
1060 
1061     FREE(history[history_len - 1 - l->history_index]);
1062     history[history_len - 1 - l->history_index] = strdup(l->buf);
1063     if (!history[history_len - 1 - l->history_index])
1064       {
1065         fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1066                  __func__, __FILE__, __LINE__);
1067 # if defined(USE_BACKTRACE)
1068 #  ifdef SIGUSR2
1069         (void)raise(SIGUSR2);
1070         /*NOTREACHED*/ /* unreachable */
1071 #  endif /* ifdef SIGUSR2 */
1072 # endif /* if defined(USE_BACKTRACE) */
1073         abort();
1074       }
1075     /* Show the new entry */
1076     l->history_index += ( dir == LINENOISE_HISTORY_PREV ) ? 1 : -1;
1077     if (l->history_index < 0)
1078     {
1079       l->history_index = 0;
1080       return;
1081     }
1082     else if (l->history_index >= history_len)
1083     {
1084       l->history_index = history_len - 1;
1085       return;
1086     }
1087 
1088     strncpy(l->buf, history[history_len - 1 - l->history_index], l->buflen);
1089     l->buf[l->buflen - 1] = '\0';
1090     l->len = l->pos = strlen(l->buf);
1091     refreshLine(l);
1092   }
1093 }
1094 
1095 /*
1096  * Search a line in history that start with the same characters as the
1097  * currently edited line. Substitute the current line with this history
1098  */
1099 
1100 # define LINENOISE_SEARCH_HISTORY_FORWARD 0
1101 # define LINENOISE_SEARCH_HISTORY_REVERSE 1
1102 void
1103 linenoiseSearchInHistory(struct linenoiseState *l, int direction)
     /* [previous][next][first][last][top][bottom][index][help] */
1104 {
1105   if (history_len > 1)
1106   {
1107 
1108     /*
1109      * Update the current history entry before to
1110      * overwrite it with the next one.
1111      */
1112 
1113     FREE(history[history_len - 1 - l->history_index]);
1114     history[history_len - 1 - l->history_index] = strdup(l->buf);
1115     if (!history[history_len - 1 - l->history_index])
1116       {
1117         fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1118                  __func__, __FILE__, __LINE__);
1119 # if defined(USE_BACKTRACE)
1120 #  ifdef SIGUSR2
1121         (void)raise(SIGUSR2);
1122         /*NOTREACHED*/ /* unreachable */
1123 #  endif /* ifdef SIGUSR2 */
1124 # endif /* if defined(USE_BACKTRACE) */
1125         abort();
1126       }
1127 
1128     /* Search new entry */
1129     int cnt;
1130     if (direction == LINENOISE_SEARCH_HISTORY_FORWARD)
1131     {
1132       cnt = history_len - 2 - l->history_index;
1133       for (; cnt >= 0; cnt--)
1134       {
1135 
1136         /*
1137          * Search a history entry that start with same
1138          * as the current line until the cursor position
1139          */
1140 
1141         if (strncmp(l->buf, history[cnt], l->pos) == 0)
1142         {
1143           strncpy(l->buf, history[cnt], l->buflen);
1144           l->buf[l->buflen - 1] = '\0';
1145           /* Don't change old cursor position */
1146           l->len = strlen(l->buf);
1147 
1148           /*
1149            * Set history index so that we can contiune
1150            * the search on this postiion
1151            */
1152 
1153           l->history_index = history_len - 1 - cnt;
1154           refreshLine(l);
1155           return;
1156         }
1157       }
1158     }
1159     else if (direction == LINENOISE_SEARCH_HISTORY_REVERSE)
1160     {
1161       cnt = history_len - l->history_index;
1162       for (; cnt < history_len; cnt++)
1163       {
1164 
1165         /*
1166          * Search a history entry that start with same
1167          * as the current line until the cursor position
1168          */
1169 
1170         if (strncmp(l->buf, history[cnt], l->pos) == 0)
1171         {
1172           strncpy(l->buf, history[cnt], l->buflen);
1173           l->buf[l->buflen - 1] = '\0';
1174           /* Don't change old cursor position */
1175           l->len = strlen(l->buf);
1176 
1177           /*
1178            * Set history index so that we can contiune
1179            * the search on this postiion
1180            */
1181 
1182           l->history_index = history_len - 1 - cnt;
1183           refreshLine(l);
1184           return;
1185         }
1186       }
1187     }
1188   }
1189 }
1190 
1191 /*
1192  * Delete the character at the right of the cursor without altering the cursor
1193  * position. Basically this is what happens with the "Delete" keyboard key.
1194  */
1195 
1196 void
1197 linenoiseEditDelete(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1198 {
1199   if (l->len > 0 && l->pos < l->len)
1200   {
1201     memmove(l->buf + l->pos, l->buf + l->pos + 1, l->len - l->pos - 1);
1202     l->len--;
1203     l->buf[l->len] = '\0';
1204     refreshLine(l);
1205   }
1206 }
1207 
1208 /* Backspace implementation. */
1209 void
1210 linenoiseEditBackspace(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1211 {
1212   if (l->pos > 0 && l->len > 0)
1213   {
1214     memmove(l->buf + l->pos - 1, l->buf + l->pos, l->len - l->pos);
1215     l->pos--;
1216     l->len--;
1217     l->buf[l->len] = '\0';
1218     refreshLine(l);
1219   }
1220 }
1221 
1222 /*
1223  * Delete the previous word, maintaining the
1224  * cursor at the start of the current word.
1225  */
1226 
1227 void
1228 linenoiseEditDeletePrevWord(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1229 {
1230   size_t old_pos = l->pos;
1231   size_t diff;
1232 
1233   while (l->pos > 0 && l->buf[l->pos - 1] == ' ')
1234   {
1235     l->pos--;
1236   }
1237   while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
1238   {
1239     l->pos--;
1240   }
1241   diff = old_pos - l->pos;
1242   memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1);
1243   l->len -= diff;
1244   refreshLine(l);
1245 }
1246 
1247 /* Delete the next word, maintaining the cursor at the same position */
1248 void
1249 linenoiseEditDeleteNextWord(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1250 {
1251   size_t next_word_end = l->pos;
1252 
1253   while (next_word_end < l->len && l->buf[next_word_end] == ' ')
1254   {
1255     ++next_word_end;
1256   }
1257   while (next_word_end < l->len && l->buf[next_word_end] != ' ')
1258   {
1259     ++next_word_end;
1260   }
1261   memmove(l->buf + l->pos, l->buf + next_word_end, l->len - next_word_end);
1262   l->len -= next_word_end - l->pos;
1263   refreshLine(l);
1264 }
1265 
1266 /*
1267  * This function is the core of the line editing capability of linenoise.
1268  * It expects 'fd' to be already in "raw mode" so that every key pressed
1269  * will be returned ASAP to read().
1270  *
1271  * The resulting string is put into 'buf' when the user type enter, or
1272  * when ctrl+d is typed.
1273  *
1274  * The function returns the length of the current buffer.
1275  */
1276 
1277 static int
1278 linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
     /* [previous][next][first][last][top][bottom][index][help] */
1279               const char *prompt)
1280 {
1281   struct linenoiseState l;
1282 
1283   /*
1284    * Populate the linenoise state that we pass to functions implementing
1285    * specific editing functionalities.
1286    */
1287 
1288   l.ifd           = stdin_fd;
1289   l.ofd           = stdout_fd;
1290   l.buf           = buf;
1291   l.buflen        = buflen;
1292   l.prompt        = prompt;
1293   l.plen          = pstrlen(prompt);
1294   l.oldpos        = l.pos = 0;
1295   l.len           = 0;
1296   l.cols          = getColumns(stdin_fd, stdout_fd);
1297   l.maxrows       = 0;
1298   l.history_index = 0;
1299 
1300   /* Buffer starts empty. */
1301   l.buf[0] = '\0';
1302   l.buflen--; /* Make sure there is always space for the nulterm */
1303 
1304   /*
1305    * The latest history entry is always our current
1306    * buffer, that initially is just an empty string.
1307    */
1308 
1309   (void)linenoiseHistoryAdd("");
1310 
1311   if (write(l.ofd, prompt, strlen(prompt)) == -1)
1312   {
1313     return ( -1 );
1314   }
1315 
1316   while (1)
1317   {
1318     signed char c;
1319     int    nread;
1320     char   seq[3];
1321 
1322     nread = read(l.ifd, &c, 1);
1323     if (nread <= 0)
1324     {
1325       return ( l.len );
1326     }
1327 
1328 # ifdef LH_COMPLETION
1329 
1330     /*
1331      * Only autocomplete when the callback is set. It returns < 0 when
1332      * there was an error reading from fd. Otherwise it will return the
1333      * character that should be handled next.
1334      */
1335 
1336     if (c == 9 && completionCallback != NULL)
1337     {
1338       int cint = completeLine(&l);
1339       /* Return on errors */
1340       if (cint < 0)
1341       {
1342         return ( l.len );
1343       }
1344 
1345       /* Read next character when 0 */
1346       if (cint == 0)
1347       {
1348         continue;
1349       }
1350 
1351       c = (char)cint;
1352     }
1353 
1354 # endif /* ifdef LH_COMPLETION */
1355 
1356     switch (c)
1357     {
1358     case 9:
1359       break;    /* johnsonjh - disable processing of tabs */
1360 
1361     case ENTER: /* Enter */
1362       history_len--;
1363       FREE(history[history_len]);
1364       if (mlmode)
1365       {
1366         linenoiseEditMoveEnd(&l);
1367       }
1368 
1369 # ifdef LH_HINTS
1370       if (hintsCallback)
1371       {
1372 
1373         /*
1374          * Force a refresh without hints to leave the previous
1375          * line as the user typed it after a newline.
1376          */
1377 
1378         linenoiseHintsCallback *hc = hintsCallback;
1379         hintsCallback              = NULL;
1380         refreshLine(&l);
1381         hintsCallback              = hc;
1382       }
1383 
1384 # endif /* ifdef LH_HINTS */
1385       return ((int)l.len );
1386 
1387     case CTRL_C: /* Ctrl-C */
1388       errno = EAGAIN;
1389       return ( -1 );
1390 
1391     case BACKSPACE: /* Backspace */
1392     case 8:         /* Ctrl-H */
1393       linenoiseEditBackspace(&l);
1394       break;
1395 
1396     case CTRL_D:     /* Ctrl-D, remove char at right of cursor, or */
1397       if (l.len > 0) /* if the line is empty, act as end-of-file.  */
1398       {
1399         linenoiseEditDelete(&l);
1400       }
1401       else
1402       {
1403         history_len--;
1404         FREE(history[history_len]);
1405         return ( -1 );
1406       }
1407 
1408       break;
1409 
1410     case CTRL_T: /* Ctrl-T */
1411       break;
1412 
1413     case CTRL_B: /* Ctrl-B */
1414       linenoiseEditMoveLeft(&l);
1415       break;
1416 
1417     case CTRL_F: /* Ctrl-F */
1418       linenoiseEditMoveRight(&l);
1419       break;
1420 
1421     case CTRL_P: /* Ctrl-P */
1422       linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1423       break;
1424 
1425     case CTRL_N: /* Ctrl-N */
1426       linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1427       break;
1428 
1429     case ESC: /* Escape Sequence */
1430 
1431       /*
1432        * Read the next two bytes representing the escape sequence.
1433        * Use two calls to handle slow terminals returning the two
1434        * chars at different times.
1435        */
1436 
1437       if (read(l.ifd, seq, 1) == -1)
1438       {
1439         break;
1440       }
1441 
1442       if (read(l.ifd, seq + 1, 1) == -1)
1443       {
1444         break;
1445       }
1446 
1447       /* ESC [ sequences. */
1448       if (seq[0] == '[')
1449       {
1450         if (seq[1] >= '0' && seq[1] <= '9')
1451         {
1452           /* Extended escape, read additional byte. */
1453           if (read(l.ifd, seq + 2, 1) == -1)
1454           {
1455             break;
1456           }
1457 
1458           if (seq[2] == '~')
1459           {
1460             switch (seq[1])
1461             {
1462             case '3': /* Delete */
1463               linenoiseEditDelete(&l);
1464               break;
1465 
1466             case '6': /* Page Down */
1467               linenoiseSearchInHistory(
1468                 &l,
1469                 LINENOISE_SEARCH_HISTORY_REVERSE);
1470               break;
1471 
1472             case '5': /* Page Up */
1473               linenoiseSearchInHistory(
1474                 &l,
1475                 LINENOISE_SEARCH_HISTORY_FORWARD);
1476               break;
1477             }
1478           }
1479         }
1480         else
1481         {
1482           switch (seq[1])
1483           {
1484           case 'A': /* Up */
1485             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1486             break;
1487 
1488           case 'B': /* Down */
1489             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1490             break;
1491 
1492           case 'C': /* Right */
1493             linenoiseEditMoveRight(&l);
1494             break;
1495 
1496           case 'D': /* Left */
1497             linenoiseEditMoveLeft(&l);
1498             break;
1499 
1500           case 'H': /* Home */
1501             linenoiseEditMoveHome(&l);
1502             break;
1503 
1504           case 'F': /* End */
1505             linenoiseEditMoveEnd(&l);
1506             break;
1507           }
1508         }
1509       }
1510 
1511       break;
1512 
1513     default:
1514       if (linenoiseEditInsert(&l, c))
1515       {
1516         return ( -1 );
1517       }
1518 
1519       break;
1520 
1521     case CTRL_U: /* Ctrl+U, delete the whole line. */
1522       buf[0] = '\0';
1523       l.pos  = l.len = 0;
1524       refreshLine(&l);
1525       break;
1526 
1527     case CTRL_K: /* Ctrl+K, delete from current to end of line. */
1528       buf[l.pos] = '\0';
1529       l.len      = l.pos;
1530       refreshLine(&l);
1531       break;
1532 
1533     case CTRL_A: /* Ctrl+A, go to the start of the line */
1534       linenoiseEditMoveHome(&l);
1535       break;
1536 
1537     case CTRL_E: /* Ctrl+E, go to the end of the line */
1538       linenoiseEditMoveEnd(&l);
1539       break;
1540 
1541     case CTRL_L: /* Ctrl+L, clear screen */
1542       linenoiseClearScreen();
1543       refreshLine(&l);
1544       break;
1545 
1546     case CTRL_W: /* Ctrl+W, delete previous word */
1547       linenoiseEditDeletePrevWord(&l);
1548       break;
1549     }
1550   }
1551  /*NOTREACHED*/ /* unreachable */
1552  return ( -1 );
1553 }
1554 
1555 /*
1556  * This function calls the line editing function linenoiseEdit() using
1557  * the STDIN file descriptor set in raw mode.
1558  */
1559 
1560 static int
1561 linenoiseRaw(char *buf, size_t buflen, const char *prompt)
     /* [previous][next][first][last][top][bottom][index][help] */
1562 {
1563   int count;
1564 
1565   if (buflen == 0)
1566   {
1567     errno = EINVAL;
1568     return ( -1 );
1569   }
1570 
1571   if (enableRawMode(STDIN_FILENO) == -1)
1572   {
1573     return ( -1 );
1574   }
1575 
1576   count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1577   disableRawMode(STDIN_FILENO);
1578   printf("\n");
1579   return ( count );
1580 }
1581 
1582 /*
1583  * This function is called when linenoise() is called with the standard
1584  * input file descriptor not attached to a TTY. So for example when the
1585  * program using linenoise is called in pipe or with a file redirected
1586  * to its standard input. In this case, we want to be able to return the
1587  * line regardless of its length (by default we are limited to 4k).
1588  */
1589 
1590 static char *
1591 linenoiseNoTTY(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1592 {
1593   char *line = NULL;
1594   size_t len = 0, maxlen = 0;
1595 
1596   while (1)
1597   {
1598     if (len == maxlen)
1599     {
1600       if (maxlen == 0)
1601       {
1602         maxlen = 16;
1603       }
1604 
1605       maxlen *= 2;
1606       char *oldval = line;
1607       line = realloc(line, maxlen); //-V701
1608       if (line == NULL)
1609       {
1610         if (oldval)
1611         {
1612           FREE(oldval);
1613         }
1614 
1615         return ( NULL );
1616       }
1617     }
1618 
1619     int c = fgetc(stdin);
1620     if (c == EOF || c == '\n')
1621     {
1622       if (c == EOF && len == 0)
1623       {
1624         FREE(line);
1625         return ( NULL );
1626       }
1627       else
1628       {
1629         line[len] = '\0';
1630         return ( line );
1631       }
1632     }
1633     else
1634     {
1635       line[len] = c;
1636       len++;
1637     }
1638   }
1639  /*NOTREACHED*/ /* unreachable */
1640  return ( NULL );
1641 }
1642 
1643 /*
1644  * The high level function that is the main API of the linenoise library.
1645  * This function checks if the terminal has basic capabilities, just checking
1646  * for a blacklist of stupid terminals, and later either calls the line
1647  * editing function or uses dummy fgets() so that you will be able to type
1648  * something even in the most desperate of the conditions.
1649  */
1650 
1651 char *
1652 linenoise(const char *prompt)
     /* [previous][next][first][last][top][bottom][index][help] */
1653 {
1654   char buf[LINENOISE_MAX_LINE];
1655   int count;
1656 
1657   if (!isatty(STDIN_FILENO))
1658   {
1659 
1660     /*
1661      * Not a tty: read from file / pipe. In this mode we don't want any
1662      * limit to the line size, so we call a function to handle that.
1663      */
1664 
1665     return ( linenoiseNoTTY());
1666   }
1667   else if (isUnsupportedTerm())
1668   {
1669     size_t len;
1670 
1671     printf("%s", prompt);
1672     fflush(stdout);
1673     if (fgets(buf, LINENOISE_MAX_LINE, stdin) == NULL)
1674     {
1675       return ( NULL );
1676     }
1677 
1678     len = strlen(buf);
1679     while (len && ( buf[len - 1] == '\n' || buf[len - 1] == '\r' ))
1680     {
1681       len--;
1682       buf[len] = '\0';
1683     }
1684     return ( strdup(buf));
1685   }
1686   else
1687   {
1688     count = linenoiseRaw(buf, LINENOISE_MAX_LINE, prompt);
1689     if (count == -1)
1690     {
1691       return ( NULL );
1692     }
1693 
1694     return ( strdup(buf));
1695   }
1696 }
1697 
1698 /*
1699  * This is just a wrapper the user may want to call in order to make sure
1700  * the linenoise returned buffer is freed with the same allocator it was
1701  * created with. Useful when the main program is using an alternative
1702  * allocator.
1703  */
1704 
1705 void
1706 linenoiseFree(void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1707 {
1708   FREE(ptr);
1709 }
1710 
1711 /*
1712  * Free the history, but does not reset it. Only used when we have to
1713  * exit() to avoid memory leaks are reported by valgrind & co.
1714  */
1715 
1716 static void
1717 freeHistory(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1718 {
1719   if (history)
1720   {
1721     int j;
1722 
1723     for (j = 0; j < history_len; j++)
1724     {
1725       FREE(history[j]);
1726     }
1727 
1728     FREE(history);
1729   }
1730 }
1731 
1732 /* At exit we'll try to fix the terminal to the initial conditions. */
1733 static void
1734 linenoiseAtExit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1735 {
1736   disableRawMode(STDIN_FILENO);
1737   freeHistory();
1738 }
1739 
1740 /*
1741  * This is the API call to add a new entry in the linenoise history.
1742  * It uses a fixed array of char pointers that are shifted (memmoved)
1743  * when the history max length is reached in order to remove the older
1744  * entry and make room for the new one, so it is not exactly suitable for huge
1745  * histories, but will work well for a few hundred of entries.
1746  */
1747 
1748 int
1749 linenoiseHistoryAdd(const char *line)
     /* [previous][next][first][last][top][bottom][index][help] */
1750 {
1751   char *linecopy;
1752 
1753   if (history_max_len == 0)
1754   {
1755     return ( 0 );
1756   }
1757 
1758   /* Initialization on first call. */
1759   if (history == NULL)
1760   {
1761     history = malloc(sizeof ( char * ) * history_max_len);
1762     if (history == NULL)
1763     {
1764       return ( 0 );
1765     }
1766 
1767     memset(history, 0, ( sizeof ( char * ) * history_max_len ));
1768   }
1769 
1770   /* Don't add duplicated lines. */
1771   if (( history_len > 0 ) && ( !strcmp(history[history_len - 1], line)))
1772   {
1773     return ( 0 );
1774   }
1775 
1776   /*
1777    * Add an heap allocated copy of the line in the history.
1778    * If we reached the max length, remove the older line.
1779    */
1780 
1781   linecopy = strdup(line);
1782   if (!linecopy)
1783   {
1784     return ( 0 );
1785   }
1786 
1787   if (history_len == history_max_len)
1788   {
1789     FREE(history[0]);
1790     memmove(
1791       history,
1792       history + 1,
1793       sizeof ( char * ) * ( history_max_len - 1 ));
1794     history_len--;
1795   }
1796 
1797   history[history_len] = linecopy;
1798   history_len++;
1799   return ( 1 );
1800 }
1801 
1802 /*
1803  * Set the maximum length for the history. This function can be called even
1804  * if there is already some history, the function will make sure to retain
1805  * just the latest 'len' elements if the new history length value is smaller
1806  * than the amount of items already inside the history.
1807  */
1808 
1809 int
1810 linenoiseHistorySetMaxLen(int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1811 {
1812   char **new;
1813 
1814   if (len < 1)
1815   {
1816     return ( 0 );
1817   }
1818 
1819   if (history)
1820   {
1821     int tocopy = history_len;
1822 
1823     new = malloc(sizeof ( char * ) * len);
1824     if (new == NULL)
1825     {
1826       return ( 0 );
1827     }
1828 
1829     /* If we can't copy everything, free the elements we'll not use. */
1830     if (len < tocopy)
1831     {
1832       int j;
1833 
1834       for (j = 0; j < tocopy - len; j++)
1835       {
1836         FREE(history[j]);
1837       }
1838 
1839       tocopy = len;
1840     }
1841 
1842     memset(new, 0, sizeof ( char * ) * len);
1843     memcpy(
1844       new,
1845       history + ( history_len - tocopy ),
1846       sizeof ( char * ) * tocopy);
1847     FREE(history);
1848     history = new;
1849   }
1850 
1851   history_max_len = len;
1852   if (history_len > history_max_len)
1853   {
1854     history_len = history_max_len;
1855   }
1856 
1857   return ( 1 );
1858 }
1859 
1860 /* Calculate length of the prompt string as seen from a terminal. */
1861 size_t
1862 pstrlen(const char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
1863 {
1864   size_t len = 0, i = 0;
1865 
1866   while (s[i] != '\0')
1867   {
1868     if (s[i] == '\033') //-V536
1869     {
1870       i = strpbrk(s + i, "m") - s + 1; //-V769
1871       continue;
1872     }
1873 
1874     len++;
1875     i++;
1876   }
1877   return ( len );
1878 }
1879 
1880 #endif /* if !defined ( __MINGW32__ )
1881            && !defined ( CROSS_MINGW32 )
1882            && !defined ( CROSS_MINGW64 )
1883            && !defined ( __MINGW64__ )
1884            && !defined ( _MSC_VER )
1885            && !defined ( _MSC_BUILD ) */

/* [previous][next][first][last][top][bottom][index][help] */