mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-19 18:02:53 +02:00
commit bash-20150123 snapshot
This commit is contained in:
+44
-41
@@ -1,6 +1,6 @@
|
||||
/* casemod.c -- functions to change case of strings */
|
||||
|
||||
/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2008,2009,2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#if !defined (HANDLE_MULTIBYTE)
|
||||
# define cval(s, i) ((s)[(i)])
|
||||
# define iswalnum(c) (isalnum(c))
|
||||
# define TOGGLE(x) (ISUPPER (x) ? tolower (x) : (TOUPPER (x)))
|
||||
# define TOGGLE(x) (ISUPPER (x) ? tolower ((unsigned char)x) : (TOUPPER (x)))
|
||||
#else
|
||||
# define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x)))
|
||||
#endif
|
||||
@@ -105,7 +105,7 @@ sh_modcase (string, pat, flags)
|
||||
char *pat;
|
||||
int flags;
|
||||
{
|
||||
int start, next, end;
|
||||
int start, next, end, retind;
|
||||
int inword, c, nc, nop, match, usewords;
|
||||
char *ret, *s;
|
||||
wchar_t wc;
|
||||
@@ -131,8 +131,8 @@ sh_modcase (string, pat, flags)
|
||||
start = 0;
|
||||
end = strlen (string);
|
||||
|
||||
ret = (char *)xmalloc (end + 1);
|
||||
strcpy (ret, string);
|
||||
ret = (char *)xmalloc (2*end + 1);
|
||||
retind = 0;
|
||||
|
||||
/* See if we are supposed to split on alphanumerics and operate on each word */
|
||||
usewords = (flags & CASE_USEWORDS);
|
||||
@@ -141,26 +141,23 @@ sh_modcase (string, pat, flags)
|
||||
inword = 0;
|
||||
while (start < end)
|
||||
{
|
||||
wc = cval (ret, start);
|
||||
wc = cval (string, start);
|
||||
|
||||
if (iswalnum (wc) == 0)
|
||||
{
|
||||
inword = 0;
|
||||
#if 0
|
||||
ADVANCE_CHAR (ret, end, start);
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
inword = 0;
|
||||
|
||||
if (pat)
|
||||
{
|
||||
next = start;
|
||||
ADVANCE_CHAR (ret, end, next);
|
||||
s = substring (ret, start, next);
|
||||
ADVANCE_CHAR (string, end, next);
|
||||
s = substring (string, start, next);
|
||||
match = strmatch (pat, s, FNM_EXTMATCH) != FNM_NOMATCH;
|
||||
free (s);
|
||||
if (match == 0)
|
||||
{
|
||||
/* copy unmatched portion */
|
||||
memcpy (ret + retind, string + start, next - start);
|
||||
retind += next - start;
|
||||
start = next;
|
||||
inword = 1;
|
||||
continue;
|
||||
@@ -210,27 +207,27 @@ sh_modcase (string, pat, flags)
|
||||
else
|
||||
nop = flags;
|
||||
|
||||
/* Need to check UCHAR_MAX since wc may have already been converted to a
|
||||
wide character by cval() */
|
||||
if (MB_CUR_MAX == 1 || (wc <= UCHAR_MAX && is_basic ((int)wc)))
|
||||
/* Can't short-circuit, some locales have multibyte upper and lower
|
||||
case equivalents of single-byte ascii characters (e.g., Turkish) */
|
||||
if (MB_CUR_MAX == 1)
|
||||
{
|
||||
singlebyte:
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nc = wc; break;
|
||||
case CASE_UPPER: nc = TOUPPER (wc); break;
|
||||
case CASE_LOWER: nc = TOLOWER (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nc = TOGGLE (wc); break;
|
||||
}
|
||||
ret[start] = nc;
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nc = wc; break;
|
||||
case CASE_UPPER: nc = TOUPPER (wc); break;
|
||||
case CASE_LOWER: nc = TOLOWER (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nc = TOGGLE (wc); break;
|
||||
}
|
||||
ret[retind++] = nc;
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
else
|
||||
{
|
||||
m = mbrtowc (&wc, string + start, end - start, &state);
|
||||
if (MB_INVALIDCH (m))
|
||||
if (MB_INVALIDCH (m) || m == 1)
|
||||
{
|
||||
wc = (unsigned char)string[start];
|
||||
goto singlebyte;
|
||||
@@ -238,28 +235,34 @@ singlebyte:
|
||||
else if (MB_NULLWCH (m))
|
||||
wc = L'\0';
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nwc = wc; break;
|
||||
case CASE_UPPER: nwc = _to_wupper (wc); break;
|
||||
case CASE_LOWER: nwc = _to_wlower (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nwc = TOGGLE (wc); break;
|
||||
}
|
||||
if (nwc != wc) /* just skip unchanged characters */
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nwc = wc; break;
|
||||
case CASE_UPPER: nwc = _to_wupper (wc); break;
|
||||
case CASE_LOWER: nwc = _to_wlower (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nwc = TOGGLE (wc); break;
|
||||
}
|
||||
|
||||
/* We don't have to convert `wide' characters that are in the
|
||||
unsigned char range back to single-byte `multibyte' characters. */
|
||||
if ((int)nwc <= UCHAR_MAX && is_basic ((int)nwc))
|
||||
ret[retind++] = nwc;
|
||||
else
|
||||
{
|
||||
mlen = wcrtomb (mb, nwc, &state);
|
||||
if (mlen > 0)
|
||||
mb[mlen] = '\0';
|
||||
/* Assume the same width */
|
||||
strncpy (ret + start, mb, mlen);
|
||||
/* Don't assume the same width */
|
||||
strncpy (ret + retind, mb, mlen);
|
||||
retind += mlen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This assumes that the upper and lower case versions are the same width. */
|
||||
ADVANCE_CHAR (ret, end, start);
|
||||
ADVANCE_CHAR (string, end, start);
|
||||
}
|
||||
|
||||
ret[retind] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
/* casemod.c -- functions to change case of strings */
|
||||
|
||||
/* Copyright (C) 2008,2009,2015 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/>.
|
||||
*/
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#include <stdc.h>
|
||||
|
||||
#include <bashansi.h>
|
||||
#include <bashintl.h>
|
||||
#include <bashtypes.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <xmalloc.h>
|
||||
|
||||
#include <shmbchar.h>
|
||||
#include <shmbutil.h>
|
||||
#include <chartypes.h>
|
||||
#include <typemax.h>
|
||||
|
||||
#include <glob/strmatch.h>
|
||||
|
||||
#define _to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc))
|
||||
#define _to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc))
|
||||
|
||||
#if !defined (HANDLE_MULTIBYTE)
|
||||
# define cval(s, i) ((s)[(i)])
|
||||
# define iswalnum(c) (isalnum(c))
|
||||
# define TOGGLE(x) (ISUPPER (x) ? tolower ((unsigned char)x) : (TOUPPER (x)))
|
||||
#else
|
||||
# define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x)))
|
||||
#endif
|
||||
|
||||
/* These must agree with the defines in externs.h */
|
||||
#define CASE_NOOP 0x0000
|
||||
#define CASE_LOWER 0x0001
|
||||
#define CASE_UPPER 0x0002
|
||||
#define CASE_CAPITALIZE 0x0004
|
||||
#define CASE_UNCAP 0x0008
|
||||
#define CASE_TOGGLE 0x0010
|
||||
#define CASE_TOGGLEALL 0x0020
|
||||
#define CASE_UPFIRST 0x0040
|
||||
#define CASE_LOWFIRST 0x0080
|
||||
|
||||
#define CASE_USEWORDS 0x1000 /* modify behavior to act on words in passed string */
|
||||
|
||||
extern char *substring __P((char *, int, int));
|
||||
|
||||
#ifndef UCHAR_MAX
|
||||
# define UCHAR_MAX TYPE_MAXIMUM(unsigned char)
|
||||
#endif
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static wchar_t
|
||||
cval (s, i)
|
||||
char *s;
|
||||
int i;
|
||||
{
|
||||
size_t tmp;
|
||||
wchar_t wc;
|
||||
int l;
|
||||
mbstate_t mps;
|
||||
|
||||
if (MB_CUR_MAX == 1 || is_basic (s[i]))
|
||||
return ((wchar_t)s[i]);
|
||||
l = strlen (s);
|
||||
if (i >= (l - 1))
|
||||
return ((wchar_t)s[i]);
|
||||
memset (&mps, 0, sizeof (mbstate_t));
|
||||
tmp = mbrtowc (&wc, s + i, l - i, &mps);
|
||||
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp))
|
||||
return ((wchar_t)s[i]);
|
||||
return wc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modify the case of characters in STRING matching PAT based on the value of
|
||||
FLAGS. If PAT is null, modify the case of each character */
|
||||
char *
|
||||
sh_modcase (string, pat, flags)
|
||||
const char *string;
|
||||
char *pat;
|
||||
int flags;
|
||||
{
|
||||
int start, next, end, retind;
|
||||
int inword, c, nc, nop, match, usewords;
|
||||
char *ret, *s;
|
||||
wchar_t wc;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
wchar_t nwc;
|
||||
char mb[MB_LEN_MAX+1];
|
||||
int mlen;
|
||||
size_t m;
|
||||
mbstate_t state;
|
||||
#endif
|
||||
|
||||
if (string == 0 || *string == 0)
|
||||
{
|
||||
ret = (char *)xmalloc (1);
|
||||
ret[0] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (&state, 0, sizeof (mbstate_t));
|
||||
#endif
|
||||
|
||||
start = 0;
|
||||
end = strlen (string);
|
||||
|
||||
ret = (char *)xmalloc (2*end + 1);
|
||||
retind = 0;
|
||||
|
||||
/* See if we are supposed to split on alphanumerics and operate on each word */
|
||||
usewords = (flags & CASE_USEWORDS);
|
||||
flags &= ~CASE_USEWORDS;
|
||||
|
||||
inword = 0;
|
||||
while (start < end)
|
||||
{
|
||||
wc = cval (string, start);
|
||||
|
||||
if (iswalnum (wc) == 0)
|
||||
inword = 0;
|
||||
|
||||
if (pat)
|
||||
{
|
||||
next = start;
|
||||
ADVANCE_CHAR (string, end, next);
|
||||
s = substring (string, start, next);
|
||||
match = strmatch (pat, s, FNM_EXTMATCH) != FNM_NOMATCH;
|
||||
free (s);
|
||||
if (match == 0)
|
||||
{
|
||||
/* copy unmatched portion */
|
||||
memcpy (ret + retind, string + start, next - start);
|
||||
retind += next - start;
|
||||
start = next;
|
||||
inword = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX - for now, the toggling operators work on the individual
|
||||
words in the string, breaking on alphanumerics. Should I
|
||||
leave the capitalization operators to do that also? */
|
||||
if (flags == CASE_CAPITALIZE)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_LOWER : CASE_UPPER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_LOWER : CASE_UPPER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_UNCAP)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_UPPER : CASE_LOWER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_UPPER : CASE_LOWER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_UPFIRST)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_NOOP : CASE_UPPER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_NOOP : CASE_UPPER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_LOWFIRST)
|
||||
{
|
||||
if (usewords)
|
||||
nop = inword ? CASE_NOOP : CASE_LOWER;
|
||||
else
|
||||
nop = (start > 0) ? CASE_NOOP : CASE_LOWER;
|
||||
inword = 1;
|
||||
}
|
||||
else if (flags == CASE_TOGGLE)
|
||||
{
|
||||
nop = inword ? CASE_NOOP : CASE_TOGGLE;
|
||||
inword = 1;
|
||||
}
|
||||
else
|
||||
nop = flags;
|
||||
|
||||
/* Can't short-circuit, some locales have multibyte upper and lower
|
||||
case equivalents of single-byte ascii characters (e.g., Turkish) */
|
||||
if (MB_CUR_MAX == 1)
|
||||
{
|
||||
singlebyte:
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nc = wc; break;
|
||||
case CASE_UPPER: nc = TOUPPER (wc); break;
|
||||
case CASE_LOWER: nc = TOLOWER (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nc = TOGGLE (wc); break;
|
||||
}
|
||||
ret[retind++] = nc;
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
else
|
||||
{
|
||||
m = mbrtowc (&wc, string + start, end - start, &state);
|
||||
if (m == 1)
|
||||
itrace("sh_modcase: mbrtowc returns 1 for single byte char");
|
||||
if (MB_INVALIDCH (m) || m == 1)
|
||||
{
|
||||
wc = (unsigned char)string[start];
|
||||
goto singlebyte;
|
||||
}
|
||||
else if (MB_NULLWCH (m))
|
||||
wc = L'\0';
|
||||
switch (nop)
|
||||
{
|
||||
default:
|
||||
case CASE_NOOP: nwc = wc; break;
|
||||
case CASE_UPPER: nwc = _to_wupper (wc); break;
|
||||
case CASE_LOWER: nwc = _to_wlower (wc); break;
|
||||
case CASE_TOGGLEALL:
|
||||
case CASE_TOGGLE: nwc = TOGGLE (wc); break;
|
||||
}
|
||||
|
||||
/* We don't have to convert `wide' characters that are in the
|
||||
unsigned char range back to single-byte `multibyte' characters. */
|
||||
if ((int)nwc <= UCHAR_MAX && is_basic ((int)nwc))
|
||||
ret[retind++] = nwc;
|
||||
else
|
||||
{
|
||||
mlen = wcrtomb (mb, nwc, &state);
|
||||
if (mlen > 0)
|
||||
mb[mlen] = '\0';
|
||||
/* Don't assume the same width */
|
||||
strncpy (ret + retind, mb, mlen);
|
||||
retind += mlen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ADVANCE_CHAR (string, end, start);
|
||||
}
|
||||
|
||||
ret[retind] = '\0';
|
||||
return ret;
|
||||
}
|
||||
+17
-2
@@ -33,6 +33,9 @@
|
||||
#include "syntax.h"
|
||||
#include <xmalloc.h>
|
||||
|
||||
#include "shmbchar.h"
|
||||
#include "shmbutil.h"
|
||||
|
||||
extern char *ansic_quote __P((char *, int, int *));
|
||||
extern int ansic_shouldquote __P((const char *));
|
||||
|
||||
@@ -231,13 +234,25 @@ sh_backslash_quote (string, table, flags)
|
||||
int flags;
|
||||
{
|
||||
int c;
|
||||
char *result, *r, *s, *backslash_table;
|
||||
size_t slen;
|
||||
char *result, *r, *s, *backslash_table, *send;
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
result = (char *)xmalloc (2 * strlen (string) + 1);
|
||||
slen = strlen (string);
|
||||
send = string + slen;
|
||||
result = (char *)xmalloc (2 * slen + 1);
|
||||
|
||||
backslash_table = table ? table : (char *)bstab;
|
||||
for (r = result, s = string; s && (c = *s); s++)
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && is_basic (c) == 0)
|
||||
{
|
||||
COPY_CHAR_P (r, s, send);
|
||||
s--; /* compensate for auto-increment in loop above */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (backslash_table[c] == 1)
|
||||
*r++ = '\\';
|
||||
else if (c == '#' && s == string) /* comment char */
|
||||
|
||||
Reference in New Issue
Block a user