Annotation of embedaddon/readline/history.c, revision 1.1

1.1     ! misho       1: /* history.c -- standalone history library */
        !             2: 
        !             3: /* Copyright (C) 1989-2011 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 "history.h"
        !            47: #include "histlib.h"
        !            48: 
        !            49: #include "xmalloc.h"
        !            50: 
        !            51: /* The number of slots to increase the_history by. */
        !            52: #define DEFAULT_HISTORY_GROW_SIZE 50
        !            53: 
        !            54: static char *hist_inittime PARAMS((void));
        !            55: 
        !            56: /* **************************************************************** */
        !            57: /*                                                                 */
        !            58: /*                     History Functions                           */
        !            59: /*                                                                 */
        !            60: /* **************************************************************** */
        !            61: 
        !            62: /* An array of HIST_ENTRY.  This is where we store the history. */
        !            63: static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
        !            64: 
        !            65: /* Non-zero means that we have enforced a limit on the amount of
        !            66:    history that we save. */
        !            67: static int history_stifled;
        !            68: 
        !            69: /* The current number of slots allocated to the input_history. */
        !            70: static int history_size;
        !            71: 
        !            72: /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
        !            73:    entries to remember. */
        !            74: int history_max_entries;
        !            75: int max_input_history; /* backwards compatibility */
        !            76: 
        !            77: /* The current location of the interactive history pointer.  Just makes
        !            78:    life easier for outside callers. */
        !            79: int history_offset;
        !            80: 
        !            81: /* The number of strings currently stored in the history list. */
        !            82: int history_length;
        !            83: 
        !            84: /* The logical `base' of the history array.  It defaults to 1. */
        !            85: int history_base = 1;
        !            86: 
        !            87: /* Return the current HISTORY_STATE of the history. */
        !            88: HISTORY_STATE *
        !            89: history_get_history_state ()
        !            90: {
        !            91:   HISTORY_STATE *state;
        !            92: 
        !            93:   state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
        !            94:   state->entries = the_history;
        !            95:   state->offset = history_offset;
        !            96:   state->length = history_length;
        !            97:   state->size = history_size;
        !            98:   state->flags = 0;
        !            99:   if (history_stifled)
        !           100:     state->flags |= HS_STIFLED;
        !           101: 
        !           102:   return (state);
        !           103: }
        !           104: 
        !           105: /* Set the state of the current history array to STATE. */
        !           106: void
        !           107: history_set_history_state (state)
        !           108:      HISTORY_STATE *state;
        !           109: {
        !           110:   the_history = state->entries;
        !           111:   history_offset = state->offset;
        !           112:   history_length = state->length;
        !           113:   history_size = state->size;
        !           114:   if (state->flags & HS_STIFLED)
        !           115:     history_stifled = 1;
        !           116: }
        !           117: 
        !           118: /* Begin a session in which the history functions might be used.  This
        !           119:    initializes interactive variables. */
        !           120: void
        !           121: using_history ()
        !           122: {
        !           123:   history_offset = history_length;
        !           124: }
        !           125: 
        !           126: /* Return the number of bytes that the primary history entries are using.
        !           127:    This just adds up the lengths of the_history->lines and the associated
        !           128:    timestamps. */
        !           129: int
        !           130: history_total_bytes ()
        !           131: {
        !           132:   register int i, result;
        !           133: 
        !           134:   for (i = result = 0; the_history && the_history[i]; i++)
        !           135:     result += HISTENT_BYTES (the_history[i]);
        !           136: 
        !           137:   return (result);
        !           138: }
        !           139: 
        !           140: /* Returns the magic number which says what history element we are
        !           141:    looking at now.  In this implementation, it returns history_offset. */
        !           142: int
        !           143: where_history ()
        !           144: {
        !           145:   return (history_offset);
        !           146: }
        !           147: 
        !           148: /* Make the current history item be the one at POS, an absolute index.
        !           149:    Returns zero if POS is out of range, else non-zero. */
        !           150: int
        !           151: history_set_pos (pos)
        !           152:      int pos;
        !           153: {
        !           154:   if (pos > history_length || pos < 0 || !the_history)
        !           155:     return (0);
        !           156:   history_offset = pos;
        !           157:   return (1);
        !           158: }
        !           159:  
        !           160: /* Return the current history array.  The caller has to be careful, since this
        !           161:    is the actual array of data, and could be bashed or made corrupt easily.
        !           162:    The array is terminated with a NULL pointer. */
        !           163: HIST_ENTRY **
        !           164: history_list ()
        !           165: {
        !           166:   return (the_history);
        !           167: }
        !           168: 
        !           169: /* Return the history entry at the current position, as determined by
        !           170:    history_offset.  If there is no entry there, return a NULL pointer. */
        !           171: HIST_ENTRY *
        !           172: current_history ()
        !           173: {
        !           174:   return ((history_offset == history_length) || the_history == 0)
        !           175:                ? (HIST_ENTRY *)NULL
        !           176:                : the_history[history_offset];
        !           177: }
        !           178: 
        !           179: /* Back up history_offset to the previous history entry, and return
        !           180:    a pointer to that entry.  If there is no previous entry then return
        !           181:    a NULL pointer. */
        !           182: HIST_ENTRY *
        !           183: previous_history ()
        !           184: {
        !           185:   return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
        !           186: }
        !           187: 
        !           188: /* Move history_offset forward to the next history entry, and return
        !           189:    a pointer to that entry.  If there is no next entry then return a
        !           190:    NULL pointer. */
        !           191: HIST_ENTRY *
        !           192: next_history ()
        !           193: {
        !           194:   return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
        !           195: }
        !           196: 
        !           197: /* Return the history entry which is logically at OFFSET in the history array.
        !           198:    OFFSET is relative to history_base. */
        !           199: HIST_ENTRY *
        !           200: history_get (offset)
        !           201:      int offset;
        !           202: {
        !           203:   int local_index;
        !           204: 
        !           205:   local_index = offset - history_base;
        !           206:   return (local_index >= history_length || local_index < 0 || the_history == 0)
        !           207:                ? (HIST_ENTRY *)NULL
        !           208:                : the_history[local_index];
        !           209: }
        !           210: 
        !           211: HIST_ENTRY *
        !           212: alloc_history_entry (string, ts)
        !           213:      char *string;
        !           214:      char *ts;
        !           215: {
        !           216:   HIST_ENTRY *temp;
        !           217: 
        !           218:   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
        !           219: 
        !           220:   temp->line = string ? savestring (string) : string;
        !           221:   temp->data = (char *)NULL;
        !           222:   temp->timestamp = ts;
        !           223: 
        !           224:   return temp;
        !           225: }
        !           226: 
        !           227: time_t
        !           228: history_get_time (hist)
        !           229:      HIST_ENTRY *hist;
        !           230: {
        !           231:   char *ts;
        !           232:   time_t t;
        !           233: 
        !           234:   if (hist == 0 || hist->timestamp == 0)
        !           235:     return 0;
        !           236:   ts = hist->timestamp;
        !           237:   if (ts[0] != history_comment_char)
        !           238:     return 0;
        !           239:   t = (time_t) strtol (ts + 1, (char **)NULL, 10);             /* XXX - should use strtol() here */
        !           240:   return t;
        !           241: }
        !           242: 
        !           243: static char *
        !           244: hist_inittime ()
        !           245: {
        !           246:   time_t t;
        !           247:   char ts[64], *ret;
        !           248: 
        !           249:   t = (time_t) time ((time_t *)0);
        !           250: #if defined (HAVE_VSNPRINTF)           /* assume snprintf if vsnprintf exists */
        !           251:   snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
        !           252: #else
        !           253:   sprintf (ts, "X%lu", (unsigned long) t);
        !           254: #endif
        !           255:   ret = savestring (ts);
        !           256:   ret[0] = history_comment_char;
        !           257: 
        !           258:   return ret;
        !           259: }
        !           260: 
        !           261: /* Place STRING at the end of the history list.  The data field
        !           262:    is  set to NULL. */
        !           263: void
        !           264: add_history (string)
        !           265:      const char *string;
        !           266: {
        !           267:   HIST_ENTRY *temp;
        !           268: 
        !           269:   if (history_stifled && (history_length == history_max_entries))
        !           270:     {
        !           271:       register int i;
        !           272: 
        !           273:       /* If the history is stifled, and history_length is zero,
        !           274:         and it equals history_max_entries, we don't save items. */
        !           275:       if (history_length == 0)
        !           276:        return;
        !           277: 
        !           278:       /* If there is something in the slot, then remove it. */
        !           279:       if (the_history[0])
        !           280:        (void) free_history_entry (the_history[0]);
        !           281: 
        !           282:       /* Copy the rest of the entries, moving down one slot. */
        !           283:       for (i = 0; i < history_length; i++)
        !           284:        the_history[i] = the_history[i + 1];
        !           285: 
        !           286:       history_base++;
        !           287:     }
        !           288:   else
        !           289:     {
        !           290:       if (history_size == 0)
        !           291:        {
        !           292:          history_size = DEFAULT_HISTORY_GROW_SIZE;
        !           293:          the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
        !           294:          history_length = 1;
        !           295:        }
        !           296:       else
        !           297:        {
        !           298:          if (history_length == (history_size - 1))
        !           299:            {
        !           300:              history_size += DEFAULT_HISTORY_GROW_SIZE;
        !           301:              the_history = (HIST_ENTRY **)
        !           302:                xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
        !           303:            }
        !           304:          history_length++;
        !           305:        }
        !           306:     }
        !           307: 
        !           308:   temp = alloc_history_entry (string, hist_inittime ());
        !           309: 
        !           310:   the_history[history_length] = (HIST_ENTRY *)NULL;
        !           311:   the_history[history_length - 1] = temp;
        !           312: }
        !           313: 
        !           314: /* Change the time stamp of the most recent history entry to STRING. */
        !           315: void
        !           316: add_history_time (string)
        !           317:      const char *string;
        !           318: {
        !           319:   HIST_ENTRY *hs;
        !           320: 
        !           321:   if (string == 0 || history_length < 1)
        !           322:     return;
        !           323:   hs = the_history[history_length - 1];
        !           324:   FREE (hs->timestamp);
        !           325:   hs->timestamp = savestring (string);
        !           326: }
        !           327: 
        !           328: /* Free HIST and return the data so the calling application can free it
        !           329:    if necessary and desired. */
        !           330: histdata_t
        !           331: free_history_entry (hist)
        !           332:      HIST_ENTRY *hist;
        !           333: {
        !           334:   histdata_t x;
        !           335: 
        !           336:   if (hist == 0)
        !           337:     return ((histdata_t) 0);
        !           338:   FREE (hist->line);
        !           339:   FREE (hist->timestamp);
        !           340:   x = hist->data;
        !           341:   xfree (hist);
        !           342:   return (x);
        !           343: }
        !           344: 
        !           345: HIST_ENTRY *
        !           346: copy_history_entry (hist)
        !           347:      HIST_ENTRY *hist;
        !           348: {
        !           349:   HIST_ENTRY *ret;
        !           350:   char *ts;
        !           351: 
        !           352:   if (hist == 0)
        !           353:     return hist;
        !           354: 
        !           355:   ret = alloc_history_entry (hist->line, (char *)NULL);
        !           356: 
        !           357:   ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
        !           358:   ret->timestamp = ts;
        !           359: 
        !           360:   ret->data = hist->data;
        !           361: 
        !           362:   return ret;
        !           363: }
        !           364:   
        !           365: /* Make the history entry at WHICH have LINE and DATA.  This returns
        !           366:    the old entry so you can dispose of the data.  In the case of an
        !           367:    invalid WHICH, a NULL pointer is returned. */
        !           368: HIST_ENTRY *
        !           369: replace_history_entry (which, line, data)
        !           370:      int which;
        !           371:      const char *line;
        !           372:      histdata_t data;
        !           373: {
        !           374:   HIST_ENTRY *temp, *old_value;
        !           375: 
        !           376:   if (which < 0 || which >= history_length)
        !           377:     return ((HIST_ENTRY *)NULL);
        !           378: 
        !           379:   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
        !           380:   old_value = the_history[which];
        !           381: 
        !           382:   temp->line = savestring (line);
        !           383:   temp->data = data;
        !           384:   temp->timestamp = savestring (old_value->timestamp);
        !           385:   the_history[which] = temp;
        !           386: 
        !           387:   return (old_value);
        !           388: }
        !           389: 
        !           390: /* Replace the DATA in the specified history entries, replacing OLD with
        !           391:    NEW.  WHICH says which one(s) to replace:  WHICH == -1 means to replace
        !           392:    all of the history entries where entry->data == OLD; WHICH == -2 means
        !           393:    to replace the `newest' history entry where entry->data == OLD; and
        !           394:    WHICH >= 0 means to replace that particular history entry's data, as
        !           395:    long as it matches OLD. */
        !           396: void
        !           397: replace_history_data (which, old, new)
        !           398:      int which;
        !           399:      histdata_t *old, *new;
        !           400: {
        !           401:   HIST_ENTRY *entry;
        !           402:   register int i, last;
        !           403: 
        !           404:   if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
        !           405:     return;
        !           406: 
        !           407:   if (which >= 0)
        !           408:     {
        !           409:       entry = the_history[which];
        !           410:       if (entry && entry->data == old)
        !           411:        entry->data = new;
        !           412:       return;
        !           413:     }
        !           414: 
        !           415:   last = -1;
        !           416:   for (i = 0; i < history_length; i++)
        !           417:     {
        !           418:       entry = the_history[i];
        !           419:       if (entry == 0)
        !           420:        continue;
        !           421:       if (entry->data == old)
        !           422:        {
        !           423:          last = i;
        !           424:          if (which == -1)
        !           425:            entry->data = new;
        !           426:        }
        !           427:     }
        !           428:   if (which == -2 && last >= 0)
        !           429:     {
        !           430:       entry = the_history[last];
        !           431:       entry->data = new;       /* XXX - we don't check entry->old */
        !           432:     }
        !           433: }      
        !           434:   
        !           435: /* Remove history element WHICH from the history.  The removed
        !           436:    element is returned to you so you can free the line, data,
        !           437:    and containing structure. */
        !           438: HIST_ENTRY *
        !           439: remove_history (which)
        !           440:      int which;
        !           441: {
        !           442:   HIST_ENTRY *return_value;
        !           443:   register int i;
        !           444: 
        !           445:   if (which < 0 || which >= history_length || history_length ==  0 || the_history == 0)
        !           446:     return ((HIST_ENTRY *)NULL);
        !           447: 
        !           448:   return_value = the_history[which];
        !           449: 
        !           450:   for (i = which; i < history_length; i++)
        !           451:     the_history[i] = the_history[i + 1];
        !           452: 
        !           453:   history_length--;
        !           454: 
        !           455:   return (return_value);
        !           456: }
        !           457: 
        !           458: /* Stifle the history list, remembering only MAX number of lines. */
        !           459: void
        !           460: stifle_history (max)
        !           461:      int max;
        !           462: {
        !           463:   register int i, j;
        !           464: 
        !           465:   if (max < 0)
        !           466:     max = 0;
        !           467: 
        !           468:   if (history_length > max)
        !           469:     {
        !           470:       /* This loses because we cannot free the data. */
        !           471:       for (i = 0, j = history_length - max; i < j; i++)
        !           472:        free_history_entry (the_history[i]);
        !           473: 
        !           474:       history_base = i;
        !           475:       for (j = 0, i = history_length - max; j < max; i++, j++)
        !           476:        the_history[j] = the_history[i];
        !           477:       the_history[j] = (HIST_ENTRY *)NULL;
        !           478:       history_length = j;
        !           479:     }
        !           480: 
        !           481:   history_stifled = 1;
        !           482:   max_input_history = history_max_entries = max;
        !           483: }
        !           484: 
        !           485: /* Stop stifling the history.  This returns the previous maximum
        !           486:    number of history entries.  The value is positive if the history
        !           487:    was stifled, negative if it wasn't. */
        !           488: int
        !           489: unstifle_history ()
        !           490: {
        !           491:   if (history_stifled)
        !           492:     {
        !           493:       history_stifled = 0;
        !           494:       return (history_max_entries);
        !           495:     }
        !           496:   else
        !           497:     return (-history_max_entries);
        !           498: }
        !           499: 
        !           500: int
        !           501: history_is_stifled ()
        !           502: {
        !           503:   return (history_stifled);
        !           504: }
        !           505: 
        !           506: void
        !           507: clear_history ()
        !           508: {
        !           509:   register int i;
        !           510: 
        !           511:   /* This loses because we cannot free the data. */
        !           512:   for (i = 0; i < history_length; i++)
        !           513:     {
        !           514:       free_history_entry (the_history[i]);
        !           515:       the_history[i] = (HIST_ENTRY *)NULL;
        !           516:     }
        !           517: 
        !           518:   history_offset = history_length = 0;
        !           519: }

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