File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / history.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    1: /* history.c -- standalone history library */
    2: 
    3: /* Copyright (C) 1989-2017 Free Software Foundation, Inc.
    4: 
    5:    This file contains the GNU History Library (History), a set of
    6:    routines for managing the text of previously typed lines.
    7: 
    8:    History is free software: you can redistribute it and/or modify
    9:    it under the terms of the GNU General Public License as published by
   10:    the Free Software Foundation, either version 3 of the License, or
   11:    (at your option) any later version.
   12: 
   13:    History is distributed in the hope that it will be useful,
   14:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:    GNU General Public License for more details.
   17: 
   18:    You should have received a copy of the GNU General Public License
   19:    along with History.  If not, see <http://www.gnu.org/licenses/>.
   20: */
   21: 
   22: /* The goal is to make the implementation transparent, so that you
   23:    don't have to know what data types are used, just what functions
   24:    you can call.  I think I have done that. */
   25: #define READLINE_LIBRARY
   26: 
   27: #if defined (HAVE_CONFIG_H)
   28: #  include <config.h>
   29: #endif
   30: 
   31: #include <stdio.h>
   32: 
   33: #if defined (HAVE_STDLIB_H)
   34: #  include <stdlib.h>
   35: #else
   36: #  include "ansi_stdlib.h"
   37: #endif /* HAVE_STDLIB_H */
   38: 
   39: #if defined (HAVE_UNISTD_H)
   40: #  ifdef _MINIX
   41: #    include <sys/types.h>
   42: #  endif
   43: #  include <unistd.h>
   44: #endif
   45: 
   46: #include <errno.h>
   47: 
   48: #include "history.h"
   49: #include "histlib.h"
   50: 
   51: #include "xmalloc.h"
   52: 
   53: #if !defined (errno)
   54: extern int errno;
   55: #endif
   56: 
   57: /* How big to make the_history when we first allocate it. */
   58: #define DEFAULT_HISTORY_INITIAL_SIZE	502
   59: 
   60: #define MAX_HISTORY_INITIAL_SIZE	8192
   61: 
   62: /* The number of slots to increase the_history by. */
   63: #define DEFAULT_HISTORY_GROW_SIZE 50
   64: 
   65: static char *hist_inittime PARAMS((void));
   66: 
   67: /* **************************************************************** */
   68: /*								    */
   69: /*			History Functions			    */
   70: /*								    */
   71: /* **************************************************************** */
   72: 
   73: /* An array of HIST_ENTRY.  This is where we store the history. */
   74: static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
   75: 
   76: /* Non-zero means that we have enforced a limit on the amount of
   77:    history that we save. */
   78: static int history_stifled;
   79: 
   80: /* The current number of slots allocated to the input_history. */
   81: static int history_size;
   82: 
   83: /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
   84:    entries to remember. */
   85: int history_max_entries;
   86: int max_input_history;	/* backwards compatibility */
   87: 
   88: /* The current location of the interactive history pointer.  Just makes
   89:    life easier for outside callers. */
   90: int history_offset;
   91: 
   92: /* The number of strings currently stored in the history list. */
   93: int history_length;
   94: 
   95: /* The logical `base' of the history array.  It defaults to 1. */
   96: int history_base = 1;
   97: 
   98: /* Return the current HISTORY_STATE of the history. */
   99: HISTORY_STATE *
  100: history_get_history_state (void)
  101: {
  102:   HISTORY_STATE *state;
  103: 
  104:   state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
  105:   state->entries = the_history;
  106:   state->offset = history_offset;
  107:   state->length = history_length;
  108:   state->size = history_size;
  109:   state->flags = 0;
  110:   if (history_stifled)
  111:     state->flags |= HS_STIFLED;
  112: 
  113:   return (state);
  114: }
  115: 
  116: /* Set the state of the current history array to STATE. */
  117: void
  118: history_set_history_state (HISTORY_STATE *state)
  119: {
  120:   the_history = state->entries;
  121:   history_offset = state->offset;
  122:   history_length = state->length;
  123:   history_size = state->size;
  124:   if (state->flags & HS_STIFLED)
  125:     history_stifled = 1;
  126: }
  127: 
  128: /* Begin a session in which the history functions might be used.  This
  129:    initializes interactive variables. */
  130: void
  131: using_history (void)
  132: {
  133:   history_offset = history_length;
  134: }
  135: 
  136: /* Return the number of bytes that the primary history entries are using.
  137:    This just adds up the lengths of the_history->lines and the associated
  138:    timestamps. */
  139: int
  140: history_total_bytes (void)
  141: {
  142:   register int i, result;
  143: 
  144:   for (i = result = 0; the_history && the_history[i]; i++)
  145:     result += HISTENT_BYTES (the_history[i]);
  146: 
  147:   return (result);
  148: }
  149: 
  150: /* Returns the magic number which says what history element we are
  151:    looking at now.  In this implementation, it returns history_offset. */
  152: int
  153: where_history (void)
  154: {
  155:   return (history_offset);
  156: }
  157: 
  158: /* Make the current history item be the one at POS, an absolute index.
  159:    Returns zero if POS is out of range, else non-zero. */
  160: int
  161: history_set_pos (int pos)
  162: {
  163:   if (pos > history_length || pos < 0 || !the_history)
  164:     return (0);
  165:   history_offset = pos;
  166:   return (1);
  167: }
  168:  
  169: /* Return the current history array.  The caller has to be careful, since this
  170:    is the actual array of data, and could be bashed or made corrupt easily.
  171:    The array is terminated with a NULL pointer. */
  172: HIST_ENTRY **
  173: history_list (void)
  174: {
  175:   return (the_history);
  176: }
  177: 
  178: /* Return the history entry at the current position, as determined by
  179:    history_offset.  If there is no entry there, return a NULL pointer. */
  180: HIST_ENTRY *
  181: current_history (void)
  182: {
  183:   return ((history_offset == history_length) || the_history == 0)
  184: 		? (HIST_ENTRY *)NULL
  185: 		: the_history[history_offset];
  186: }
  187: 
  188: /* Back up history_offset to the previous history entry, and return
  189:    a pointer to that entry.  If there is no previous entry then return
  190:    a NULL pointer. */
  191: HIST_ENTRY *
  192: previous_history (void)
  193: {
  194:   return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
  195: }
  196: 
  197: /* Move history_offset forward to the next history entry, and return
  198:    a pointer to that entry.  If there is no next entry then return a
  199:    NULL pointer. */
  200: HIST_ENTRY *
  201: next_history (void)
  202: {
  203:   return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
  204: }
  205: 
  206: /* Return the history entry which is logically at OFFSET in the history array.
  207:    OFFSET is relative to history_base. */
  208: HIST_ENTRY *
  209: history_get (int offset)
  210: {
  211:   int local_index;
  212: 
  213:   local_index = offset - history_base;
  214:   return (local_index >= history_length || local_index < 0 || the_history == 0)
  215: 		? (HIST_ENTRY *)NULL
  216: 		: the_history[local_index];
  217: }
  218: 
  219: HIST_ENTRY *
  220: alloc_history_entry (char *string, char *ts)
  221: {
  222:   HIST_ENTRY *temp;
  223: 
  224:   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
  225: 
  226:   temp->line = string ? savestring (string) : string;
  227:   temp->data = (char *)NULL;
  228:   temp->timestamp = ts;
  229: 
  230:   return temp;
  231: }
  232: 
  233: time_t
  234: history_get_time (HIST_ENTRY *hist)
  235: {
  236:   char *ts;
  237:   time_t t;
  238: 
  239:   if (hist == 0 || hist->timestamp == 0)
  240:     return 0;
  241:   ts = hist->timestamp;
  242:   if (ts[0] != history_comment_char)
  243:     return 0;
  244:   errno = 0;
  245:   t = (time_t) strtol (ts + 1, (char **)NULL, 10);		/* XXX - should use strtol() here */
  246:   if (errno == ERANGE)
  247:     return (time_t)0;
  248:   return t;
  249: }
  250: 
  251: static char *
  252: hist_inittime (void)
  253: {
  254:   time_t t;
  255:   char ts[64], *ret;
  256: 
  257:   t = (time_t) time ((time_t *)0);
  258: #if defined (HAVE_VSNPRINTF)		/* assume snprintf if vsnprintf exists */
  259:   snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
  260: #else
  261:   sprintf (ts, "X%lu", (unsigned long) t);
  262: #endif
  263:   ret = savestring (ts);
  264:   ret[0] = history_comment_char;
  265: 
  266:   return ret;
  267: }
  268: 
  269: /* Place STRING at the end of the history list.  The data field
  270:    is  set to NULL. */
  271: void
  272: add_history (const char *string)
  273: {
  274:   HIST_ENTRY *temp;
  275:   int new_length;
  276: 
  277:   if (history_stifled && (history_length == history_max_entries))
  278:     {
  279:       register int i;
  280: 
  281:       /* If the history is stifled, and history_length is zero,
  282: 	 and it equals history_max_entries, we don't save items. */
  283:       if (history_length == 0)
  284: 	return;
  285: 
  286:       /* If there is something in the slot, then remove it. */
  287:       if (the_history[0])
  288: 	(void) free_history_entry (the_history[0]);
  289: 
  290:       /* Copy the rest of the entries, moving down one slot.  Copy includes
  291: 	 trailing NULL.  */
  292:       memmove (the_history, the_history + 1, history_length * sizeof (HIST_ENTRY *));
  293: 
  294:       new_length = history_length;
  295:       history_base++;
  296:     }
  297:   else
  298:     {
  299:       if (history_size == 0)
  300: 	{
  301: 	  if (history_stifled && history_max_entries > 0)
  302: 	    history_size = (history_max_entries > MAX_HISTORY_INITIAL_SIZE)
  303: 				? MAX_HISTORY_INITIAL_SIZE
  304: 				: history_max_entries + 2;
  305: 	  else
  306: 	    history_size = DEFAULT_HISTORY_INITIAL_SIZE;
  307: 	  the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
  308: 	  new_length = 1;
  309: 	}
  310:       else
  311: 	{
  312: 	  if (history_length == (history_size - 1))
  313: 	    {
  314: 	      history_size += DEFAULT_HISTORY_GROW_SIZE;
  315: 	      the_history = (HIST_ENTRY **)
  316: 		xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
  317: 	    }
  318: 	  new_length = history_length + 1;
  319: 	}
  320:     }
  321: 
  322:   temp = alloc_history_entry ((char *)string, hist_inittime ());
  323: 
  324:   the_history[new_length] = (HIST_ENTRY *)NULL;
  325:   the_history[new_length - 1] = temp;
  326:   history_length = new_length;
  327: }
  328: 
  329: /* Change the time stamp of the most recent history entry to STRING. */
  330: void
  331: add_history_time (const char *string)
  332: {
  333:   HIST_ENTRY *hs;
  334: 
  335:   if (string == 0 || history_length < 1)
  336:     return;
  337:   hs = the_history[history_length - 1];
  338:   FREE (hs->timestamp);
  339:   hs->timestamp = savestring (string);
  340: }
  341: 
  342: /* Free HIST and return the data so the calling application can free it
  343:    if necessary and desired. */
  344: histdata_t
  345: free_history_entry (HIST_ENTRY *hist)
  346: {
  347:   histdata_t x;
  348: 
  349:   if (hist == 0)
  350:     return ((histdata_t) 0);
  351:   FREE (hist->line);
  352:   FREE (hist->timestamp);
  353:   x = hist->data;
  354:   xfree (hist);
  355:   return (x);
  356: }
  357: 
  358: HIST_ENTRY *
  359: copy_history_entry (HIST_ENTRY *hist)
  360: {
  361:   HIST_ENTRY *ret;
  362:   char *ts;
  363: 
  364:   if (hist == 0)
  365:     return hist;
  366: 
  367:   ret = alloc_history_entry (hist->line, (char *)NULL);
  368: 
  369:   ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
  370:   ret->timestamp = ts;
  371: 
  372:   ret->data = hist->data;
  373: 
  374:   return ret;
  375: }
  376:   
  377: /* Make the history entry at WHICH have LINE and DATA.  This returns
  378:    the old entry so you can dispose of the data.  In the case of an
  379:    invalid WHICH, a NULL pointer is returned. */
  380: HIST_ENTRY *
  381: replace_history_entry (int which, const char *line, histdata_t data)
  382: {
  383:   HIST_ENTRY *temp, *old_value;
  384: 
  385:   if (which < 0 || which >= history_length)
  386:     return ((HIST_ENTRY *)NULL);
  387: 
  388:   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
  389:   old_value = the_history[which];
  390: 
  391:   temp->line = savestring (line);
  392:   temp->data = data;
  393:   temp->timestamp = savestring (old_value->timestamp);
  394:   the_history[which] = temp;
  395: 
  396:   return (old_value);
  397: }
  398: 
  399: /* Append LINE to the history line at offset WHICH, adding a newline to the
  400:    end of the current line first.  This can be used to construct multi-line
  401:    history entries while reading lines from the history file. */
  402: void
  403: _hs_append_history_line (int which, const char *line)
  404: {
  405:   HIST_ENTRY *hent;
  406:   size_t newlen, curlen, minlen;
  407:   char *newline;
  408: 
  409:   hent = the_history[which];
  410:   curlen = strlen (hent->line);
  411:   minlen = curlen + strlen (line) + 2;	/* min space needed */
  412:   if (curlen > 256)		/* XXX - for now */
  413:     {
  414:       newlen = 512;		/* now realloc in powers of 2 */
  415:       /* we recalcluate every time; the operations are cheap */
  416:       while (newlen < minlen)
  417: 	newlen <<= 1;
  418:     }
  419:   else
  420:     newlen = minlen;
  421:   /* Assume that realloc returns the same pointer and doesn't try a new
  422:      alloc/copy if the new size is the same as the one last passed. */
  423:   newline = realloc (hent->line, newlen);
  424:   if (newline)
  425:     {
  426:       hent->line = newline;
  427:       hent->line[curlen++] = '\n';
  428:       strcpy (hent->line + curlen, line);
  429:     }
  430: }
  431: 
  432: /* Replace the DATA in the specified history entries, replacing OLD with
  433:    NEW.  WHICH says which one(s) to replace:  WHICH == -1 means to replace
  434:    all of the history entries where entry->data == OLD; WHICH == -2 means
  435:    to replace the `newest' history entry where entry->data == OLD; and
  436:    WHICH >= 0 means to replace that particular history entry's data, as
  437:    long as it matches OLD. */
  438: void
  439: _hs_replace_history_data (int which, histdata_t *old, histdata_t *new)
  440: {
  441:   HIST_ENTRY *entry;
  442:   register int i, last;
  443: 
  444:   if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
  445:     return;
  446: 
  447:   if (which >= 0)
  448:     {
  449:       entry = the_history[which];
  450:       if (entry && entry->data == old)
  451: 	entry->data = new;
  452:       return;
  453:     }
  454: 
  455:   last = -1;
  456:   for (i = 0; i < history_length; i++)
  457:     {
  458:       entry = the_history[i];
  459:       if (entry == 0)
  460: 	continue;
  461:       if (entry->data == old)
  462: 	{
  463: 	  last = i;
  464: 	  if (which == -1)
  465: 	    entry->data = new;
  466: 	}
  467:     }
  468:   if (which == -2 && last >= 0)
  469:     {
  470:       entry = the_history[last];
  471:       entry->data = new;	/* XXX - we don't check entry->old */
  472:     }
  473: }      
  474:   
  475: /* Remove history element WHICH from the history.  The removed
  476:    element is returned to you so you can free the line, data,
  477:    and containing structure. */
  478: HIST_ENTRY *
  479: remove_history (int which)
  480: {
  481:   HIST_ENTRY *return_value;
  482:   register int i;
  483: #if 1
  484:   int nentries;
  485:   HIST_ENTRY **start, **end;
  486: #endif
  487: 
  488:   if (which < 0 || which >= history_length || history_length ==  0 || the_history == 0)
  489:     return ((HIST_ENTRY *)NULL);
  490: 
  491:   return_value = the_history[which];
  492: 
  493: #if 1
  494:   /* Copy the rest of the entries, moving down one slot.  Copy includes
  495:      trailing NULL.  */
  496:   nentries = history_length - which;
  497:   start = the_history + which;
  498:   end = start + 1;
  499:   memmove (start, end, nentries * sizeof (HIST_ENTRY *));
  500: #else
  501:   for (i = which; i < history_length; i++)
  502:     the_history[i] = the_history[i + 1];
  503: #endif
  504: 
  505:   history_length--;
  506: 
  507:   return (return_value);
  508: }
  509: 
  510: HIST_ENTRY **
  511: remove_history_range (int first, int last)
  512: {
  513:   HIST_ENTRY **return_value;
  514:   register int i;
  515:   int nentries;
  516:   HIST_ENTRY **start, **end;
  517: 
  518:   if (the_history == 0 || history_length == 0)
  519:     return ((HIST_ENTRY **)NULL);
  520:   if (first < 0 || first >= history_length || last < 0 || last >= history_length)
  521:     return ((HIST_ENTRY **)NULL);
  522:   if (first > last)
  523:     return (HIST_ENTRY **)NULL;
  524: 
  525:   nentries = last - first + 1;
  526:   return_value = (HIST_ENTRY **)malloc ((nentries + 1) * sizeof (HIST_ENTRY *));
  527:   if (return_value == 0)
  528:     return return_value;
  529: 
  530:   /* Return all the deleted entries in a list */
  531:   for (i = first ; i <= last; i++)
  532:     return_value[i - first] = the_history[i];
  533:   return_value[i - first] = (HIST_ENTRY *)NULL;
  534: 
  535:   /* Copy the rest of the entries, moving down NENTRIES slots.  Copy includes
  536:      trailing NULL.  */
  537:   start = the_history + first;
  538:   end = the_history + last + 1;
  539:   memmove (start, end, (history_length - last) * sizeof (HIST_ENTRY *));
  540: 
  541:   history_length -= nentries;
  542: 
  543:   return (return_value);
  544: }
  545: 
  546: /* Stifle the history list, remembering only MAX number of lines. */
  547: void
  548: stifle_history (int max)
  549: {
  550:   register int i, j;
  551: 
  552:   if (max < 0)
  553:     max = 0;
  554: 
  555:   if (history_length > max)
  556:     {
  557:       /* This loses because we cannot free the data. */
  558:       for (i = 0, j = history_length - max; i < j; i++)
  559: 	free_history_entry (the_history[i]);
  560: 
  561:       history_base = i;
  562:       for (j = 0, i = history_length - max; j < max; i++, j++)
  563: 	the_history[j] = the_history[i];
  564:       the_history[j] = (HIST_ENTRY *)NULL;
  565:       history_length = j;
  566:     }
  567: 
  568:   history_stifled = 1;
  569:   max_input_history = history_max_entries = max;
  570: }
  571: 
  572: /* Stop stifling the history.  This returns the previous maximum
  573:    number of history entries.  The value is positive if the history
  574:    was stifled, negative if it wasn't. */
  575: int
  576: unstifle_history (void)
  577: {
  578:   if (history_stifled)
  579:     {
  580:       history_stifled = 0;
  581:       return (history_max_entries);
  582:     }
  583:   else
  584:     return (-history_max_entries);
  585: }
  586: 
  587: int
  588: history_is_stifled (void)
  589: {
  590:   return (history_stifled);
  591: }
  592: 
  593: void
  594: clear_history (void)
  595: {
  596:   register int i;
  597: 
  598:   /* This loses because we cannot free the data. */
  599:   for (i = 0; i < history_length; i++)
  600:     {
  601:       free_history_entry (the_history[i]);
  602:       the_history[i] = (HIST_ENTRY *)NULL;
  603:     }
  604: 
  605:   history_offset = history_length = 0;
  606:   history_base = 1;		/* reset history base to default */
  607: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>