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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [readline/] [histexpand.c] - Blame information for rev 26

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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