The Library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
+ the Free Software Foundation; either version 2, or (at your option)
any later version.
The Library is distributed in the hope that it will be useful, but
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
- 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
# include <unistd.h>
#endif
-#if defined (HAVE_STRING_H)
-# include <string.h>
-#else
-# include <strings.h>
-#endif /* !HAVE_STRING_H */
+#include "rlmbutil.h"
#include "history.h"
#include "histlib.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
#define HISTORY_QUOTE_CHARACTERS "\"'`"
+typedef int _hist_search_func_t PARAMS((const char *, int));
+
+extern int rl_byte_oriented; /* declared in mbutil.c */
+
static char error_pointer;
static char *subst_lhs;
static int subst_lhs_len;
static int subst_rhs_len;
-static char *get_history_word_specifier ();
-static char *history_find_word ();
+static char *get_history_word_specifier PARAMS((char *, char *, int *));
+static char *history_find_word PARAMS((char *, int));
-extern int history_offset;
-
-extern char *single_quote ();
-static char *quote_breaks ();
-
-extern char *xmalloc (), *xrealloc ();
+static char *quote_breaks PARAMS((char *));
/* Variables exported by this file. */
/* The character that represents the start of a history expansion
The default is 0. */
int history_quotes_inhibit_expansion = 0;
+/* Used to split words by history_tokenize_internal. */
+char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
+
/* If set, this points to a function that is called to verify that a
particular history expansion should be performed. */
-Function *history_inhibit_expansion_function;
+rl_linebuf_func_t *history_inhibit_expansion_function;
/* **************************************************************** */
/* */
line = get_history_event ("!echo:p", &index, 0); */
char *
get_history_event (string, caller_index, delimiting_quote)
- char *string;
+ const char *string;
int *caller_index;
int delimiting_quote;
{
register char c;
HIST_ENTRY *entry;
int which, sign, local_index, substring_okay;
- Function *search_func;
+ _hist_search_func_t *search_func;
char *temp;
/* The event can be specified in a number of ways.
/* Only a closing `?' or a newline delimit a substring search string. */
for (local_index = i; c = string[i]; i++)
- if ((!substring_okay && (whitespace (c) || c == ':' ||
- (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
- string[i] == delimiting_quote)) ||
- string[i] == '\n' ||
- (substring_okay && string[i] == '?'))
- break;
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ int v;
+ mbstate_t ps;
+
+ memset (&ps, 0, sizeof (mbstate_t));
+ /* These produce warnings because we're passing a const string to a
+ function that takes a non-const string. */
+ _rl_adjust_point (string, i, &ps);
+ if ((v = _rl_get_char_len (string + i, &ps)) > 1)
+ {
+ i += v - 1;
+ continue;
+ }
+ }
+ else
+#endif /* HANDLE_MULTIBYTE */
+ if ((!substring_okay && (whitespace (c) || c == ':' ||
+ (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
+ string[i] == delimiting_quote)) ||
+ string[i] == '\n' ||
+ (substring_okay && string[i] == '?'))
+ break;
which = i - local_index;
- temp = xmalloc (1 + which);
+ temp = (char *)xmalloc (1 + which);
if (which)
strncpy (temp, string + local_index, which);
temp[which] = '\0';
len += 2;
}
- r = ret = xmalloc (len);
+ r = ret = (char *)xmalloc (len);
*r++ = '\'';
for (p = s; p && *p; )
{
char *s;
int start, current, errtype;
{
- char *temp, *emsg;
+ char *temp;
+ const char *emsg;
int ll, elen;
ll = current - start;
break;
}
- temp = xmalloc (ll + elen + 3);
+ temp = (char *)xmalloc (ll + elen + 3);
strncpy (temp, s + start, ll);
temp[ll] = ':';
temp[ll + 1] = ' ';
int *iptr, delimiter, is_rhs, *lenptr;
{
register int si, i, j, k;
- char *s = (char *) NULL;
+ char *s;
+#if defined (HANDLE_MULTIBYTE)
+ mbstate_t ps;
+#endif
+ s = (char *)NULL;
i = *iptr;
+#if defined (HANDLE_MULTIBYTE)
+ memset (&ps, 0, sizeof (mbstate_t));
+ _rl_adjust_point (str, i, &ps);
+#endif
+
for (si = i; str[si] && str[si] != delimiter; si++)
- if (str[si] == '\\' && str[si + 1] == delimiter)
- si++;
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ int v;
+ if ((v = _rl_get_char_len (str + si, &ps)) > 1)
+ si += v - 1;
+ else if (str[si] == '\\' && str[si + 1] == delimiter)
+ si++;
+ }
+ else
+#endif /* HANDLE_MULTIBYTE */
+ if (str[si] == '\\' && str[si + 1] == delimiter)
+ si++;
if (si > i || is_rhs)
{
- s = xmalloc (si - i + 1);
+ s = (char *)xmalloc (si - i + 1);
for (j = 0, k = i; k < si; j++, k++)
{
/* Remove a backslash quoting the search string delimiter. */
char *new;
int i, j, new_size;
- new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
+ new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);
for (i = j = 0; i < subst_rhs_len; i++)
{
if (subst_rhs[i] == '&')
{
if (j + subst_lhs_len >= new_size)
- new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
+ new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
strcpy (new + j, subst_lhs);
j += subst_lhs_len;
}
if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
i++;
if (j >= new_size)
- new = xrealloc (new, new_size *= 2);
+ new = (char *)xrealloc (new, new_size *= 2);
new[j++] = subst_rhs[i];
}
}
int substitute_globally, want_quotes, print_only;
char *event, *temp, *result, *tstr, *t, c, *word_spec;
int result_len;
+#if defined (HANDLE_MULTIBYTE)
+ mbstate_t ps;
+
+ memset (&ps, 0, sizeof (mbstate_t));
+#endif
- result = xmalloc (result_len = 128);
+ result = (char *)xmalloc (result_len = 128);
i = start;
quote, then this expansion takes place inside of the
quoted string. If we have to search for some text ("!foo"),
allow the delimiter to end the search string. */
- if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
- quoted_search_delimiter = string[i - 1];
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ int c, l;
+ l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY);
+ c = string[l];
+ /* XXX - original patch had i - 1 ??? If i == 0 it would fail. */
+ if (i && (c == '\'' || c == '"'))
+ quoted_search_delimiter = c;
+ }
+ else
+#endif /* HANDLE_MULTIBYTE */
+ if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+ quoted_search_delimiter = string[i - 1];
+
event = get_history_event (string, &i, quoted_search_delimiter);
}
case '&':
case 's':
{
- char *new_event, *t;
+ char *new_event;
int delimiter, failed, si, l_temp;
if (c == 's')
{
if (i + 2 < (int)strlen (string))
- delimiter = string[i + 2];
+ {
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ _rl_adjust_point (string, i + 2, &ps);
+ if (_rl_get_char_len (string + i + 2, &ps) > 1)
+ delimiter = 0;
+ else
+ delimiter = string[i + 2];
+ }
+ else
+#endif /* HANDLE_MULTIBYTE */
+ delimiter = string[i + 2];
+ }
else
break; /* no search delimiter */
if (STREQN (temp+si, subst_lhs, subst_lhs_len))
{
int len = subst_rhs_len - subst_lhs_len + l_temp;
- new_event = xmalloc (1 + len);
+ new_event = (char *)xmalloc (1 + len);
strncpy (new_event, temp, si);
strncpy (new_event + si, subst_rhs, subst_rhs_len);
strncpy (new_event + si + subst_rhs_len,
char *x;
if (want_quotes == 'q')
- x = single_quote (temp);
+ x = sh_single_quote (temp);
else if (want_quotes == 'x')
x = quote_breaks (temp);
else
n = strlen (temp);
if (n >= result_len)
- result = xrealloc (result, n + 2);
+ result = (char *)xrealloc (result, n + 2);
strcpy (result, temp);
free (temp);
{ \
while (j >= result_len) \
result_len += 128; \
- result = xrealloc (result, result_len); \
+ result = (char *)xrealloc (result, result_len); \
} \
strcpy (result + j - sl, s); \
} \
do \
{ \
if (j >= result_len - 1) \
- result = xrealloc (result, result_len += 64); \
+ result = (char *)xrealloc (result, result_len += 64); \
result[j++] = c; \
result[j] = '\0'; \
} \
int result_len;
char *result;
+#if defined (HANDLE_MULTIBYTE)
+ char mb[MB_LEN_MAX];
+ mbstate_t ps;
+#endif
+
/* Used when adding the string. */
char *temp;
+ if (output == 0)
+ return 0;
+
/* Setting the history expansion character to 0 inhibits all
history expansion. */
if (history_expansion_char == 0)
}
/* Prepare the buffer for printing error messages. */
- result = xmalloc (result_len = 256);
+ result = (char *)xmalloc (result_len = 256);
result[0] = '\0';
only_printing = modified = 0;
that is the substitution that we do. */
if (hstring[0] == history_subst_char)
{
- string = xmalloc (l + 5);
+ string = (char *)xmalloc (l + 5);
string[0] = string[1] = history_expansion_char;
string[2] = ':';
}
else
{
+#if defined (HANDLE_MULTIBYTE)
+ memset (&ps, 0, sizeof (mbstate_t));
+#endif
+
string = hstring;
/* If not quick substitution, still maybe have to do expansion. */
is NOT an expansion. */
for (i = 0; string[i]; i++)
{
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ int v;
+ v = _rl_get_char_len (string + i, &ps);
+ if (v > 1)
+ {
+ i += v - 1;
+ continue;
+ }
+ }
+#endif /* HANDLE_MULTIBYTE */
+
cc = string[i + 1];
- /* The history_comment_char, if set, appearing that the beginning
+ /* The history_comment_char, if set, appearing at the beginning
of a word signifies that the rest of the line should not have
history expansion performed on it.
Skip the rest of the line and break out of the loop. */
if (history_comment_char && string[i] == history_comment_char &&
- (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
+ (i == 0 || member (string[i - 1], history_word_delimiters)))
{
while (string[i])
i++;
continue;
}
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+ {
+ int k, c;
+
+ c = tchar;
+ memset (mb, 0, sizeof (mb));
+ for (k = 0; k < MB_LEN_MAX; k++)
+ {
+ mb[k] = (char)c;
+ memset (&ps, 0, sizeof (mbstate_t));
+ if (_rl_get_char_len (mb, &ps) == -2)
+ c = string[++i];
+ else
+ break;
+ }
+ if (strlen (mb) > 1)
+ {
+ ADD_STRING (mb);
+ break;
+ }
+ }
+#endif /* HANDLE_MULTIBYTE */
+
if (tchar == history_expansion_char)
tchar = -3;
else if (tchar == history_comment_char)
hist_string_extract_single_quoted (string, &i);
slen = i - quote + 2;
- temp = xmalloc (slen);
+ temp = (char *)xmalloc (slen);
strncpy (temp, string + quote, slen);
temp[slen - 1] = '\0';
ADD_STRING (temp);
}
case -2: /* history_comment_char */
- if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
+ if (i == 0 || member (string[i - 1], history_word_delimiters))
{
- temp = xmalloc (l - i + 1);
+ temp = (char *)xmalloc (l - i + 1);
strcpy (temp, string + i);
ADD_STRING (temp);
free (temp);
{
if (result)
{
- temp = xmalloc (1 + strlen (result));
+ temp = (char *)xmalloc (1 + strlen (result));
strcpy (temp, result);
ADD_STRING (temp);
free (temp);
i++;
last = '$';
}
- else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
+#if 0
+ else if (!spec[i] || spec[i] == ':')
+ /* check against `:' because there could be a modifier separator */
+#else
+ else
+ /* csh seems to allow anything to terminate the word spec here,
+ leaving it as an abbreviation. */
+#endif
last = -1; /* x- abbreviates x-$ omitting word `$' */
}
char *
history_arg_extract (first, last, string)
int first, last;
- char *string;
+ const char *string;
{
register int i, len;
char *result;
{
for (size = 0, i = first; i < last; i++)
size += strlen (list[i]) + 1;
- result = xmalloc (size + 1);
+ result = (char *)xmalloc (size + 1);
result[0] = '\0';
for (i = first, offset = 0; i < last; i++)
*INDP. */
static char **
history_tokenize_internal (string, wind, indp)
- char *string;
+ const char *string;
int wind, *indp;
{
char **result;
register int i, start, result_index, size;
int len, delimiter;
+ /* If we're searching for a string that's not part of a word (e.g., " "),
+ make sure we set *INDP to a reasonable value. */
+ if (indp && wind != -1)
+ *indp = -1;
+
/* Get a token, and stuff it into RESULT. The tokens are split
exactly where the shell would split them. */
for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
continue;
}
- if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
+ if (!delimiter && (member (string[i], history_word_delimiters)))
break;
if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
len = i - start;
if (result_index + 2 >= size)
result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
- result[result_index] = xmalloc (1 + len);
+ result[result_index] = (char *)xmalloc (1 + len);
strncpy (result[result_index], string + start, len);
result[result_index][len] = '\0';
result[++result_index] = (char *)NULL;
parsed out of STRING. */
char **
history_tokenize (string)
- char *string;
+ const char *string;
{
return (history_tokenize_internal (string, -1, (int *)NULL));
}
int i, wind;
words = history_tokenize_internal (line, ind, &wind);
- if (wind == -1)
+ if (wind == -1 || words == 0)
return ((char *)NULL);
s = words[wind];
for (i = 0; i < wind; i++)