Annotation of GNUtools/debug/gdb/readline/history.c, revision 1.1.1.1

1.1       root        1: /* History.c -- standalone history library */
                      2: 
                      3: /* Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                      4: 
                      5:    This file contains the GNU History Library (the Library), a set of
                      6:    routines for managing the text of previously typed lines.
                      7: 
                      8:    The Library 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 2 of the License, or
                     11:    (at your option) any later version.
                     12: 
                     13:    The Library 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 this program; if not, write to the Free Software
                     20:    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     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: 
                     26: /* Remove these declarations when we have a complete libgnu.a. */
                     27: #ifndef xmalloc
                     28: #if !defined (STATIC_MALLOC)
                     29: extern char *xmalloc (), *xrealloc ();
                     30: #else
                     31: static char *xmalloc (), *xrealloc ();
                     32: #endif
                     33: #endif /* !xmalloc */
                     34: 
                     35: #include "sysdep.h"
                     36: #include <stdio.h>
                     37: #include <errno.h>
                     38: #include <sys/types.h>
                     39: #ifndef        NO_SYS_FILE
                     40: #include <sys/file.h>
                     41: #endif
                     42: #include <sys/stat.h>
                     43: #include <fcntl.h>
                     44: 
                     45: #include "history.h"
                     46: 
                     47: #ifndef savestring
                     48: #define savestring(x) (char *)strcpy ((char *)xmalloc (1 + strlen (x)), (x))
                     49: #endif
                     50: 
                     51: #ifndef whitespace
                     52: #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
                     53: #endif
                     54: 
                     55: #ifndef digit
                     56: #define digit(c)  ((c) >= '0' && (c) <= '9')
                     57: #endif
                     58: 
                     59: #ifndef member
                     60: #define member(c, s) ((c) ? index ((s), (c)) : 0)
                     61: #endif
                     62: 
                     63: /* **************************************************************** */
                     64: /*                                                                 */
                     65: /*                     History Functions                           */
                     66: /*                                                                 */
                     67: /* **************************************************************** */
                     68: 
                     69: /* An array of HIST_ENTRY.  This is where we store the history. */
                     70: static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
                     71: 
                     72: /* Non-zero means that we have enforced a limit on the amount of
                     73:    history that we save. */
                     74: int history_stifled = 0;
                     75: 
                     76: /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
                     77:    entries to remember. */
                     78: int max_input_history;
                     79: 
                     80: /* The current location of the interactive history pointer.  Just makes
                     81:    life easier for outside callers. */
                     82: static int history_offset = 0;
                     83: 
                     84: /* The number of strings currently stored in the input_history list. */
                     85: int history_length = 0;
                     86: 
                     87: /* The current number of slots allocated to the input_history. */
                     88: static int history_size = 0;
                     89: 
                     90: /* The number of slots to increase the_history by. */
                     91: #define DEFAULT_HISTORY_GROW_SIZE 50
                     92: 
                     93: /* The character that represents the start of a history expansion
                     94:    request.  This is usually `!'. */
                     95: char history_expansion_char = '!';
                     96: 
                     97: /* The character that invokes word substitution if found at the start of
                     98:    a line.  This is usually `^'. */
                     99: char history_subst_char = '^';
                    100: 
                    101: /* During tokenization, if this character is seen as the first character
                    102:    of a word, then it, and all subsequent characters upto a newline are
                    103:    ignored.  For a Bourne shell, this should be '#'.  Bash special cases
                    104:    the interactive comment character to not be a comment delimiter. */
                    105: char history_comment_char = '\0';
                    106: 
                    107: /* The list of characters which inhibit the expansion of text if found
                    108:    immediately following history_expansion_char. */
                    109: char *history_no_expand_chars = " \t\n\r=";
                    110: 
                    111: /* The logical `base' of the history array.  It defaults to 1. */
                    112: int history_base = 1;
                    113: 
                    114: /* Begin a session in which the history functions might be used.  This
                    115:    initializes interactive variables. */
                    116: void
                    117: using_history ()
                    118: {
                    119:   history_offset = history_length;
                    120: }
                    121: 
                    122: /* Return the number of bytes that the primary history entries are using.
                    123:    This just adds up the lengths of the_history->lines. */
                    124: int
                    125: history_total_bytes ()
                    126: {
                    127:   register int i, result;
                    128: 
                    129:   result = 0;
                    130: 
                    131:   for (i = 0; the_history && the_history[i]; i++)
                    132:     result += strlen (the_history[i]->line);
                    133: 
                    134:   return (result);
                    135: }
                    136: 
                    137: /* Place STRING at the end of the history list.  The data field
                    138:    is  set to NULL. */
                    139: void
                    140: add_history (string)
                    141:      char *string;
                    142: {
                    143:   HIST_ENTRY *temp;
                    144: 
                    145:   if (history_stifled && (history_length == max_input_history))
                    146:     {
                    147:       register int i;
                    148: 
                    149:       /* If the history is stifled, and history_length is zero,
                    150:         and it equals max_input_history, we don't save items. */
                    151:       if (!history_length)
                    152:        return;
                    153: 
                    154:       /* If there is something in the slot, then remove it. */
                    155:       if (the_history[0])
                    156:        {
                    157:          free (the_history[0]->line);
                    158:          free (the_history[0]);
                    159:        }
                    160: 
                    161:       for (i = 0; i < history_length; i++)
                    162:        the_history[i] = the_history[i + 1];
                    163: 
                    164:       history_base++;
                    165: 
                    166:     }
                    167:   else
                    168:     {
                    169:       if (!history_size)
                    170:        {
                    171:          the_history = (HIST_ENTRY **)
                    172:            xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
                    173:                     * sizeof (HIST_ENTRY *));
                    174:          history_length = 1;
                    175: 
                    176:        }
                    177:       else
                    178:        {
                    179:          if (history_length == (history_size - 1))
                    180:            {
                    181:              the_history = (HIST_ENTRY **)
                    182:                xrealloc (the_history,
                    183:                          ((history_size += DEFAULT_HISTORY_GROW_SIZE)
                    184:                           * sizeof (HIST_ENTRY *)));
                    185:          }
                    186:          history_length++;
                    187:        }
                    188:     }
                    189: 
                    190:   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
                    191:   temp->line = savestring (string);
                    192:   temp->data = (char *)NULL;
                    193: 
                    194:   the_history[history_length] = (HIST_ENTRY *)NULL;
                    195:   the_history[history_length - 1] = temp;
                    196: }
                    197: 
                    198: /* Make the history entry at WHICH have LINE and DATA.  This returns
                    199:    the old entry so you can dispose of the data.  In the case of an
                    200:    invalid WHICH, a NULL pointer is returned. */
                    201: HIST_ENTRY *
                    202: replace_history_entry (which, line, data)
                    203:      int which;
                    204:      char *line;
                    205:      char *data;
                    206: {
                    207:   HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
                    208:   HIST_ENTRY *old_value;
                    209: 
                    210:   if (which >= history_length)
                    211:     return ((HIST_ENTRY *)NULL);
                    212: 
                    213:   old_value = the_history[which];
                    214: 
                    215:   temp->line = savestring (line);
                    216:   temp->data = data;
                    217:   the_history[which] = temp;
                    218: 
                    219:   return (old_value);
                    220: }
                    221: 
                    222: /* Returns the magic number which says what history element we are
                    223:    looking at now.  In this implementation, it returns history_offset. */
                    224: int
                    225: where_history ()
                    226: {
                    227:   return (history_offset);
                    228: }
                    229: 
                    230: /* Search the history for STRING, starting at history_offset.
                    231:    If DIRECTION < 0, then the search is through previous entries, else
                    232:    through subsequent.  If ANCHORED is non-zero, the string must
                    233:    appear at the beginning of a history line, otherwise, the string
                    234:    may appear anywhere in the line.  If the string is found, then
                    235:    current_history () is the history entry, and the value of this
                    236:    function is the offset in the line of that history entry that the
                    237:    string was found in.  Otherwise, nothing is changed, and a -1 is
                    238:    returned. */
                    239: 
                    240: #define ANCHORED_SEARCH 1
                    241: #define NON_ANCHORED_SEARCH 0
                    242: 
                    243: static int
                    244: history_search_internal (string, direction, anchored)
                    245:      char *string;
                    246:      int direction, anchored;
                    247: {
                    248:   register int i = history_offset;
                    249:   register int reverse = (direction < 0);
                    250:   register char *line;
                    251:   register int index;
                    252:   int string_len = strlen (string);
                    253: 
                    254:   /* Take care of trivial cases first. */
                    255: 
                    256:   if (!history_length || ((i == history_length) && !reverse))
                    257:     return (-1);
                    258: 
                    259:   if (reverse && (i == history_length))
                    260:     i--;
                    261: 
                    262:   while (1)
                    263:     {
                    264:       /* Search each line in the history list for STRING. */
                    265: 
                    266:       /* At limit for direction? */
                    267:       if ((reverse && i < 0) ||
                    268:          (!reverse && i == history_length))
                    269:        return (-1);
                    270: 
                    271:       line = the_history[i]->line;
                    272:       index = strlen (line);
                    273: 
                    274:       /* If STRING is longer than line, no match. */
                    275:       if (string_len > index)
                    276:        goto next_line;
                    277: 
                    278:       /* Handle anchored searches first. */
                    279:       if (anchored == ANCHORED_SEARCH)
                    280:        {
                    281:          if (strncmp (string, line, string_len) == 0)
                    282:            {
                    283:              history_offset = i;
                    284:              return (0);
                    285:            }
                    286: 
                    287:          goto next_line;
                    288:        }
                    289: 
                    290:       /* Do substring search. */
                    291:       if (reverse)
                    292:        {
                    293:          index -= string_len;
                    294: 
                    295:          while (index >= 0)
                    296:            {
                    297:              if (strncmp (string, line + index, string_len) == 0)
                    298:                {
                    299:                  history_offset = i;
                    300:                  return (index);
                    301:                }
                    302:              index--;
                    303:            }
                    304:        }
                    305:       else
                    306:        {
                    307:          register int limit = index - string_len + 1;
                    308:          index = 0;
                    309: 
                    310:          while (index < limit)
                    311:            {
                    312:              if (strncmp (string, line + index, string_len) == 0)
                    313:                {
                    314:                  history_offset = i;
                    315:                  return (index);
                    316:                }
                    317:              index++;
                    318:            }
                    319:        }
                    320:     next_line:
                    321:       if (reverse)
                    322:        i--;
                    323:       else
                    324:        i++;
                    325:     }
                    326: }
                    327: 
                    328: /* Do a non-anchored search for STRING through the history in DIRECTION. */
                    329: int
                    330: history_search (string, direction)
                    331:      char *string;
                    332:      int direction;
                    333: {
                    334:   return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
                    335: }
                    336: 
                    337: /* Do an anchored search for string through the history in DIRECTION. */
                    338: int
                    339: history_search_prefix (string, direction)
                    340:      char *string;
                    341:      int direction;
                    342: {
                    343:   return (history_search_internal (string, direction, ANCHORED_SEARCH));
                    344: }
                    345: 
                    346: /* Remove history element WHICH from the history.  The removed
                    347:    element is returned to you so you can free the line, data,
                    348:    and containing structure. */
                    349: HIST_ENTRY *
                    350: remove_history (which)
                    351:      int which;
                    352: {
                    353:   HIST_ENTRY *return_value;
                    354: 
                    355:   if (which >= history_length || !history_length)
                    356:     return_value = (HIST_ENTRY *)NULL;
                    357:   else
                    358:     {
                    359:       register int i;
                    360:       return_value = the_history[which];
                    361: 
                    362:       for (i = which; i < history_length; i++)
                    363:        the_history[i] = the_history[i + 1];
                    364: 
                    365:       history_length--;
                    366:     }
                    367: 
                    368:   return (return_value);
                    369: }
                    370: 
                    371: /* Stifle the history list, remembering only MAX number of lines. */
                    372: void
                    373: stifle_history (max)
                    374:      int max;
                    375: {
                    376:   if (max < 0)
                    377:     max = 0;
                    378:   if (history_length > max)
                    379:     {
                    380:       register int i, j;
                    381: 
                    382:       /* This loses because we cannot free the data. */
                    383:       for (i = 0; i < (history_length - max); i++)
                    384:        {
                    385:          free (the_history[i]->line);
                    386:          free (the_history[i]);
                    387:        }
                    388:       history_base = i;
                    389:       for (j = 0, i = history_length - max; j < max; i++, j++)
                    390:        the_history[j] = the_history[i];
                    391:       the_history[j] = (HIST_ENTRY *)NULL;
                    392:       history_length = j;
                    393:     }
                    394:   history_stifled = 1;
                    395:   max_input_history = max;
                    396: }
                    397: 
                    398: /* Stop stifling the history.  This returns the previous amount the history
                    399:  was stifled by.  The value is positive if the history was stifled, negative
                    400:  if it wasn't. */
                    401: int
                    402: unstifle_history ()
                    403: {
                    404:   int result = max_input_history;
                    405:   if (history_stifled)
                    406:     {
                    407:       result = - result;
                    408:       history_stifled = 0;
                    409:     }
                    410:   return (result);
                    411: }
                    412: 
                    413: /* Return the string that should be used in the place of this
                    414:    filename.  This only matters when you don't specify the
                    415:    filename to read_history (), or write_history (). */
                    416: static char *
                    417: history_filename (filename)
                    418:      char *filename;
                    419: {
                    420:   char *return_val = filename ? savestring (filename) : (char *)NULL;
                    421: 
                    422:   if (!return_val)
                    423:     {
                    424:       char *home = (char *)getenv ("HOME");
                    425:       if (!home) home = ".";
                    426:       return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
                    427:       sprintf (return_val, "%s/.history", home);
                    428:     }
                    429:   return (return_val);
                    430: }
                    431: 
                    432: /* Add the contents of FILENAME to the history list, a line at a time.
                    433:    If FILENAME is NULL, then read from ~/.history.  Returns 0 if
                    434:    successful, or errno if not. */
                    435: int
                    436: read_history (filename)
                    437:      char *filename;
                    438: {
                    439:   return (read_history_range (filename, 0, -1));
                    440: }
                    441: 
                    442: /* Read a range of lines from FILENAME, adding them to the history list.
                    443:    Start reading at the FROM'th line and end at the TO'th.  If FROM
                    444:    is zero, start at the beginning.  If TO is less than FROM, read
                    445:    until the end of the file.  If FILENAME is NULL, then read from
                    446:    ~/.history.  Returns 0 if successful, or errno if not. */
                    447: int
                    448: read_history_range (filename, from, to)
                    449:      char *filename;
                    450:      int from, to;
                    451: {
                    452:   register int line_start, line_end;
                    453:   char *input, *buffer = (char *)NULL;
                    454:   int file, current_line;
                    455:   struct stat finfo;
                    456:   extern int errno;
                    457: 
                    458:   input = history_filename (filename);
                    459:   file = open (input, O_RDONLY, 0666);
                    460: 
                    461:   if ((file < 0) ||
                    462:       (stat (input, &finfo) == -1))
                    463:     goto error_and_exit;
                    464: 
                    465:   buffer = (char *)xmalloc (finfo.st_size + 1);
                    466: 
                    467:   if (read (file, buffer, finfo.st_size) != finfo.st_size)
                    468:   error_and_exit:
                    469:     {
                    470:       if (file >= 0)
                    471:        close (file);
                    472: 
                    473:       if (buffer)
                    474:        free (buffer);
                    475: 
                    476:       return (errno);
                    477:     }
                    478: 
                    479:   close (file);
                    480: 
                    481:   /* Set TO to larger than end of file if negative. */
                    482:   if (to < 0)
                    483:     to = finfo.st_size;
                    484: 
                    485:   /* Start at beginning of file, work to end. */
                    486:   line_start = line_end = current_line = 0;
                    487: 
                    488:   /* Skip lines until we are at FROM. */
                    489:   while (line_start < finfo.st_size && current_line < from)
                    490:     {
                    491:       for (line_end = line_start; line_end < finfo.st_size; line_end++)
                    492:        if (buffer[line_end] == '\n')
                    493:          {
                    494:            current_line++;
                    495:            line_start = line_end + 1;
                    496:            if (current_line == from)
                    497:              break;
                    498:          }
                    499:     }
                    500: 
                    501:   /* If there are lines left to gobble, then gobble them now. */
                    502:   for (line_end = line_start; line_end < finfo.st_size; line_end++)
                    503:     if (buffer[line_end] == '\n')
                    504:       {
                    505:        buffer[line_end] = '\0';
                    506: 
                    507:        if (buffer[line_start])
                    508:          add_history (buffer + line_start);
                    509: 
                    510:        current_line++;
                    511: 
                    512:        if (current_line >= to)
                    513:          break;
                    514: 
                    515:        line_start = line_end + 1;
                    516:       }
                    517:   return (0);
                    518: }
                    519: 
                    520: /* Truncate the history file FNAME, leaving only LINES trailing lines.
                    521:    If FNAME is NULL, then use ~/.history. */
                    522: history_truncate_file (fname, lines)
                    523:      char *fname;
                    524:      register int lines;
                    525: {
                    526:   register int i;
                    527:   int file;
                    528:   char *buffer = (char *)NULL, *filename;
                    529:   struct stat finfo;
                    530: 
                    531:   filename = history_filename (fname);
                    532:   if (stat (filename, &finfo) == -1)
                    533:     goto truncate_exit;
                    534: 
                    535:   file = open (filename, O_RDONLY, 0666);
                    536: 
                    537:   if (file == -1)
                    538:     goto truncate_exit;
                    539: 
                    540:   buffer = (char *)xmalloc (finfo.st_size + 1);
                    541:   read (file, buffer, finfo.st_size);
                    542:   close (file);
                    543: 
                    544:   /* Count backwards from the end of buffer until we have passed
                    545:      LINES lines. */
                    546:   for (i = finfo.st_size; lines && i; i--)
                    547:     {
                    548:       if (buffer[i] == '\n')
                    549:        lines--;
                    550:     }
                    551: 
                    552:   /* If there are fewer lines in the file than we want to truncate to,
                    553:      then we are all done. */
                    554:   if (!i)
                    555:     goto truncate_exit;
                    556: 
                    557:   /* Otherwise, write from the start of this line until the end of the
                    558:      buffer. */
                    559:   for (--i; i; i--)
                    560:     if (buffer[i] == '\n')
                    561:       {
                    562:        i++;
                    563:        break;
                    564:       }
                    565: 
                    566:   file = open (filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
                    567:   if (file == -1)
                    568:     goto truncate_exit;
                    569: 
                    570:   write (file, buffer + i, finfo.st_size - i);
                    571:   close (file);
                    572: 
                    573:  truncate_exit:
                    574:   if (buffer)
                    575:     free (buffer);
                    576: 
                    577:   free (filename);
                    578: }
                    579: 
                    580: #define HISTORY_APPEND 0
                    581: #define HISTORY_OVERWRITE 1
                    582: 
                    583: /* Workhorse function for writing history.  Writes NELEMENT entries
                    584:    from the history list to FILENAME.  OVERWRITE is non-zero if you
                    585:    wish to replace FILENAME with the entries. */
                    586: static int
                    587: history_do_write (filename, nelements, overwrite)
                    588:      char *filename;
                    589:      int nelements, overwrite;
                    590: {
                    591:   extern int errno;
                    592:   register int i, j;
                    593:   char *output = history_filename (filename);
                    594:   int file, mode;
                    595: 
                    596:   if (overwrite)
                    597:     mode = O_WRONLY | O_CREAT | O_TRUNC;
                    598:   else
                    599:     mode = O_WRONLY | O_APPEND;
                    600: 
                    601:   if ((file = open (output, mode, 0666)) == -1)
                    602:     return (errno);
                    603: 
                    604:   if (nelements > history_length)
                    605:     nelements = history_length;
                    606: 
                    607:   /* Build a buffer of all the lines to write, and write them in one syscall.
                    608:      Suggested by Peter Ho ([email protected]). */
                    609:   {
                    610:     register int j = 0;
                    611:     int buffer_size = 0;
                    612:     char *buffer;
                    613: 
                    614:     /* Calculate the total number of bytes to write. */
                    615:     for (i = history_length - nelements; i < history_length; i++)
                    616:       buffer_size += 1 + strlen (the_history[i]->line);
                    617: 
                    618:     /* Allocate the buffer, and fill it. */
                    619:     buffer = (char *)xmalloc (buffer_size);
                    620: 
                    621:     for (i = history_length - nelements; i < history_length; i++)
                    622:       {
                    623:        strcpy (buffer + j, the_history[i]->line);
                    624:        j += strlen (the_history[i]->line);
                    625:        buffer[j++] = '\n';
                    626:       }
                    627: 
                    628:     write (file, buffer, buffer_size);
                    629:     free (buffer);
                    630:   }
                    631: 
                    632:   close (file);
                    633:   return (0);
                    634: }
                    635:   
                    636: /* Append NELEMENT entries to FILENAME.  The entries appended are from
                    637:    the end of the list minus NELEMENTs up to the end of the list. */
                    638: int
                    639: append_history (nelements, filename)
                    640:      int nelements;
                    641:      char *filename;
                    642: {
                    643:   return (history_do_write (filename, nelements, HISTORY_APPEND));
                    644: }
                    645: 
                    646: /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
                    647:    then write the history list to ~/.history.  Values returned
                    648:    are as in read_history ().*/
                    649: int
                    650: write_history (filename)
                    651:      char *filename;
                    652: {
                    653:   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
                    654: }
                    655: 
                    656: /* Return the history entry at the current position, as determined by
                    657:    history_offset.  If there is no entry there, return a NULL pointer. */
                    658: HIST_ENTRY *
                    659: current_history ()
                    660: {
                    661:   if ((history_offset == history_length) || !the_history)
                    662:     return ((HIST_ENTRY *)NULL);
                    663:   else
                    664:     return (the_history[history_offset]);
                    665: }
                    666: 
                    667: /* Back up history_offset to the previous history entry, and return
                    668:    a pointer to that entry.  If there is no previous entry then return
                    669:    a NULL pointer. */
                    670: HIST_ENTRY *
                    671: previous_history ()
                    672: {
                    673:   if (!history_offset)
                    674:     return ((HIST_ENTRY *)NULL);
                    675:   else
                    676:     return (the_history[--history_offset]);
                    677: }
                    678: 
                    679: /* Move history_offset forward to the next history entry, and return
                    680:    a pointer to that entry.  If there is no next entry then return a
                    681:    NULL pointer. */
                    682: HIST_ENTRY *
                    683: next_history ()
                    684: {
                    685:   if (history_offset == history_length)
                    686:     return ((HIST_ENTRY *)NULL);
                    687:   else
                    688:     return (the_history[++history_offset]);
                    689: }
                    690: 
                    691: /* Return the current history array.  The caller has to be carefull, since this
                    692:    is the actual array of data, and could be bashed or made corrupt easily.
                    693:    The array is terminated with a NULL pointer. */
                    694: HIST_ENTRY **
                    695: history_list ()
                    696: {
                    697:   return (the_history);
                    698: }
                    699: 
                    700: /* Return the history entry which is logically at OFFSET in the history array.
                    701:    OFFSET is relative to history_base. */
                    702: HIST_ENTRY *
                    703: history_get (offset)
                    704:      int offset;
                    705: {
                    706:   int index = offset - history_base;
                    707: 
                    708:   if (index >= history_length ||
                    709:       index < 0 ||
                    710:       !the_history)
                    711:     return ((HIST_ENTRY *)NULL);
                    712:   return (the_history[index]);
                    713: }
                    714: 
                    715: /* Search for STRING in the history list.  DIR is < 0 for searching
                    716:    backwards.  POS is an absolute index into the history list at
                    717:    which point to begin searching. */
                    718: int
                    719: history_search_pos (string, dir, pos)
                    720:      char *string;
                    721:      int dir, pos;
                    722: {
                    723:   int ret, old = where_history ();
                    724:   history_set_pos (pos);
                    725:   if (history_search (string, dir) == -1)
                    726:     {
                    727:       history_set_pos (old);
                    728:       return (-1);
                    729:     }
                    730:   ret = where_history ();
                    731:   history_set_pos (old);
                    732:   return ret;
                    733: }
                    734: 
                    735: /* Make the current history item be the one at POS, an absolute index.
                    736:    Returns zero if POS is out of range, else non-zero. */
                    737: int
                    738: history_set_pos (pos)
                    739:      int pos;
                    740: {
                    741:   if (pos > history_length || pos < 0 || !the_history)
                    742:     return (0);
                    743:   history_offset = pos;
                    744:   return (1);
                    745: }
                    746:  
                    747: 
                    748: /* **************************************************************** */
                    749: /*                                                                 */
                    750: /*                     History Expansion                           */
                    751: /*                                                                 */
                    752: /* **************************************************************** */
                    753: 
                    754: /* Hairy history expansion on text, not tokens.  This is of general
                    755:    use, and thus belongs in this library. */
                    756: 
                    757: /* The last string searched for in a !?string? search. */
                    758: static char *search_string = (char *)NULL;
                    759: 
                    760: /* Return the event specified at TEXT + OFFSET modifying OFFSET to
                    761:    point to after the event specifier.  Just a pointer to the history
                    762:    line is returned; NULL is returned in the event of a bad specifier.
                    763:    You pass STRING with *INDEX equal to the history_expansion_char that
                    764:    begins this specification.
                    765:    DELIMITING_QUOTE is a character that is allowed to end the string
                    766:    specification for what to search for in addition to the normal
                    767:    characters `:', ` ', `\t', `\n', and sometimes `?'.
                    768:    So you might call this function like:
                    769:    line = get_history_event ("!echo:p", &index, 0);  */
                    770: char *
                    771: get_history_event (string, caller_index, delimiting_quote)
                    772:      char *string;
                    773:      int *caller_index;
                    774:      int delimiting_quote;
                    775: {
                    776:   register int i = *caller_index;
                    777:   int which, sign = 1;
                    778:   HIST_ENTRY *entry;
                    779: 
                    780:   /* The event can be specified in a number of ways.
                    781: 
                    782:      !!   the previous command
                    783:      !n   command line N
                    784:      !-n  current command-line minus N
                    785:      !str the most recent command starting with STR
                    786:      !?str[?]
                    787:          the most recent command containing STR
                    788: 
                    789:      All values N are determined via HISTORY_BASE. */
                    790: 
                    791:   if (string[i] != history_expansion_char)
                    792:     return ((char *)NULL);
                    793: 
                    794:   /* Move on to the specification. */
                    795:   i++;
                    796: 
                    797:   /* Handle !! case. */
                    798:   if (string[i] == history_expansion_char)
                    799:     {
                    800:       i++;
                    801:       which = history_base + (history_length - 1);
                    802:       *caller_index = i;
                    803:       goto get_which;
                    804:     }
                    805: 
                    806:   /* Hack case of numeric line specification. */
                    807:  read_which:
                    808:   if (string[i] == '-')
                    809:     {
                    810:       sign = -1;
                    811:       i++;
                    812:     }
                    813: 
                    814:   if (digit (string[i]))
                    815:     {
                    816:       int start = i;
                    817: 
                    818:       /* Get the extent of the digits. */
                    819:       for (; digit (string[i]); i++);
                    820: 
                    821:       /* Get the digit value. */
                    822:       sscanf (string + start, "%d", &which);
                    823: 
                    824:       *caller_index = i;
                    825: 
                    826:       if (sign < 0)
                    827:        which = (history_length + history_base) - which;
                    828: 
                    829:     get_which:
                    830:       if (entry = history_get (which))
                    831:        return (entry->line);
                    832: 
                    833:       return ((char *)NULL);
                    834:     }
                    835: 
                    836:   /* This must be something to search for.  If the spec begins with
                    837:      a '?', then the string may be anywhere on the line.  Otherwise,
                    838:      the string must be found at the start of a line. */
                    839:   {
                    840:     int index;
                    841:     char *temp;
                    842:     int substring_okay = 0;
                    843: 
                    844:     if (string[i] == '?')
                    845:       {
                    846:        substring_okay++;
                    847:        i++;
                    848:       }
                    849: 
                    850:     for (index = i; string[i]; i++)
                    851:       if (whitespace (string[i]) ||
                    852:          string[i] == '\n' ||
                    853:          string[i] == ':' ||
                    854:          (substring_okay && string[i] == '?') ||
                    855:          string[i] == delimiting_quote)
                    856:        break;
                    857: 
                    858:     temp = (char *)alloca (1 + (i - index));
                    859:     strncpy (temp, &string[index], (i - index));
                    860:     temp[i - index] = '\0';
                    861: 
                    862:     if (string[i] == '?')
                    863:       i++;
                    864: 
                    865:     *caller_index = i;
                    866: 
                    867:   search_again:
                    868: 
                    869:     index = history_search_internal
                    870:       (temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH);
                    871: 
                    872:     if (index < 0)
                    873:     search_lost:
                    874:       {
                    875:        history_offset = history_length;
                    876:        return ((char *)NULL);
                    877:       }
                    878: 
                    879:     if (index == 0)
                    880:       {
                    881:       search_won:
                    882:        entry = current_history ();
                    883:        history_offset = history_length;
                    884:        
                    885:        /* If this was a substring search, then remember the string that
                    886:           we matched for word substitution. */
                    887:        if (substring_okay)
                    888:          {
                    889:            if (search_string)
                    890:              free (search_string);
                    891:            search_string = savestring (temp);
                    892:          }
                    893: 
                    894:        return (entry->line);
                    895:       }
                    896: 
                    897:     if (history_offset)
                    898:       history_offset--;
                    899:     else
                    900:       goto search_lost;
                    901:     
                    902:     goto search_again;
                    903:   }
                    904: }
                    905: 
                    906: /* Expand the string STRING, placing the result into OUTPUT, a pointer
                    907:    to a string.  Returns:
                    908: 
                    909:    0) If no expansions took place (or, if the only change in
                    910:       the text was the de-slashifying of the history expansion
                    911:       character)
                    912:    1) If expansions did take place
                    913:   -1) If there was an error in expansion.
                    914: 
                    915:   If an error ocurred in expansion, then OUTPUT contains a descriptive
                    916:   error message. */
                    917: int
                    918: history_expand (string, output)
                    919:      char *string;
                    920:      char **output;
                    921: {
                    922:   register int j, l = strlen (string);
                    923:   int i, word_spec_error = 0;
                    924:   int cc, modified = 0;
                    925:   char *word_spec, *event;
                    926:   int starting_index, only_printing = 0, substitute_globally = 0;
                    927: 
                    928:   char *get_history_word_specifier (), *rindex ();
                    929: 
                    930:   /* The output string, and its length. */
                    931:   int len = 0;
                    932:   char *result = (char *)NULL;
                    933: 
                    934:   /* Used in add_string; */
                    935:   char *temp, tt[2], tbl[3];
                    936: 
                    937:   /* Prepare the buffer for printing error messages. */
                    938:   result = (char *)xmalloc (len = 255);
                    939: 
                    940:   result[0] = tt[1] = tbl[2] = '\0';
                    941:   tbl[0] = '\\';
                    942:   tbl[1] = history_expansion_char;
                    943: 
                    944:   /* Grovel the string.  Only backslash can quote the history escape
                    945:      character.  We also handle arg specifiers. */
                    946: 
                    947:   /* Before we grovel forever, see if the history_expansion_char appears
                    948:      anywhere within the text. */
                    949: 
                    950:   /* The quick substitution character is a history expansion all right.  That
                    951:      is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
                    952:      that is the substitution that we do. */
                    953:   if (string[0] == history_subst_char)
                    954:     {
                    955:       char *format_string = (char *)alloca (10 + strlen (string));
                    956: 
                    957:       sprintf (format_string, "%c%c:s%s",
                    958:               history_expansion_char, history_expansion_char,
                    959:               string);
                    960:       string = format_string;
                    961:       l += 4;
                    962:       goto grovel;
                    963:     }
                    964: 
                    965:   /* If not quick substitution, still maybe have to do expansion. */
                    966: 
                    967:   /* `!' followed by one of the characters in history_no_expand_chars
                    968:      is NOT an expansion. */
                    969:   for (i = 0; string[i]; i++)
                    970:     if (string[i] == history_expansion_char)
                    971:       if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
                    972:        continue;
                    973:       else
                    974:        goto grovel;
                    975: 
                    976:   free (result);
                    977:   *output = savestring (string);
                    978:   return (0);
                    979: 
                    980:  grovel:
                    981: 
                    982:   for (i = j = 0; i < l; i++)
                    983:     {
                    984:       int tchar = string[i];
                    985:       if (tchar == history_expansion_char)
                    986:        tchar = -3;
                    987: 
                    988:       switch (tchar)
                    989:        {
                    990:        case '\\':
                    991:          if (string[i + 1] == history_expansion_char)
                    992:            {
                    993:              i++;
                    994:              temp = tbl;
                    995:              goto do_add;
                    996:            }
                    997:          else
                    998:            goto add_char;
                    999: 
                   1000:          /* case history_expansion_char: */
                   1001:        case -3:
                   1002:          starting_index = i + 1;
                   1003:          cc = string[i + 1];
                   1004: 
                   1005:          /* If the history_expansion_char is followed by one of the
                   1006:             characters in history_no_expand_chars, then it is not a
                   1007:             candidate for expansion of any kind. */
                   1008:          if (member (cc, history_no_expand_chars))
                   1009:            goto add_char;
                   1010: 
                   1011:          /* There is something that is listed as a `word specifier' in csh
                   1012:             documentation which means `the expanded text to this point'.
                   1013:             That is not a word specifier, it is an event specifier. */
                   1014: 
                   1015:          if (cc == '#')
                   1016:            goto hack_pound_sign;
                   1017: 
                   1018:          /* If it is followed by something that starts a word specifier,
                   1019:             then !! is implied as the event specifier. */
                   1020: 
                   1021:          if (member (cc, ":$*%^"))
                   1022:            {
                   1023:              char fake_s[3];
                   1024:              int fake_i = 0;
                   1025:              i++;
                   1026:              fake_s[0] = fake_s[1] = history_expansion_char;
                   1027:              fake_s[2] = '\0';
                   1028:              event = get_history_event (fake_s, &fake_i, 0);
                   1029:            }
                   1030:          else
                   1031:            {
                   1032:              int quoted_search_delimiter = 0;
                   1033: 
                   1034:              /* If the character before this `!' is a double or single
                   1035:                 quote, then this expansion takes place inside of the
                   1036:                 quoted string.  If we have to search for some text ("!foo"),
                   1037:                 allow the delimiter to end the search string. */
                   1038:              if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
                   1039:                quoted_search_delimiter = string[i - 1];
                   1040: 
                   1041:              event = get_history_event (string, &i, quoted_search_delimiter);
                   1042:            }
                   1043:          
                   1044:          if (!event)
                   1045:          event_not_found:
                   1046:            {
                   1047:            int l = 1 + (i - starting_index);
                   1048: 
                   1049:            temp = (char *)alloca (1 + l);
                   1050:            strncpy (temp, string + starting_index, l);
                   1051:            temp[l - 1] = 0;
                   1052:            sprintf (result, "%s: %s.", temp,
                   1053:                     word_spec_error ? "Bad word specifier" : "Event not found");
                   1054:          error_exit:
                   1055:            *output = result;
                   1056:            return (-1);
                   1057:          }
                   1058: 
                   1059:          /* If a word specifier is found, then do what that requires. */
                   1060:          starting_index = i;
                   1061: 
                   1062:          word_spec = get_history_word_specifier (string, event, &i);
                   1063: 
                   1064:          /* There is no such thing as a `malformed word specifier'.  However,
                   1065:             it is possible for a specifier that has no match.  In that case,
                   1066:             we complain. */
                   1067:          if (word_spec == (char *)-1)
                   1068:          bad_word_spec:
                   1069:          {
                   1070:            word_spec_error++;
                   1071:            goto event_not_found;
                   1072:          }
                   1073: 
                   1074:          /* If no word specifier, than the thing of interest was the event. */
                   1075:          if (!word_spec)
                   1076:            temp = event;
                   1077:          else
                   1078:            {
                   1079:              temp = (char *)alloca (1 + strlen (word_spec));
                   1080:              strcpy (temp, word_spec);
                   1081:              free (word_spec);
                   1082:            }
                   1083: 
                   1084:          /* Perhaps there are other modifiers involved.  Do what they say. */
                   1085: 
                   1086:        hack_specials:
                   1087: 
                   1088:          if (string[i] == ':')
                   1089:            {
                   1090:              char *tstr;
                   1091: 
                   1092:              switch (string[i + 1])
                   1093:                {
                   1094:                  /* :p means make this the last executed line.  So we
                   1095:                     return an error state after adding this line to the
                   1096:                     history. */
                   1097:                case 'p':
                   1098:                  only_printing++;
                   1099:                  goto next_special;
                   1100: 
                   1101:                  /* :t discards all but the last part of the pathname. */
                   1102:                case 't':
                   1103:                  tstr = rindex (temp, '/');
                   1104:                  if (tstr)
                   1105:                    temp = ++tstr;
                   1106:                  goto next_special;
                   1107: 
                   1108:                  /* :h discards the last part of a pathname. */
                   1109:                case 'h':
                   1110:                  tstr = rindex (temp, '/');
                   1111:                  if (tstr)
                   1112:                    *tstr = '\0';
                   1113:                  goto next_special;
                   1114: 
                   1115:                  /* :r discards the suffix. */
                   1116:                case 'r':
                   1117:                  tstr = rindex (temp, '.');
                   1118:                  if (tstr)
                   1119:                    *tstr = '\0';
                   1120:                  goto next_special;
                   1121: 
                   1122:                  /* :e discards everything but the suffix. */
                   1123:                case 'e':
                   1124:                  tstr = rindex (temp, '.');
                   1125:                  if (tstr)
                   1126:                    temp = tstr;
                   1127:                  goto next_special;
                   1128: 
                   1129:                  /* :s/this/that substitutes `this' for `that'. */
                   1130:                  /* :gs/this/that substitutes `this' for `that' globally. */
                   1131:                case 'g':
                   1132:                  if (string[i + 2] == 's')
                   1133:                    {
                   1134:                      i++;
                   1135:                      substitute_globally = 1;
                   1136:                      goto substitute;
                   1137:                    }
                   1138:                  else
                   1139:                    
                   1140:                case 's':
                   1141:                  substitute:
                   1142:                  {
                   1143:                    char *this, *that, *new_event;
                   1144:                    int delimiter = 0;
                   1145:                    int si, l_this, l_that, l_temp = strlen (temp);
                   1146: 
                   1147:                    if (i + 2 < strlen (string))
                   1148:                      delimiter = string[i + 2];
                   1149: 
                   1150:                    if (!delimiter)
                   1151:                      break;
                   1152: 
                   1153:                    i += 3;
                   1154: 
                   1155:                    /* Get THIS. */
                   1156:                    for (si = i; string[si] && string[si] != delimiter; si++);
                   1157:                    l_this = (si - i);
                   1158:                    this = (char *)alloca (1 + l_this);
                   1159:                    strncpy (this, string + i, l_this);
                   1160:                    this[l_this] = '\0';
                   1161: 
                   1162:                    i = si;
                   1163:                    if (string[si])
                   1164:                      i++;
                   1165: 
                   1166:                    /* Get THAT. */
                   1167:                    for (si = i; string[si] && string[si] != delimiter; si++);
                   1168:                    l_that = (si - i);
                   1169:                    that = (char *)alloca (1 + l_that);
                   1170:                    strncpy (that, string + i, l_that);
                   1171:                    that[l_that] = '\0';
                   1172: 
                   1173:                    i = si;
                   1174:                    if (string[si]) i++;
                   1175: 
                   1176:                    /* Ignore impossible cases. */
                   1177:                    if (l_this > l_temp)
                   1178:                      goto cant_substitute;
                   1179: 
                   1180:                    /* Find the first occurrence of THIS in TEMP. */
                   1181:                    si = 0;
                   1182:                    for (; (si + l_this) <= l_temp; si++)
                   1183:                      if (strncmp (temp + si, this, l_this) == 0)
                   1184:                        {
                   1185:                          new_event =
                   1186:                            (char *)alloca (1 + (l_that - l_this) + l_temp);
                   1187:                          strncpy (new_event, temp, si);
                   1188:                          strncpy (new_event + si, that, l_that);
                   1189:                          strncpy (new_event + si + l_that,
                   1190:                                   temp + si + l_this,
                   1191:                                   l_temp - (si + l_this));
                   1192:                          new_event[(l_that - l_this) + l_temp] = '\0';
                   1193:                          temp = new_event;
                   1194: 
                   1195:                          if (substitute_globally)
                   1196:                            {
                   1197:                              si += l_that;
                   1198:                              l_temp = strlen (temp);
                   1199:                              substitute_globally++;
                   1200:                              continue;
                   1201:                            }
                   1202: 
                   1203:                          goto hack_specials;
                   1204:                        }
                   1205: 
                   1206:                  cant_substitute:
                   1207: 
                   1208:                    if (substitute_globally > 1)
                   1209:                      {
                   1210:                        substitute_globally = 0;
                   1211:                        goto hack_specials;
                   1212:                      }
                   1213: 
                   1214:                    goto event_not_found;
                   1215:                  }
                   1216: 
                   1217:                  /* :# is the line so far.  Note that we have to
                   1218:                     alloca () it since RESULT could be realloc ()'ed
                   1219:                     below in add_string. */
                   1220:                case '#':
                   1221:                hack_pound_sign:
                   1222:                  if (result)
                   1223:                    {
                   1224:                      temp = (char *)alloca (1 + strlen (result));
                   1225:                      strcpy (temp, result);
                   1226:                    }
                   1227:                  else
                   1228:                    temp = "";
                   1229: 
                   1230:                next_special:
                   1231:                  i += 2;
                   1232:                  goto hack_specials;
                   1233:                }
                   1234: 
                   1235:            }
                   1236:          /* Believe it or not, we have to back the pointer up by one. */
                   1237:          --i;
                   1238:          goto add_string;
                   1239: 
                   1240:          /* A regular character.  Just add it to the output string. */
                   1241:        default:
                   1242:        add_char:
                   1243:          tt[0] = string[i];
                   1244:          temp = tt;
                   1245:          goto do_add;
                   1246: 
                   1247:        add_string:
                   1248:          modified++;
                   1249: 
                   1250:        do_add:
                   1251:          j += strlen (temp);
                   1252:          while (j > len)
                   1253:            result = (char *)xrealloc (result, (len += 255));
                   1254: 
                   1255:          strcpy (result + (j - strlen (temp)), temp);
                   1256:        }
                   1257:     }
                   1258: 
                   1259:   *output = result;
                   1260: 
                   1261:   if (only_printing)
                   1262:     {
                   1263:       add_history (result);
                   1264:       return (-1);
                   1265:     }
                   1266: 
                   1267:   return (modified != 0);
                   1268: }
                   1269: 
                   1270: /* Return a consed string which is the word specified in SPEC, and found
                   1271:    in FROM.  NULL is returned if there is no spec.  -1 is returned if
                   1272:    the word specified cannot be found.  CALLER_INDEX is the offset in
                   1273:    SPEC to start looking; it is updated to point to just after the last
                   1274:    character parsed. */
                   1275: char *
                   1276: get_history_word_specifier (spec, from, caller_index)
                   1277:      char *spec, *from;
                   1278:      int *caller_index;
                   1279: {
                   1280:   register int i = *caller_index;
                   1281:   int first, last;
                   1282:   int expecting_word_spec = 0;
                   1283:   char *history_arg_extract ();
                   1284: 
                   1285:   /* The range of words to return doesn't exist yet. */
                   1286:   first = last = 0;
                   1287: 
                   1288:   /* If we found a colon, then this *must* be a word specification.  If
                   1289:      it isn't, then it is an error. */
                   1290:   if (spec[i] == ':')
                   1291:     i++, expecting_word_spec++;
                   1292: 
                   1293:   /* Handle special cases first. */
                   1294: 
                   1295:   /* `%' is the word last searched for. */
                   1296:   if (spec[i] == '%')
                   1297:     {
                   1298:       *caller_index = i + 1;
                   1299:       if (search_string)
                   1300:        return (savestring (search_string));
                   1301:       else
                   1302:        return (savestring (""));
                   1303:     }
                   1304: 
                   1305:   /* `*' matches all of the arguments, but not the command. */
                   1306:   if (spec[i] == '*')
                   1307:     {
                   1308:       char *star_result;
                   1309: 
                   1310:       *caller_index = i + 1;
                   1311:       star_result = history_arg_extract (1, '$', from);
                   1312: 
                   1313:       if (!star_result)
                   1314:        star_result = savestring ("");
                   1315: 
                   1316:       return (star_result);
                   1317:     }
                   1318: 
                   1319:   /* `$' is last arg. */
                   1320:   if (spec[i] == '$')
                   1321:     {
                   1322:       *caller_index = i + 1;
                   1323:       return (history_arg_extract ('$', '$', from));
                   1324:     }
                   1325: 
                   1326:   /* Try to get FIRST and LAST figured out. */
                   1327:   if (spec[i] == '-' || spec[i] == '^')
                   1328:     {
                   1329:       first = 1;
                   1330:       goto get_last;
                   1331:     }
                   1332: 
                   1333:  get_first:
                   1334:   if (digit (spec[i]) && expecting_word_spec)
                   1335:     {
                   1336:       sscanf (spec + i, "%d", &first);
                   1337:       for (; digit (spec[i]); i++);
                   1338:     }
                   1339:   else
                   1340:     return ((char *)NULL);
                   1341: 
                   1342:  get_last:
                   1343:   if (spec[i] == '^')
                   1344:     {
                   1345:       i++;
                   1346:       last = 1;
                   1347:       goto get_args;
                   1348:     }
                   1349: 
                   1350:   if (spec[i] != '-')
                   1351:     {
                   1352:       last = first;
                   1353:       goto get_args;
                   1354:     }
                   1355: 
                   1356:   i++;
                   1357: 
                   1358:   if (digit (spec[i]))
                   1359:     {
                   1360:       sscanf (spec + i, "%d", &last);
                   1361:       for (; digit (spec[i]); i++);
                   1362:     }
                   1363:   else
                   1364:     if (spec[i] == '$')
                   1365:       {
                   1366:        i++;
                   1367:        last = '$';
                   1368:       }
                   1369: 
                   1370:  get_args:
                   1371:   {
                   1372:     char *result = (char *)NULL;
                   1373: 
                   1374:     *caller_index = i;
                   1375: 
                   1376:     if (last >= first)
                   1377:       result = history_arg_extract (first, last, from);
                   1378: 
                   1379:     if (result)
                   1380:       return (result);
                   1381:     else
                   1382:       return ((char *)-1);
                   1383:   }
                   1384: }
                   1385: 
                   1386: /* Extract the args specified, starting at FIRST, and ending at LAST.
                   1387:    The args are taken from STRING.  If either FIRST or LAST is < 0,
                   1388:    then make that arg count from the right (subtract from the number of
                   1389:    tokens, so that FIRST = -1 means the next to last token on the line). */
                   1390: char *
                   1391: history_arg_extract (first, last, string)
                   1392:      int first, last;
                   1393:      char *string;
                   1394: {
                   1395:   register int i, len;
                   1396:   char *result = (char *)NULL;
                   1397:   int size = 0, offset = 0;
                   1398: 
                   1399:   char **history_tokenize (), **list;
                   1400: 
                   1401:   if (!(list = history_tokenize (string)))
                   1402:     return ((char *)NULL);
                   1403: 
                   1404:   for (len = 0; list[len]; len++);
                   1405: 
                   1406:   if (last < 0)
                   1407:     last = len + last - 1;
                   1408: 
                   1409:   if (first < 0)
                   1410:     first = len + first - 1;
                   1411: 
                   1412:   if (last == '$')
                   1413:     last = len - 1;
                   1414: 
                   1415:   if (first == '$')
                   1416:     first = len - 1;
                   1417: 
                   1418:   last++;
                   1419: 
                   1420:   if (first > len || last > len || first < 0 || last < 0)
                   1421:     result = ((char *)NULL);
                   1422:   else
                   1423:     {
                   1424:       for (i = first; i < last; i++)
                   1425:        {
                   1426:          int l = strlen (list[i]);
                   1427: 
                   1428:          if (!result)
                   1429:            result = (char *)xmalloc ((size = (2 + l)));
                   1430:          else
                   1431:            result = (char *)xrealloc (result, (size += (2 + l)));
                   1432:          strcpy (result + offset, list[i]);
                   1433:          offset += l;
                   1434:          if (i + 1 < last)
                   1435:            {
                   1436:              strcpy (result + offset, " ");
                   1437:              offset++;
                   1438:            }
                   1439:        }
                   1440:     }
                   1441: 
                   1442:   for (i = 0; i < len; i++)
                   1443:     free (list[i]);
                   1444: 
                   1445:   free (list);
                   1446: 
                   1447:   return (result);
                   1448: }
                   1449: 
                   1450: #define slashify_in_quotes "\\`\"$"
                   1451: 
                   1452: /* Return an array of tokens, much as the shell might.  The tokens are
                   1453:    parsed out of STRING. */
                   1454: char **
                   1455: history_tokenize (string)
                   1456:      char *string;
                   1457: {
                   1458:   char **result = (char **)NULL;
                   1459:   register int i, start, result_index, size;
                   1460:   int len;
                   1461: 
                   1462:   i = result_index = size = 0;
                   1463: 
                   1464:   /* Get a token, and stuff it into RESULT.  The tokens are split
                   1465:      exactly where the shell would split them. */
                   1466:  get_token:
                   1467: 
                   1468:   /* Skip leading whitespace. */
                   1469:   for (; string[i] && whitespace(string[i]); i++);
                   1470: 
                   1471:   start = i;
                   1472: 
                   1473:   if (!string[i] || string[i] == history_comment_char)
                   1474:     return (result);
                   1475: 
                   1476:   if (member (string[i], "()\n")) {
                   1477:     i++;
                   1478:     goto got_token;
                   1479:   }
                   1480: 
                   1481:   if (member (string[i], "<>;&|")) {
                   1482:     int peek = string[i + 1];
                   1483: 
                   1484:     if (peek == string[i]) {
                   1485:       if (peek ==  '<') {
                   1486:        if (string[1 + 2] == '-')
                   1487:          i++;
                   1488:        i += 2;
                   1489:        goto got_token;
                   1490:       }
                   1491: 
                   1492:       if (member (peek, ">:&|")) {
                   1493:        i += 2;
                   1494:        goto got_token;
                   1495:       }
                   1496:     } else {
                   1497:       if ((peek == '&' &&
                   1498:          (string[i] == '>' || string[i] == '<')) ||
                   1499:          ((peek == '>') &&
                   1500:          (string[i] == '&'))) {
                   1501:        i += 2;
                   1502:        goto got_token;
                   1503:       }
                   1504:     }
                   1505:     i++;
                   1506:     goto got_token;
                   1507:   }
                   1508: 
                   1509:   /* Get word from string + i; */
                   1510:   {
                   1511:     int delimiter = 0;
                   1512: 
                   1513:     if (member (string[i], "\"'`"))
                   1514:       delimiter = string[i++];
                   1515: 
                   1516:     for (;string[i]; i++) {
                   1517: 
                   1518:       if (string[i] == '\\') {
                   1519: 
                   1520:        if (string[i + 1] == '\n') {
                   1521:          i++;
                   1522:          continue;
                   1523:        } else {
                   1524:          if (delimiter != '\'')
                   1525:            if ((delimiter != '"') ||
                   1526:                (member (string[i], slashify_in_quotes))) {
                   1527:              i++;
                   1528:              continue;
                   1529:            }
                   1530:        }
                   1531:       }
                   1532: 
                   1533:       if (delimiter && string[i] == delimiter) {
                   1534:        delimiter = 0;
                   1535:        continue;
                   1536:       }
                   1537: 
                   1538:       if (!delimiter && (member (string[i], " \t\n;&()|<>")))
                   1539:        goto got_token;
                   1540: 
                   1541:       if (!delimiter && member (string[i], "\"'`")) {
                   1542:        delimiter = string[i];
                   1543:        continue;
                   1544:       }
                   1545:     }
                   1546:     got_token:
                   1547: 
                   1548:     len = i - start;
                   1549:     if (result_index + 2 >= size) {
                   1550:       if (!size)
                   1551:        result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
                   1552:       else
                   1553:        result =
                   1554:          (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
                   1555:     }
                   1556:     result[result_index] = (char *)xmalloc (1 + len);
                   1557:     strncpy (result[result_index], string + start, len);
                   1558:     result[result_index][len] = '\0';
                   1559:     result_index++;
                   1560:     result[result_index] = (char *)NULL;
                   1561:   }
                   1562:   if (string[i])
                   1563:     goto get_token;
                   1564: 
                   1565:   return (result);
                   1566: }
                   1567: 
                   1568: #if defined (STATIC_MALLOC)
                   1569: 
                   1570: /* **************************************************************** */
                   1571: /*                                                                 */
                   1572: /*                     xmalloc and xrealloc ()                     */
                   1573: /*                                                                 */
                   1574: /* **************************************************************** */
                   1575: 
                   1576: static void memory_error_and_abort ();
                   1577: 
                   1578: static char *
                   1579: xmalloc (bytes)
                   1580:      int bytes;
                   1581: {
                   1582:   char *temp = (char *)malloc (bytes);
                   1583: 
                   1584:   if (!temp)
                   1585:     memory_error_and_abort ();
                   1586:   return (temp);
                   1587: }
                   1588: 
                   1589: static char *
                   1590: xrealloc (pointer, bytes)
                   1591:      char *pointer;
                   1592:      int bytes;
                   1593: {
                   1594:   char *temp;
                   1595: 
                   1596:   if (!pointer)
                   1597:     temp = (char *)xmalloc (bytes);
                   1598:   else
                   1599:     temp = (char *)realloc (pointer, bytes);
                   1600: 
                   1601:   if (!temp)
                   1602:     memory_error_and_abort ();
                   1603: 
                   1604:   return (temp);
                   1605: }
                   1606: 
                   1607: static void
                   1608: memory_error_and_abort ()
                   1609: {
                   1610:   fprintf (stderr, "history: Out of virtual memory!\n");
                   1611:   abort ();
                   1612: }
                   1613: #endif /* STATIC_MALLOC */
                   1614: 
                   1615: 
                   1616: /* **************************************************************** */
                   1617: /*                                                                 */
                   1618: /*                             Test Code                           */
                   1619: /*                                                                 */
                   1620: /* **************************************************************** */
                   1621: #ifdef TEST
                   1622: main ()
                   1623: {
                   1624:   char line[1024], *t;
                   1625:   int done = 0;
                   1626: 
                   1627:   line[0] = 0;
                   1628: 
                   1629:   while (!done)
                   1630:     {
                   1631:       fprintf (stdout, "history%% ");
                   1632:       t = gets (line);
                   1633: 
                   1634:       if (!t)
                   1635:        strcpy (line, "quit");
                   1636: 
                   1637:       if (line[0])
                   1638:        {
                   1639:          char *expansion;
                   1640:          int result;
                   1641: 
                   1642:          using_history ();
                   1643: 
                   1644:          result = history_expand (line, &expansion);
                   1645:          strcpy (line, expansion);
                   1646:          free (expansion);
                   1647:          if (result)
                   1648:            fprintf (stderr, "%s\n", line);
                   1649: 
                   1650:          if (result < 0)
                   1651:            continue;
                   1652: 
                   1653:          add_history (line);
                   1654:        }
                   1655: 
                   1656:       if (strcmp (line, "quit") == 0) done = 1;
                   1657:       if (strcmp (line, "save") == 0) write_history (0);
                   1658:       if (strcmp (line, "read") == 0) read_history (0);
                   1659:       if (strcmp (line, "list") == 0)
                   1660:        {
                   1661:          register HIST_ENTRY **the_list = history_list ();
                   1662:          register int i;
                   1663: 
                   1664:          if (the_list)
                   1665:            for (i = 0; the_list[i]; i++)
                   1666:              fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
                   1667:        }
                   1668:       if (strncmp (line, "delete", strlen ("delete")) == 0)
                   1669:        {
                   1670:          int which;
                   1671:          if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
                   1672:            {
                   1673:              HIST_ENTRY *entry = remove_history (which);
                   1674:              if (!entry)
                   1675:                fprintf (stderr, "No such entry %d\n", which);
                   1676:              else
                   1677:                {
                   1678:                  free (entry->line);
                   1679:                  free (entry);
                   1680:                }
                   1681:            }
                   1682:          else
                   1683:            {
                   1684:              fprintf (stderr, "non-numeric arg given to `delete'\n");
                   1685:            }
                   1686:        }
                   1687:     }
                   1688: }
                   1689: 
                   1690: #endif                         /* TEST */
                   1691: 
                   1692: /*
                   1693: * Local variables:
                   1694: * compile-command: "gcc -g -DTEST -o history history.c"
                   1695: * end:
                   1696: */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.