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