mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-11 06:00:49 +02:00
printf changes: %q/%Q altform, %ls/%lc wide character strings; posix mode changes for function execution; allow <( and >) in function names
This commit is contained in:
+69
-1
@@ -5135,7 +5135,7 @@ subst.c
|
||||
lib/readline/histfile.c
|
||||
- history_write_slow: a fallback function that uses stdio to write the
|
||||
history list to a supplied file descriptor
|
||||
- history_do_write: call history_write_slow if ftrucate/mmap/malloc
|
||||
- history_do_write: call history_write_slow if ftruncate/mmap/malloc
|
||||
fail; hope the simpler approach works
|
||||
|
||||
1/27
|
||||
@@ -5183,3 +5183,71 @@ parse.y
|
||||
|
||||
subst.c
|
||||
- use locale_mb_cur_max instead of MB_CUR_MAX consistently
|
||||
|
||||
2/1
|
||||
---
|
||||
builtins/printf.def
|
||||
- printf_builtin: %q and %Q use the `alternate form' flag to force
|
||||
single quoting instead of backslash quoting. $'...' is still
|
||||
preferred if there are characters that require it
|
||||
- getwidestr, getwidechar: functions to take a possibly multibyte
|
||||
character string and convert to a wide character string or a wide
|
||||
character, respectively
|
||||
- convwidestr, convwidechar: functions to take a wide character string
|
||||
or single character, apply any precision, convert back to a multibyte
|
||||
character string, and return the result for printing
|
||||
- printf_builtin: consistently print an error message if printstr()
|
||||
returns < 0, since it will only do that if ferror(stdout) is true;
|
||||
let the PRETURN macro do that if appropriate, so we don't duplicate
|
||||
code
|
||||
|
||||
2/2
|
||||
---
|
||||
builtins/printf.def
|
||||
- printwidestr: wide-character version of printstr; understands
|
||||
fieldwidth and precision as characters instead of bytes
|
||||
- printf_builtin: interpret %ls and %lc as referring to wide strings
|
||||
and characters, respectively; use printwidestr to print the wide-
|
||||
character string obtained from the (presumably multibyte) argument.
|
||||
Fieldwidth and precision are characters, not bytes
|
||||
|
||||
2/3
|
||||
---
|
||||
builtins/set.def
|
||||
- unset_builtin: since tokenize_array_reference modifies its NAME
|
||||
argument, we need to restore the original word if there is no
|
||||
array variable found with that name, so we can do ahead and try to
|
||||
unset a function with that wonky name. Inspired by a report from
|
||||
Emanuele Torre <torreemanuele6@gmail.com>
|
||||
|
||||
parse.y
|
||||
- read_token_word: don't set the W_HASDOLLAR flag in the returned WORD
|
||||
for <(command) and >(command). That way they can be used in function
|
||||
names.
|
||||
|
||||
execute_cmd.c
|
||||
- execute_simple_command: if in posix mode, don't perform function
|
||||
lookup for command names that contain a slash
|
||||
|
||||
builtins/enable.def
|
||||
- dyn_load_builtins: don't allow dynamically loaded builtins to have
|
||||
slashes in their name
|
||||
|
||||
2/4
|
||||
---
|
||||
general.c
|
||||
- valid_function_word: new function, used to check whether a word can
|
||||
be used as a function name. Replaces call to check_identifier();
|
||||
incorporates POSIX interp 383 check for special builtin so we can
|
||||
move it out of execute_intern_function().
|
||||
- valid_function_name: use the FLAGS argument instead of POSIXLY_CORRECT;
|
||||
only reject reserved words if FLAGS&1
|
||||
|
||||
execute_cmd.c
|
||||
- execute_intern_function: call valid_function_word() instead of
|
||||
check_identifier(); remove check for special builtin that
|
||||
valid_function_word performs
|
||||
|
||||
print_cmd.c
|
||||
- print_function_def,named_function_string: pass POSIXLY_CORRECT to
|
||||
valid_function_name as the FLAGS argument
|
||||
|
||||
@@ -1216,6 +1216,7 @@ tests/intl.tests f
|
||||
tests/intl1.sub f
|
||||
tests/intl2.sub f
|
||||
tests/intl3.sub f
|
||||
tests/intl4.sub f
|
||||
tests/intl.right f
|
||||
tests/iquote.tests f
|
||||
tests/iquote.right f
|
||||
|
||||
Vendored
+1
@@ -1770,6 +1770,7 @@ AC_CHECK_FUNC(wcscoll, AC_DEFINE(HAVE_WCSCOLL))
|
||||
AC_CHECK_FUNC(wcsdup, AC_DEFINE(HAVE_WCSDUP))
|
||||
AC_CHECK_FUNC(wcwidth, AC_DEFINE(HAVE_WCWIDTH))
|
||||
AC_CHECK_FUNC(wctype, AC_DEFINE(HAVE_WCTYPE))
|
||||
AC_CHECK_FUNC(wcsnrtombs, AC_DEFINE(HAVE_WCSNRTOMBS))
|
||||
|
||||
AC_REPLACE_FUNCS(wcswidth)
|
||||
|
||||
|
||||
@@ -384,6 +384,11 @@ dyn_load_builtin (WORD_LIST *list, int flags, char *filename)
|
||||
for (replaced = 0, new = 0; list; list = list->next)
|
||||
{
|
||||
name = list->word->word;
|
||||
if (absolute_program (name))
|
||||
{
|
||||
builtin_error (_("%s: builtin names may not contain slashes"), name);
|
||||
continue;
|
||||
}
|
||||
|
||||
size = strlen (name);
|
||||
struct_name = (char *)xmalloc (size + 8);
|
||||
|
||||
+233
-30
@@ -1,7 +1,7 @@
|
||||
This file is printf.def, from which is created printf.c.
|
||||
It implements the builtin "printf" in Bash.
|
||||
|
||||
Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -232,6 +232,9 @@ static intmax_t asciicode (void);
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static wchar_t *getwidestr (size_t *);
|
||||
static wint_t getwidechar (void);
|
||||
static char *convwidestr (wchar_t *, int);
|
||||
static char *convwidechar (wint_t, int);
|
||||
static int printwidestr (char *, wchar_t *, size_t, int, int);
|
||||
#endif
|
||||
|
||||
static WORD_LIST *garglist, *orig_arglist;
|
||||
@@ -250,11 +253,22 @@ static intmax_t tw;
|
||||
static char *conv_buf;
|
||||
static size_t conv_bufsize;
|
||||
|
||||
static inline int
|
||||
decodeprec (char *ps)
|
||||
{
|
||||
int mpr;
|
||||
|
||||
mpr = *ps++ - '0';
|
||||
while (DIGIT (*ps))
|
||||
mpr = (mpr * 10) + (*ps++ - '0');
|
||||
return mpr;
|
||||
}
|
||||
|
||||
int
|
||||
printf_builtin (WORD_LIST *list)
|
||||
{
|
||||
int ch, fieldwidth, precision;
|
||||
int have_fieldwidth, have_precision, use_Lmod, altform;
|
||||
int have_fieldwidth, have_precision, use_Lmod, altform, longform;
|
||||
char convch, thisch, nextch, *format, *modstart, *precstart, *fmt, *start;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
char mbch[25]; /* 25 > MB_LEN_MAX, plus can handle 4-byte UTF-8 and large Unicode characters*/
|
||||
@@ -345,7 +359,7 @@ printf_builtin (WORD_LIST *list)
|
||||
for (fmt = format; *fmt; fmt++)
|
||||
{
|
||||
precision = fieldwidth = 0;
|
||||
have_fieldwidth = have_precision = altform = 0;
|
||||
have_fieldwidth = have_precision = altform = longform = 0;
|
||||
precstart = 0;
|
||||
|
||||
if (*fmt == '\\')
|
||||
@@ -435,6 +449,7 @@ printf_builtin (WORD_LIST *list)
|
||||
while (*fmt && strchr (LENMODS, *fmt))
|
||||
{
|
||||
use_Lmod |= USE_LONG_DOUBLE && *fmt == 'L';
|
||||
longform |= *fmt == 'l';
|
||||
fmt++;
|
||||
}
|
||||
|
||||
@@ -457,6 +472,22 @@ printf_builtin (WORD_LIST *list)
|
||||
{
|
||||
char p;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (longform)
|
||||
{
|
||||
wchar_t wc, ws[2];
|
||||
int r;
|
||||
|
||||
wc = getwidechar ();
|
||||
ws[0] = wc;
|
||||
ws[1] = L'\0';
|
||||
|
||||
r = printwidestr (start, ws, 1, fieldwidth, precision);
|
||||
if (r < 0)
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
p = getchr ();
|
||||
PF(start, p);
|
||||
break;
|
||||
@@ -465,7 +496,21 @@ printf_builtin (WORD_LIST *list)
|
||||
case 's':
|
||||
{
|
||||
char *p;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (longform)
|
||||
{
|
||||
wchar_t *wp;
|
||||
size_t slen;
|
||||
int r;
|
||||
|
||||
wp = getwidestr (&slen);
|
||||
r = printwidestr (start, wp, slen, fieldwidth, precision);
|
||||
free (wp);
|
||||
if (r < 0)
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
p = getstr ();
|
||||
PF(start, p);
|
||||
break;
|
||||
@@ -537,14 +582,7 @@ printf_builtin (WORD_LIST *list)
|
||||
modstart[1] = '\0';
|
||||
r = printstr (start, timebuf, strlen (timebuf), fieldwidth, precision); /* XXX - %s for now */
|
||||
if (r < 0)
|
||||
{
|
||||
if (ferror (stdout) == 0)
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
}
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -581,14 +619,7 @@ printf_builtin (WORD_LIST *list)
|
||||
in XP -- printf does not handle that well. */
|
||||
r = printstr (start, xp, rlen, fieldwidth, precision);
|
||||
if (r < 0)
|
||||
{
|
||||
if (ferror (stdout) == 0)
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
}
|
||||
retval = EXECUTION_FAILURE;
|
||||
}
|
||||
retval = EXECUTION_FAILURE;
|
||||
free (xp);
|
||||
}
|
||||
|
||||
@@ -609,9 +640,7 @@ printf_builtin (WORD_LIST *list)
|
||||
/* Decode precision and apply it to the unquoted string. */
|
||||
if (convch == 'Q' && precstart)
|
||||
{
|
||||
mpr = *precstart++ - '0';
|
||||
while (DIGIT (*precstart))
|
||||
mpr = (mpr * 10) + (*precstart++ - '0');
|
||||
mpr = decodeprec (precstart);
|
||||
/* Error if precision > INT_MAX here? */
|
||||
precision = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
|
||||
slen = strlen (p);
|
||||
@@ -623,23 +652,21 @@ printf_builtin (WORD_LIST *list)
|
||||
xp = savestring ("''");
|
||||
else if (ansic_shouldquote (p))
|
||||
xp = ansic_quote (p, 0, (int *)0);
|
||||
else if (altform)
|
||||
xp = sh_single_quote (p);
|
||||
else
|
||||
xp = sh_backslash_quote (p, 0, 3);
|
||||
if (xp)
|
||||
{
|
||||
slen = strlen (xp);
|
||||
if (convch == 'Q')
|
||||
{
|
||||
slen = strlen (xp);
|
||||
if (slen > precision)
|
||||
precision = slen;
|
||||
}
|
||||
/* Use printstr to get fieldwidth and precision right. */
|
||||
r = printstr (start, xp, strlen (xp), fieldwidth, precision);
|
||||
if (r < 0)
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
}
|
||||
r = printstr (start, xp, slen, fieldwidth, precision);
|
||||
/* Let PRETURN print the error message. */
|
||||
free (xp);
|
||||
}
|
||||
|
||||
@@ -765,7 +792,10 @@ printf_erange (char *s)
|
||||
STRING: expanded string argument
|
||||
LEN: length of expanded string
|
||||
FIELDWIDTH: argument for width of `*'
|
||||
PRECISION: argument for precision of `*' */
|
||||
PRECISION: argument for precision of `*'
|
||||
|
||||
Returns -1 on detectable write error, 0 otherwise. */
|
||||
|
||||
static int
|
||||
printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
|
||||
{
|
||||
@@ -873,6 +903,114 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
|
||||
|
||||
return (ferror (stdout) ? -1 : 0);
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* A wide-character version of printstr */
|
||||
static int
|
||||
printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int precision)
|
||||
{
|
||||
#if 0
|
||||
char *s;
|
||||
#endif
|
||||
char *string;
|
||||
int padlen, nc, ljust, i;
|
||||
int fw, pr; /* fieldwidth and precision */
|
||||
intmax_t mfw, mpr;
|
||||
|
||||
if (wstring == 0)
|
||||
wstring = L"";
|
||||
|
||||
#if 0
|
||||
s = fmt;
|
||||
#endif
|
||||
if (*fmt == '%')
|
||||
fmt++;
|
||||
|
||||
ljust = fw = 0;
|
||||
pr = -1;
|
||||
mfw = 0;
|
||||
mpr = -1;
|
||||
|
||||
/* skip flags */
|
||||
while (strchr (SKIP1, *fmt))
|
||||
{
|
||||
if (*fmt == '-')
|
||||
ljust = 1;
|
||||
fmt++;
|
||||
}
|
||||
|
||||
/* get fieldwidth, if present. rely on caller to clamp fieldwidth at INT_MAX */
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
fw = fieldwidth;
|
||||
if (fw < 0)
|
||||
{
|
||||
fw = -fw;
|
||||
ljust = 1;
|
||||
}
|
||||
}
|
||||
else if (DIGIT (*fmt))
|
||||
{
|
||||
mfw = *fmt++ - '0';
|
||||
while (DIGIT (*fmt))
|
||||
mfw = (mfw * 10) + (*fmt++ - '0');
|
||||
/* Error if fieldwidth > INT_MAX here? */
|
||||
fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw;
|
||||
}
|
||||
|
||||
/* get precision, if present. doesn't handle negative precisions */
|
||||
if (*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
pr = precision;
|
||||
}
|
||||
else if (DIGIT (*fmt))
|
||||
{
|
||||
mpr = *fmt++ - '0';
|
||||
while (DIGIT (*fmt))
|
||||
mpr = (mpr * 10) + (*fmt++ - '0');
|
||||
/* Error if precision > INT_MAX here? */
|
||||
pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
|
||||
if (pr < precision && precision < INT_MAX)
|
||||
pr = precision; /* XXX */
|
||||
}
|
||||
else
|
||||
pr = 0; /* "a null digit string is treated as zero" */
|
||||
}
|
||||
|
||||
/* chars from wide string to print */
|
||||
nc = (pr >= 0 && pr <= len) ? pr : len;
|
||||
|
||||
padlen = fw - nc;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (ljust)
|
||||
padlen = -padlen;
|
||||
|
||||
/* leading pad characters */
|
||||
for (; padlen > 0; padlen--)
|
||||
PC (' ');
|
||||
|
||||
/* convert WSTRING to multibyte character STRING, honoring PRECISION */
|
||||
string = convwidestr (wstring, pr);
|
||||
|
||||
/* output STRING, assuming that convwidestr has taken care of the precision
|
||||
and returned only the necessary bytes. */
|
||||
for (i = 0; string[i]; i++)
|
||||
PC (string[i]);
|
||||
|
||||
/* output any necessary trailing padding */
|
||||
for (; padlen < 0; padlen++)
|
||||
PC (' ');
|
||||
|
||||
free (string);
|
||||
return (ferror (stdout) ? -1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Convert STRING by expanding the escape sequences specified by the
|
||||
POSIX standard for printf's `%b' format string. If SAWC is non-null,
|
||||
@@ -1387,4 +1525,69 @@ getwidechar (void)
|
||||
garglist = garglist->next;
|
||||
return (wc);
|
||||
}
|
||||
|
||||
/* The basic approach is to take the wide character string, apply any
|
||||
precision in terms of characters (otherwise the precision is useless),
|
||||
compute the size of the output buffer, call wcsrtombs to convert back
|
||||
to multibyte characters, and return the result. */
|
||||
static char *
|
||||
convwidestr (wchar_t *ws, int prec)
|
||||
{
|
||||
const wchar_t *ts;
|
||||
wchar_t wc;
|
||||
char *ret;
|
||||
size_t rlen, rsize;
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
ts = (const wchar_t *)ws;
|
||||
|
||||
if (prec > 0)
|
||||
{
|
||||
rsize = prec * MB_CUR_MAX;
|
||||
ret = (char *)xmalloc (rsize + 1);
|
||||
#if defined (HAVE_WCSNRTOMBS)
|
||||
rlen = wcsnrtombs (ret, &ts, prec, rsize, &state);
|
||||
#else
|
||||
wc = ws[prec];
|
||||
ws[prec] = L'\0';
|
||||
rlen = wcsrtombs (ret, &ts, rsize, &state);
|
||||
ws[prec] = wc;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rlen = wcsrtombs (NULL, &ts, 0, &state);
|
||||
if (rlen != (size_t)-1)
|
||||
{
|
||||
memset (&state, '\0', sizeof (mbstate_t));
|
||||
ret = (char *)xmalloc (rlen + 1);
|
||||
rlen = wcsrtombs (ret, &ts, rlen, &state);
|
||||
}
|
||||
else
|
||||
ret = (char *)xmalloc (1);
|
||||
}
|
||||
if (MB_INVALIDCH (rlen))
|
||||
rlen = 0;
|
||||
|
||||
ret[rlen] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
convwidechar (wint_t wi, int prec)
|
||||
{
|
||||
wchar_t wc;
|
||||
char *ret;
|
||||
size_t rlen;
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
wc = (wchar_t)wi;
|
||||
ret = (char *)xmalloc (MB_LEN_MAX + 1);
|
||||
rlen = wcrtomb (ret, wc, &state);
|
||||
if (MB_INVALIDCH (rlen))
|
||||
rlen = 0;
|
||||
|
||||
ret[rlen] = '\0';
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
+30
-5
@@ -812,6 +812,16 @@ $END
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
#define RESTORE_NAME() \
|
||||
do { \
|
||||
tname = name + strlen (name); \
|
||||
if (tname == t - 1) /* probably a paranoid check */ \
|
||||
{ \
|
||||
tname[0] = '['; \
|
||||
t[strlen (t)] = ']'; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
unset_builtin (WORD_LIST *list)
|
||||
{
|
||||
@@ -874,14 +884,13 @@ unset_builtin (WORD_LIST *list)
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
vflags = builtin_arrayref_flags (list->word, base_vflags);
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
unset_array = 0;
|
||||
/* XXX valid array reference second arg was 0 */
|
||||
if (!unset_function && nameref == 0 && tokenize_array_reference (name, vflags, &t))
|
||||
/* XXX tokenize_array_reference modifies NAME if it succeeds */
|
||||
if (unset_function == 0 && nameref == 0 && tokenize_array_reference (name, vflags, &t))
|
||||
unset_array = 1;
|
||||
#endif
|
||||
|
||||
/* Get error checking out of the way first. The low-level functions
|
||||
just perform the unset, relying on the caller to verify. */
|
||||
valid_id = legal_identifier (name);
|
||||
@@ -891,6 +900,10 @@ unset_builtin (WORD_LIST *list)
|
||||
treat them as potential shell function names. */
|
||||
if (global_unset_func == 0 && global_unset_var == 0 && valid_id == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (unset_array)
|
||||
RESTORE_NAME ();
|
||||
#endif
|
||||
unset_variable = unset_array = 0;
|
||||
unset_function = 1;
|
||||
}
|
||||
@@ -926,8 +939,20 @@ unset_builtin (WORD_LIST *list)
|
||||
find a function after unsuccessfully searching for a variable,
|
||||
note that we're acting on a function now as if -f were
|
||||
supplied. The readonly check below takes care of it. */
|
||||
if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
|
||||
if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
/* We modified NAME in the call to tokenize_array_reference, so we
|
||||
need to restore it here. We turned the original `[' and `]' into
|
||||
NULL, to isolate the array name and subscript. This only happens
|
||||
if tokenize_array_reference succeeds with a non-NULL subscript
|
||||
pointer, and UNSET_ARRAY is set to 1 only in this case. */
|
||||
if (unset_array)
|
||||
{
|
||||
RESTORE_NAME();
|
||||
unset_array = 0;
|
||||
}
|
||||
#endif
|
||||
if (var = find_function (name))
|
||||
unset_function = 1;
|
||||
}
|
||||
|
||||
@@ -948,6 +948,9 @@
|
||||
/* Define if you have the wcsdup function. */
|
||||
#undef HAVE_WCSDUP
|
||||
|
||||
/* Define if you have the wcsnrtombs function. */
|
||||
#undef HAVE_WCSNRTOMBS
|
||||
|
||||
/* Define if you have the wctype function. */
|
||||
#undef HAVE_WCTYPE
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# From configure.ac for Bash 5.2, version 5.047.
|
||||
# From configure.ac for Bash 5.2, version 5.048.
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for bash 5.2-maint.
|
||||
#
|
||||
@@ -16365,6 +16365,13 @@ then :
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "wcsnrtombs" "ac_cv_func_wcsnrtombs"
|
||||
if test "x$ac_cv_func_wcsnrtombs" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_WCSNRTOMBS 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "wcswidth" "ac_cv_func_wcswidth"
|
||||
if test "x$ac_cv_func_wcswidth" = xyes
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ dnl report bugs to chet@po.cwru.edu
|
||||
dnl
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
# Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1987-2023 Free Software Foundation, Inc.
|
||||
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_REVISION([for Bash 5.2, version 5.047])dnl
|
||||
AC_REVISION([for Bash 5.2, version 5.048])dnl
|
||||
|
||||
define(bashvers, 5.2)
|
||||
define(relstatus, maint)
|
||||
|
||||
@@ -8218,6 +8218,11 @@ causes a fatal syntax error in non-interactive shells.
|
||||
Function names may not be the same as one of the @sc{posix} special
|
||||
builtins.
|
||||
|
||||
@item
|
||||
Even if a shell function whose name contains a slash was defined before
|
||||
entering @sc{posix} mode, the shell will not execute a function whose name
|
||||
contains one or more slashes.
|
||||
|
||||
@item
|
||||
@sc{posix} special builtins are found before shell functions
|
||||
during command lookup.
|
||||
|
||||
+4
-12
@@ -4480,7 +4480,7 @@ execute_simple_command (SIMPLE_COM *simple_command, int pipe_in, int pipe_out, i
|
||||
builtin_is_special = 1;
|
||||
}
|
||||
if (builtin == 0)
|
||||
func = find_function (words->word->word);
|
||||
func = (posixly_correct == 0 || absolute_program (words->word->word) == 0) ? find_function (words->word->word) : 0;
|
||||
}
|
||||
|
||||
/* What happens in posix mode when an assignment preceding a command name
|
||||
@@ -6022,12 +6022,12 @@ execute_intern_function (WORD_DESC *name, FUNCTION_DEF *funcdef)
|
||||
SHELL_VAR *var;
|
||||
char *t;
|
||||
|
||||
if (check_identifier (name, posixly_correct) == 0)
|
||||
if (valid_function_word (name, posixly_correct) == 0)
|
||||
{
|
||||
if (posixly_correct && interactive_shell == 0)
|
||||
if (posixly_correct)
|
||||
{
|
||||
last_command_exit_value = EX_BADUSAGE;
|
||||
jump_to_top_level (ERREXIT);
|
||||
jump_to_top_level (interactive_shell ? DISCARD : ERREXIT);
|
||||
}
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
@@ -6039,14 +6039,6 @@ execute_intern_function (WORD_DESC *name, FUNCTION_DEF *funcdef)
|
||||
name->word = t;
|
||||
}
|
||||
|
||||
/* Posix interpretation 383 */
|
||||
if (posixly_correct && find_special_builtin (name->word))
|
||||
{
|
||||
internal_error (_("`%s': is a special builtin"), name->word);
|
||||
last_command_exit_value = EX_BADUSAGE;
|
||||
jump_to_top_level (interactive_shell ? DISCARD : ERREXIT);
|
||||
}
|
||||
|
||||
var = find_function (name->word);
|
||||
if (var && (readonly_p (var) || noassign_p (var)))
|
||||
{
|
||||
|
||||
@@ -404,20 +404,55 @@ legal_alias_name (const char *string, int flags)
|
||||
}
|
||||
|
||||
/* Return 1 if this is a valid identifer that can be used to declare a function
|
||||
without the `function' reserved word. FLAGS is currently unused; a
|
||||
placeholder for the future. */
|
||||
without the `function' reserved word. FLAGS&1 means to reject POSIX
|
||||
non-identifiers and reserved words; FLAGS&2 means to suppress the check
|
||||
for ASSIGNMENT_WORD. So you can pass posixly_correct as FLAGS and get
|
||||
POSIX checks. */
|
||||
int
|
||||
valid_function_name (const char *name, int flags)
|
||||
{
|
||||
if (find_reserved_word (name) >= 0)
|
||||
if ((flags & 1) && find_reserved_word (name) >= 0)
|
||||
return 0;
|
||||
if (posixly_correct && (all_digits (name) || legal_identifier (name) == 0))
|
||||
if ((flags & 1) && (all_digits (name) || legal_identifier (name) == 0))
|
||||
return 0;
|
||||
if (assignment (name, 0)) /* difference between WORD and ASSIGNMENT_WORD */
|
||||
/* pass flags & 2 to suppress this check */
|
||||
if ((flags & 2) == 0 && assignment (name, 0)) /* difference between WORD and ASSIGNMENT_WORD */
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return 1 if this is an identifier that can be used as a function name
|
||||
when declaring a function. We don't allow `$' for historical reasons.
|
||||
We allow quotes (for now), slashes, and pretty much everything else.
|
||||
If FLAGS is non-zero (it's usually posixly_correct), we check the name
|
||||
for additional posix restrictions using valid_function_name(). We pass
|
||||
flags|2 to valid_function_name to suppress the check for an assignment
|
||||
word, since we want to allow those here. */
|
||||
int
|
||||
valid_function_word (WORD_DESC *word, int flags)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = word->word;
|
||||
if ((word->flags & W_HASDOLLAR)) /* allow quotes for now */
|
||||
{
|
||||
internal_error (_("`%s': not a valid identifier"), name);
|
||||
return (0);
|
||||
}
|
||||
/* POSIX interpretation 383 */
|
||||
if (flags && find_special_builtin (name))
|
||||
{
|
||||
internal_error (_("`%s': is a special builtin"), name);
|
||||
return (0);
|
||||
}
|
||||
if (flags && valid_function_name (name, flags|2) == 0)
|
||||
{
|
||||
internal_error (_("`%s': not a valid identifier"), name);
|
||||
return (0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns non-zero if STRING is an assignment statement. The returned value
|
||||
is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment
|
||||
and require an array subscript before the `=' to denote an assignment
|
||||
|
||||
@@ -322,6 +322,7 @@ extern int valid_nameref_value (const char *, int);
|
||||
extern int check_selfref (const char *, char *, int);
|
||||
extern int legal_alias_name (const char *, int);
|
||||
extern int valid_function_name (const char *, int);
|
||||
extern int valid_function_word (WORD_DESC *, int);
|
||||
extern int line_isblank (const char *);
|
||||
extern int assignment (const char *, int);
|
||||
|
||||
|
||||
@@ -5176,7 +5176,7 @@ read_token_word (int character)
|
||||
strcpy (token + token_index, ttok);
|
||||
token_index += ttoklen;
|
||||
FREE (ttok);
|
||||
dollar_present = 1;
|
||||
dollar_present |= character == '$';
|
||||
all_digit_token = 0;
|
||||
goto next_character;
|
||||
}
|
||||
|
||||
+5
-4
@@ -1265,10 +1265,12 @@ print_function_def (FUNCTION_DEF *func)
|
||||
`function' to words that are not valid POSIX identifiers. */
|
||||
if (posixly_correct == 0)
|
||||
cprintf ("function %s () \n", func->name->word);
|
||||
else if (valid_function_name (func->name->word, 0) == 0)
|
||||
else if (valid_function_name (func->name->word, posixly_correct) == 0)
|
||||
cprintf ("function %s () \n", func->name->word);
|
||||
else
|
||||
cprintf ("%s () \n", func->name->word);
|
||||
|
||||
begin_unwind_frame ("function-def");
|
||||
add_unwind_protect (reset_locals, 0);
|
||||
|
||||
indent (indentation);
|
||||
@@ -1305,8 +1307,7 @@ print_function_def (FUNCTION_DEF *func)
|
||||
was_heredoc = 0; /* not printing any here-documents now */
|
||||
}
|
||||
|
||||
remove_unwind_protect (); /* unwind_protect_pointer */
|
||||
remove_unwind_protect (); /* reset_locals */
|
||||
discard_unwind_frame ("function-def");
|
||||
}
|
||||
|
||||
/* Return the string representation of the named function.
|
||||
@@ -1331,7 +1332,7 @@ named_function_string (char *name, COMMAND *command, int flags)
|
||||
|
||||
if (name && *name)
|
||||
{
|
||||
if (valid_function_name (name, 0) == 0)
|
||||
if (valid_function_name (name, posixly_correct) == 0)
|
||||
cprintf ("function ");
|
||||
cprintf ("%s ", name);
|
||||
}
|
||||
|
||||
@@ -55,3 +55,13 @@ Passed all 1378 Unicode tests
|
||||
$'5\247@3\231+\306S8\237\242\352\263'
|
||||
+ : $'5\247@3\231+\306S8\237\242\352\263'
|
||||
+ set +x
|
||||
ಇಳಿಕೆಗಳು
|
||||
ಇಳ
|
||||
ಇ
|
||||
ಇಳ
|
||||
ಇಳ
|
||||
ಇಳ ---
|
||||
ಇ
|
||||
ಇ
|
||||
ಇ
|
||||
ಇ ---
|
||||
|
||||
@@ -66,3 +66,5 @@ ${THIS_SH} ./unicode1.sub # 2>/dev/null
|
||||
${THIS_SH} ./unicode2.sub
|
||||
|
||||
${THIS_SH} ./unicode3.sub 2>&1
|
||||
|
||||
${THIS_SH} ./intl4.sub
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# printf "%ls" and "%lc" format specifiers for multibyte characters with
|
||||
# field width and precision in characters instead of bytes
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
V=ಇಳಿಕೆಗಳು
|
||||
V2=${V:0:2}
|
||||
V3=${V:0:1}
|
||||
|
||||
printf "%ls\n" "$V"
|
||||
printf "%ls\n" "$V2"
|
||||
printf "%lc\n" "$V"
|
||||
printf "%.2ls\n" "$V"
|
||||
|
||||
printf "%4.2ls\n" "$V"
|
||||
printf "%-4.2ls---\n" "$V"
|
||||
|
||||
printf "%ls\n" "$V3"
|
||||
printf "%lc\n" "$V3"
|
||||
|
||||
printf "%4.2lc\n" "$V3"
|
||||
printf "%-4.2lc---\n" "$V3"
|
||||
@@ -326,9 +326,6 @@ printf "<%3s><%3b>\n"
|
||||
|
||||
# tests variable assignment with -v
|
||||
${THIS_SH} ./printf1.sub
|
||||
|
||||
${THIS_SH} ./printf2.sub
|
||||
|
||||
${THIS_SH} ./printf3.sub
|
||||
|
||||
${THIS_SH} ./printf4.sub
|
||||
|
||||
Reference in New Issue
Block a user