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-2024 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 #if !defined(_POSIX_C_SOURCE)
  49 # define _POSIX_C_SOURCE 200809L
  50 #endif /* if !defined(_POSIX_C_SOURCE) */
  51 
  52 #if !defined(__MINGW32__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && \
  53     !defined(__MINGW64__) && !defined(_MSC_VER) && !defined(_MSC_BUILD)
  54 
  55 # if defined(__sun) && defined(__SVR4)
  56 #  if !defined(__EXTENSIONS__)
  57 #   define __EXTENSIONS__ 1
  58 #  endif /* if !defined(__EXTENSIONS__) */
  59 # endif /* if defined(__sun) && defined(__SVR4) */
  60 # include <termios.h>
  61 # if defined(__sun) && defined(__SVR4)
  62 #  include <sys/termiox.h>
  63 # endif /* if defined(__sun) && defined(__SVR4) */
  64 # include "linehistory.h"
  65 # if !defined(__NetBSD__)
  66 #  include "../dps8/dps8.h"
  67 # endif /* if !defined(__NetBSD__) */
  68 # include <ctype.h>
  69 # include <errno.h>
  70 # include <stdio.h>
  71 # include <stdlib.h>
  72 # include <string.h>
  73 # include <strings.h>
  74 # include <sys/ioctl.h>
  75 # include <sys/stat.h>
  76 # include <sys/types.h>
  77 # include <unistd.h>
  78 
  79 # if defined(FREE)
  80 #  undef FREE
  81 # endif /* if defined(FREE) */
  82 # define FREE(p) do  \
  83   {                  \
  84     free((p));       \
  85     (p) = NULL;      \
  86   } while(0)
  87 
  88 # define LINENOISE_DEFAULT_HISTORY_MAX_LEN  100
  89 # define LINENOISE_MAX_LINE                4096
  90 
  91 static char *unsupported_term[] = {
  92   "dumb", "cons25", "emacs", NULL
  93 };
  94 
  95 # if defined(LH_COMPLETION)
  96 static linenoiseCompletionCallback *completionCallback = NULL;
  97 # endif /* if defined(LH_COMPLETION) */
  98 
  99 # if defined(LH_HINTS)
 100 static linenoiseHintsCallback *hintsCallback           = NULL;
 101 static linenoiseFreeHintsCallback *freeHintsCallback   = NULL;
 102 # endif /* if defined(LH_HINTS) */
 103 
 104 static struct termios orig_termios; /* In order to restore at exit.*/
 105 
 106 # if defined(LH_MASKMODE)
 107 static int maskmode          = 0;   /* Show "**" instead of input for passwords */
 108 # endif /* if defined(LH_MASKMODE) */
 109 
 110 static int rawmode           = 0;
 111 static int mlmode            = 0;   /* Multi line mode. Default is single line. */
 112 static int atexit_registered = 0;   /* Register atexit just 1 time.             */
 113 static int history_max_len   = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
 114 static int history_len       = 0;
 115 static char **history        = NULL;
 116 
 117 /*
 118  * The linenoiseState structure represents the state during line editing.
 119  * We pass this state to functions implementing specific editing
 120  * functionalities.
 121  */
 122 
 123 struct linenoiseState
 124 {
 125   int    ifd;            /* Terminal stdin file descriptor.                  */
 126   int    ofd;            /* Terminal stdout file descriptor.                 */
 127   char   *buf;           /* Edited line buffer.                              */
 128   size_t buflen;         /* Edited line buffer size.                         */
 129   const  char *prompt;   /* Prompt to display.                               */
 130   size_t plen;           /* Prompt length.                                   */
 131   size_t pos;            /* Current cursor position.                         */
 132   size_t oldpos;         /* Previous refresh cursor position.                */
 133   size_t len;            /* Current edited line length.                      */
 134   size_t cols;           /* Number of columns in terminal.                   */
 135   size_t maxrows;        /* Maximum num of rows used so far (multiline mode) */
 136   int    history_index;  /* The history index we are currently editing.      */
 137 };
 138 
 139 enum KEY_ACTION
 140 {
 141   KEY_NULL  = 0,  /* NULL      */
 142   CTRL_A    = 1,  /* Ctrl-A    */
 143   CTRL_B    = 2,  /* Ctrl-B    */
 144   CTRL_C    = 3,  /* Ctrl-C    */
 145   CTRL_D    = 4,  /* Ctrl-D    */
 146   CTRL_E    = 5,  /* Ctrl-E    */
 147   CTRL_F    = 6,  /* Ctrl-F    */
 148   CTRL_H    = 8,  /* Ctrl-H    */
 149   TAB       = 9,  /* Tab       */
 150   CTRL_K    = 11, /* Ctrl-K    */
 151   CTRL_L    = 12, /* Ctrl-L    */
 152   ENTER     = 13, /* Enter     */
 153   CTRL_N    = 14, /* Ctrl-N    */
 154   CTRL_P    = 16, /* Ctrl-P    */
 155   CTRL_T    = 20, /* Ctrl-T    */
 156   CTRL_U    = 21, /* Ctrl-U    */
 157   CTRL_W    = 23, /* Ctrl-W    */
 158   ESC       = 27, /* Escape    */
 159   BACKSPACE = 127 /* Backspace */
 160 };
 161 
 162 static void linenoiseAtExit(void);
 163 static void refreshLine(struct linenoiseState *l);
 164 size_t pstrlen(const char *s);
 165 
 166 # if defined(LH_MASKMODE)
 167 
 168 /*
 169  * Enable "mask mode". When it is enabled, instead of the input that
 170  * the user is typing, the terminal will just display a corresponding
 171  * number of asterisks, like "****". This is useful for passwords and other
 172  * secrets that should not be displayed.
 173  */
 174 
 175 void
 176 linenoiseMaskModeEnable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178   maskmode = 1;
 179 }
 180 
 181 /* Disable mask mode. */
 182 void
 183 linenoiseMaskModeDisable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185   maskmode = 0;
 186 }
 187 # endif /* if defined(LH_MASKMODE) */
 188 
 189 /* Set if to use or not the multi line mode. */
 190 void
 191 linenoiseSetMultiLine(int ml)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193   mlmode = ml;
 194 }
 195 
 196 /*
 197  * Return true if the terminal name is in the list of terminals we know are
 198  * not able to understand basic escape sequences.
 199  */
 200 
 201 static int
 202 isUnsupportedTerm(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204   char *term = getenv("TERM");
 205   int j;
 206 
 207   if (term == NULL)
 208   {
 209     return ( 0 );
 210   }
 211 
 212   for (j = 0; unsupported_term[j]; j++)
 213   {
 214     if (!strcasecmp(term, unsupported_term[j]))
 215     {
 216       return ( 1 );
 217     }
 218   }
 219 
 220   return ( 0 );
 221 }
 222 
 223 /* Raw mode */
 224 static int
 225 enableRawMode(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227   struct termios raw;
 228 
 229   if (!isatty(STDIN_FILENO))
 230   {
 231     goto fatal;
 232   }
 233 
 234   if (!atexit_registered)
 235   {
 236     atexit(linenoiseAtExit);
 237     atexit_registered = 1;
 238   }
 239 
 240   if (tcgetattr(fd, &orig_termios) == -1)
 241   {
 242     goto fatal;
 243   }
 244 
 245   raw = orig_termios; /* modify the original mode */
 246   /* input modes: no break, no CR to NL, no parity check, no strip char,
 247    * no start/stop output control. */
 248   raw.c_iflag &= ~( BRKINT | ICRNL | INPCK | ISTRIP | IXON );
 249   /* control modes - set 8 bit chars */
 250   raw.c_cflag |= ( CS8 );
 251   /* local modes - echoing off, canonical off, no extended functions,
 252    * no signal chars (^Z,^C) */
 253   raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
 254   /* control chars - set return condition: min number of bytes and timer.
 255    * We want read to return every single byte, without timeout. */
 256   raw.c_cc[VMIN]  = 1;
 257   raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
 258 
 259   /* put terminal in raw mode after flushing */
 260 # if defined(__ANDROID__)
 261 #  define TCSA_TYPE TCSANOW
 262   (void)fflush(stdout);
 263   (void)fflush(stderr);
 264 # else
 265 #  define TCSA_TYPE TCSAFLUSH
 266 # endif
 267   if (tcsetattr(fd, TCSA_TYPE, &raw) < 0)
 268   {
 269     goto fatal;
 270   }
 271 
 272   rawmode = 1;
 273   return ( 0 );
 274 
 275 fatal:
 276   errno = ENOTTY;
 277   return ( -1 );
 278 }
 279 
 280 static void
 281 disableRawMode(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283   /* Don't even check the return value as it's too late. */
 284 # if defined(__ANDROID__)
 285   (void)fflush(stdout);
 286   (void)fflush(stderr);
 287 # endif
 288   if (rawmode && tcsetattr(fd, TCSA_TYPE, &orig_termios) != -1)
 289   {
 290     rawmode = 0;
 291   }
 292 }
 293 
 294 /*
 295  * Use the ESC [6n escape sequence to query the horizontal cursor position
 296  * and return it. On error -1 is returned, on success the position of the
 297  * cursor.
 298  */
 299 
 300 static int
 301 getCursorPosition(int ifd, int ofd)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303   char     buf[32];
 304   int      cols, rows;
 305   unsigned int i = 0;
 306 
 307   /* Report cursor location */
 308   if (write(ofd, "\x1b[6n", 4) != 4)
 309   {
 310     return ( -1 );
 311   }
 312 
 313   /* Read the response: ESC [ rows ; cols R */
 314   while (i < sizeof ( buf ) - 1)
 315   {
 316     if (read(ifd, buf + i, 1) != 1)
 317     {
 318       break;
 319     }
 320 
 321     if (buf[i] == 'R')
 322     {
 323       break;
 324     }
 325 
 326     i++;
 327   }
 328   buf[i] = '\0';
 329 
 330   /* Parse it. */
 331   if (buf[0] != ESC || buf[1] != '[')
 332   {
 333     return ( -1 );
 334   }
 335 
 336   if (sscanf(buf + 2, "%d;%d", &rows, &cols) != 2)
 337   {
 338     return ( -1 );
 339   }
 340 
 341   return ( cols );
 342 }
 343 
 344 /* Try to get the number of columns in terminal, or assume 80 */
 345 static int
 346 getColumns(int ifd, int ofd)
     /* [previous][next][first][last][top][bottom][index][help] */
 347 {
 348   struct winsize ws;
 349 
 350   if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0)
 351   {
 352     /* ioctl() failed. Try to query the terminal itself. */
 353     int start, cols;
 354 
 355     /* Get the initial position so we can restore it later. */
 356     start = getCursorPosition(ifd, ofd);
 357     if (start == -1)
 358     {
 359       goto failed;
 360     }
 361 
 362     /* Go to right margin and get position. */
 363     if (write(ofd, "\x1b[999C", 6) != 6)
 364     {
 365       goto failed;
 366     }
 367 
 368     cols = getCursorPosition(ifd, ofd);
 369     if (cols == -1)
 370     {
 371       goto failed;
 372     }
 373 
 374     /* Restore position. */
 375     if (cols > start)
 376     {
 377       char seq[32];
 378       (void)snprintf(seq, sizeof ( seq ), "\x1b[%dD", cols - start);
 379       if (write(ofd, seq, strlen(seq)) == -1) { /* Can't recover... */ }
 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 # if defined(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   (void)fflush(stdout);
 413   (void)fprintf(stderr, "\x7");
 414   (void)fflush(stderr);
 415 }
 416 
 417 /* Free a list of completion option populated by linenoiseAddCompletion(). */
 418 static void
 419 freeCompletions(const linenoiseCompletions *lc)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421   size_t i;
 422 
 423   for (i = 0; i < lc->len; i++)
 424   {
 425     FREE(lc->cvec[i]);
 426   }
 427 
 428   if (lc->cvec != NULL)
 429   {
 430     FREE(lc->cvec);
 431   }
 432 }
 433 
 434 /*
 435  * This is an helper function for linenoiseEdit() and is called when the
 436  * user types the <tab> key in order to complete the string currently in the
 437  * input.
 438  *
 439  * The state of the editing is encapsulated into the pointed linenoiseState
 440  * structure as described in the structure definition.
 441  */
 442 
 443 static int
 444 completeLine(struct linenoiseState *ls)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 446   linenoiseCompletions lc = {
 447     0, NULL
 448   };
 449   int nread, nwritten;
 450   char c = 0;
 451 
 452   completionCallback(ls->buf, &lc);
 453   if (lc.len == 0)
 454   {
 455     linenoiseBeep();
 456   }
 457   else
 458   {
 459     size_t stop = 0, i = 0;
 460 
 461     while (!stop)
 462     {
 463       /* Show completion or original buffer */
 464       if (i < lc.len)
 465       {
 466         struct linenoiseState saved = *ls;
 467 
 468         ls->len = ls->pos = strlen(lc.cvec[i]);
 469         ls->buf = lc.cvec[i];
 470         refreshLine(ls);
 471         ls->len = saved.len;
 472         ls->pos = saved.pos;
 473         ls->buf = saved.buf;
 474       }
 475       else
 476       {
 477         refreshLine(ls);
 478       }
 479 
 480       nread = read(ls->ifd, &c, 1);
 481       if (nread <= 0)
 482       {
 483         freeCompletions(&lc);
 484         return ( -1 );
 485       }
 486 
 487       switch (c)
 488       {
 489       case 9: /* Tab */
 490         i = ( i + 1 ) % ( lc.len + 1 );
 491         if (i == lc.len)
 492         {
 493           linenoiseBeep();
 494         }
 495 
 496         stop = 1;
 497         break;
 498 
 499       default:
 500         /* Update buffer and return */
 501         if (i < lc.len)
 502         {
 503           nwritten = snprintf(ls->buf, ls->buflen, "%s", lc.cvec[i]);
 504           ls->len  = ls->pos = nwritten;
 505         }
 506 
 507         stop = 1;
 508         break;
 509       }
 510     }
 511   }
 512 
 513   freeCompletions(&lc);
 514   return ( c ); /* Return last read character */
 515 }
 516 
 517 /* Register a callback function to be called for tab-completion. */
 518 void
 519 linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 520 {
 521   completionCallback = fn;
 522 }
 523 
 524 # endif /* if defined(LH_COMPLETION) */
 525 
 526 # if defined(LH_HINTS)
 527 
 528 /*
 529  * Register a hits function to be called to show hits to the user at the
 530  * right of the prompt.
 531  */
 532 
 533 void
 534 linenoiseSetHintsCallback(linenoiseHintsCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 535 {
 536   hintsCallback = fn;
 537 }
 538 
 539 /*
 540  * Register a function to free the hints returned by the hints callback
 541  * registered with linenoiseSetHintsCallback().
 542  */
 543 
 544 void
 545 linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 546 {
 547   freeHintsCallback = fn;
 548 }
 549 
 550 # endif /* if defined(LH_HINTS) */
 551 
 552 # if defined(LH_COMPLETION)
 553 
 554 /*
 555  * This function is used by the callback function registered by the user
 556  * in order to add completion options given the input string when the
 557  * user typed <tab>.
 558  */
 559 
 560 void
 561 linenoiseAddCompletion(linenoiseCompletions *lc, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
 562 {
 563   size_t len = strlen(str);
 564   char *copy, **cvec;
 565 
 566   copy = malloc(len + 1);
 567   if (copy == NULL)
 568   {
 569     return;
 570   }
 571 
 572   memcpy(copy, str, len + 1);
 573   cvec = realloc(lc->cvec, sizeof ( char * ) * ( lc->len + 1 ));
 574   if (cvec == NULL)
 575   {
 576     FREE(copy);
 577     return;
 578   }
 579 
 580   lc->cvec            = cvec;
 581   lc->cvec[lc->len++] = copy;
 582 }
 583 
 584 # endif /* if defined(LH_COMPLETION) */
 585 
 586 /*
 587  * We define a very simple "append buffer" structure, that is an heap
 588  * allocated string where we can append to. This is useful in order to
 589  * write all the escape sequences in a buffer and flush them to the standard
 590  * output in a single call, to avoid flickering effects.
 591  */
 592 
 593 struct abuf
 594 {
 595   char *b;
 596   int len;
 597 };
 598 
 599 static void
 600 abInit(struct abuf *ab)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602   ab->b = NULL;
 603   ab->len = 0;
 604 }
 605 
 606 static void
 607 abAppend(struct abuf *ab, const char *s, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 608 {
 609   if (len <= 0)
 610   {
 611     return;
 612   }
 613 
 614   char *new = realloc(ab->b, 1 + ab->len + len);
 615 
 616   if (new == NULL)
 617   {
 618     return;
 619   }
 620 
 621   memcpy(new + ab->len, s, len);
 622   ab->b    = new;
 623   ab->len += len;
 624 }
 625 
 626 static void
 627 abFree(const struct abuf *ab)
     /* [previous][next][first][last][top][bottom][index][help] */
 628 {
 629   free(ab->b); /* X-LINTED: FREE */
 630 }
 631 
 632 # if defined(LH_HINTS)
 633 
 634 /*
 635  * Helper of refreshSingleLine() and refreshMultiLine() to show hints
 636  * to the right of the prompt.
 637  */
 638 
 639 static void
 640 refreshShowHints(struct abuf *ab, const struct linenoiseState *l, int plen)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642   char seq[64];
 643 
 644   seq[0] = '\0';
 645   if (hintsCallback && plen + l->len < l->cols)
 646   {
 647     int color = -1, bold = 0;
 648     char *hint = hintsCallback(l->buf, &color, &bold);
 649     if (hint)
 650     {
 651       int hintlen    = strlen(hint);
 652       int hintmaxlen = l->cols - ( plen + l->len );
 653       if (hintlen > hintmaxlen)
 654       {
 655         hintlen = hintmaxlen;
 656       }
 657 
 658       if (bold == 1 && color == -1)
 659       {
 660         color = 37;
 661       }
 662 
 663       if (color != -1 || bold != 0)
 664       {
 665         (void)snprintf(seq, sizeof ( seq ), "\033[%d;%d;49m", bold, color);
 666       }
 667       else
 668       {
 669         seq[0] = '\0';
 670       }
 671 
 672       abAppend(ab, seq, strlen(seq));
 673       abAppend(ab, hint, hintlen);
 674       if (color != -1 || bold != 0)
 675       {
 676         abAppend(ab, "\033[0m", 4);
 677       }
 678 
 679       /* Call the function to free the hint returned. */
 680       if (freeHintsCallback)
 681       {
 682         freeHintsCallback(hint);
 683       }
 684     }
 685   }
 686 }
 687 
 688 # endif /* if defined(LH_HINTS) */
 689 
 690 /*
 691  * Single line low level line refresh.
 692  *
 693  * Rewrite the currently edited line accordingly to the buffer content,
 694  * cursor position, and number of columns of the terminal.
 695  */
 696 
 697 static void
 698 refreshSingleLine(const struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 699 {
 700   char   seq[64];
 701   size_t plen = pstrlen(l->prompt);
 702   int    fd   = l->ofd;
 703   char   *buf = l->buf;
 704   size_t len  = l->len;
 705   size_t pos  = l->pos;
 706   struct abuf ab;
 707 
 708   while (( plen + pos ) >= l->cols)
 709   {
 710     buf++;
 711     len--;
 712     pos--;
 713   }
 714   while (plen + len > l->cols)
 715   {
 716     len--;
 717   }
 718 
 719   abInit(&ab);
 720   /* Cursor to left edge */
 721   (void)snprintf(seq, sizeof ( seq ), "\r");
 722   abAppend(&ab, seq, strlen(seq));
 723   /* Write the prompt and the current buffer content */
 724   abAppend(&ab, l->prompt, strlen(l->prompt));
 725 # if defined(LH_MASKMODE)
 726   if (maskmode == 1)
 727   {
 728     while (len--)
 729     {
 730       abAppend(&ab, "*", 1);
 731     }
 732   }
 733   else
 734   {
 735 # endif /* if defined(LH_MASKMODE) */
 736   abAppend(&ab, buf, len);
 737 # if defined(LH_MASKMODE)
 738 }
 739 # endif /* if defined(LH_MASKMODE) */
 740 # if defined(LH_HINTS)
 741   /* Show hits if any. */
 742   refreshShowHints(&ab, l, plen);
 743 # endif /* if defined(LH_HINTS) */
 744   /* Erase to right */
 745   (void)snprintf(seq, sizeof ( seq ), "\x1b[0K");
 746   abAppend(&ab, seq, strlen(seq));
 747   /* Move cursor to original position. */
 748   (void)snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", (int)( pos + plen ));
 749   abAppend(&ab, seq, strlen(seq));
 750   if (write(fd, ab.b, ab.len) == -1)
 751   { /* Can't recover from write error. */
 752   }
 753 
 754   abFree(&ab);
 755 }
 756 
 757 /*
 758  * Multi line low level line refresh.
 759  *
 760  * Rewrite the currently edited line accordingly to the buffer content,
 761  * cursor position, and number of columns of the terminal.
 762  */
 763 
 764 static void
 765 refreshMultiLine(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 766 {
 767   char seq[64];
 768   int plen = strlen(l->prompt);
 769   int rows = ( plen + l->len + l->cols - 1 )
 770              / l->cols; /* rows used by current buf. */
 771   int rpos = ( plen + l->oldpos + l->cols ) / l->cols; /* cursor relative row. */
 772   int rpos2; /* rpos after refresh. */
 773   int col; /* column position, zero-based. */
 774   int old_rows = l->maxrows;
 775   int fd = l->ofd, j;
 776   struct abuf ab;
 777 
 778   /* Update maxrows if needed. */
 779   if (rows > (int)l->maxrows)
 780   {
 781     l->maxrows = rows;
 782   }
 783 
 784   /*
 785    * First step: clear all the lines used before. To do so start by
 786    * going to the last row.
 787    */
 788 
 789   abInit(&ab);
 790   if (old_rows - rpos > 0)
 791   {
 792     (void)snprintf(seq, sizeof ( seq ), "\x1b[%dB", old_rows - rpos);
 793     abAppend(&ab, seq, strlen(seq));
 794   }
 795 
 796   /* Now for every row clear it, go up. */
 797   for (j = 0; j < old_rows - 1; j++)
 798   {
 799     (void)snprintf(seq, sizeof ( seq ), "\r\x1b[0K\x1b[1A");
 800     abAppend(&ab, seq, strlen(seq));
 801   }
 802 
 803   /* Clean the top line. */
 804   (void)snprintf(seq, sizeof ( seq ), "\r\x1b[0K");
 805   abAppend(&ab, seq, strlen(seq));
 806 
 807   /* Write the prompt and the current buffer content */
 808   abAppend(&ab, l->prompt, strlen(l->prompt));
 809 # if defined(LH_MASKMODE)
 810   if (maskmode == 1)
 811   {
 812     unsigned int i;
 813     for (i = 0; i < l->len; i++)
 814     {
 815       abAppend(&ab, "*", 1);
 816     }
 817   }
 818   else
 819   {
 820 # endif /* if defined(LH_MASKMODE) */
 821   abAppend(&ab, l->buf, l->len);
 822 # if defined(LH_MASKMODE)
 823 }
 824 # endif /* if defined(LH_MASKMODE) */
 825 
 826 # if defined(LH_HINTS)
 827   /* Show hits if any. */
 828   refreshShowHints(&ab, l, plen);
 829 # endif /* if defined(LH_HINTS) */
 830 
 831   /*
 832    * If we are at the very end of the screen with our prompt, we need to
 833    * emit a newline and move the prompt to the first column.
 834    */
 835 
 836   if (l->pos && l->pos == l->len && ( l->pos + plen ) % l->cols == 0)
 837   {
 838     abAppend(&ab, "\n", 1);
 839     (void)snprintf(seq, sizeof ( seq ), "\r");
 840     abAppend(&ab, seq, strlen(seq));
 841     rows++;
 842     if (rows > (int)l->maxrows)
 843     {
 844       l->maxrows = rows;
 845     }
 846   }
 847 
 848   /* Move cursor to right position. */
 849   rpos2 = ( plen + l->pos + l->cols ) / l->cols;
 850 
 851   /* Go up till we reach the expected position. */
 852   if (rows - rpos2 > 0)
 853   {
 854     (void)snprintf(seq, sizeof ( seq ), "\x1b[%dA", rows - rpos2);
 855     abAppend(&ab, seq, strlen(seq));
 856   }
 857 
 858   /* Set column. */
 859   col = ( plen + (int)l->pos ) % (int)l->cols;
 860   if (col)
 861   {
 862     (void)snprintf(seq, sizeof ( seq ), "\r\x1b[%dC", col);
 863   }
 864   else
 865   {
 866     (void)snprintf(seq, sizeof ( seq ), "\r");
 867   }
 868 
 869   abAppend(&ab, seq, strlen(seq));
 870 
 871   l->oldpos = l->pos;
 872 
 873   if (write(fd, ab.b, ab.len) == -1)
 874   { /* Can't recover from write error. */
 875   }
 876 
 877   abFree(&ab);
 878 }
 879 
 880 /*
 881  * Calls the two low level functions refreshSingleLine() or
 882  * refreshMultiLine() according to the selected mode.
 883  */
 884 
 885 static void
 886 refreshLine(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 887 {
 888   l->cols = getColumns(STDIN_FILENO, STDOUT_FILENO);
 889   if (mlmode)
 890   {
 891     refreshMultiLine(l);
 892   }
 893   else
 894   {
 895     refreshSingleLine(l);
 896   }
 897 }
 898 
 899 /*
 900  * Insert the character 'c' at cursor current position.
 901  * On error writing to the terminal -1 is returned, otherwise 0.
 902  */
 903 
 904 int
 905 linenoiseEditInsert(struct linenoiseState *l, char c)
     /* [previous][next][first][last][top][bottom][index][help] */
 906 {
 907   if (l->len < l->buflen)
 908   {
 909     if (l->len == l->pos)
 910     {
 911       l->buf[l->pos] = c;
 912       l->pos++;
 913       l->len++;
 914       l->buf[l->len] = '\0';
 915 # if defined(LH_MASKMODE) && defined(LH_HINTS)
 916       if (( !mlmode && l->plen + l->len < l->cols && !hintsCallback ))
 917       {
 918         /* Avoid a full update of the line in the trivial case. */
 919         char d = ( maskmode == 1 ) ? '*' : (char)c;
 920         if (write(l->ofd, &d, 1) == -1)
 921         {
 922           return ( -1 );
 923         }
 924       }
 925       else
 926       {
 927 # endif /* if defined(LH_MASKMODE) && defined(LH_HINTS) */
 928       refreshLine(l);
 929 # if defined(LH_MASKMODE) && defined(LH_HINTS)
 930       }
 931 # endif /* if defined(LH_MASKMODE) && defined(LH_HINTS) */
 932     }
 933     else
 934     {
 935       memmove(l->buf + l->pos + 1, l->buf + l->pos, l->len - l->pos);
 936       l->buf[l->pos] = c;
 937       l->len++;
 938       l->pos++;
 939       l->buf[l->len] = '\0';
 940       refreshLine(l);
 941     }
 942   }
 943 
 944   return ( 0 );
 945 }
 946 
 947 /* Move cursor on the left. */
 948 void
 949 linenoiseEditMoveLeft(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 950 {
 951   if (l->pos > 0)
 952   {
 953     l->pos--;
 954     refreshLine(l);
 955   }
 956 }
 957 
 958 /* Move cursor on the right. */
 959 void
 960 linenoiseEditMoveRight(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 961 {
 962   if (l->pos != l->len)
 963   {
 964     l->pos++;
 965     refreshLine(l);
 966   }
 967 }
 968 
 969 /* Move cursor to the end of the current word. */
 970 void
 971 linenoiseEditMoveWordEnd(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 972 {
 973   if (l->len == 0 || l->pos >= l->len)
 974   {
 975     return;
 976   }
 977 
 978   if (l->buf[l->pos] == ' ')
 979   {
 980     while (l->pos < l->len && l->buf[l->pos] == ' ')
 981     {
 982       ++l->pos;
 983     }
 984   }
 985 
 986   while (l->pos < l->len && l->buf[l->pos] != ' ')
 987   {
 988     ++l->pos;
 989   }
 990   refreshLine(l);
 991 }
 992 
 993 /* Move cursor to the start of the current word. */
 994 void
 995 linenoiseEditMoveWordStart(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
 996 {
 997   if (l->len == 0)
 998   {
 999     return;
1000   }
1001 
1002   if (l->buf[l->pos - 1] == ' ')
1003   {
1004     --l->pos;
1005   }
1006 
1007   if (l->buf[l->pos] == ' ')
1008   {
1009     while (l->pos > 0 && l->buf[l->pos] == ' ')
1010     {
1011       --l->pos;
1012     }
1013   }
1014 
1015   while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
1016   {
1017     --l->pos;
1018   }
1019   refreshLine(l);
1020 }
1021 
1022 /* Move cursor to the start of the line. */
1023 void
1024 linenoiseEditMoveHome(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1025 {
1026   if (l->pos != 0)
1027   {
1028     l->pos = 0;
1029     refreshLine(l);
1030   }
1031 }
1032 
1033 /* Move cursor to the end of the line. */
1034 void
1035 linenoiseEditMoveEnd(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1036 {
1037   if (l->pos != l->len)
1038   {
1039     l->pos = l->len;
1040     refreshLine(l);
1041   }
1042 }
1043 
1044 /*
1045  * Substitute the currently edited line with the next
1046  * or previous history entry as specified by 'dir'.
1047  */
1048 
1049 # define LINENOISE_HISTORY_NEXT 0
1050 # define LINENOISE_HISTORY_PREV 1
1051 void
1052 linenoiseEditHistoryNext(struct linenoiseState *l, int dir)
     /* [previous][next][first][last][top][bottom][index][help] */
1053 {
1054   if (history_len > 1)
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         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1066                        __func__, __FILE__, __LINE__);
1067 # if defined(USE_BACKTRACE)
1068 #  if defined(SIGUSR2)
1069         (void)raise(SIGUSR2);
1070         /*NOTREACHED*/ /* unreachable */
1071 #  endif /* if defined(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      * Update the current history entry before to
1109      * overwrite it with the next one.
1110      */
1111 
1112     FREE(history[history_len - 1 - l->history_index]);
1113     history[history_len - 1 - l->history_index] = strdup(l->buf);
1114     if (!history[history_len - 1 - l->history_index])
1115       {
1116         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1117                        __func__, __FILE__, __LINE__);
1118 # if defined(USE_BACKTRACE)
1119 #  if defined(SIGUSR2)
1120         (void)raise(SIGUSR2);
1121         /*NOTREACHED*/ /* unreachable */
1122 #  endif /* if defined(SIGUSR2) */
1123 # endif /* if defined(USE_BACKTRACE) */
1124         abort();
1125       }
1126 
1127     /* Search new entry */
1128     int cnt;
1129     if (direction == LINENOISE_SEARCH_HISTORY_FORWARD)
1130     {
1131       cnt = history_len - 2 - l->history_index;
1132       for (; cnt >= 0; cnt--)
1133       {
1134         /*
1135          * Search a history entry that start with same
1136          * as the current line until the cursor position
1137          */
1138 
1139         if (strncmp(l->buf, history[cnt], l->pos) == 0)
1140         {
1141           strncpy(l->buf, history[cnt], l->buflen);
1142           l->buf[l->buflen - 1] = '\0';
1143           /* Don't change old cursor position */
1144           l->len = strlen(l->buf);
1145 
1146           /*
1147            * Set history index so that we can contiune
1148            * the search on this position
1149            */
1150 
1151           l->history_index = history_len - 1 - cnt;
1152           refreshLine(l);
1153           return;
1154         }
1155       }
1156     }
1157     else if (direction == LINENOISE_SEARCH_HISTORY_REVERSE)
1158     {
1159       cnt = history_len - l->history_index;
1160       for (; cnt < history_len; cnt++)
1161       {
1162         /*
1163          * Search a history entry that start with same
1164          * as the current line until the cursor position
1165          */
1166 
1167         if (strncmp(l->buf, history[cnt], l->pos) == 0)
1168         {
1169           strncpy(l->buf, history[cnt], l->buflen);
1170           l->buf[l->buflen - 1] = '\0';
1171           /* Don't change old cursor position */
1172           l->len = strlen(l->buf);
1173 
1174           /*
1175            * Set history index so that we can contiune
1176            * the search on this position
1177            */
1178 
1179           l->history_index = history_len - 1 - cnt;
1180           refreshLine(l);
1181           return;
1182         }
1183       }
1184     }
1185   }
1186 }
1187 
1188 /*
1189  * Delete the character at the right of the cursor without altering the cursor
1190  * position. Basically this is what happens with the "Delete" keyboard key.
1191  */
1192 
1193 void
1194 linenoiseEditDelete(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1195 {
1196   if (l->len > 0 && l->pos < l->len)
1197   {
1198     memmove(l->buf + l->pos, l->buf + l->pos + 1, l->len - l->pos - 1);
1199     l->len--;
1200     l->buf[l->len] = '\0';
1201     refreshLine(l);
1202   }
1203 }
1204 
1205 /* Backspace implementation. */
1206 void
1207 linenoiseEditBackspace(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1208 {
1209   if (l->pos > 0 && l->len > 0)
1210   {
1211     memmove(l->buf + l->pos - 1, l->buf + l->pos, l->len - l->pos);
1212     l->pos--;
1213     l->len--;
1214     l->buf[l->len] = '\0';
1215     refreshLine(l);
1216   }
1217 }
1218 
1219 /*
1220  * Delete the previous word, maintaining the
1221  * cursor at the start of the current word.
1222  */
1223 
1224 void
1225 linenoiseEditDeletePrevWord(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1226 {
1227   size_t old_pos = l->pos;
1228   size_t diff;
1229 
1230   while (l->pos > 0 && l->buf[l->pos - 1] == ' ')
1231   {
1232     l->pos--;
1233   }
1234   while (l->pos > 0 && l->buf[l->pos - 1] != ' ')
1235   {
1236     l->pos--;
1237   }
1238   diff = old_pos - l->pos;
1239   memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1);
1240   l->len -= diff;
1241   refreshLine(l);
1242 }
1243 
1244 /* Delete the next word, maintaining the cursor at the same position */
1245 void
1246 linenoiseEditDeleteNextWord(struct linenoiseState *l)
     /* [previous][next][first][last][top][bottom][index][help] */
1247 {
1248   size_t next_word_end = l->pos;
1249 
1250   while (next_word_end < l->len && l->buf[next_word_end] == ' ')
1251   {
1252     ++next_word_end;
1253   }
1254   while (next_word_end < l->len && l->buf[next_word_end] != ' ')
1255   {
1256     ++next_word_end;
1257   }
1258   memmove(l->buf + l->pos, l->buf + next_word_end, l->len - next_word_end);
1259   l->len -= next_word_end - l->pos;
1260   refreshLine(l);
1261 }
1262 
1263 /*
1264  * This function is the core of the line editing capability of linenoise.
1265  * It expects 'fd' to be already in "raw mode" so that every key pressed
1266  * will be returned ASAP to read().
1267  *
1268  * The resulting string is put into 'buf' when the user type enter, or
1269  * when ctrl+d is typed.
1270  *
1271  * The function returns the length of the current buffer.
1272  */
1273 
1274 static int
1275 linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
     /* [previous][next][first][last][top][bottom][index][help] */
1276               const char *prompt)
1277 {
1278   struct linenoiseState l;
1279 
1280   /*
1281    * Populate the linenoise state that we pass to functions implementing
1282    * specific editing functionalities.
1283    */
1284 
1285   l.ifd           = stdin_fd;
1286   l.ofd           = stdout_fd;
1287   l.buf           = buf;
1288   l.buflen        = buflen;
1289   l.prompt        = prompt;
1290   l.plen          = pstrlen(prompt);
1291   l.oldpos        = l.pos = 0;
1292   l.len           = 0;
1293   l.cols          = getColumns(stdin_fd, stdout_fd);
1294   l.maxrows       = 0;
1295   l.history_index = 0;
1296 
1297   /* Buffer starts empty. */
1298   l.buf[0] = '\0';
1299   l.buflen--; /* Make sure there is always space for the nulterm */
1300 
1301   /*
1302    * The latest history entry is always our current
1303    * buffer, that initially is just an empty string.
1304    */
1305 
1306   (void)linenoiseHistoryAdd("");
1307 
1308   if (write(l.ofd, prompt, strlen(prompt)) == -1)
1309   {
1310     return ( -1 );
1311   }
1312 
1313   while (1)
1314   {
1315     signed char c;
1316     int    nread;
1317     char   seq[3];
1318 
1319     nread = read(l.ifd, &c, 1);
1320     if (nread <= 0)
1321     {
1322       return ( l.len );
1323     }
1324 
1325 # if defined(LH_COMPLETION)
1326 
1327     /*
1328      * Only autocomplete when the callback is set. It returns < 0 when
1329      * there was an error reading from fd. Otherwise it will return the
1330      * character that should be handled next.
1331      */
1332 
1333     if (c == 9 && completionCallback != NULL)
1334     {
1335       int cint = completeLine(&l);
1336       /* Return on errors */
1337       if (cint < 0)
1338       {
1339         return ( l.len );
1340       }
1341 
1342       /* Read next character when 0 */
1343       if (cint == 0)
1344       {
1345         continue;
1346       }
1347 
1348       c = (char)cint;
1349     }
1350 
1351 # endif /* if defined(LH_COMPLETION) */
1352 
1353     switch (c)
1354     {
1355     case 9:
1356       break;    /* johnsonjh - disable processing of tabs */
1357 
1358     case ENTER: /* Enter */
1359       history_len--;
1360       FREE(history[history_len]);
1361       if (mlmode)
1362       {
1363         linenoiseEditMoveEnd(&l);
1364       }
1365 
1366 # if defined(LH_HINTS)
1367       if (hintsCallback)
1368       {
1369         /*
1370          * Force a refresh without hints to leave the previous
1371          * line as the user typed it after a newline.
1372          */
1373 
1374         linenoiseHintsCallback *hc = hintsCallback;
1375         hintsCallback              = NULL;
1376         refreshLine(&l);
1377         hintsCallback              = hc;
1378       }
1379 
1380 # endif /* if defined(LH_HINTS) */
1381       return ((int)l.len );
1382 
1383     case CTRL_C: /* Ctrl-C */
1384       errno = EAGAIN;
1385       return ( -1 );
1386 
1387     case BACKSPACE: /* Backspace */
1388     case 8:         /* Ctrl-H */
1389       linenoiseEditBackspace(&l);
1390       break;
1391 
1392     case CTRL_D:     /* Ctrl-D, remove char at right of cursor, or */
1393       if (l.len > 0) /* if the line is empty, act as end-of-file.  */
1394       {
1395         linenoiseEditDelete(&l);
1396       }
1397       else
1398       {
1399         history_len--;
1400         FREE(history[history_len]);
1401         return ( -1 );
1402       }
1403 
1404       break;
1405 
1406     case CTRL_T: /* Ctrl-T */
1407       break;
1408 
1409     case CTRL_B: /* Ctrl-B */
1410       linenoiseEditMoveLeft(&l);
1411       break;
1412 
1413     case CTRL_F: /* Ctrl-F */
1414       linenoiseEditMoveRight(&l);
1415       break;
1416 
1417     case CTRL_P: /* Ctrl-P */
1418       linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1419       break;
1420 
1421     case CTRL_N: /* Ctrl-N */
1422       linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1423       break;
1424 
1425     case ESC: /* Escape Sequence */
1426 
1427       /*
1428        * Read the next two bytes representing the escape sequence.
1429        * Use two calls to handle slow terminals returning the two
1430        * chars at different times.
1431        */
1432 
1433       if (read(l.ifd, seq, 1) == -1)
1434       {
1435         break;
1436       }
1437 
1438       if (read(l.ifd, seq + 1, 1) == -1)
1439       {
1440         break;
1441       }
1442 
1443       /* ESC [ sequences. */
1444       if (seq[0] == '[')
1445       {
1446         if (seq[1] >= '0' && seq[1] <= '9')
1447         {
1448           /* Extended escape, read additional byte. */
1449           if (read(l.ifd, seq + 2, 1) == -1)
1450           {
1451             break;
1452           }
1453 
1454           if (seq[2] == '~')
1455           {
1456             switch (seq[1])
1457             {
1458             case '3': /* Delete */
1459               linenoiseEditDelete(&l);
1460               break;
1461 
1462             case '6': /* Page Down */
1463               linenoiseSearchInHistory(
1464                 &l,
1465                 LINENOISE_SEARCH_HISTORY_REVERSE);
1466               break;
1467 
1468             case '5': /* Page Up */
1469               linenoiseSearchInHistory(
1470                 &l,
1471                 LINENOISE_SEARCH_HISTORY_FORWARD);
1472               break;
1473             }
1474           }
1475         }
1476         else
1477         {
1478           switch (seq[1])
1479           {
1480           case 'A': /* Up */
1481             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
1482             break;
1483 
1484           case 'B': /* Down */
1485             linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
1486             break;
1487 
1488           case 'C': /* Right */
1489             linenoiseEditMoveRight(&l);
1490             break;
1491 
1492           case 'D': /* Left */
1493             linenoiseEditMoveLeft(&l);
1494             break;
1495 
1496           case 'H': /* Home */
1497             linenoiseEditMoveHome(&l);
1498             break;
1499 
1500           case 'F': /* End */
1501             linenoiseEditMoveEnd(&l);
1502             break;
1503           }
1504         }
1505       }
1506 
1507       break;
1508 
1509     default:
1510       if (linenoiseEditInsert(&l, c))
1511       {
1512         return ( -1 );
1513       }
1514 
1515       break;
1516 
1517     case CTRL_U: /* Ctrl+U, delete the whole line. */
1518       buf[0] = '\0';
1519       l.pos  = l.len = 0;
1520       refreshLine(&l);
1521       break;
1522 
1523     case CTRL_K: /* Ctrl+K, delete from current to end of line. */
1524       buf[l.pos] = '\0';
1525       l.len      = l.pos;
1526       refreshLine(&l);
1527       break;
1528 
1529     case CTRL_A: /* Ctrl+A, go to the start of the line */
1530       linenoiseEditMoveHome(&l);
1531       break;
1532 
1533     case CTRL_E: /* Ctrl+E, go to the end of the line */
1534       linenoiseEditMoveEnd(&l);
1535       break;
1536 
1537     case CTRL_L: /* Ctrl+L, clear screen */
1538       linenoiseClearScreen();
1539       refreshLine(&l);
1540       break;
1541 
1542     case CTRL_W: /* Ctrl+W, delete previous word */
1543       linenoiseEditDeletePrevWord(&l);
1544       break;
1545     }
1546   }
1547 # if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
1548  /*NOTREACHED*/ /* unreachable */
1549  return ( -1 );
1550 # endif /* if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) */
1551 }
1552 
1553 /*
1554  * This function calls the line editing function linenoiseEdit() using
1555  * the STDIN file descriptor set in raw mode.
1556  */
1557 
1558 static int
1559 linenoiseRaw(char *buf, size_t buflen, const char *prompt)
     /* [previous][next][first][last][top][bottom][index][help] */
1560 {
1561   int count;
1562 
1563   if (buflen == 0)
1564   {
1565     errno = EINVAL;
1566     return ( -1 );
1567   }
1568 
1569   if (enableRawMode(STDIN_FILENO) == -1)
1570   {
1571     return ( -1 );
1572   }
1573 
1574   count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1575   disableRawMode(STDIN_FILENO);
1576   (void)printf("\n");
1577   return ( count );
1578 }
1579 
1580 /*
1581  * This function is called when linenoise() is called with the standard
1582  * input file descriptor not attached to a TTY. So for example when the
1583  * program using linenoise is called in pipe or with a file redirected
1584  * to its standard input. In this case, we want to be able to return the
1585  * line regardless of its length (by default we are limited to 4k).
1586  */
1587 
1588 static char *
1589 linenoiseNoTTY(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1590 {
1591   char *line = NULL;
1592   size_t len = 0, maxlen = 0;
1593 
1594   while (1)
1595   {
1596     if (len == maxlen)
1597     {
1598       if (maxlen == 0)
1599       {
1600         maxlen = 16;
1601       }
1602 
1603       maxlen *= 2;
1604       char *oldval = line;
1605       line = realloc(line, maxlen); //-V701
1606       if (line == NULL)
1607       {
1608         if (oldval)
1609         {
1610           FREE(oldval);
1611         }
1612 
1613         return ( NULL );
1614       }
1615     }
1616 
1617     int c = fgetc(stdin);
1618     if (c == EOF || c == '\n')
1619     {
1620       if (c == EOF && len == 0)
1621       {
1622         FREE(line);
1623         return ( NULL );
1624       }
1625       else
1626       {
1627         line[len] = '\0';
1628         return ( line );
1629       }
1630     }
1631     else
1632     {
1633       line[len] = c;
1634       len++;
1635     }
1636   }
1637 # if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
1638  /*NOTREACHED*/ /* unreachable */
1639  return ( NULL );
1640 # endif /* if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) */
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      * Not a tty: read from file / pipe. In this mode we don't want any
1661      * limit to the line size, so we call a function to handle that.
1662      */
1663 
1664     return ( linenoiseNoTTY());
1665   }
1666   else if (isUnsupportedTerm())
1667   {
1668     size_t len;
1669 
1670     (void)fflush(stderr);
1671     (void)printf("%s", prompt);
1672     (void)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     (void)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     (void)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

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