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

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