~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to cmd-line-utils/readline/histexpand.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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