bash-5.0-beta release

This commit is contained in:
Chet Ramey
2018-09-17 15:10:56 -04:00
parent 9a51695bed
commit 2f5dfe5a18
144 changed files with 27560 additions and 36005 deletions
+60 -10
View File
@@ -84,6 +84,10 @@
#include <errno.h>
#include <stdio.h>
#if defined (HAVE_MMAP)
#include <sys/mman.h>
#endif
/* Define getpagesize () if the system does not. */
#ifndef HAVE_GETPAGESIZE
# include "getpagesize.h"
@@ -111,6 +115,7 @@
# define NO_VALLOC
#endif
/* SIZEOF_LONG * 4 - 2, usable bins from 1..NBUCKETS-1 */
#define NBUCKETS 30
#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
@@ -197,6 +202,23 @@ typedef union _malloc_guard {
#define STARTBUCK 1
/* Should we use mmap for large allocations? */
#if defined (HAVE_MMAP)
# if !defined (MAP_ANON) && defined (MAP_ANONYMOUS)
# define MAP_ANON MAP_ANONYMOUS
# endif
#endif
#if defined (HAVE_MMAP) && defined (MAP_ANON)
# define USE_MMAP
#endif
#if defined (USE_MMAP)
# define MMAP_THRESHOLD 14 /* must be >= SPLIT_MAX, COMBINE_MAX */
#else
# define MMAP_THRESHOLD (8 * SIZEOF_LONG)
#endif
/* Flags for the internal functions. */
#define MALLOC_WRAPPER 0x01 /* wrapper function */
#define MALLOC_INTERNAL 0x02 /* internal function calling another */
@@ -288,6 +310,9 @@ int malloc_flags = 0; /* future use */
int malloc_trace = 0; /* trace allocations and frees to stderr */
int malloc_register = 0; /* future use */
/* Use a variable in case we want to dynamically adapt it in the future */
int malloc_mmap_threshold = MMAP_THRESHOLD;
#ifdef MALLOC_TRACE
char _malloc_trace_buckets[NBUCKETS];
@@ -594,7 +619,7 @@ morecore (nu)
/* Try to split a larger block here, if we're within the range of sizes
to split. */
if (nu >= SPLIT_MIN)
if (nu >= SPLIT_MIN && nu <= malloc_mmap_threshold)
{
bsplit (nu);
if (nextf[nu] != 0)
@@ -603,7 +628,7 @@ morecore (nu)
/* Try to coalesce two adjacent blocks from the free list on nextf[nu - 1],
if we can, and we're within the range of the block coalescing limits. */
if (nu >= COMBINE_MIN && nu < COMBINE_MAX && busy[nu - 1] == 0 && nextf[nu - 1])
if (nu >= COMBINE_MIN && nu < COMBINE_MAX && nu <= malloc_mmap_threshold && busy[nu - 1] == 0 && nextf[nu - 1])
{
bcoalesce (nu);
if (nextf[nu] != 0)
@@ -632,6 +657,25 @@ morecore (nu)
nblks = 1;
}
#if defined (USE_MMAP)
if (nu > malloc_mmap_threshold)
{
mp = (union mhead *)mmap (0, sbrk_amt, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if ((void *)mp == MAP_FAILED)
goto morecore_done;
nextf[nu] = mp;
mp->mh_alloc = ISFREE;
mp->mh_index = nu;
CHAIN (mp) = 0;
#ifdef MALLOC_STATS
_mstats.nmmap++;
_mstats.tmmap += sbrk_amt;
#endif
goto morecore_done;
}
#endif
#ifdef MALLOC_STATS
_mstats.nsbrk++;
_mstats.tsbrk += sbrk_amt;
@@ -915,6 +959,17 @@ internal_free (mem, file, line, flags)
if (mg.i != p->mh_nbytes)
xbotch (mem, ERR_ASSERT_FAILED, _("free: start and end chunk sizes differ"), file, line);
#if defined (USE_MMAP)
if (nunits > malloc_mmap_threshold)
{
munmap (p, binsize (nunits));
#if defined (MALLOC_STATS)
_mstats.nlesscore[nunits]++;
#endif
goto free_return;
}
#endif
#if GLIBC21
if (nunits >= LESSCORE_MIN && ((char *)p + binsize(nunits) == sbrk (0)))
#else
@@ -1053,12 +1108,9 @@ internal_realloc (mem, n, file, line, flags)
/* If ok, use the same block, just marking its size as changed. */
if (RIGHT_BUCKET(nbytes, nunits) || RIGHT_BUCKET(nbytes, nunits-1))
{
#if 0
m = (char *)mem + p->mh_nbytes;
#else
/* Compensate for increment above. */
m -= 4;
#endif
*m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
m = (char *)mem + (p->mh_nbytes = n);
@@ -1076,6 +1128,8 @@ internal_realloc (mem, n, file, line, flags)
_mstats.nrcopy++;
#endif
/* If we are using mmap and have mremap, we could use it here. */
if ((m = internal_malloc (n, file, line, MALLOC_INTERNAL|MALLOC_NOTRACE|MALLOC_NOREG)) == 0)
return 0;
FASTCOPY (mem, m, tocopy);
@@ -1120,11 +1174,7 @@ internal_memalign (alignment, size, file, line, flags)
if (((long) ptr & (alignment - 1)) == 0)
return ptr;
/* Otherwise, get address of byte in the block that has that alignment. */
#if 0
aligned = (char *) (((long) ptr + alignment - 1) & -alignment);
#else
aligned = (char *) (((long) ptr + alignment - 1) & (~alignment + 1));
#endif
/* Store a suitable indication of how to free the block,
so that free can find the true beginning of it. */
+4
View File
@@ -25,6 +25,7 @@
#ifdef MALLOC_STATS
/* This needs to change if the definition in malloc.c changes */
#ifndef NBUCKETS
# define NBUCKETS 30
#endif
@@ -77,6 +78,8 @@ struct _malstats {
int nsplit[NBUCKETS];
int tbcoalesce;
int ncoalesce[NBUCKETS];
int nmmap;
bits32_t tmmap;
};
/* Return statistics describing allocation of blocks of size BLOCKSIZE.
@@ -98,6 +101,7 @@ struct bucket_stats {
int nlesscore;
int nsplit;
int ncoalesce;
int nmmap; /* currently unused */
};
extern struct bucket_stats malloc_bucket_stats __P((int));
+9 -1
View File
@@ -36,6 +36,8 @@
extern int malloc_free_blocks __P((int));
extern int malloc_mmap_threshold;
extern struct _malstats _mstats;
extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
@@ -103,8 +105,12 @@ _print_malloc_stats (s, fp)
for (i = totused = totfree = 0; i < NBUCKETS; i++)
{
v = malloc_bucket_stats (i);
/* Show where the mmap threshold is; sizes greater than this use mmap to
allocate and munmap to free (munmap shows up as lesscore). */
if (i == malloc_mmap_threshold+1)
fprintf (fp, "--------\n");
if (v.nmal > 0)
fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce);
fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%8d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce);
totfree += v.nfree * v.blocksize;
totused += v.nused * v.blocksize;
}
@@ -115,6 +121,8 @@ _print_malloc_stats (s, fp)
_mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy);
fprintf (fp, "Total sbrks: %d, total bytes via sbrk: %d\n",
_mstats.nsbrk, _mstats.tsbrk);
fprintf (fp, "Total mmaps: %d, total bytes via mmap: %d\n",
_mstats.nmmap, _mstats.tmmap);
fprintf (fp, "Total blocks split: %d, total block coalesces: %d\n",
_mstats.tbsplit, _mstats.tbcoalesce);
}
+2 -1
View File
@@ -2987,7 +2987,8 @@ _rl_update_final (void)
putc (last_line[_rl_screenwidth - 1 + woff], rl_outstream);
}
_rl_vis_botlin = 0;
rl_crlf ();
if (botline_length > 0 || _rl_last_c_pos > 0)
rl_crlf ();
fflush (rl_outstream);
rl_display_fixed++;
}
+19 -3
View File
@@ -403,7 +403,7 @@ to the ``normal'' terminating characters.
Return an array of tokens parsed out of @var{string}, much as the
shell might. The tokens are split on the characters in the
@var{history_word_delimiters} variable,
and shell quoting conventions are obeyed.
and shell quoting conventions are obeyed as described below.
@end deftypefun
@deftypefun {char *} history_arg_extract (int first, int last, const char *string)
@@ -476,8 +476,24 @@ carriage return, and @samp{=}.
@end deftypevar
@deftypevar int history_quotes_inhibit_expansion
If non-zero, double-quoted words are not scanned for the history expansion
character or the history comment character. The default value is 0.
If non-zero, the history expansion code implements shell-like quoting:
single-quoted words are not scanned for the history expansion
character or the history comment character, and double-quoted words may
have history expansion performed, since single quotes are not special
within double quotes.
The default value is 0.
@end deftypevar
@deftypevar int history_quoting_state
An application may set this variable to indicate that the current line
being expanded is subject to existing quoting. If set to @samp{'}, the
history expansion function will assume that the line is single-quoted and
inhibit expansion until it reads an unquoted closing single quote; if set
to @samp{"}, history expansion will assume the line is double quoted until
it reads an unquoted closing double quote. If set to zero, the default,
the history expansion function will assume the line is not quoted and
treat quote characters within the line as described above.
This is only effective if @var{history_quotes_inhibit_expansion} is set.
@end deftypevar
@deftypevar {rl_linebuf_func_t *} history_inhibit_expansion_function
+14 -4
View File
@@ -262,8 +262,8 @@ fix errors in previous commands quickly.
@ifset BashFeatures
History expansion is performed immediately after a complete line
is read, before the shell breaks it into words, and is performed
on each line individually without taking quoting on previous lines into
account.
on each line individually. Bash attempts to inform the history
expansion functions about quoting still in effect from previous lines.
@end ifset
History expansion takes place in two parts. The first is to determine
@@ -277,9 +277,19 @@ that Bash does, so that several words
surrounded by quotes are considered one word.
History expansions are introduced by the appearance of the
history expansion character, which is @samp{!} by default.
History expansion implements shell-like quoting conventions:
a backslash can be used to remove the special handling for the next character;
single quotes enclose verbatim sequences of characters, and can be used to
inhibit history expansion;
and characters enclosed within double quotes may be subject to history
expansion, since backslash can escape the history expansion character,
but single quotes may not, since they are not treated specially within
double quotes.
@ifset BashFeatures
Only @samp{\} and @samp{'} may be used to escape the history expansion
character, but the history expansion character is
When using the shell, only @samp{\} and @samp{'} may be used to escape the
history expansion character, but the history expansion character is
also treated as quoted if it immediately precedes the closing double quote
in a double-quoted string.
@end ifset
+5 -1
View File
@@ -846,12 +846,16 @@ Return the function invoked by @var{keyseq} in keymap @var{map}.
If @var{map} is @code{NULL}, the current keymap is used. If @var{type} is
not @code{NULL}, the type of the object is returned in the @code{int} variable
it points to (one of @code{ISFUNC}, @code{ISKMAP}, or @code{ISMACR}).
It takes a "translated" key sequence and should not be used if the key sequence
can include NUL.
@end deftypefun
@deftypefun {rl_command_func_t *} rl_function_of_keyseq_len (const char *keyseq, size_t len Keymap map, int *type)
@deftypefun {rl_command_func_t *} rl_function_of_keyseq_len (const char *keyseq, size_t len, Keymap map, int *type)
Return the function invoked by @var{keyseq} of length @var{len}
in keymap @var{map}. Equivalent to @code{rl_function_of_keyseq} with the
addition of the @var{len} parameter.
It takes a "translated" key sequence and should be used if the key sequence
can include NUL.
@end deftypefun
@deftypefun {char **} rl_invoking_keyseqs (rl_command_func_t *function)
+29 -15
View File
@@ -475,6 +475,7 @@ The default value is @samp{off}.
If set to @samp{on}, and @var{completion-ignore-case} is enabled, Readline
treats hyphens (@samp{-}) and underscores (@samp{_}) as equivalent when
performing case-insensitive filename matching and completion.
The default value is @samp{off}.
@item completion-prefix-display-length
@vindex completion-prefix-display-length
@@ -802,7 +803,7 @@ Meta-Rubout: backward-kill-word
Control-o: "> output"
@end example
In the above example, @kbd{C-u} is bound to the function
In the example above, @kbd{C-u} is bound to the function
@code{universal-argument},
@kbd{M-DEL} is bound to the function @code{backward-kill-word}, and
@kbd{C-o} is bound to run the macro
@@ -1352,7 +1353,7 @@ This function is intended to be bound to the "bracketed paste" escape
sequence sent by some terminals, and such a binding is assigned by default.
It allows Readline to insert the pasted text as a single unit without treating
each character as if it had been read from the keyboard. The characters
are inserted as if each one was bound to @code{self-insert}) instead of
are inserted as if each one was bound to @code{self-insert} instead of
executing any editing commands.
@item transpose-chars (C-t)
@@ -2019,10 +2020,10 @@ matches were generated.
@item complete
@btindex complete
@example
@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-DE] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}]
[-F @var{function}] [-C @var{command}] [-X @var{filterpat}]
@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-DEI] [-A @var{action}] [-G @var{globpat}]
[-W @var{wordlist}] [-F @var{function}] [-C @var{command}] [-X @var{filterpat}]
[-P @var{prefix}] [-S @var{suffix}] @var{name} [@var{name} @dots{}]}
@code{complete -pr [-DE] [@var{name} @dots{}]}
@code{complete -pr [-DEI] [@var{name} @dots{}]}
@end example
Specify how arguments to each @var{name} should be completed.
@@ -2032,16 +2033,24 @@ reused as input.
The @option{-r} option removes a completion specification for
each @var{name}, or, if no @var{name}s are supplied, all
completion specifications.
The @option{-D} option indicates that the remaining options and actions should
The @option{-D} option indicates that other supplied options and actions should
apply to the ``default'' command completion; that is, completion attempted
on a command for which no completion has previously been defined.
The @option{-E} option indicates that the remaining options and actions should
The @option{-E} option indicates that other supplied options and actions should
apply to ``empty'' command completion; that is, completion attempted on a
blank line.
The @option{-I} option indicates that other supplied options and actions should
apply to completion on the inital non-assignment word on the line, or after a
command delimiter such as @samp{;} or @samp{|}, which is usually command
name completion.
If multiple options are supplied, the @option{-D} option takes precedence
over @option{-E}, and both take precedence over @option{-I}.
If any of @option{-D}, @option{-E}, or @option{-I} are supplied, any other
@var{name} arguments are ignored; these completions only apply to the case
specified by the option.
The process of applying these completion specifications when word completion
is attempted is described above (@pxref{Programmable Completion}). The
@option{-D} option takes precedence over @option{-E}.
is attempted is described above (@pxref{Programmable Completion}).
Other options, if specified, have the following meanings.
The arguments to the @option{-G}, @option{-W}, and @option{-X} options
@@ -2071,7 +2080,7 @@ Perform directory name completion if the compspec generates no matches.
@item filenames
Tell Readline that the compspec generates filenames, so it can perform any
filename-specific processing (like adding a slash to directory names
filename-specific processing (like adding a slash to directory names,
quoting special characters, or suppressing trailing spaces).
This option is intended to be used with shell functions specified
with @option{-F}.
@@ -2226,7 +2235,7 @@ an error occurs adding a completion specification.
@item compopt
@btindex compopt
@example
@code{compopt} [-o @var{option}] [-DE] [+o @var{option}] [@var{name}]
@code{compopt} [-o @var{option}] [-DEI] [+o @var{option}] [@var{name}]
@end example
Modify completion options for each @var{name} according to the
@var{option}s, or for the currently-executing completion if no @var{name}s
@@ -2235,14 +2244,19 @@ If no @var{option}s are given, display the completion options for each
@var{name} or the current completion.
The possible values of @var{option} are those valid for the @code{complete}
builtin described above.
The @option{-D} option indicates that the remaining options should
The @option{-D} option indicates that other supplied options should
apply to the ``default'' command completion; that is, completion attempted
on a command for which no completion has previously been defined.
The @option{-E} option indicates that the remaining options should
The @option{-E} option indicates that other supplied options should
apply to ``empty'' command completion; that is, completion attempted on a
blank line.
The @option{-I} option indicates that other supplied options should
apply to completion on the inital non-assignment word on the line, or after a
command delimiter such as @samp{;} or @samp{|}, which is usually command
name completion.
The @option{-D} option takes precedence over @option{-E}.
If multiple options are supplied, the @option{-D} option takes precedence
over @option{-E}, and both take precedence over @option{-I}
The return value is true unless an invalid option is supplied, an attempt
is made to modify the options for a @var{name} for which no completion
@@ -2289,7 +2303,7 @@ _comp_cd()
local cur _skipdot _cdpath
local i j k
# Tilde expansion, with side effect of expanding tilde to full pathname
# Tilde expansion, which also expands tilde to full pathname
case "$2" in
\~*) eval cur="$2" ;;
*) cur=$2 ;;
+6 -6
View File
@@ -1,10 +1,10 @@
@ignore
Copyright (C) 1988-2017 Free Software Foundation, Inc.
Copyright (C) 1988-2018 Free Software Foundation, Inc.
@end ignore
@set EDITION 7.0
@set VERSION 7.0
@set UPDATED 28 December 2017
@set UPDATED-MONTH December 2017
@set EDITION 8.0
@set VERSION 8.0
@set UPDATED 6 July 2018
@set UPDATED-MONTH July 2018
@set LASTCHANGE Thu Dec 28 14:44:16 EST 2017
@set LASTCHANGE Fri Jul 6 16:25:22 MDT 2018
+58 -35
View File
@@ -1,6 +1,6 @@
/* histexpand.c -- history expansion. */
/* Copyright (C) 1989-2017 Free Software Foundation, Inc.
/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -107,6 +107,8 @@ char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
particular history expansion should be performed. */
rl_linebuf_func_t *history_inhibit_expansion_function;
int history_quoting_state = 0;
/* **************************************************************** */
/* */
/* History Expansion */
@@ -961,7 +963,22 @@ history_expand (char *hstring, char **output)
/* `!' followed by one of the characters in history_no_expand_chars
is NOT an expansion. */
for (i = dquote = squote = 0; string[i]; i++)
dquote = history_quoting_state == '"';
squote = history_quoting_state == '\'';
/* If the calling application tells us we are already reading a
single-quoted string, consume the rest of the string right now
and then go on. */
i = 0;
if (squote && history_quotes_inhibit_expansion)
{
hist_string_extract_single_quoted (string, &i, 0);
squote = 0;
if (string[i])
i++;
}
for ( ; string[i]; i++)
{
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
@@ -1049,7 +1066,29 @@ history_expand (char *hstring, char **output)
}
/* Extract and perform the substitution. */
for (passc = dquote = squote = i = j = 0; i < l; i++)
dquote = history_quoting_state == '"';
squote = history_quoting_state == '\'';
/* If the calling application tells us we are already reading a
single-quoted string, consume the rest of the string right now
and then go on. */
i = j = 0;
if (squote && history_quotes_inhibit_expansion)
{
int c;
hist_string_extract_single_quoted (string, &i, 0);
squote = 0;
for (c = 0; c < i; c++)
ADD_CHAR (string[c]);
if (string[i])
{
ADD_CHAR (string[i]);
i++;
}
}
for (passc = 0; i < l; i++)
{
int qc, tchar = string[i];
@@ -1429,11 +1468,11 @@ history_tokenize_word (const char *string, int ind)
}
}
if (member (string[i], "<>;&|$"))
if (member (string[i], "<>;&|"))
{
int peek = string[i + 1];
if (peek == string[i] && peek != '$')
if (peek == string[i])
{
if (peek == '<' && string[i + 2] == '-')
i++;
@@ -1456,9 +1495,8 @@ history_tokenize_word (const char *string, int ind)
i += 2;
return i;
}
/* XXX - separated out for later -- bash-4.2 */
else if ((peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
(peek == '(' && string[i] == '$')) /*)*/
/* XXX - process substitution -- separated out for later -- bash-4.2 */
else if (peek == '(' && (string[i] == '>' || string[i] == '<')) /*)*/
{
i += 2;
delimopen = '(';
@@ -1466,34 +1504,9 @@ history_tokenize_word (const char *string, int ind)
nestdelim = 1;
goto get_word;
}
#if 0
else if (peek == '\'' && string[i] == '$')
{
i += 2; /* XXX */
return i;
}
#endif
if (string[i] != '$')
{
i++;
return i;
}
}
/* same code also used for $(...)/<(...)/>(...) above */
if (member (string[i], "!@?+*"))
{
int peek = string[i + 1];
if (peek == '(') /*)*/
{
/* Shell extended globbing patterns */
i += 2;
delimopen = '(';
delimiter = ')'; /* XXX - not perfect */
nestdelim = 1;
}
i++;
return i;
}
get_word:
@@ -1538,6 +1551,16 @@ get_word:
continue;
}
/* Command and process substitution; shell extended globbing patterns */
if (nestdelim == 0 && delimiter == 0 && member (string[i], "<>$!@?+*") && string[i+1] == '(') /*)*/
{
i += 2;
delimopen = '(';
delimiter = ')';
nestdelim = 1;
continue;
}
if (delimiter == 0 && (member (string[i], history_word_delimiters)))
break;
+2 -2
View File
@@ -1,6 +1,6 @@
/* histfile.c - functions to manipulate the history file. */
/* Copyright (C) 1989-2017 Free Software Foundation, Inc.
/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -396,7 +396,7 @@ read_history_range (const char *filename, int from, int to)
{
if (HIST_TIMESTAMP_START(line_start) == 0)
{
if (last_ts == NULL && history_multiline_entries)
if (last_ts == NULL && history_length > 0 && history_multiline_entries)
_hs_append_history_line (history_length - 1, line_start);
else
add_history (line_start);
+2
View File
@@ -261,7 +261,9 @@ extern char *history_word_delimiters;
extern char history_comment_char;
extern char *history_no_expand_chars;
extern char *history_search_delimiter_chars;
extern int history_quotes_inhibit_expansion;
extern int history_quoting_state;
extern int history_write_timestamps;
+4 -4
View File
@@ -322,7 +322,7 @@ rl_unix_word_rubout (int count, int key)
rl_point--;
while (rl_point && (whitespace (rl_line_buffer[rl_point - 1]) == 0))
rl_point--;
rl_point--; /* XXX - multibyte? */
}
rl_kill_text (orig_point, rl_point);
@@ -359,7 +359,7 @@ rl_unix_filename_rubout (int count, int key)
while (rl_point && (whitespace (c) == 0) && c != '/')
{
rl_point--;
rl_point--; /* XXX - multibyte? */
c = rl_line_buffer[rl_point - 1];
}
}
@@ -677,7 +677,7 @@ rl_bracketed_paste_begin (int count, int key)
size_t len, cap;
char *buf;
retval = 1;
retval = 0;
len = 0;
buf = xmalloc (cap = 64);
@@ -708,7 +708,7 @@ rl_bracketed_paste_begin (int count, int key)
if (len == cap)
buf = xrealloc (buf, cap + 1);
buf[len] = '\0';
retval = rl_insert_text (buf);
retval = rl_insert_text (buf) == len ? 0 : 1;
}
xfree (buf);
+59 -3
View File
@@ -75,6 +75,57 @@ int _rl_utf8locale = 0;
#if defined(HANDLE_MULTIBYTE)
/* **************************************************************** */
/* */
/* UTF-8 specific Character Utility Functions */
/* */
/* **************************************************************** */
/* Return the length in bytes of the possibly-multibyte character beginning
at S. Encoding is UTF-8. */
static int
_rl_utf8_mblen (const char *s, size_t n)
{
unsigned char c, c1;
if (s == 0)
return (0); /* no shift states */
if (n <= 0)
return (-1);
c = (unsigned char)*s;
if (c < 0x80)
return (c != 0);
if (c >= 0xc2)
{
c1 = (unsigned char)s[1];
if (c < 0xe0)
{
if (n >= 2 && (s[1] ^ 0x80) < 0x40)
return 2;
}
else if (c < 0xf0)
{
if (n >= 3
&& (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (c >= 0xe1 || c1 >= 0xa0)
&& (c != 0xed || c1 < 0xa0))
return 3;
}
else if (c < 0xf8)
{
if (n >= 4
&& (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40
&& (c >= 0xf1 || c1 >= 0x90)
&& (c < 0xf4 || (c == 0xf4 && c1 < 0x90)))
return 4;
}
}
/* invalid or incomplete multibyte character */
return -1;
}
static int
_rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_zero)
{
@@ -228,11 +279,16 @@ _rl_get_char_len (char *src, mbstate_t *ps)
/* Look at no more than MB_CUR_MAX characters */
l = (size_t)strlen (src);
mb_cur_max = MB_CUR_MAX;
tmp = mbrlen((const char *)src, (l < mb_cur_max) ? l : mb_cur_max, ps);
if (_rl_utf8locale && l > 0 && UTF8_SINGLEBYTE(*src))
tmp = (*src != 0) ? 1 : 0;
else
{
mb_cur_max = MB_CUR_MAX;
tmp = mbrlen((const char *)src, (l < mb_cur_max) ? l : mb_cur_max, ps);
}
if (tmp == (size_t)(-2))
{
/* shorted to compose multibyte char */
/* too short to compose multibyte char */
if (ps)
memset (ps, 0, sizeof(mbstate_t));
return -2;
+7 -6
View File
@@ -214,6 +214,9 @@ int _rl_eof_char = CTRL ('D');
/* Non-zero makes this the next keystroke to read. */
int rl_pending_input = 0;
/* If non-zero when readline_internal returns, it means we found EOF */
int _rl_eof_found = 0;
/* Pointer to a useful terminal name. */
const char *rl_terminal_name = (const char *)NULL;
@@ -222,7 +225,7 @@ int _rl_horizontal_scroll_mode = 0;
/* Non-zero means to display an asterisk at the starts of history lines
which have been modified. */
int _rl_mark_modified_lines = 0;
int _rl_mark_modified_lines = 0;
/* The style of `bell' notification preferred. This can be set to NO_BELL,
AUDIBLE_BELL, or VISIBLE_BELL. */
@@ -664,11 +667,9 @@ readline_internal_charloop (void)
static char *
readline_internal (void)
{
int eof;
readline_internal_setup ();
eof = readline_internal_charloop ();
return (readline_internal_teardown (eof));
_rl_eof_found = readline_internal_charloop ();
return (readline_internal_teardown (_rl_eof_found));
}
void
@@ -1055,7 +1056,7 @@ _rl_subseq_result (int r, Keymap map, int key, int got_subseq)
/* We probably shadowed a keymap, so keep going. */
r = _rl_dispatch (ANYOTHERKEY, m);
}
else if (r && map[ANYOTHERKEY].function)
else if (r < 0 && map[ANYOTHERKEY].function)
{
/* We didn't match (r is probably -1), so return something to
tell the caller that it should try ANYOTHERKEY for an
+2 -2
View File
@@ -39,8 +39,8 @@ extern "C" {
#endif
/* Hex-encoded Readline version number. */
#define RL_READLINE_VERSION 0x0700 /* Readline 7.0 */
#define RL_VERSION_MAJOR 7
#define RL_READLINE_VERSION 0x0800 /* Readline 8.0 */
#define RL_VERSION_MAJOR 8
#define RL_VERSION_MINOR 0
/* Readline data structures. */
+2
View File
@@ -173,6 +173,8 @@ _rl_wcwidth (wc)
#endif
#define UTF8_SINGLEBYTE(c) (((c) & 0x80) == 0)
#define UTF8_MBFIRSTCHAR(c) (((c) & 0xc0) == 0xc0)
#define UTF8_MBCHAR(c) (((c) & 0xc0) == 0x80)
#else /* !HANDLE_MULTIBYTE */
+2
View File
@@ -382,6 +382,7 @@ extern void _rl_set_cursor PARAMS((int, int));
extern void _rl_fix_point PARAMS((int));
extern int _rl_replace_text PARAMS((const char *, int, int));
extern int _rl_forward_char_internal PARAMS((int));
extern int _rl_backward_char_internal PARAMS((int));
extern int _rl_insert_char PARAMS((int, int));
extern int _rl_overwrite_char PARAMS((int, int));
extern int _rl_overwrite_rubout PARAMS((int, int));
@@ -511,6 +512,7 @@ extern FILE *_rl_in_stream;
extern FILE *_rl_out_stream;
extern int _rl_last_command_was_kill;
extern int _rl_eof_char;
extern int _rl_eof_found;
extern procenv_t _rl_top_level;
extern _rl_keyseq_cxt *_rl_kscxt;
extern int _rl_keyseq_timeout;
+5 -1
View File
@@ -691,7 +691,11 @@ rl_deprep_terminal (void)
tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
if (terminal_prepped & TPX_BRACKPASTE)
fprintf (rl_outstream, BRACK_PASTE_FINI);
{
fprintf (rl_outstream, BRACK_PASTE_FINI);
if (_rl_eof_found)
fprintf (rl_outstream, "\n");
}
if (_rl_enable_keypad)
_rl_control_keypad (0);
+30 -3
View File
@@ -297,13 +297,40 @@ _rl_forward_char_internal (int count)
#endif
if (rl_end < 0)
rl_end = 0;
rl_end = 0;
#else
point = rl_point + count;
if (point > rl_end)
point = rl_end;
#endif
if (point > rl_end)
point = rl_end;
return (point);
}
int
_rl_backward_char_internal (int count)
{
int point;
point = rl_point;
#if defined (HANDLE_MULTIBYTE)
if (count > 0)
{
while (count > 0 && point > 0)
{
point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO);
count--;
}
if (count > 0)
return 0; /* XXX - rl_ding() here? */
}
#else
if (count > 0)
point -= count;
#endif
if (point < 0)
point = 0;
return (point);
}
+168 -74
View File
@@ -1,7 +1,7 @@
/* vi_mode.c -- A vi emulation mode for Bash.
Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
/* Copyright (C) 1987-2017 Free Software Foundation, Inc.
/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
@@ -63,6 +63,19 @@
#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
#endif
/* Increment START to the next character in RL_LINE_BUFFER, handling multibyte chars */
#if defined (HANDLE_MULTIBYTE)
#define INCREMENT_POS(start) \
do { \
if (MB_CUR_MAX == 1 || rl_byte_oriented) \
start++; \
else \
start = _rl_find_next_mbchar (rl_line_buffer, start, 1, MB_FIND_ANY); \
} while (0)
#else /* !HANDLE_MULTIBYTE */
#define INCREMENT_POS(start) (start)++
#endif /* !HANDLE_MULTIBYTE */
/* This is global so other parts of the code can check whether the last
command was a text modification command. */
int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
@@ -118,7 +131,7 @@ static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
static void vi_save_insert_buffer PARAMS ((int, int));
static void _rl_vi_backup PARAMS((void));
static inline void _rl_vi_backup PARAMS((void));
static int _rl_vi_arg_dispatch PARAMS((int));
static int rl_digit_loop1 PARAMS((void));
@@ -126,6 +139,9 @@ static int rl_digit_loop1 PARAMS((void));
static int _rl_vi_set_mark PARAMS((void));
static int _rl_vi_goto_mark PARAMS((void));
static inline int _rl_vi_advance_point PARAMS((void));
static inline int _rl_vi_backup_point PARAMS((void));
static void _rl_vi_append_forward PARAMS((int));
static int _rl_vi_callback_getchar PARAMS((char *, int));
@@ -383,7 +399,7 @@ rl_vi_complete (int ignore, int key)
{
if (!whitespace (rl_line_buffer[rl_point + 1]))
rl_vi_end_word (1, 'E');
rl_point++;
_rl_vi_advance_point ();
}
if (key == '*')
@@ -451,6 +467,69 @@ rl_vi_next_word (int count, int key)
return (0);
}
static inline int
_rl_vi_advance_point (void)
{
int point;
point = rl_point;
if (rl_point < rl_end)
#if defined (HANDLE_MULTIBYTE)
{
if (MB_CUR_MAX == 1 || rl_byte_oriented)
rl_point++;
else
{
point = rl_point;
rl_point = _rl_forward_char_internal (1);
if (point == rl_point || rl_point > rl_end)
rl_point = rl_end;
}
}
#else
rl_point++;
#endif
return point;
}
/* Move the cursor back one character. */
static inline void
_rl_vi_backup (void)
{
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
else
rl_point--;
}
/* Move the point back one character, returning the starting value and not
doing anything at the beginning of the line */
static inline int
_rl_vi_backup_point (void)
{
int point;
point = rl_point;
if (rl_point > 0)
#if defined (HANDLE_MULTIBYTE)
{
if (MB_CUR_MAX == 1 || rl_byte_oriented)
rl_point--;
else
{
point = rl_point;
rl_point = _rl_backward_char_internal (1);
if (rl_point < 0)
rl_point = 0; /* XXX - not really necessary */
}
}
#else
rl_point--;
#endif
return point;
}
/* Move to the end of the ?next? word. */
int
rl_vi_end_word (int count, int key)
@@ -476,11 +555,11 @@ rl_vi_fWord (int count, int ignore)
{
/* Skip until whitespace. */
while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
_rl_vi_advance_point ();
/* Now skip whitespace. */
while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
_rl_vi_advance_point ();
}
return (0);
}
@@ -497,12 +576,18 @@ rl_vi_bWord (int count, int ignore)
rl_point--;
while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
rl_point--;
_rl_vi_backup_point ();
if (rl_point > 0)
{
while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
rl_point++;
do
_rl_vi_backup_point ();
while (rl_point > 0 && !whitespace (rl_line_buffer[rl_point]));
if (rl_point > 0) /* hit whitespace */
rl_point++;
if (rl_point < 0)
rl_point = 0;
}
}
return (0);
@@ -511,28 +596,32 @@ rl_vi_bWord (int count, int ignore)
int
rl_vi_eWord (int count, int ignore)
{
int opoint;
while (count-- && rl_point < (rl_end - 1))
{
if (!whitespace (rl_line_buffer[rl_point]))
rl_point++;
if (whitespace (rl_line_buffer[rl_point]) == 0)
_rl_vi_advance_point ();
/* Move to the next non-whitespace character (to the start of the
next word). */
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
rl_point++;
_rl_vi_advance_point ();
if (rl_point && rl_point < rl_end)
{
opoint = rl_point;
/* Skip whitespace. */
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
rl_point++;
opoint = _rl_vi_advance_point (); /* XXX - why? */
/* Skip until whitespace. */
while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
rl_point++;
opoint = _rl_vi_advance_point ();
/* Move back to the last character of the word. */
rl_point--;
rl_point = opoint;
}
}
return (0);
@@ -541,24 +630,28 @@ rl_vi_eWord (int count, int ignore)
int
rl_vi_fword (int count, int ignore)
{
int opoint;
while (count-- && rl_point < (rl_end - 1))
{
/* Move to white space (really non-identifer). */
if (_rl_isident (rl_line_buffer[rl_point]))
{
while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
_rl_vi_advance_point ();
}
else /* if (!whitespace (rl_line_buffer[rl_point])) */
{
while (!_rl_isident (rl_line_buffer[rl_point]) &&
!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
_rl_vi_advance_point ();
}
opoint = rl_point;
/* Move past whitespace. */
while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
opoint = _rl_vi_advance_point ();
}
return (0);
}
@@ -566,9 +659,11 @@ rl_vi_fword (int count, int ignore)
int
rl_vi_bword (int count, int ignore)
{
int opoint;
while (count-- && rl_point > 0)
{
int last_is_ident;
int prev_is_ident, cur_is_ident;
/* If we are at the start of a word, move back to whitespace
so we will go back to the start of the previous word. */
@@ -581,22 +676,35 @@ rl_vi_bword (int count, int ignore)
back so we don't get messed up by the rl_point++ down there in
the while loop. Without this code, words like `l;' screw up the
function. */
last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
(!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
rl_point--;
cur_is_ident = _rl_isident (rl_line_buffer[rl_point]);
opoint = _rl_vi_backup_point ();
prev_is_ident = _rl_isident (rl_line_buffer[rl_point]);
if ((cur_is_ident && !prev_is_ident) || (!cur_is_ident && prev_is_ident))
; /* leave point alone, we backed it up one character */
else
rl_point = opoint;
while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
rl_point--;
_rl_vi_backup_point ();
if (rl_point > 0)
{
opoint = rl_point;
if (_rl_isident (rl_line_buffer[rl_point]))
while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
do
opoint = _rl_vi_backup_point ();
while (rl_point > 0 && _rl_isident (rl_line_buffer[rl_point]));
else
while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
do
opoint = _rl_vi_backup_point ();
while (rl_point > 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
!whitespace (rl_line_buffer[rl_point]));
rl_point++;
if (rl_point > 0)
rl_point = opoint;
if (rl_point < 0)
rl_point = 0;
}
}
return (0);
@@ -605,23 +713,34 @@ rl_vi_bword (int count, int ignore)
int
rl_vi_eword (int count, int ignore)
{
while (count-- && rl_point < rl_end - 1)
int opoint;
while (count-- && rl_point < (rl_end - 1))
{
if (!whitespace (rl_line_buffer[rl_point]))
rl_point++;
if (whitespace (rl_line_buffer[rl_point]) == 0)
_rl_vi_advance_point ();
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
rl_point++;
_rl_vi_advance_point ();
opoint = rl_point;
if (rl_point < rl_end)
{
if (_rl_isident (rl_line_buffer[rl_point]))
while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
do
{
opoint = _rl_vi_advance_point ();
}
while (rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
else
while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
do
{
opoint = _rl_vi_advance_point ();
}
while (rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
&& !whitespace (rl_line_buffer[rl_point]));
}
rl_point--;
rl_point = opoint;
}
return (0);
}
@@ -637,20 +756,7 @@ rl_vi_insert_beg (int count, int key)
static void
_rl_vi_append_forward (int key)
{
int point;
if (rl_point < rl_end)
{
if (MB_CUR_MAX == 1 || rl_byte_oriented)
rl_point++;
else
{
point = rl_point;
rl_point = _rl_forward_char_internal (1);
if (point == rl_point)
rl_point = rl_end;
}
}
_rl_vi_advance_point ();
}
int
@@ -859,7 +965,7 @@ _rl_vi_change_mbchar_case (int count)
rl_begin_undo_group ();
rl_vi_delete (1, 0);
if (rl_point < p) /* Did we retreat at EOL? */
rl_point++; /* XXX - should we advance more than 1 for mbchar? */
_rl_vi_advance_point ();
rl_insert_text (mb);
rl_end_undo_group ();
rl_vi_check ();
@@ -931,27 +1037,12 @@ rl_vi_put (int count, int key)
return (0);
}
/* Move the cursor back one character. */
static void
_rl_vi_backup (void)
{
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
else
rl_point--;
}
/* Move the cursor back one character if you're at the end of the line */
int
rl_vi_check (void)
{
if (rl_point && rl_point == rl_end)
{
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
else
rl_point--;
}
_rl_vi_backup ();
return (0);
}
@@ -962,7 +1053,10 @@ rl_vi_column (int count, int key)
if (count > rl_end)
rl_end_of_line (1, key);
else
rl_point = count - 1;
{
rl_point = 0;
rl_point = _rl_forward_char_internal (count - 1);
}
return (0);
}
@@ -1113,7 +1207,7 @@ _rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m)
non-whitespace character, move back one (presumably to whitespace). */
if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
!whitespace (rl_line_buffer[rl_point]))
rl_point--;
rl_point--; /* XXX */
/* If cw or cW, back up to the end of a word, so the behaviour of ce
or cE is the actual result. Brute-force, no subtlety. */
@@ -1126,14 +1220,14 @@ _rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m)
/* Posix.2 says that if cw or cW moves the cursor towards the end of
the line, the character under the cursor should be deleted. */
if (rl_point == rl_mark)
rl_point++;
_rl_vi_advance_point ();
else
{
/* Move past the end of the word so that the kill doesn't
remove the last letter of the previous word. Only do this
if we are not at the end of the line. */
if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
rl_point++;
_rl_vi_advance_point ();
}
}
@@ -1271,7 +1365,7 @@ vi_delete_dispatch (_rl_vimotion_cxt *m)
mark. */
if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
(rl_mark < rl_end))
rl_mark++;
INCREMENT_POS (rl_mark);
rl_kill_text (rl_point, rl_mark);
return (0);
@@ -1334,7 +1428,7 @@ vi_change_dispatch (_rl_vimotion_cxt *m)
and already leave the mark at the correct location. */
if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
(rl_mark < rl_end))
rl_mark++;
INCREMENT_POS (rl_mark);
/* The cursor never moves with c[wW]. */
if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
@@ -1421,7 +1515,7 @@ vi_yank_dispatch (_rl_vimotion_cxt *m)
mark. */
if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
(rl_mark < rl_end))
rl_mark++;
INCREMENT_POS (rl_mark);
rl_begin_undo_group ();
rl_kill_text (rl_point, rl_mark);
@@ -1611,8 +1705,8 @@ rl_vi_unix_word_rubout (int count, int key)
while (rl_point && vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
rl_point--;
else if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0)
while (rl_point && (vi_unix_word_boundary (rl_line_buffer[rl_point - 1]) == 0))
rl_point--;
while (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point - 1]) == 0))
_rl_vi_backup_point ();
}
rl_kill_text (orig_point, rl_point);
@@ -2100,7 +2194,7 @@ rl_vi_possible_completions (void)
{
while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
rl_line_buffer[rl_point] != ';')
rl_point++;
_rl_vi_advance_point ();
}
else if (rl_line_buffer[rl_point - 1] == ';')
{
+9 -2
View File
@@ -92,7 +92,8 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \
wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \
casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c
strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \
utf8.c
# The header files for this library.
HSOURCES =
@@ -107,7 +108,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \
fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o \
wcsnwidth.o ${LIBOBJS}
utf8.o wcsnwidth.o ${LIBOBJS}
SUPPORT = Makefile
@@ -200,6 +201,7 @@ tmpfile.o: tmpfile.c
uconvert.o: uconvert.c
ufuncs.o: ufuncs.c
unicode.o: unicode.c
utf8.o: utf8.c
vprint.o: vprint.c
wcsdup.o: wcsdup.c
wcsnwidth.o: wcsnwidth.c
@@ -277,6 +279,7 @@ tmpfile.o: ${BUILD_DIR}/config.h
uconvert.o: ${BUILD_DIR}/config.h
ufuncs.o: ${BUILD_DIR}/config.h
unicode.o: ${BUILD_DIR}/config.h
utf8.o: ${BUILD_DIR}/config.h
vprint.o: ${BUILD_DIR}/config.h
wcsdup.o: ${BUILD_DIR}/config.h
wcsnwidth.o: ${BUILD_DIR}/config.h
@@ -612,6 +615,10 @@ unicode.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
unicode.o: ${BASHINCDIR}/stdc.h
unicode.o: ${topdir}/xmalloc.h
utf8.o: ${topdir}/bashansi.h
utf8.o: ${BASHINCDIR}/ansi_stdlib.h
utf8.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
winsize.o: ${BASHINCDIR}/stdc.h
winsize.o: ${topdir}/xmalloc.h
winsize.o: ${topdir}/bashtypes.h
+1 -1
View File
@@ -69,7 +69,7 @@ getenv (name)
if (var && exported_p (var))
return (value_cell (var));
}
else
else if (environ)
{
register int i, len;
+1 -7
View File
@@ -32,13 +32,7 @@ extern int locale_utf8locale;
#undef mbschr
static inline char *
utf8_mbschr (s, c)
const char *s;
int c;
{
return strchr (s, c); /* for now */
}
extern char *utf8_mbschr (const char *, int); /* XXX */
/* In some locales, the non-first byte of some multibyte characters have
the same value as some ascii character. Faced with these strings, a
+5 -1
View File
@@ -1,6 +1,6 @@
/* mbscmp - multibyte string comparison. */
/* Copyright (C) 1995-2015 Free Software Foundation, Inc.
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -26,6 +26,10 @@
#include <stddef.h>
#include <string.h>
extern int locale_utf8locale;
extern int utf8_mbscmp (const char *, const char *);
/* Compare MBS1 and MBS2. */
int
mbscmp (mbs1, mbs2)
+3 -124
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2001, 2006, 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
/* Copyright (C) 2001, 2006, 2009, 2010, 2012, 2015-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,102 +45,9 @@ const unsigned int is_basic_table [UCHAR_MAX / 32 + 1] =
extern int locale_utf8locale;
/* We can optimize this if we know the locale is UTF-8, but needs to handle
malformed byte sequences. */
static inline size_t
utf8_mbstrlen(s)
const char *s;
{
size_t num = 0;
register unsigned char c;
extern char *utf8_mbsmbchar (const char *);
extern int utf8_mblen (const char *, size_t);
while ((c = *s++))
/* bytes 0xc0 through 0xff are first byte of multi-byte sequence */
if ((c & 0xc0) != 0x80) /* skip continuation bytes */
++num;
return (num);
}
/* Adapted from GNU libutf8 */
static inline int
utf8_mblen (s, n)
const char *s;
int n;
{
unsigned char c;
if (s == 0)
return 0;
else if (n == 0)
return -1;
c = (unsigned char) *s;
if (c < 0x80)
return (c != 0);
else if (c < 0xc0)
goto return_error;
else
{
const char *start = s;
size_t count;
int check_unsafe;
if (c < 0xe0)
{
count = 1;
if (c < 0xc2)
goto return_error;
check_unsafe = 0;
}
else if (c < 0xf0)
{
count = 2;
check_unsafe = (c == 0xe0);
}
#if SIZEOF_WCHAR_T == 4
else if (c < 0xf8)
{
count = 3;
check_unsafe = (c == 0xe0);
}
else if (c < 0xfc)
{
count = 4;
check_unsafe = (c == 0xf8);
}
else if (c < 0xfe)
{
count = 5;
check_unsafe = (c == 0xfc);
}
#endif
else
goto return_error;
if (n <= count)
return -1;
s++;
c = (unsigned char) *s++ ^ 0x80;
if (c >= 0x40)
goto return_error;
if (--count > 0)
{
if (check_unsafe && ((c >> (6 - count)) == 0))
goto return_error;
do
{
c = (unsigned char) *s++ ^ 0x80;
if (c >= 0x40)
goto return_error;
}
while (--count > 0);
}
return s - start;
}
return_error:
errno = EILSEQ;
return -1;
}
/* Count the number of characters in S, counting multi-byte characters as a
single character. */
size_t
@@ -170,18 +77,6 @@ mbstrlen (s)
return nc;
}
static inline char *
utf8_mbsmbchar (str)
const char *str;
{
register char *s;
for (s = (char *)str; *s; s++)
if ((*s & 0xc0) == 0x80)
return s;
return (0);
}
/* Return pointer to first multibyte char in S, or NULL if none. */
/* XXX - if we know that the locale is UTF-8, we can just check whether or
not any byte has the eighth bit turned on */
@@ -219,22 +114,6 @@ mbsmbchar (s)
return 0;
}
static inline int
utf_mbsnlen(src, srclen, maxlen)
const char *src;
size_t srclen;
int maxlen;
{
register int sind, count;
for (sind = count = 0; src[sind] && sind <= maxlen; sind++)
{
if ((src[sind] & 0xc0) != 0x80)
count++;
}
return (count);
}
int
sh_mbsnlen(src, srclen, maxlen)
const char *src;
+2
View File
@@ -142,9 +142,11 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
302 / 1000 is log10 (2) rounded up;
add one for integer division truncation;
add one more for a minus sign if t is signed. */
#ifndef INT_STRLEN_BOUND
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
+ 1 + TYPE_SIGNED (t))
#endif
/* conversion flags */
#define PF_ALTFORM 0x00001 /* # */
+147
View File
@@ -0,0 +1,147 @@
/* utf8.c - UTF-8 character handling functions */
/* Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash 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 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include "bashansi.h"
#include "shmbutil.h"
extern int locale_mb_cur_max;
extern int locale_utf8locale;
#if defined (HANDLE_MULTIBYTE)
char *
utf8_mbschr (s, c)
const char *s;
int c;
{
return strchr (s, c); /* for now */
}
int
utf8_mbscmp (s1, s2)
const char *s1, *s2;
{
/* Use the fact that the UTF-8 encoding preserves lexicographic order. */
return strcmp (s1, s2);
}
char *
utf8_mbsmbchar (str)
const char *str;
{
register char *s;
for (s = (char *)str; *s; s++)
if ((*s & 0xc0) == 0x80)
return s;
return (0);
}
int
utf8_mbsnlen(src, srclen, maxlen)
const char *src;
size_t srclen;
int maxlen;
{
register int sind, count;
for (sind = count = 0; src[sind] && sind <= maxlen; sind++)
{
if ((src[sind] & 0xc0) != 0x80)
count++;
}
return (count);
}
/* Adapted from GNU gnulib */
int
utf8_mblen (s, n)
const char *s;
size_t n;
{
unsigned char c, c1;
if (s == 0)
return (0); /* no shift states */
if (n <= 0)
return (-1);
c = (unsigned char)*s;
if (c < 0x80)
return (c != 0);
if (c >= 0xc2)
{
c1 = (unsigned char)s[1];
if (c < 0xe0)
{
if (n >= 2 && (s[1] ^ 0x80) < 0x40)
return 2;
}
else if (c < 0xf0)
{
if (n >= 3
&& (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (c >= 0xe1 || c1 >= 0xa0)
&& (c != 0xed || c1 < 0xa0))
return 3;
}
else if (c < 0xf8)
{
if (n >= 4
&& (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40
&& (c >= 0xf1 || c1 >= 0x90)
&& (c < 0xf4 || (c == 0xf4 && c1 < 0x90)))
return 4;
}
}
/* invalid or incomplete multibyte character */
return -1;
}
/* We can optimize this if we know the locale is UTF-8, but needs to handle
malformed byte sequences. */
size_t
utf8_mbstrlen(s)
const char *s;
{
size_t clen, nc;
int mb_cur_max;
nc = 0;
mb_cur_max = MB_CUR_MAX;
while (*s && (clen = (size_t)utf8_mblen(s, mb_cur_max)) != 0)
{
if (MB_INVALIDCH(clen))
clen = 1; /* assume single byte */
s += clen;
nc++;
}
return nc;
}
#endif