mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-11 22:20:49 +02:00
bash-5.0-beta release
This commit is contained in:
+60
-10
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ;;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user