⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 history.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
    goto truncate_exit;  write (file, buffer + i, finfo.st_size - i);  close (file); truncate_exit:  if (buffer)    free (buffer);  free (filename);}#define HISTORY_APPEND 0#define HISTORY_OVERWRITE 1/* Workhorse function for writing history.  Writes NELEMENT entries   from the history list to FILENAME.  OVERWRITE is non-zero if you   wish to replace FILENAME with the entries. */static inthistory_do_write (filename, nelements, overwrite)     char *filename;     int nelements, overwrite;{  extern int errno;  register int i, j;  char *output = history_filename (filename);  int file, mode;  if (overwrite)    mode = O_WRONLY | O_CREAT | O_TRUNC;  else    mode = O_WRONLY | O_APPEND;  if ((file = open (output, mode, 0666)) == -1)    return (errno);  if (nelements > history_length)    nelements = history_length;  /* Build a buffer of all the lines to write, and write them in one syscall.     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */  {    register int j = 0;    int buffer_size = 0;    char *buffer;    /* Calculate the total number of bytes to write. */    for (i = history_length - nelements; i < history_length; i++)      buffer_size += 1 + strlen (the_history[i]->line);    /* Allocate the buffer, and fill it. */    buffer = (char *)xmalloc (buffer_size);    for (i = history_length - nelements; i < history_length; i++)      {	strcpy (buffer + j, the_history[i]->line);	j += strlen (the_history[i]->line);	buffer[j++] = '\n';      }    write (file, buffer, buffer_size);    free (buffer);  }  close (file);  return (0);}  /* Append NELEMENT entries to FILENAME.  The entries appended are from   the end of the list minus NELEMENTs up to the end of the list. */intappend_history (nelements, filename)     int nelements;     char *filename;{  return (history_do_write (filename, nelements, HISTORY_APPEND));}/* Overwrite FILENAME with the current history.  If FILENAME is NULL,   then write the history list to ~/.history.  Values returned   are as in read_history ().*/intwrite_history (filename)     char *filename;{  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));}/* Return the history entry at the current position, as determined by   history_offset.  If there is no entry there, return a NULL pointer. */HIST_ENTRY *current_history (){  if ((history_offset == history_length) || !the_history)    return ((HIST_ENTRY *)NULL);  else    return (the_history[history_offset]);}/* Back up history_offset to the previous history entry, and return   a pointer to that entry.  If there is no previous entry then return   a NULL pointer. */HIST_ENTRY *previous_history (){  if (!history_offset)    return ((HIST_ENTRY *)NULL);  else    return (the_history[--history_offset]);}/* Move history_offset forward to the next history entry, and return   a pointer to that entry.  If there is no next entry then return a   NULL pointer. */HIST_ENTRY *next_history (){  if (history_offset == history_length)    return ((HIST_ENTRY *)NULL);  else    return (the_history[++history_offset]);}/* Return the current history array.  The caller has to be carefull, since this   is the actual array of data, and could be bashed or made corrupt easily.   The array is terminated with a NULL pointer. */HIST_ENTRY **history_list (){  return (the_history);}/* Return the history entry which is logically at OFFSET in the history array.   OFFSET is relative to history_base. */HIST_ENTRY *history_get (offset)     int offset;{  int index = offset - history_base;  if (index >= history_length ||      index < 0 ||      !the_history)    return ((HIST_ENTRY *)NULL);  return (the_history[index]);}/* Search for STRING in the history list.  DIR is < 0 for searching   backwards.  POS is an absolute index into the history list at   which point to begin searching. */inthistory_search_pos (string, dir, pos)     char *string;     int dir, pos;{  int ret, old = where_history ();  history_set_pos (pos);  if (history_search (string, dir) == -1)    {      history_set_pos (old);      return (-1);    }  ret = where_history ();  history_set_pos (old);  return ret;}/* Make the current history item be the one at POS, an absolute index.   Returns zero if POS is out of range, else non-zero. */inthistory_set_pos (pos)     int pos;{  if (pos > history_length || pos < 0 || !the_history)    return (0);  history_offset = pos;  return (1);} /* **************************************************************** *//*								    *//*			History Expansion			    *//*								    *//* **************************************************************** *//* Hairy history expansion on text, not tokens.  This is of general   use, and thus belongs in this library. *//* The last string searched for in a !?string? search. */static char *search_string = (char *)NULL;/* Return the event specified at TEXT + OFFSET modifying OFFSET to   point to after the event specifier.  Just a pointer to the history   line is returned; NULL is returned in the event of a bad specifier.   You pass STRING with *INDEX equal to the history_expansion_char that   begins this specification.   DELIMITING_QUOTE is a character that is allowed to end the string   specification for what to search for in addition to the normal   characters `:', ` ', `\t', `\n', and sometimes `?'.   So you might call this function like:   line = get_history_event ("!echo:p", &index, 0);  */char *get_history_event (string, caller_index, delimiting_quote)     char *string;     int *caller_index;     int delimiting_quote;{  register int i = *caller_index;  int which, sign = 1;  HIST_ENTRY *entry;  /* The event can be specified in a number of ways.     !!   the previous command     !n   command line N     !-n  current command-line minus N     !str the most recent command starting with STR     !?str[?]	  the most recent command containing STR     All values N are determined via HISTORY_BASE. */  if (string[i] != history_expansion_char)    return ((char *)NULL);  /* Move on to the specification. */  i++;  /* Handle !! case. */  if (string[i] == history_expansion_char)    {      i++;      which = history_base + (history_length - 1);      *caller_index = i;      goto get_which;    }  /* Hack case of numeric line specification. */ read_which:  if (string[i] == '-')    {      sign = -1;      i++;    }  if (digit (string[i]))    {      int start = i;      /* Get the extent of the digits. */      for (; digit (string[i]); i++);      /* Get the digit value. */      sscanf (string + start, "%d", &which);      *caller_index = i;      if (sign < 0)	which = (history_length + history_base) - which;    get_which:      if (entry = history_get (which))	return (entry->line);      return ((char *)NULL);    }  /* This must be something to search for.  If the spec begins with     a '?', then the string may be anywhere on the line.  Otherwise,     the string must be found at the start of a line. */  {    int index;    char *temp;    int substring_okay = 0;    if (string[i] == '?')      {	substring_okay++;	i++;      }    for (index = i; string[i]; i++)      if (whitespace (string[i]) ||	  string[i] == '\n' ||	  string[i] == ':' ||	  (substring_okay && string[i] == '?') ||	  string[i] == delimiting_quote)	break;    temp = (char *)alloca (1 + (i - index));    strncpy (temp, &string[index], (i - index));    temp[i - index] = '\0';    if (string[i] == '?')      i++;    *caller_index = i;  search_again:    index = history_search_internal      (temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH);    if (index < 0)    search_lost:      {	history_offset = history_length;	return ((char *)NULL);      }    if (index == 0)      {      search_won:	entry = current_history ();	history_offset = history_length;		/* If this was a substring search, then remember the string that	   we matched for word substitution. */	if (substring_okay)	  {	    if (search_string)	      free (search_string);	    search_string = savestring (temp);	  }	return (entry->line);      }    if (history_offset)      history_offset--;    else      goto search_lost;        goto search_again;  }}/* Expand the string STRING, placing the result into OUTPUT, a pointer   to a string.  Returns:   0) If no expansions took place (or, if the only change in      the text was the de-slashifying of the history expansion      character)   1) If expansions did take place  -1) If there was an error in expansion.  If an error ocurred in expansion, then OUTPUT contains a descriptive  error message. */inthistory_expand (string, output)     char *string;     char **output;{  register int j, l = strlen (string);  int i, word_spec_error = 0;  int cc, modified = 0;  char *word_spec, *event;  int starting_index, only_printing = 0, substitute_globally = 0;  char *get_history_word_specifier (), *rindex ();  /* The output string, and its length. */  int len = 0;  char *result = (char *)NULL;  /* Used in add_string; */  char *temp, tt[2], tbl[3];  /* Prepare the buffer for printing error messages. */  result = (char *)xmalloc (len = 255);  result[0] = tt[1] = tbl[2] = '\0';  tbl[0] = '\\';  tbl[1] = history_expansion_char;  /* Grovel the string.  Only backslash can quote the history escape     character.  We also handle arg specifiers. */  /* Before we grovel forever, see if the history_expansion_char appears     anywhere within the text. */  /* The quick substitution character is a history expansion all right.  That     is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,     that is the substitution that we do. */  if (string[0] == history_subst_char)    {      char *format_string = (char *)alloca (10 + strlen (string));      sprintf (format_string, "%c%c:s%s",	       history_expansion_char, history_expansion_char,	       string);      string = format_string;      l += 4;      goto grovel;    }  /* If not quick substitution, still maybe have to do expansion. */  /* `!' followed by one of the characters in history_no_expand_chars     is NOT an expansion. */  for (i = 0; string[i]; i++)    if (string[i] == history_expansion_char)      if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))	continue;      else	goto grovel;  free (result);  *output = savestring (string);  return (0); grovel:  for (i = j = 0; i < l; i++)    {      int tchar = string[i];      if (tchar == history_expansion_char)	tchar = -3;      switch (tchar)	{	case '\\':	  if (string[i + 1] == history_expansion_char)	    {	      i++;	      temp = tbl;	      goto do_add;	    }	  else	    goto add_char;	  /* case history_expansion_char: */	case -3:	  starting_index = i + 1;	  cc = string[i + 1];	  /* If the history_expansion_char is followed by one of the	     characters in history_no_expand_chars, then it is not a	     candidate for expansion of any kind. */	  if (member (cc, history_no_expand_chars))	    goto add_char;	  /* There is something that is listed as a `word specifier' in csh	     documentation which means `the expanded text to this point'.	     That is not a word specifier, it is an event specifier. */	  if (cc == '#')	    goto hack_pound_sign;	  /* If it is followed by something that starts a word specifier,	     then !! is implied as the event specifier. */	  if (member (cc, ":$*%^"))	    {	      char fake_s[3];	      int fake_i = 0;	      i++;	      fake_s[0] = fake_s[1] = history_expansion_char;	      fake_s[2] = '\0';	      event = get_history_event (fake_s, &fake_i, 0);	    }	  else	    {	      int quoted_search_delimiter = 0;	      /* If the character before this `!' is a double or single		 quote, then this expansion takes place inside of the		 quoted string.  If we have to search for some text ("!foo"),		 allow the delimiter to end the search string. */	      if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))		quoted_search_delimiter = string[i - 1];	      event = get_history_event (string, &i, quoted_search_delimiter);	    }	  	  if (!event)	  event_not_found:	    {	    int l = 1 + (i - starting_index);	    temp = (char *)alloca (1 + l);	    strncpy (temp, string + starting_index, l);	    temp[l - 1] = 0;	    sprintf (result, "%s: %s.", temp,		     word_spec_error ? "Bad word specifier" : "Event not found");	  error_exit:	    *output = result;	    return (-1);	  }	  /* If a word specifier is found, then do what that requires. */	  starting_index = i;	  word_spec = get_history_word_specifier (string, event, &i);	  /* There is no such thing as a `malformed word specifier'.  However,	     it is possible for a specifier that has no match.  In that case,	     we complain. */	  if (word_spec == (char *)-1)	  bad_word_spec:	  {	    word_spec_error++;	    goto event_not_found;	  }	  /* If no word specifier, than the thing of interest was the event. */	  if (!word_spec)	    temp = event;	  else	    {	      temp = (char *)alloca (1 + strlen (word_spec));	      strcpy (temp, word_spec);	      free (word_spec);	    }	  /* Perhaps there are other modifiers involved.  Do what they say. */	hack_specials:	  if (string[i] == ':')	    {	      char *tstr;	      switch (string[i + 1])		{		  /* :p means make this the last executed line.  So we		     return an error state after adding this line to the		     history. */		case 'p':		  only_printing++;		  goto next_special;		  /* :t discards all but the last part of the pathname. */		case 't':		  tstr = rindex (temp, '/');		  if (tstr)		    temp = ++tstr;		  goto next_special;		  /* :h discards the last part of a pathname. */		case 'h':		  tstr = rindex (temp, '/');		  if (tstr)		    *tstr = '\0';		  goto next_special;		  /* :r discards the suffix. */		case 'r':		  tstr = rindex (temp, '.');		  if (tstr)		    *tstr = '\0';		  goto next_special;		  /* :e discards everything but the suffix. */		case 'e':		  tstr = rindex (temp, '.');		  if (tstr)		    temp = tstr;		  goto next_special;		  /* :s/this/that substitutes `this' for `that'. */		  /* :gs/this/that substitutes `this' for `that' globally. */		case 'g':		  if (string[i + 2] == 's')

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -