commit bash-20120224 snapshot

This commit is contained in:
Chet Ramey
2012-03-05 21:17:40 -05:00
parent 1f6ec1a86f
commit 863d31ae77
18 changed files with 1811 additions and 465 deletions
+61 -5
View File
@@ -13196,6 +13196,16 @@ trap.c
- use BLOCK_SIGNAL/UNBLOCK_SIGNAL instead of code dependent on
HAVE_POSIX_SIGNALS and BSD signals
1/24
----
print_cmd.c
- print_redirection_list: change the conditions under which
r_duplicating_output_word is mapped to r_err_and_out to more or
less match those used in redir.c. Fixes bug pointed out by
Dan Douglas <ormaaj@gmail.com>
1/29
----
lib/readline/signals.c
@@ -13386,12 +13396,58 @@ lib/sh/unicode.c
- u32reset: new function, resets local static state to uninitialized
(locale information, currently)
lib/sh/strtrans.c
- ansicstr: allocate a new string 6 times longer than the original
if the \U escape sequence appears, to accommodate UTF-8 chars
of maximum theoretical length
locale.c
- call u32reset whenever LC_CTYPE/LC_ALL/LANG is changed to reset the
cached locale information used by u32cconv. From a report from
John Kearney <dethrophes@web.de>
2/21
----
doc/{bash,builtins}.1
- minor changes from Bjarni Ingi Gislason <bjarniig@rhi.hi.is>
lib/sh/unicode.c
- u32cconv: only assume you can directly call wctomb on the passed
value if __STDC_ISO_10646__ is defined and the value is <=
0x7fffffff
- stub_charset: return locale as default instead of "ASCII", let
rest of code decide what to do with it
lib/readline/parens.c
- _rl_enable_paren_matching: make paren matching work in vi insert
mode. Bug report from <derflob@derflob.de>
2/22
----
lib/sh/shquote.c
- sh_backslash_quote: quote tilde in places where it would be
expanded. From a report from John Kearney <dethrophes@web.de>
2/23
----
execute_cmd.c
- execute_pipeline: wrap the discard_unwind_frame call in #ifdef
JOB_CONTROL, since the frame is only created if JOB_CONTROL is
defined. Bug and fix from Doug Kehn <rdkehn@yahoo.com>
2/25
----
error.c
- report_error: make sure last_command_exit_value is non-zero before
we call exit_shell, since the exit trap may reference it. Call
exit_shell with last_command_exit_value to allow exit statuses
other than 1
unicode.c
- stub_charset: use local static buffer to hold charset, don't change
value returned by get_locale_var. Based on idea and code from
John Kearney <dethrophes@web.de>
- u32toutf16: function to convert unsigned 32-bit value (unicode) to
UTF-16. From John Kearney <dethrophes@web.de>
- u32cconv: call u32toutf16 if __STDC_ISO_10646__ defined and wchar_t
is two bytes, send result to wcstombs, return if not encoding error.
From John Kearney <dethrophes@web.de>
- u32cconv: return UTF-8 conversion if iconv conversion to local
charset is unsupported
+61 -6
View File
@@ -13196,6 +13196,16 @@ trap.c
- use BLOCK_SIGNAL/UNBLOCK_SIGNAL instead of code dependent on
HAVE_POSIX_SIGNALS and BSD signals
1/24
----
print_cmd.c
- print_redirection_list: change the conditions under which
r_duplicating_output_word is mapped to r_err_and_out to more or
less match those used in redir.c. Fixes bug pointed out by
Dan Douglas <ormaaj@gmail.com>
1/29
----
lib/readline/signals.c
@@ -13386,11 +13396,56 @@ lib/sh/unicode.c
- u32reset: new function, resets local static state to uninitialized
(locale information, currently)
lib/sh/strtrans.c
- ansicstr: allocate a new string 6 times longer than the original
if the \U escape sequence appears, to accommodate UTF-8 chars
of maximum theoretical length
locale.c
- call u32reset whenever LC_CTYPE/LC_ALL/LANG is changed to reset the
cached locale information used by u32cconv
cached locale information used by u32cconv. From a report from
John Kearney <dethrophes@web.de>
2/21
----
doc/{bash,builtins}.1
- minor changes from Bjarni Ingi Gislason <bjarniig@rhi.hi.is>
lib/sh/unicode.c
- u32cconv: only assume you can directly call wctomb on the passed
value if __STDC_ISO_10646__ is defined and the value is <=
0x7fffffff
- stub_charset: return locale as default instead of "ASCII", let
rest of code decide what to do with it
lib/readline/parens.c
- _rl_enable_paren_matching: make paren matching work in vi insert
mode. Bug report from <derflob@derflob.de>
2/22
----
lib/sh/shquote.c
- sh_backslash_quote: quote tilde in places where it would be
expanded. From a report from John Kearney <dethrophes@web.de>
2/23
----
execute_cmd.c
- execute_pipeline: wrap the discard_unwind_frame call in #ifdef
JOB_CONTROL, since the frame is only created if JOB_CONTROL is
defined. Bug and fix from Doug Kehn <rdkehn@yahoo.com>
2/25
----
error.c
- report_error: make sure last_command_exit_value is non-zero before
we call exit_shell, since the exit trap may reference it. Call
exit_shell with last_command_exit_value to allow exit statuses
other than 1
unicode.c
- stub_charset: use local static buffer to hold charset, don't change
value returned by get_locale_var. Based on idea and code from
John Kearney <dethrophes@web.de>
- u32toutf16: function to convert unsigned 32-bit value (unicode) to
UTF-16. From John Kearney <dethrophes@web.de>
- u32cconv: call u32toutf16 if __STDC_ISO_10646__ defined and wchar_t
is two bytes, send result to wcstombs, return if not encoding error.
From John Kearney <dethrophes@web.de>
+21
View File
@@ -0,0 +1,21 @@
#include <stdio.h>
main()
{
union {
long int l;
char c[sizeof(long int)];
} u;
int x0, x1, x2, x3;
u.l = 1;
x0 = u.c[0];
x3 = u.c[sizeof (long int) - 1];
printf ("x0 = %d x3 = %d (%s)\n", x0, x3, x3 == 1 ? "bigendian" : "littleendian");
x0 = u.l >> 24;
x1 = u.l >> 16;
x2 = u.l >> 8;
x3 = u.l & 0xff;
printf ("x0:x3: %d %d %d %d\n", x0, x1, x2, x3);
}
+13
View File
@@ -0,0 +1,13 @@
#include <stdio.h>
int
main()
{
int i = 0x12345678;
char *x;
x = (char *)&i;
printf ("0x%x\n", *x);
printf ((*x == 0x78) ? "little endian\n" : "big endian\n");
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#include <stdio.h>
main()
{
union {
int l;
char c[sizeof(int)];
} u;
int x0, x1, x2, x3;
u.l = 0x012345678;
x0 = u.c[0];
x3 = u.c[sizeof (int) - 1];
printf ("x0 = 0x%x x3 = 0x%x (%s)\n", x0, x3, x3 == 0x78 ? "bigendian" : "littleendian");
x0 = (u.l >> 24) & 0xff;
x1 = (u.l >> 16) & 0xff;
x2 = (u.l >> 8) & 0xff;
x3 = u.l & 0xff;
printf ("big endian x0:x3: %x %x %x %x\n", x0, x1, x2, x3);
}
+4
View File
@@ -505,10 +505,14 @@ po/fr.gmo f
po/fr.po f
po/ga.gmo f
po/ga.po f
po/gl.gmo f
po/gl.po f
po/hu.gmo f
po/hu.po f
po/id.gmo f
po/id.po f
po/it.gmo f
po/it.po f
po/ja.gmo f
po/ja.po f
po/lt.gmo f
+1 -1
View File
@@ -6377,7 +6377,7 @@ is similar to the history expansion in
This section describes what syntax features are available. This
feature is enabled by default for interactive shells, and can be
disabled using the
.B \+H
.B +H
option to the
.B set
builtin command (see
+8 -1
View File
@@ -1,6 +1,13 @@
.\" This is a hack to force bash builtins into the whatis database
.\" and to get the list of builtins to come up with the man command.
.TH BASH_BUILTINS 1 "2004 Apr 20" "GNU Bash-4.0"
.\"
.\" File Name macro. This used to be `.PN', for Path Name,
.\" but Sun doesn't seem to like that very much.
.\"
.de FN
\fI\|\\$1\|\fP
..
.TH BASH_BUILTINS 1 "2004 Apr 20" "GNU Bash-4.2"
.SH NAME
bash, :, ., [, alias, bg, bind, break, builtin, caller,
cd, command, compgen, complete,
+5 -1
View File
@@ -200,7 +200,11 @@ report_error (format, va_alist)
va_end (args);
if (exit_immediately_on_error)
exit_shell (1);
{
if (last_command_exit_value == 0)
last_command_exit_value = 1;
exit_shell (last_command_exit_value);
}
}
void
+455
View File
@@ -0,0 +1,455 @@
/* error.c -- Functions for handling errors. */
/* Copyright (C) 1993-2009 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"
#include "bashtypes.h"
#include <fcntl.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <stdio.h>
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include "bashansi.h"
#include "bashintl.h"
#include "shell.h"
#include "flags.h"
#include "input.h"
#if defined (HISTORY)
# include "bashhist.h"
#endif
extern int executing_line_number __P((void));
extern int last_command_exit_value;
extern char *shell_name;
#if defined (JOB_CONTROL)
extern pid_t shell_pgrp;
extern int give_terminal_to __P((pid_t, int));
#endif /* JOB_CONTROL */
#if defined (ARRAY_VARS)
extern const char * const bash_badsub_errmsg;
#endif
static void error_prolog __P((int));
/* The current maintainer of the shell. You change this in the
Makefile. */
#if !defined (MAINTAINER)
#define MAINTAINER "bash-maintainers@gnu.org"
#endif
const char * const the_current_maintainer = MAINTAINER;
int gnu_error_format = 0;
static void
error_prolog (print_lineno)
int print_lineno;
{
char *ename;
int line;
ename = get_name_for_error ();
line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1;
if (line > 0)
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line);
else
fprintf (stderr, "%s: ", ename);
}
/* Return the name of the shell or the shell script for error reporting. */
char *
get_name_for_error ()
{
char *name;
#if defined (ARRAY_VARS)
SHELL_VAR *bash_source_v;
ARRAY *bash_source_a;
#endif
name = (char *)NULL;
if (interactive_shell == 0)
{
#if defined (ARRAY_VARS)
bash_source_v = find_variable ("BASH_SOURCE");
if (bash_source_v && array_p (bash_source_v) &&
(bash_source_a = array_cell (bash_source_v)))
name = array_reference (bash_source_a, 0);
if (name == 0 || *name == '\0') /* XXX - was just name == 0 */
#endif
name = dollar_vars[0];
}
if (name == 0 && shell_name && *shell_name)
name = base_pathname (shell_name);
if (name == 0)
#if defined (PROGRAM)
name = PROGRAM;
#else
name = "bash";
#endif
return (name);
}
/* Report an error having to do with FILENAME. This does not use
sys_error so the filename is not interpreted as a printf-style
format string. */
void
file_error (filename)
const char *filename;
{
report_error ("%s: %s", filename, strerror (errno));
}
void
#if defined (PREFER_STDARG)
programming_error (const char *format, ...)
#else
programming_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
char *h;
#if defined (JOB_CONTROL)
give_terminal_to (shell_pgrp, 0);
#endif /* JOB_CONTROL */
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
#if defined (HISTORY)
if (remember_on_history)
{
h = last_history_line ();
fprintf (stderr, _("last command: %s\n"), h ? h : "(null)");
}
#endif
#if 0
fprintf (stderr, "Report this to %s\n", the_current_maintainer);
#endif
fprintf (stderr, _("Aborting..."));
fflush (stderr);
abort ();
}
/* Print an error message and, if `set -e' has been executed, exit the
shell. Used in this file by file_error and programming_error. Used
outside this file mostly to report substitution and expansion errors,
and for bad invocation options. */
void
#if defined (PREFER_STDARG)
report_error (const char *format, ...)
#else
report_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (1);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
if (exit_immediately_on_error)
exit_shell (1);
}
void
#if defined (PREFER_STDARG)
fatal_error (const char *format, ...)
#else
fatal_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (0);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
sh_exit (2);
}
void
#if defined (PREFER_STDARG)
internal_error (const char *format, ...)
#else
internal_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (1);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
}
void
#if defined (PREFER_STDARG)
internal_warning (const char *format, ...)
#else
internal_warning (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (1);
fprintf (stderr, _("warning: "));
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
}
void
#if defined (PREFER_STDARG)
sys_error (const char *format, ...)
#else
sys_error (format, va_alist)
const char *format;
va_dcl
#endif
{
int e;
va_list args;
e = errno;
error_prolog (0);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, ": %s\n", strerror (e));
va_end (args);
}
/* An error from the parser takes the general form
shell_name: input file name: line number: message
The input file name and line number are omitted if the shell is
currently interactive. If the shell is not currently interactive,
the input file name is inserted only if it is different from the
shell name. */
void
#if defined (PREFER_STDARG)
parser_error (int lineno, const char *format, ...)
#else
parser_error (lineno, format, va_alist)
int lineno;
const char *format;
va_dcl
#endif
{
va_list args;
char *ename, *iname;
ename = get_name_for_error ();
iname = yy_input_name ();
if (interactive)
fprintf (stderr, "%s: ", ename);
else if (interactive_shell)
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);
else if (STREQ (ename, iname))
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno);
else
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
if (exit_immediately_on_error)
exit_shell (last_command_exit_value = 2);
}
#ifdef DEBUG
void
#if defined (PREFER_STDARG)
itrace (const char *format, ...)
#else
itrace (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
fprintf(stderr, "TRACE: pid %ld: ", (long)getpid());
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
fflush(stderr);
}
/* A trace function for silent debugging -- doesn't require a control
terminal. */
void
#if defined (PREFER_STDARG)
trace (const char *format, ...)
#else
trace (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
static FILE *tracefp = (FILE *)NULL;
if (tracefp == NULL)
tracefp = fopen("/tmp/bash-trace.log", "a+");
if (tracefp == NULL)
tracefp = stderr;
else
fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */
fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid());
SH_VA_START (args, format);
vfprintf (tracefp, format, args);
fprintf (tracefp, "\n");
va_end (args);
fflush(tracefp);
}
#endif /* DEBUG */
/* **************************************************************** */
/* */
/* Common error reporting */
/* */
/* **************************************************************** */
static const char * const cmd_error_table[] = {
N_("unknown command error"), /* CMDERR_DEFAULT */
N_("bad command type"), /* CMDERR_BADTYPE */
N_("bad connector"), /* CMDERR_BADCONN */
N_("bad jump"), /* CMDERR_BADJUMP */
0
};
void
command_error (func, code, e, flags)
const char *func;
int code, e, flags; /* flags currently unused */
{
if (code > CMDERR_LAST)
code = CMDERR_DEFAULT;
programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e);
}
char *
command_errstr (code)
int code;
{
if (code > CMDERR_LAST)
code = CMDERR_DEFAULT;
return (_(cmd_error_table[code]));
}
#ifdef ARRAY_VARS
void
err_badarraysub (s)
const char *s;
{
report_error ("%s: %s", s, _(bash_badsub_errmsg));
}
#endif
void
err_unboundvar (s)
const char *s;
{
report_error (_("%s: unbound variable"), s);
}
void
err_readonly (s)
const char *s;
{
report_error (_("%s: readonly variable"), s);
}
+2
View File
@@ -2370,7 +2370,9 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
unfreeze_jobs_list ();
}
#if defined (JOB_CONTROL)
discard_unwind_frame ("lastpipe-exec");
#endif
return (exec_result);
}
+4
View File
@@ -226,6 +226,10 @@ sh_backslash_quote (string, table)
*r++ = '\\';
else if (c == '#' && s == string) /* comment char */
*r++ = '\\';
else if (c == '~' && (s == string || s[-1] == ':' || s[-1] == '='))
/* Tildes are special at the start of a word or after a `:' or `='
(technically unquoted, but it doesn't make a difference in practice) */
*r++ = '\\';
*r++ = c;
}
+1 -4
View File
@@ -60,10 +60,7 @@ ansicstr (string, len, flags, sawc, rlen)
return ((char *)NULL);
#if defined (HANDLE_MULTIBYTE)
if (strstr (string, "\\U") != 0)
ret = (char *)xmalloc (6*len + 1);
else
ret = (char *)xmalloc (4*len + 1);
ret = (char *)xmalloc (4*len + 1);
#else
ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
#endif
+61 -34
View File
@@ -1,6 +1,6 @@
/* unicode.c - functions to convert unicode characters */
/* Copyright (C) 2010 Free Software Foundation, Inc.
/* Copyright (C) 2010-2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -61,6 +61,8 @@ static iconv_t localconv;
#endif
#ifndef HAVE_LOCALE_CHARSET
static char charsetbuf[40];
static char *
stub_charset ()
{
@@ -68,19 +70,21 @@ stub_charset ()
locale = get_locale_var ("LC_CTYPE");
if (locale == 0 || *locale == 0)
return "ASCII";
{
strcpy (charsetbuf, "ASCII");
return charsetbuf;
}
s = strrchr (locale, '.');
if (s)
{
t = strchr (s, '@');
strcpy (charsetbuf, s+1);
t = strchr (charsetbuf, '@');
if (t)
*t = 0;
return ++s;
return charsetbuf;
}
else if (STREQ (locale, "UTF-8"))
return "UTF-8";
else
return "ASCII";
strcpy (charsetbuf, locale);
return charsetbuf;
}
#endif
@@ -93,14 +97,12 @@ u32reset ()
/* u32toascii ? */
int
u32tochar (wc, s)
wchar_t wc;
u32tochar (x, s)
unsigned long x;
char *s;
{
unsigned long x;
int l;
x = wc;
l = (x <= UCHAR_MAX) ? 1 : ((x <= USHORT_MAX) ? 2 : 4);
if (x <= UCHAR_MAX)
@@ -165,7 +167,7 @@ u32toutf8 (wc, s)
s[4] = (wc & 0x3f) | 0x80;
l = 5;
}
else
else if (wc < 0x080000000)
{
s[0] = (wc >> 30) | 0xf8;
s[1] = ((wc >> 24) & 0x3f) | 0x80;
@@ -175,11 +177,39 @@ u32toutf8 (wc, s)
s[5] = (wc & 0x3f) | 0x80;
l = 6;
}
else
l = 0;
s[l] = '\0';
return l;
}
/* Convert a 32-bit unsigned int (unicode) to a UTF-16 string. Rarely used,
only if sizeof(wchar_t) == 2. */
int
u32toutf16 (c, s)
u_bits32_t c;
unsigned short *s;
{
int l;
l = 0;
if (c < 0x0d800)
{
s[0] = (unsigned short) (c & 0xFFFF);
l = 1;
}
else if (c >= 0x0e000 && c <= 0x010ffff)
{
c -= 0x010000;
s[0] = (unsigned short)((c >> 10) + 0xd800);
s[1] = (unsigned short)((c & 0x3ff) + 0xdc00);
l = 2;
}
s[l] = 0;
return l;
}
/* convert a single unicode-32 character into a multibyte string and put the
result in S, which must be large enough (at least MB_LEN_MAX bytes) */
int
@@ -188,6 +218,7 @@ u32cconv (c, s)
char *s;
{
wchar_t wc;
wchar_t ws[3];
int n;
#if HAVE_ICONV
const char *charset;
@@ -197,14 +228,16 @@ u32cconv (c, s)
size_t sn;
#endif
wc = c;
#if __STDC_ISO_10646__
if (sizeof (wchar_t) == 4)
{
n = wctomb (s, wc);
return n;
}
wc = c;
if (sizeof (wchar_t) == 4 && c <= 0x7fffffff)
n = wctomb (s, wc);
else if (sizeof (wchar_t) == 2 && c <= 0x10ffff && u32toutf16 (c, ws))
n = wcstombs (s, ws, MB_LEN_MAX);
else
n = -1;
if (n != -1)
return n;
#endif
#if HAVE_NL_LANGINFO
@@ -236,19 +269,9 @@ u32cconv (c, s)
u32init = 1;
}
if (utf8locale)
{
n = u32toutf8 (c, s);
return n;
}
if (localconv == (iconv_t)-1)
{
n = u32tochar (wc, s);
return n;
}
n = u32toutf8 (c, s);
if (utf8locale || localconv == (iconv_t)-1)
return n;
optr = obuf;
obytesleft = sizeof (obuf);
@@ -268,8 +291,12 @@ u32cconv (c, s)
return (optr - obuf);
#endif
n = u32tochar (wc, s); /* fallback */
n = u32tochar (c, s); /* fallback */
return n;
}
#else
void
u32reset ()
{
}
#endif /* HANDLE_MULTIBYTE */
+319
View File
@@ -0,0 +1,319 @@
/* unicode.c - functions to convert unicode characters */
/* Copyright (C) 2010-2012 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>
#if defined (HANDLE_MULTIBYTE)
#include <stdc.h>
#include <wchar.h>
#include <bashansi.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <limits.h>
#if HAVE_ICONV
# include <iconv.h>
#endif
#include <xmalloc.h>
#ifndef USHORT_MAX
# ifdef USHRT_MAX
# define USHORT_MAX USHRT_MAX
# else
# define USHORT_MAX ((unsigned short) ~(unsigned short)0)
# endif
#endif
#if !defined (STREQ)
# define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
#endif /* !STREQ */
#if defined (HAVE_LOCALE_CHARSET)
extern const char *locale_charset __P((void));
#else
extern char *get_locale_var __P((char *));
#endif
static int u32init = 0;
static int utf8locale = 0;
#if defined (HAVE_ICONV)
static iconv_t localconv;
#endif
#ifndef HAVE_LOCALE_CHARSET
static char charsetbuf[40];
static char *
stub_charset ()
{
char *locale, *s, *t;
locale = get_locale_var ("LC_CTYPE");
if (locale == 0 || *locale == 0)
{
strcpy (charsetbuf, "ASCII");
return charsetbuf;
}
s = strrchr (locale, '.');
if (s)
{
strcpy (charsetbuf, s+1);
t = strchr (charsetbuf, '@');
if (t)
*t = 0;
return charsetbuf;
}
strcpy (charsetbuf, locale);
return charsetbuf;
}
#endif
void
u32reset ()
{
u32init = 0;
utf8locale = 0;
}
/* u32toascii ? */
int
u32tochar (x, s)
unsigned long x;
char *s;
{
int l;
l = (x <= UCHAR_MAX) ? 1 : ((x <= USHORT_MAX) ? 2 : 4);
if (x <= UCHAR_MAX)
s[0] = x & 0xFF;
else if (x <= USHORT_MAX) /* assume unsigned short = 16 bits */
{
s[0] = (x >> 8) & 0xFF;
s[1] = x & 0xFF;
}
else
{
s[0] = (x >> 24) & 0xFF;
s[1] = (x >> 16) & 0xFF;
s[2] = (x >> 8) & 0xFF;
s[3] = x & 0xFF;
}
s[l] = '\0';
return l;
}
/* Convert unsigned 32-bit int to utf-8 character string */
int
u32toutf8 (wc, s)
u_bits32_t wc;
char *s;
{
int l;
if (wc < 0x0080)
{
s[0] = (char)wc;
l = 1;
}
else if (wc < 0x0800)
{
s[0] = (wc >> 6) | 0xc0;
s[1] = (wc & 0x3f) | 0x80;
l = 2;
}
else if (wc < 0x10000)
{
s[0] = (wc >> 12) | 0xe0;
s[1] = ((wc >> 6) & 0x3f) | 0x80;
s[2] = (wc & 0x3f) | 0x80;
l = 3;
}
else if (wc < 0x200000)
{
s[0] = (wc >> 18) | 0xf0;
s[1] = ((wc >> 12) & 0x3f) | 0x80;
s[2] = ((wc >> 6) & 0x3f) | 0x80;
s[3] = (wc & 0x3f) | 0x80;
l = 4;
}
/* Strictly speaking, UTF-8 doesn't have characters longer than 4 bytes */
else if (wc < 0x04000000)
{
s[0] = (wc >> 24) | 0xf8;
s[1] = ((wc >> 18) & 0x3f) | 0x80;
s[2] = ((wc >> 12) & 0x3f) | 0x80;
s[3] = ((wc >> 6) & 0x3f) | 0x80;
s[4] = (wc & 0x3f) | 0x80;
l = 5;
}
else if (wc < 0x080000000)
{
s[0] = (wc >> 30) | 0xf8;
s[1] = ((wc >> 24) & 0x3f) | 0x80;
s[2] = ((wc >> 18) & 0x3f) | 0x80;
s[3] = ((wc >> 12) & 0x3f) | 0x80;
s[4] = ((wc >> 6) & 0x3f) | 0x80;
s[5] = (wc & 0x3f) | 0x80;
l = 6;
}
else
l = 0;
s[l] = '\0';
return l;
}
/* Convert a 32-bit unsigned int (unicode) to a UTF-16 string. Rarely used,
only if sizeof(wchar_t) == 2. */
int
u32toutf16 (c, s)
u_bits32_t c;
unsigned short *s;
{
int l;
l = 0;
if (c < 0x0d800)
{
s[0] = (unsigned short) (c & 0xFFFF);
l = 1;
}
else if (c >= 0x0e000 && c <= 0x010ffff)
{
c -= 0x010000;
s[0] = (unsigned short)((c >> 10) + 0xd800);
s[1] = (unsigned short)((c & 0x3ff) + 0xdc00);
l = 2;
}
s[l] = 0;
return l;
}
/* convert a single unicode-32 character into a multibyte string and put the
result in S, which must be large enough (at least MB_LEN_MAX bytes) */
int
u32cconv (c, s)
unsigned long c;
char *s;
{
wchar_t wc;
wchar_t ws[3];
int n;
#if HAVE_ICONV
const char *charset;
char obuf[25], *optr;
size_t obytesleft;
const char *iptr;
size_t sn;
#endif
#if __STDC_ISO_10646__
wc = c;
if (sizeof (wchar_t) == 4 && c <= 0x7fffffff)
{
n = wctomb (s, wc);
if (n != -1)
return n;
}
else if (sizeof (wchar_t) == 2)
{
if (u32toutf16 (c, ws))
{
n = wcstombs (s, ws, MB_LEN_MAX);
if (n != -1)
return n;
}
}
#endif
#if HAVE_NL_LANGINFO
codeset = nl_langinfo (CODESET);
if (STREQ (codeset, "UTF-8"))
{
n = u32toutf8 (c, s);
return n;
}
#endif
#if HAVE_ICONV
/* this is mostly from coreutils-8.5/lib/unicodeio.c */
if (u32init == 0)
{
# if HAVE_LOCALE_CHARSET
charset = locale_charset (); /* XXX - fix later */
# else
charset = stub_charset ();
# endif
if (STREQ (charset, "UTF-8"))
utf8locale = 1;
else
{
localconv = iconv_open (charset, "UTF-8");
if (localconv == (iconv_t)-1)
localconv = iconv_open (charset, "ASCII");
}
u32init = 1;
}
if (utf8locale)
{
n = u32toutf8 (c, s);
return n;
}
if (localconv == (iconv_t)-1)
{
n = u32tochar (c, s);
return n;
}
n = u32toutf8 (c, s);
optr = obuf;
obytesleft = sizeof (obuf);
iptr = s;
sn = n;
iconv (localconv, NULL, NULL, NULL, NULL);
if (iconv (localconv, (ICONV_CONST char **)&iptr, &sn, &optr, &obytesleft) == (size_t)-1)
return n; /* You get utf-8 if iconv fails */
*optr = '\0';
/* number of chars to be copied is optr - obuf if we want to do bounds
checking */
strcpy (s, obuf);
return (optr - obuf);
#endif
n = u32tochar (c, s); /* fallback */
return n;
}
#else
void
u32reset ()
{
}
#endif /* HANDLE_MULTIBYTE */
+1 -1
View File
@@ -1,6 +1,6 @@
/* locale.c - Miscellaneous internationalization functions. */
/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
/* Copyright (C) 1996-2009,2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+765 -410
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -4666,12 +4666,18 @@ sv_locale (name)
char *name;
{
char *v;
int r;
v = get_string_value (name);
if (name[0] == 'L' && name[1] == 'A') /* LANG */
set_lang (name, v);
r = set_lang (name, v);
else
set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
#if 1
if (r == 0 && posixly_correct)
last_command_exit_value = 1;
#endif
}
#if defined (ARRAY_VARS)