PageRenderTime 1429ms CodeModel.GetById 262ms app.highlight 485ms RepoModel.GetById 575ms app.codeStats 1ms

/src/readline/history.c

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