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

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