]>
git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/casemod.c
1 /* casemod.c -- functions to change case of strings */
3 /* Copyright (C) 2008,2009 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 #if defined (HAVE_CONFIG_H)
25 #if defined (HAVE_UNISTD_H)
27 #endif /* HAVE_UNISTD_H */
33 #include <bashtypes.h>
41 #include <chartypes.h>
43 #include <glob/strmatch.h>
45 #define _to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc))
46 #define _to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc))
48 #if !defined (HANDLE_MULTIBYTE)
49 # define cval(s, i) ((s)[(i)])
50 # define iswalnum(c) (isalnum(c))
51 # define TOGGLE(x) (ISUPPER (x) ? tolower (x) : (TOUPPER (x)))
53 # define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x)))
56 /* These must agree with the defines in externs.h */
57 #define CASE_NOOP 0x0000
58 #define CASE_LOWER 0x0001
59 #define CASE_UPPER 0x0002
60 #define CASE_CAPITALIZE 0x0004
61 #define CASE_UNCAP 0x0008
62 #define CASE_TOGGLE 0x0010
63 #define CASE_TOGGLEALL 0x0020
64 #define CASE_UPFIRST 0x0040
65 #define CASE_LOWFIRST 0x0080
67 #define CASE_USEWORDS 0x1000 /* modify behavior to act on words in passed string */
69 extern char *substring
__P((char *, int, int));
71 #if defined (HANDLE_MULTIBYTE)
82 if (MB_CUR_MAX
== 1 || is_basic (s
[i
]))
83 return ((wchar_t)s
[i
]);
86 return ((wchar_t)s
[i
]);
87 memset (&mps
, 0, sizeof (mbstate_t));
88 tmp
= mbrtowc (&wc
, s
+ i
, l
- i
, &mps
);
89 if (MB_INVALIDCH (tmp
) || MB_NULLWCH (tmp
))
90 return ((wchar_t)s
[i
]);
95 /* Modify the case of characters in STRING matching PAT based on the value of
96 FLAGS. If PAT is null, modify the case of each character */
98 sh_modcase (string
, pat
, flags
)
103 int start
, next
, end
;
104 int inword
, c
, nc
, nop
, match
, usewords
;
107 #if defined (HANDLE_MULTIBYTE)
109 char mb
[MB_LEN_MAX
+1];
115 if (string
== 0 || *string
== 0)
117 ret
= (char *)xmalloc (1);
122 #if defined (HANDLE_MULTIBYTE)
123 memset (&state
, 0, sizeof (mbstate_t));
127 end
= strlen (string
);
129 ret
= (char *)xmalloc (end
+ 1);
130 strcpy (ret
, string
);
132 /* See if we are supposed to split on alphanumerics and operate on each word */
133 usewords
= (flags
& CASE_USEWORDS
);
134 flags
&= ~CASE_USEWORDS
;
139 wc
= cval (ret
, start
);
141 if (iswalnum (wc
) == 0)
144 ADVANCE_CHAR (ret
, end
, start
);
151 ADVANCE_CHAR (ret
, end
, next
);
152 s
= substring (ret
, start
, next
);
153 match
= strmatch (pat
, s
, FNM_EXTMATCH
) != FNM_NOMATCH
;
163 /* XXX - for now, the toggling operators work on the individual
164 words in the string, breaking on alphanumerics. Should I
165 leave the capitalization operators to do that also? */
166 if (flags
== CASE_CAPITALIZE
)
169 nop
= inword
? CASE_LOWER
: CASE_UPPER
;
171 nop
= (start
> 0) ? CASE_LOWER
: CASE_UPPER
;
174 else if (flags
== CASE_UNCAP
)
177 nop
= inword
? CASE_UPPER
: CASE_LOWER
;
179 nop
= (start
> 0) ? CASE_UPPER
: CASE_LOWER
;
182 else if (flags
== CASE_UPFIRST
)
185 nop
= inword
? CASE_NOOP
: CASE_UPPER
;
187 nop
= (start
> 0) ? CASE_NOOP
: CASE_UPPER
;
190 else if (flags
== CASE_LOWFIRST
)
193 nop
= inword
? CASE_NOOP
: CASE_LOWER
;
195 nop
= (start
> 0) ? CASE_NOOP
: CASE_LOWER
;
198 else if (flags
== CASE_TOGGLE
)
200 nop
= inword
? CASE_NOOP
: CASE_TOGGLE
;
206 if (MB_CUR_MAX
== 1 || is_basic ((int)wc
))
211 case CASE_NOOP
: nc
= wc
; break;
212 case CASE_UPPER
: nc
= TOUPPER (wc
); break;
213 case CASE_LOWER
: nc
= TOLOWER (wc
); break;
215 case CASE_TOGGLE
: nc
= TOGGLE (wc
); break;
219 #if defined (HANDLE_MULTIBYTE)
222 m
= mbrtowc (&wc
, string
+ start
, end
- start
, &state
);
223 if (MB_INVALIDCH (m
))
224 wc
= (wchar_t)string
[start
];
225 else if (MB_NULLWCH (m
))
230 case CASE_NOOP
: nwc
= wc
; break;
231 case CASE_UPPER
: nwc
= _to_wupper (wc
); break;
232 case CASE_LOWER
: nwc
= _to_wlower (wc
); break;
234 case CASE_TOGGLE
: nwc
= TOGGLE (wc
); break;
236 if (nwc
!= wc
) /* just skip unchanged characters */
238 mlen
= wcrtomb (mb
, nwc
, &state
);
241 /* Assume the same width */
242 strncpy (ret
+ start
, mb
, mlen
);
247 /* This assumes that the upper and lower case versions are the same width. */
248 ADVANCE_CHAR (ret
, end
, start
);