OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [readline/] [histexpand.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 106 markom
/* histexpand.c -- history expansion. */
2
 
3
/* Copyright (C) 1989, 1992 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
#define READLINE_LIBRARY
24
 
25
#if defined (HAVE_CONFIG_H)
26
#  include <config.h>
27
#endif
28
 
29
#include <stdio.h>
30
 
31
#if defined (HAVE_STDLIB_H)
32
#  include <stdlib.h>
33
#else
34
#  include "ansi_stdlib.h"
35
#endif /* HAVE_STDLIB_H */
36
 
37
#if defined (HAVE_UNISTD_H)
38
#  ifndef _MINIX
39
#    include <sys/types.h>
40
#  endif
41
#  include <unistd.h>
42
#endif
43
 
44
#if defined (HAVE_STRING_H)
45
#  include <string.h>
46
#else
47
#  include <strings.h>
48
#endif /* !HAVE_STRING_H */
49
 
50
#include "history.h"
51
#include "histlib.h"
52
 
53
#define HISTORY_WORD_DELIMITERS         " \t\n;&()|<>"
54
#define HISTORY_QUOTE_CHARACTERS        "\"'`"
55
 
56
static char error_pointer;
57
 
58
static char *subst_lhs;
59
static char *subst_rhs;
60
static int subst_lhs_len;
61
static int subst_rhs_len;
62
 
63
static char *get_history_word_specifier ();
64
static char *history_find_word ();
65
 
66
extern int history_offset;
67
 
68
extern char *single_quote ();
69
static char *quote_breaks ();
70
 
71
extern char *xmalloc (), *xrealloc ();
72
 
73
/* Variables exported by this file. */
74
/* The character that represents the start of a history expansion
75
   request.  This is usually `!'. */
76
char history_expansion_char = '!';
77
 
78
/* The character that invokes word substitution if found at the start of
79
   a line.  This is usually `^'. */
80
char history_subst_char = '^';
81
 
82
/* During tokenization, if this character is seen as the first character
83
   of a word, then it, and all subsequent characters upto a newline are
84
   ignored.  For a Bourne shell, this should be '#'.  Bash special cases
85
   the interactive comment character to not be a comment delimiter. */
86
char history_comment_char = '\0';
87
 
88
/* The list of characters which inhibit the expansion of text if found
89
   immediately following history_expansion_char. */
90
char *history_no_expand_chars = " \t\n\r=";
91
 
92
/* If set to a non-zero value, single quotes inhibit history expansion.
93
   The default is 0. */
94
int history_quotes_inhibit_expansion = 0;
95
 
96
/* If set, this points to a function that is called to verify that a
97
   particular history expansion should be performed. */
98
Function *history_inhibit_expansion_function;
99
 
100
/* **************************************************************** */
101
/*                                                                  */
102
/*                      History Expansion                           */
103
/*                                                                  */
104
/* **************************************************************** */
105
 
106
/* Hairy history expansion on text, not tokens.  This is of general
107
   use, and thus belongs in this library. */
108
 
109
/* The last string searched for by a !?string? search. */
110
static char *search_string;
111
 
112
/* The last string matched by a !?string? search. */
113
static char *search_match;
114
 
115
/* Return the event specified at TEXT + OFFSET modifying OFFSET to
116
   point to after the event specifier.  Just a pointer to the history
117
   line is returned; NULL is returned in the event of a bad specifier.
118
   You pass STRING with *INDEX equal to the history_expansion_char that
119
   begins this specification.
120
   DELIMITING_QUOTE is a character that is allowed to end the string
121
   specification for what to search for in addition to the normal
122
   characters `:', ` ', `\t', `\n', and sometimes `?'.
123
   So you might call this function like:
124
   line = get_history_event ("!echo:p", &index, 0);  */
125
char *
126
get_history_event (string, caller_index, delimiting_quote)
127
     char *string;
128
     int *caller_index;
129
     int delimiting_quote;
130
{
131
  register int i;
132
  register char c;
133
  HIST_ENTRY *entry;
134
  int which, sign, local_index, substring_okay;
135
  Function *search_func;
136
  char *temp;
137
 
138
  /* The event can be specified in a number of ways.
139
 
140
     !!   the previous command
141
     !n   command line N
142
     !-n  current command-line minus N
143
     !str the most recent command starting with STR
144
     !?str[?]
145
          the most recent command containing STR
146
 
147
     All values N are determined via HISTORY_BASE. */
148
 
149
  i = *caller_index;
150
 
151
  if (string[i] != history_expansion_char)
152
    return ((char *)NULL);
153
 
154
  /* Move on to the specification. */
155
  i++;
156
 
157
  sign = 1;
158
  substring_okay = 0;
159
 
160
#define RETURN_ENTRY(e, w) \
161
        return ((e = history_get (w)) ? e->line : (char *)NULL)
162
 
163
  /* Handle !! case. */
164
  if (string[i] == history_expansion_char)
165
    {
166
      i++;
167
      which = history_base + (history_length - 1);
168
      *caller_index = i;
169
      RETURN_ENTRY (entry, which);
170
    }
171
 
172
  /* Hack case of numeric line specification. */
173
  if (string[i] == '-')
174
    {
175
      sign = -1;
176
      i++;
177
    }
178
 
179
  if (_rl_digit_p (string[i]))
180
    {
181
      /* Get the extent of the digits and compute the value. */
182
      for (which = 0; _rl_digit_p (string[i]); i++)
183
        which = (which * 10) + _rl_digit_value (string[i]);
184
 
185
      *caller_index = i;
186
 
187
      if (sign < 0)
188
        which = (history_length + history_base) - which;
189
 
190
      RETURN_ENTRY (entry, which);
191
    }
192
 
193
  /* This must be something to search for.  If the spec begins with
194
     a '?', then the string may be anywhere on the line.  Otherwise,
195
     the string must be found at the start of a line. */
196
  if (string[i] == '?')
197
    {
198
      substring_okay++;
199
      i++;
200
    }
201
 
202
  /* Only a closing `?' or a newline delimit a substring search string. */
203
  for (local_index = i; c = string[i]; i++)
204
    if ((!substring_okay && (whitespace (c) || c == ':' ||
205
        (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
206
        string[i] == delimiting_quote)) ||
207
        string[i] == '\n' ||
208
        (substring_okay && string[i] == '?'))
209
      break;
210
 
211
  which = i - local_index;
212
  temp = xmalloc (1 + which);
213
  if (which)
214
    strncpy (temp, string + local_index, which);
215
  temp[which] = '\0';
216
 
217
  if (substring_okay && string[i] == '?')
218
    i++;
219
 
220
  *caller_index = i;
221
 
222
#define FAIL_SEARCH() \
223
  do { \
224
    history_offset = history_length; free (temp) ; return (char *)NULL; \
225
  } while (0)
226
 
227
  /* If there is no search string, try to use the previous search string,
228
     if one exists.  If not, fail immediately. */
229
  if (*temp == '\0' && substring_okay)
230
    {
231
      if (search_string)
232
        {
233
          free (temp);
234
          temp = savestring (search_string);
235
        }
236
      else
237
        FAIL_SEARCH ();
238
    }
239
 
240
  search_func = substring_okay ? history_search : history_search_prefix;
241
  while (1)
242
    {
243
      local_index = (*search_func) (temp, -1);
244
 
245
      if (local_index < 0)
246
        FAIL_SEARCH ();
247
 
248
      if (local_index == 0 || substring_okay)
249
        {
250
          entry = current_history ();
251
          history_offset = history_length;
252
 
253
          /* If this was a substring search, then remember the
254
             string that we matched for word substitution. */
255
          if (substring_okay)
256
            {
257
              FREE (search_string);
258
              search_string = temp;
259
 
260
              FREE (search_match);
261
              search_match = history_find_word (entry->line, local_index);
262
            }
263
          else
264
            free (temp);
265
 
266
          return (entry->line);
267
        }
268
 
269
      if (history_offset)
270
        history_offset--;
271
      else
272
        FAIL_SEARCH ();
273
    }
274
#undef FAIL_SEARCH
275
#undef RETURN_ENTRY
276
}
277
 
278
/* Function for extracting single-quoted strings.  Used for inhibiting
279
   history expansion within single quotes. */
280
 
281
/* Extract the contents of STRING as if it is enclosed in single quotes.
282
   SINDEX, when passed in, is the offset of the character immediately
283
   following the opening single quote; on exit, SINDEX is left pointing
284
   to the closing single quote. */
285
static void
286
hist_string_extract_single_quoted (string, sindex)
287
     char *string;
288
     int *sindex;
289
{
290
  register int i;
291
 
292
  for (i = *sindex; string[i] && string[i] != '\''; i++)
293
    ;
294
 
295
  *sindex = i;
296
}
297
 
298
static char *
299
quote_breaks (s)
300
     char *s;
301
{
302
  register char *p, *r;
303
  char *ret;
304
  int len = 3;
305
 
306
  for (p = s; p && *p; p++, len++)
307
    {
308
      if (*p == '\'')
309
        len += 3;
310
      else if (whitespace (*p) || *p == '\n')
311
        len += 2;
312
    }
313
 
314
  r = ret = xmalloc (len);
315
  *r++ = '\'';
316
  for (p = s; p && *p; )
317
    {
318
      if (*p == '\'')
319
        {
320
          *r++ = '\'';
321
          *r++ = '\\';
322
          *r++ = '\'';
323
          *r++ = '\'';
324
          p++;
325
        }
326
      else if (whitespace (*p) || *p == '\n')
327
        {
328
          *r++ = '\'';
329
          *r++ = *p++;
330
          *r++ = '\'';
331
        }
332
      else
333
        *r++ = *p++;
334
    }
335
  *r++ = '\'';
336
  *r = '\0';
337
  return ret;
338
}
339
 
340
static char *
341
hist_error(s, start, current, errtype)
342
      char *s;
343
      int start, current, errtype;
344
{
345
  char *temp, *emsg;
346
  int ll, elen;
347
 
348
  ll = current - start;
349
 
350
  switch (errtype)
351
    {
352
    case EVENT_NOT_FOUND:
353
      emsg = "event not found";
354
      elen = 15;
355
      break;
356
    case BAD_WORD_SPEC:
357
      emsg = "bad word specifier";
358
      elen = 18;
359
      break;
360
    case SUBST_FAILED:
361
      emsg = "substitution failed";
362
      elen = 19;
363
      break;
364
    case BAD_MODIFIER:
365
      emsg = "unrecognized history modifier";
366
      elen = 29;
367
      break;
368
    case NO_PREV_SUBST:
369
      emsg = "no previous substitution";
370
      elen = 24;
371
      break;
372
    default:
373
      emsg = "unknown expansion error";
374
      elen = 23;
375
      break;
376
    }
377
 
378
  temp = xmalloc (ll + elen + 3);
379
  strncpy (temp, s + start, ll);
380
  temp[ll] = ':';
381
  temp[ll + 1] = ' ';
382
  strcpy (temp + ll + 2, emsg);
383
  return (temp);
384
}
385
 
386
/* Get a history substitution string from STR starting at *IPTR
387
   and return it.  The length is returned in LENPTR.
388
 
389
   A backslash can quote the delimiter.  If the string is the
390
   empty string, the previous pattern is used.  If there is
391
   no previous pattern for the lhs, the last history search
392
   string is used.
393
 
394
   If IS_RHS is 1, we ignore empty strings and set the pattern
395
   to "" anyway.  subst_lhs is not changed if the lhs is empty;
396
   subst_rhs is allowed to be set to the empty string. */
397
 
398
static char *
399
get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
400
     char *str;
401
     int *iptr, delimiter, is_rhs, *lenptr;
402
{
403
  register int si, i, j, k;
404
  char *s = (char *) NULL;
405
 
406
  i = *iptr;
407
 
408
  for (si = i; str[si] && str[si] != delimiter; si++)
409
    if (str[si] == '\\' && str[si + 1] == delimiter)
410
      si++;
411
 
412
  if (si > i || is_rhs)
413
    {
414
      s = xmalloc (si - i + 1);
415
      for (j = 0, k = i; k < si; j++, k++)
416
        {
417
          /* Remove a backslash quoting the search string delimiter. */
418
          if (str[k] == '\\' && str[k + 1] == delimiter)
419
            k++;
420
          s[j] = str[k];
421
        }
422
      s[j] = '\0';
423
      if (lenptr)
424
        *lenptr = j;
425
    }
426
 
427
  i = si;
428
  if (str[i])
429
    i++;
430
  *iptr = i;
431
 
432
  return s;
433
}
434
 
435
static void
436
postproc_subst_rhs ()
437
{
438
  char *new;
439
  int i, j, new_size;
440
 
441
  new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
442
  for (i = j = 0; i < subst_rhs_len; i++)
443
    {
444
      if (subst_rhs[i] == '&')
445
        {
446
          if (j + subst_lhs_len >= new_size)
447
            new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
448
          strcpy (new + j, subst_lhs);
449
          j += subst_lhs_len;
450
        }
451
      else
452
        {
453
          /* a single backslash protects the `&' from lhs interpolation */
454
          if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
455
            i++;
456
          if (j >= new_size)
457
            new = xrealloc (new, new_size *= 2);
458
          new[j++] = subst_rhs[i];
459
        }
460
    }
461
  new[j] = '\0';
462
  free (subst_rhs);
463
  subst_rhs = new;
464
  subst_rhs_len = j;
465
}
466
 
467
/* Expand the bulk of a history specifier starting at STRING[START].
468
   Returns 0 if everything is OK, -1 if an error occurred, and 1
469
   if the `p' modifier was supplied and the caller should just print
470
   the returned string.  Returns the new index into string in
471
   *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
472
static int
473
history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
474
     char *string;
475
     int start, *end_index_ptr;
476
     char **ret_string;
477
     char *current_line;        /* for !# */
478
{
479
  int i, n, starting_index;
480
  int substitute_globally, want_quotes, print_only;
481
  char *event, *temp, *result, *tstr, *t, c, *word_spec;
482
  int result_len;
483
 
484
  result = xmalloc (result_len = 128);
485
 
486
  i = start;
487
 
488
  /* If it is followed by something that starts a word specifier,
489
     then !! is implied as the event specifier. */
490
 
491
  if (member (string[i + 1], ":$*%^"))
492
    {
493
      char fake_s[3];
494
      int fake_i = 0;
495
      i++;
496
      fake_s[0] = fake_s[1] = history_expansion_char;
497
      fake_s[2] = '\0';
498
      event = get_history_event (fake_s, &fake_i, 0);
499
    }
500
  else if (string[i + 1] == '#')
501
    {
502
      i += 2;
503
      event = current_line;
504
    }
505
  else
506
    {
507
      int quoted_search_delimiter = 0;
508
 
509
      /* If the character before this `!' is a double or single
510
         quote, then this expansion takes place inside of the
511
         quoted string.  If we have to search for some text ("!foo"),
512
         allow the delimiter to end the search string. */
513
      if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
514
        quoted_search_delimiter = string[i - 1];
515
      event = get_history_event (string, &i, quoted_search_delimiter);
516
    }
517
 
518
  if (event == 0)
519
    {
520
      *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
521
      free (result);
522
      return (-1);
523
    }
524
 
525
  /* If a word specifier is found, then do what that requires. */
526
  starting_index = i;
527
  word_spec = get_history_word_specifier (string, event, &i);
528
 
529
  /* There is no such thing as a `malformed word specifier'.  However,
530
     it is possible for a specifier that has no match.  In that case,
531
     we complain. */
532
  if (word_spec == (char *)&error_pointer)
533
    {
534
      *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
535
      free (result);
536
      return (-1);
537
    }
538
 
539
  /* If no word specifier, than the thing of interest was the event. */
540
  temp = word_spec ? savestring (word_spec) : savestring (event);
541
  FREE (word_spec);
542
 
543
  /* Perhaps there are other modifiers involved.  Do what they say. */
544
  want_quotes = substitute_globally = print_only = 0;
545
  starting_index = i;
546
 
547
  while (string[i] == ':')
548
    {
549
      c = string[i + 1];
550
 
551
      if (c == 'g')
552
        {
553
          substitute_globally = 1;
554
          i++;
555
          c = string[i + 1];
556
        }
557
 
558
      switch (c)
559
        {
560
        default:
561
          *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
562
          free (result);
563
          free (temp);
564
          return -1;
565
 
566
        case 'q':
567
          want_quotes = 'q';
568
          break;
569
 
570
        case 'x':
571
          want_quotes = 'x';
572
          break;
573
 
574
          /* :p means make this the last executed line.  So we
575
             return an error state after adding this line to the
576
             history. */
577
        case 'p':
578
          print_only++;
579
          break;
580
 
581
          /* :t discards all but the last part of the pathname. */
582
        case 't':
583
          tstr = strrchr (temp, '/');
584
          if (tstr)
585
            {
586
              tstr++;
587
              t = savestring (tstr);
588
              free (temp);
589
              temp = t;
590
            }
591
          break;
592
 
593
          /* :h discards the last part of a pathname. */
594
        case 'h':
595
          tstr = strrchr (temp, '/');
596
          if (tstr)
597
            *tstr = '\0';
598
          break;
599
 
600
          /* :r discards the suffix. */
601
        case 'r':
602
          tstr = strrchr (temp, '.');
603
          if (tstr)
604
            *tstr = '\0';
605
          break;
606
 
607
          /* :e discards everything but the suffix. */
608
        case 'e':
609
          tstr = strrchr (temp, '.');
610
          if (tstr)
611
            {
612
              t = savestring (tstr);
613
              free (temp);
614
              temp = t;
615
            }
616
          break;
617
 
618
        /* :s/this/that substitutes `that' for the first
619
           occurrence of `this'.  :gs/this/that substitutes `that'
620
           for each occurrence of `this'.  :& repeats the last
621
           substitution.  :g& repeats the last substitution
622
           globally. */
623
 
624
        case '&':
625
        case 's':
626
          {
627
            char *new_event, *t;
628
            int delimiter, failed, si, l_temp;
629
 
630
            if (c == 's')
631
              {
632
                if (i + 2 < (int)strlen (string))
633
                  delimiter = string[i + 2];
634
                else
635
                  break;        /* no search delimiter */
636
 
637
                i += 3;
638
 
639
                t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
640
                /* An empty substitution lhs with no previous substitution
641
                   uses the last search string as the lhs. */
642
                if (t)
643
                  {
644
                    FREE (subst_lhs);
645
                    subst_lhs = t;
646
                  }
647
                else if (!subst_lhs)
648
                  {
649
                    if (search_string && *search_string)
650
                      {
651
                        subst_lhs = savestring (search_string);
652
                        subst_lhs_len = strlen (subst_lhs);
653
                      }
654
                    else
655
                      {
656
                        subst_lhs = (char *) NULL;
657
                        subst_lhs_len = 0;
658
                      }
659
                  }
660
 
661
                FREE (subst_rhs);
662
                subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
663
 
664
                /* If `&' appears in the rhs, it's supposed to be replaced
665
                   with the lhs. */
666
                if (member ('&', subst_rhs))
667
                  postproc_subst_rhs ();
668
              }
669
            else
670
              i += 2;
671
 
672
            /* If there is no lhs, the substitution can't succeed. */
673
            if (subst_lhs_len == 0)
674
              {
675
                *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
676
                free (result);
677
                free (temp);
678
                return -1;
679
              }
680
 
681
            l_temp = strlen (temp);
682
            /* Ignore impossible cases. */
683
            if (subst_lhs_len > l_temp)
684
              {
685
                *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
686
                free (result);
687
                free (temp);
688
                return (-1);
689
              }
690
 
691
            /* Find the first occurrence of THIS in TEMP. */
692
            si = 0;
693
            for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
694
              if (STREQN (temp+si, subst_lhs, subst_lhs_len))
695
                {
696
                  int len = subst_rhs_len - subst_lhs_len + l_temp;
697
                  new_event = xmalloc (1 + len);
698
                  strncpy (new_event, temp, si);
699
                  strncpy (new_event + si, subst_rhs, subst_rhs_len);
700
                  strncpy (new_event + si + subst_rhs_len,
701
                           temp + si + subst_lhs_len,
702
                           l_temp - (si + subst_lhs_len));
703
                  new_event[len] = '\0';
704
                  free (temp);
705
                  temp = new_event;
706
 
707
                  failed = 0;
708
 
709
                  if (substitute_globally)
710
                    {
711
                      si += subst_rhs_len;
712
                      l_temp = strlen (temp);
713
                      substitute_globally++;
714
                      continue;
715
                    }
716
                  else
717
                    break;
718
                }
719
 
720
            if (substitute_globally > 1)
721
              {
722
                substitute_globally = 0;
723
                continue;       /* don't want to increment i */
724
              }
725
 
726
            if (failed == 0)
727
              continue;         /* don't want to increment i */
728
 
729
            *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
730
            free (result);
731
            free (temp);
732
            return (-1);
733
          }
734
        }
735
      i += 2;
736
    }
737
  /* Done with modfiers. */
738
  /* Believe it or not, we have to back the pointer up by one. */
739
  --i;
740
 
741
  if (want_quotes)
742
    {
743
      char *x;
744
 
745
      if (want_quotes == 'q')
746
        x = single_quote (temp);
747
      else if (want_quotes == 'x')
748
        x = quote_breaks (temp);
749
      else
750
        x = savestring (temp);
751
 
752
      free (temp);
753
      temp = x;
754
    }
755
 
756
  n = strlen (temp);
757
  if (n >= result_len)
758
    result = xrealloc (result, n + 2);
759
  strcpy (result, temp);
760
  free (temp);
761
 
762
  *end_index_ptr = i;
763
  *ret_string = result;
764
  return (print_only);
765
}
766
 
767
/* Expand the string STRING, placing the result into OUTPUT, a pointer
768
   to a string.  Returns:
769
 
770
  -1) If there was an error in expansion.
771
   0) If no expansions took place (or, if the only change in
772
      the text was the de-slashifying of the history expansion
773
      character)
774
   1) If expansions did take place
775
   2) If the `p' modifier was given and the caller should print the result
776
 
777
  If an error ocurred in expansion, then OUTPUT contains a descriptive
778
  error message. */
779
 
780
#define ADD_STRING(s) \
781
        do \
782
          { \
783
            int sl = strlen (s); \
784
            j += sl; \
785
            if (j >= result_len) \
786
              { \
787
                while (j >= result_len) \
788
                  result_len += 128; \
789
                result = xrealloc (result, result_len); \
790
              } \
791
            strcpy (result + j - sl, s); \
792
          } \
793
        while (0)
794
 
795
#define ADD_CHAR(c) \
796
        do \
797
          { \
798
            if (j >= result_len - 1) \
799
              result = xrealloc (result, result_len += 64); \
800
            result[j++] = c; \
801
            result[j] = '\0'; \
802
          } \
803
        while (0)
804
 
805
int
806
history_expand (hstring, output)
807
     char *hstring;
808
     char **output;
809
{
810
  register int j;
811
  int i, r, l, passc, cc, modified, eindex, only_printing;
812
  char *string;
813
 
814
  /* The output string, and its length. */
815
  int result_len;
816
  char *result;
817
 
818
  /* Used when adding the string. */
819
  char *temp;
820
 
821
  /* Setting the history expansion character to 0 inhibits all
822
     history expansion. */
823
  if (history_expansion_char == 0)
824
    {
825
      *output = savestring (hstring);
826
      return (0);
827
    }
828
 
829
  /* Prepare the buffer for printing error messages. */
830
  result = xmalloc (result_len = 256);
831
  result[0] = '\0';
832
 
833
  only_printing = modified = 0;
834
  l = strlen (hstring);
835
 
836
  /* Grovel the string.  Only backslash and single quotes can quote the
837
     history escape character.  We also handle arg specifiers. */
838
 
839
  /* Before we grovel forever, see if the history_expansion_char appears
840
     anywhere within the text. */
841
 
842
  /* The quick substitution character is a history expansion all right.  That
843
     is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
844
     that is the substitution that we do. */
845
  if (hstring[0] == history_subst_char)
846
    {
847
      string = xmalloc (l + 5);
848
 
849
      string[0] = string[1] = history_expansion_char;
850
      string[2] = ':';
851
      string[3] = 's';
852
      strcpy (string + 4, hstring);
853
      l += 4;
854
    }
855
  else
856
    {
857
      string = hstring;
858
      /* If not quick substitution, still maybe have to do expansion. */
859
 
860
      /* `!' followed by one of the characters in history_no_expand_chars
861
         is NOT an expansion. */
862
      for (i = 0; string[i]; i++)
863
        {
864
          cc = string[i + 1];
865
          /* The history_comment_char, if set, appearing that the beginning
866
             of a word signifies that the rest of the line should not have
867
             history expansion performed on it.
868
             Skip the rest of the line and break out of the loop. */
869
          if (history_comment_char && string[i] == history_comment_char &&
870
              (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
871
            {
872
              while (string[i])
873
                i++;
874
              break;
875
            }
876
          else if (string[i] == history_expansion_char)
877
            {
878
              if (!cc || member (cc, history_no_expand_chars))
879
                continue;
880
              /* If the calling application has set
881
                 history_inhibit_expansion_function to a function that checks
882
                 for special cases that should not be history expanded,
883
                 call the function and skip the expansion if it returns a
884
                 non-zero value. */
885
              else if (history_inhibit_expansion_function &&
886
                        (*history_inhibit_expansion_function) (string, i))
887
                continue;
888
              else
889
                break;
890
            }
891
          /* XXX - at some point, might want to extend this to handle
892
                   double quotes as well. */
893
          else if (history_quotes_inhibit_expansion && string[i] == '\'')
894
            {
895
              /* If this is bash, single quotes inhibit history expansion. */
896
              i++;
897
              hist_string_extract_single_quoted (string, &i);
898
            }
899
          else if (history_quotes_inhibit_expansion && string[i] == '\\')
900
            {
901
              /* If this is bash, allow backslashes to quote single
902
                 quotes and the history expansion character. */
903
              if (cc == '\'' || cc == history_expansion_char)
904
                i++;
905
            }
906
        }
907
 
908
      if (string[i] != history_expansion_char)
909
        {
910
          free (result);
911
          *output = savestring (string);
912
          return (0);
913
        }
914
    }
915
 
916
  /* Extract and perform the substitution. */
917
  for (passc = i = j = 0; i < l; i++)
918
    {
919
      int tchar = string[i];
920
 
921
      if (passc)
922
        {
923
          passc = 0;
924
          ADD_CHAR (tchar);
925
          continue;
926
        }
927
 
928
      if (tchar == history_expansion_char)
929
        tchar = -3;
930
      else if (tchar == history_comment_char)
931
        tchar = -2;
932
 
933
      switch (tchar)
934
        {
935
        default:
936
          ADD_CHAR (string[i]);
937
          break;
938
 
939
        case '\\':
940
          passc++;
941
          ADD_CHAR (tchar);
942
          break;
943
 
944
        case '\'':
945
          {
946
            /* If history_quotes_inhibit_expansion is set, single quotes
947
               inhibit history expansion. */
948
            if (history_quotes_inhibit_expansion)
949
              {
950
                int quote, slen;
951
 
952
                quote = i++;
953
                hist_string_extract_single_quoted (string, &i);
954
 
955
                slen = i - quote + 2;
956
                temp = xmalloc (slen);
957
                strncpy (temp, string + quote, slen);
958
                temp[slen - 1] = '\0';
959
                ADD_STRING (temp);
960
                free (temp);
961
              }
962
            else
963
              ADD_CHAR (string[i]);
964
            break;
965
          }
966
 
967
        case -2:                /* history_comment_char */
968
          if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
969
            {
970
              temp = xmalloc (l - i + 1);
971
              strcpy (temp, string + i);
972
              ADD_STRING (temp);
973
              free (temp);
974
              i = l;
975
            }
976
          else
977
            ADD_CHAR (string[i]);
978
          break;
979
 
980
        case -3:                /* history_expansion_char */
981
          cc = string[i + 1];
982
 
983
          /* If the history_expansion_char is followed by one of the
984
             characters in history_no_expand_chars, then it is not a
985
             candidate for expansion of any kind. */
986
          if (member (cc, history_no_expand_chars))
987
            {
988
              ADD_CHAR (string[i]);
989
              break;
990
            }
991
 
992
#if defined (NO_BANG_HASH_MODIFIERS)
993
          /* There is something that is listed as a `word specifier' in csh
994
             documentation which means `the expanded text to this point'.
995
             That is not a word specifier, it is an event specifier.  If we
996
             don't want to allow modifiers with `!#', just stick the current
997
             output line in again. */
998
          if (cc == '#')
999
            {
1000
              if (result)
1001
                {
1002
                  temp = xmalloc (1 + strlen (result));
1003
                  strcpy (temp, result);
1004
                  ADD_STRING (temp);
1005
                  free (temp);
1006
                }
1007
              i++;
1008
              break;
1009
            }
1010
#endif
1011
 
1012
          r = history_expand_internal (string, i, &eindex, &temp, result);
1013
          if (r < 0)
1014
            {
1015
              *output = temp;
1016
              free (result);
1017
              if (string != hstring)
1018
                free (string);
1019
              return -1;
1020
            }
1021
          else
1022
            {
1023
              if (temp)
1024
                {
1025
                  modified++;
1026
                  if (*temp)
1027
                    ADD_STRING (temp);
1028
                  free (temp);
1029
                }
1030
              only_printing = r == 1;
1031
              i = eindex;
1032
            }
1033
          break;
1034
        }
1035
    }
1036
 
1037
  *output = result;
1038
  if (string != hstring)
1039
    free (string);
1040
 
1041
  if (only_printing)
1042
    {
1043
      add_history (result);
1044
      return (2);
1045
    }
1046
 
1047
  return (modified != 0);
1048
}
1049
 
1050
/* Return a consed string which is the word specified in SPEC, and found
1051
   in FROM.  NULL is returned if there is no spec.  The address of
1052
   ERROR_POINTER is returned if the word specified cannot be found.
1053
   CALLER_INDEX is the offset in SPEC to start looking; it is updated
1054
   to point to just after the last character parsed. */
1055
static char *
1056
get_history_word_specifier (spec, from, caller_index)
1057
     char *spec, *from;
1058
     int *caller_index;
1059
{
1060
  register int i = *caller_index;
1061
  int first, last;
1062
  int expecting_word_spec = 0;
1063
  char *result;
1064
 
1065
  /* The range of words to return doesn't exist yet. */
1066
  first = last = 0;
1067
  result = (char *)NULL;
1068
 
1069
  /* If we found a colon, then this *must* be a word specification.  If
1070
     it isn't, then it is an error. */
1071
  if (spec[i] == ':')
1072
    {
1073
      i++;
1074
      expecting_word_spec++;
1075
    }
1076
 
1077
  /* Handle special cases first. */
1078
 
1079
  /* `%' is the word last searched for. */
1080
  if (spec[i] == '%')
1081
    {
1082
      *caller_index = i + 1;
1083
      return (search_match ? savestring (search_match) : savestring (""));
1084
    }
1085
 
1086
  /* `*' matches all of the arguments, but not the command. */
1087
  if (spec[i] == '*')
1088
    {
1089
      *caller_index = i + 1;
1090
      result = history_arg_extract (1, '$', from);
1091
      return (result ? result : savestring (""));
1092
    }
1093
 
1094
  /* `$' is last arg. */
1095
  if (spec[i] == '$')
1096
    {
1097
      *caller_index = i + 1;
1098
      return (history_arg_extract ('$', '$', from));
1099
    }
1100
 
1101
  /* Try to get FIRST and LAST figured out. */
1102
 
1103
  if (spec[i] == '-')
1104
    first = 0;
1105
  else if (spec[i] == '^')
1106
    first = 1;
1107
  else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1108
    {
1109
      for (first = 0; _rl_digit_p (spec[i]); i++)
1110
        first = (first * 10) + _rl_digit_value (spec[i]);
1111
    }
1112
  else
1113
    return ((char *)NULL);      /* no valid `first' for word specifier */
1114
 
1115
  if (spec[i] == '^' || spec[i] == '*')
1116
    {
1117
      last = (spec[i] == '^') ? 1 : '$';        /* x* abbreviates x-$ */
1118
      i++;
1119
    }
1120
  else if (spec[i] != '-')
1121
    last = first;
1122
  else
1123
    {
1124
      i++;
1125
 
1126
      if (_rl_digit_p (spec[i]))
1127
        {
1128
          for (last = 0; _rl_digit_p (spec[i]); i++)
1129
            last = (last * 10) + _rl_digit_value (spec[i]);
1130
        }
1131
      else if (spec[i] == '$')
1132
        {
1133
          i++;
1134
          last = '$';
1135
        }
1136
      else if (!spec[i] || spec[i] == ':')  /* could be modifier separator */
1137
        last = -1;              /* x- abbreviates x-$ omitting word `$' */
1138
    }
1139
 
1140
  *caller_index = i;
1141
 
1142
  if (last >= first || last == '$' || last < 0)
1143
    result = history_arg_extract (first, last, from);
1144
 
1145
  return (result ? result : (char *)&error_pointer);
1146
}
1147
 
1148
/* Extract the args specified, starting at FIRST, and ending at LAST.
1149
   The args are taken from STRING.  If either FIRST or LAST is < 0,
1150
   then make that arg count from the right (subtract from the number of
1151
   tokens, so that FIRST = -1 means the next to last token on the line).
1152
   If LAST is `$' the last arg from STRING is used. */
1153
char *
1154
history_arg_extract (first, last, string)
1155
     int first, last;
1156
     char *string;
1157
{
1158
  register int i, len;
1159
  char *result;
1160
  int size, offset;
1161
  char **list;
1162
 
1163
  /* XXX - think about making history_tokenize return a struct array,
1164
     each struct in array being a string and a length to avoid the
1165
     calls to strlen below. */
1166
  if ((list = history_tokenize (string)) == NULL)
1167
    return ((char *)NULL);
1168
 
1169
  for (len = 0; list[len]; len++)
1170
    ;
1171
 
1172
  if (last < 0)
1173
    last = len + last - 1;
1174
 
1175
  if (first < 0)
1176
    first = len + first - 1;
1177
 
1178
  if (last == '$')
1179
    last = len - 1;
1180
 
1181
  if (first == '$')
1182
    first = len - 1;
1183
 
1184
  last++;
1185
 
1186
  if (first >= len || last > len || first < 0 || last < 0 || first > last)
1187
    result = ((char *)NULL);
1188
  else
1189
    {
1190
      for (size = 0, i = first; i < last; i++)
1191
        size += strlen (list[i]) + 1;
1192
      result = xmalloc (size + 1);
1193
      result[0] = '\0';
1194
 
1195
      for (i = first, offset = 0; i < last; i++)
1196
        {
1197
          strcpy (result + offset, list[i]);
1198
          offset += strlen (list[i]);
1199
          if (i + 1 < last)
1200
            {
1201
              result[offset++] = ' ';
1202
              result[offset] = 0;
1203
            }
1204
        }
1205
    }
1206
 
1207
  for (i = 0; i < len; i++)
1208
    free (list[i]);
1209
  free (list);
1210
 
1211
  return (result);
1212
}
1213
 
1214
#define slashify_in_quotes "\\`\"$"
1215
 
1216
/* Parse STRING into tokens and return an array of strings.  If WIND is
1217
   not -1 and INDP is not null, we also want the word surrounding index
1218
   WIND.  The position in the returned array of strings is returned in
1219
   *INDP. */
1220
static char **
1221
history_tokenize_internal (string, wind, indp)
1222
     char *string;
1223
     int wind, *indp;
1224
{
1225
  char **result;
1226
  register int i, start, result_index, size;
1227
  int len, delimiter;
1228
 
1229
  /* Get a token, and stuff it into RESULT.  The tokens are split
1230
     exactly where the shell would split them. */
1231
  for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1232
    {
1233
      delimiter = 0;
1234
 
1235
      /* Skip leading whitespace. */
1236
      for (; string[i] && whitespace (string[i]); i++)
1237
        ;
1238
      if (string[i] == 0 || string[i] == history_comment_char)
1239
        return (result);
1240
 
1241
      start = i;
1242
 
1243
      if (member (string[i], "()\n"))
1244
        {
1245
          i++;
1246
          goto got_token;
1247
        }
1248
 
1249
      if (member (string[i], "<>;&|$"))
1250
        {
1251
          int peek = string[i + 1];
1252
 
1253
          if (peek == string[i] && peek != '$')
1254
            {
1255
              if (peek == '<' && string[i + 2] == '-')
1256
                i++;
1257
              i += 2;
1258
              goto got_token;
1259
            }
1260
          else
1261
            {
1262
              if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1263
                  ((peek == '>') && (string[i] == '&')) ||
1264
                  ((peek == '(') && (string[i] == '$')))
1265
                {
1266
                  i += 2;
1267
                  goto got_token;
1268
                }
1269
            }
1270
          if (string[i] != '$')
1271
            {
1272
              i++;
1273
              goto got_token;
1274
            }
1275
        }
1276
 
1277
      /* Get word from string + i; */
1278
 
1279
      if (member (string[i], HISTORY_QUOTE_CHARACTERS))
1280
        delimiter = string[i++];
1281
 
1282
      for (; string[i]; i++)
1283
        {
1284
          if (string[i] == '\\' && string[i + 1] == '\n')
1285
            {
1286
              i++;
1287
              continue;
1288
            }
1289
 
1290
          if (string[i] == '\\' && delimiter != '\'' &&
1291
              (delimiter != '"' || member (string[i], slashify_in_quotes)))
1292
            {
1293
              i++;
1294
              continue;
1295
            }
1296
 
1297
          if (delimiter && string[i] == delimiter)
1298
            {
1299
              delimiter = 0;
1300
              continue;
1301
            }
1302
 
1303
          if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
1304
            break;
1305
 
1306
          if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
1307
            delimiter = string[i];
1308
        }
1309
 
1310
    got_token:
1311
 
1312
      /* If we are looking for the word in which the character at a
1313
         particular index falls, remember it. */
1314
      if (indp && wind != -1 && wind >= start && wind < i)
1315
        *indp = result_index;
1316
 
1317
      len = i - start;
1318
      if (result_index + 2 >= size)
1319
        result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1320
      result[result_index] = xmalloc (1 + len);
1321
      strncpy (result[result_index], string + start, len);
1322
      result[result_index][len] = '\0';
1323
      result[++result_index] = (char *)NULL;
1324
    }
1325
 
1326
  return (result);
1327
}
1328
 
1329
/* Return an array of tokens, much as the shell might.  The tokens are
1330
   parsed out of STRING. */
1331
char **
1332
history_tokenize (string)
1333
     char *string;
1334
{
1335
  return (history_tokenize_internal (string, -1, (int *)NULL));
1336
}
1337
 
1338
/* Find and return the word which contains the character at index IND
1339
   in the history line LINE.  Used to save the word matched by the
1340
   last history !?string? search. */
1341
static char *
1342
history_find_word (line, ind)
1343
     char *line;
1344
     int ind;
1345
{
1346
  char **words, *s;
1347
  int i, wind;
1348
 
1349
  words = history_tokenize_internal (line, ind, &wind);
1350
  if (wind == -1)
1351
    return ((char *)NULL);
1352
  s = words[wind];
1353
  for (i = 0; i < wind; i++)
1354
    free (words[i]);
1355
  for (i = wind + 1; words[i]; i++)
1356
    free (words[i]);
1357
  free (words);
1358
  return s;
1359
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.