597b03167545f5e6b8ebaebed268159226e869ed
[nivanova/samba-autobuild/.git] / lib / util / charset / util_str.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Andrew Tridgell 1992-2001
5    Copyright (C) Simo Sorce 2001
6    Copyright (C) Andrew Bartlett 2011
7    Copyright (C) Jeremy Allison  1992-2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/locale.h"
25
26 #ifdef strcasecmp
27 #undef strcasecmp
28 #endif
29
30 /**
31  Case insensitive string compararison
32 **/
33 _PUBLIC_ int strcasecmp_m(const char *s1, const char *s2)
34 {
35         codepoint_t c1=0, c2=0;
36         size_t size1, size2;
37         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
38
39         /* handle null ptr comparisons to simplify the use in qsort */
40         if (s1 == s2) return 0;
41         if (s1 == NULL) return -1;
42         if (s2 == NULL) return 1;
43
44         while (*s1 && *s2) {
45                 c1 = next_codepoint_convenience(iconv_convenience, s1, &size1);
46                 c2 = next_codepoint_convenience(iconv_convenience, s2, &size2);
47
48                 s1 += size1;
49                 s2 += size2;
50
51                 if (c1 == c2) {
52                         continue;
53                 }
54
55                 if (c1 == INVALID_CODEPOINT ||
56                     c2 == INVALID_CODEPOINT) {
57                         /* what else can we do?? */
58                         return strcasecmp(s1, s2);
59                 }
60
61                 if (toupper_m(c1) != toupper_m(c2)) {
62                         return c1 - c2;
63                 }
64         }
65
66         return *s1 - *s2;
67 }
68
69 /**
70  Case insensitive string compararison, length limited
71 **/
72 _PUBLIC_ int strncasecmp_m(const char *s1, const char *s2, size_t n)
73 {
74         codepoint_t c1=0, c2=0;
75         size_t size1, size2;
76         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
77
78         /* handle null ptr comparisons to simplify the use in qsort */
79         if (s1 == s2) return 0;
80         if (s1 == NULL) return -1;
81         if (s2 == NULL) return 1;
82
83         while (*s1 && *s2 && n) {
84                 n--;
85
86                 c1 = next_codepoint_convenience(iconv_convenience, s1, &size1);
87                 c2 = next_codepoint_convenience(iconv_convenience, s2, &size2);
88
89                 s1 += size1;
90                 s2 += size2;
91
92                 if (c1 == c2) {
93                         continue;
94                 }
95
96                 if (c1 == INVALID_CODEPOINT ||
97                     c2 == INVALID_CODEPOINT) {
98                         /* what else can we do?? */
99                         return strcasecmp(s1, s2);
100                 }
101
102                 if (toupper_m(c1) != toupper_m(c2)) {
103                         return c1 - c2;
104                 }
105         }
106
107         if (n == 0) {
108                 return 0;
109         }
110
111         return *s1 - *s2;
112 }
113
114 /**
115  * Compare 2 strings.
116  *
117  * @note The comparison is case-insensitive.
118  **/
119 _PUBLIC_ bool strequal_m(const char *s1, const char *s2)
120 {
121         return strcasecmp_m(s1,s2) == 0;
122 }
123
124 /**
125  Compare 2 strings (case sensitive).
126 **/
127 _PUBLIC_ bool strcsequal(const char *s1,const char *s2)
128 {
129         if (s1 == s2)
130                 return true;
131         if (!s1 || !s2)
132                 return false;
133
134         return strcmp(s1,s2) == 0;
135 }
136
137 /**
138  * Calculate the number of units (8 or 16-bit, depending on the
139  * destination charset), that would be needed to convert the input
140  * string which is expected to be in in src_charset encoding to the
141  * destination charset (which should be a unicode charset).
142  */
143 _PUBLIC_ size_t strlen_m_ext(const char *s, charset_t src_charset, charset_t dst_charset)
144 {
145         size_t count = 0;
146         struct smb_iconv_convenience *ic = get_iconv_convenience();
147
148         if (!s) {
149                 return 0;
150         }
151
152         while (*s && !(((uint8_t)*s) & 0x80)) {
153                 s++;
154                 count++;
155         }
156
157         if (!*s) {
158                 return count;
159         }
160
161         while (*s) {
162                 size_t c_size;
163                 codepoint_t c = next_codepoint_convenience_ext(ic, s, src_charset, &c_size);
164                 s += c_size;
165
166                 switch (dst_charset) {
167                 case CH_UTF16LE:
168                 case CH_UTF16BE:
169                 case CH_UTF16MUNGED:
170                         if (c < 0x10000) {
171                                 /* Unicode char fits into 16 bits. */
172                                 count += 1;
173                         } else {
174                                 /* Double-width unicode char - 32 bits. */
175                                 count += 2;
176                         }
177                         break;
178                 case CH_UTF8:
179                         /*
180                          * this only checks ranges, and does not
181                          * check for invalid codepoints
182                          */
183                         if (c < 0x80) {
184                                 count += 1;
185                         } else if (c < 0x800) {
186                                 count += 2;
187                         } else if (c < 0x1000) {
188                                 count += 3;
189                         } else {
190                                 count += 4;
191                         }
192                         break;
193                 default:
194                         /*
195                          * non-unicode encoding:
196                          * assume that each codepoint fits into
197                          * one unit in the destination encoding.
198                          */
199                         count += 1;
200                 }
201         }
202
203         return count;
204 }
205
206 _PUBLIC_ size_t strlen_m_ext_term(const char *s, const charset_t src_charset,
207                                   const charset_t dst_charset)
208 {
209         if (!s) {
210                 return 0;
211         }
212         return strlen_m_ext(s, src_charset, dst_charset) + 1;
213 }
214
215 /**
216  * Calculate the number of 16-bit units that would be needed to convert
217  * the input string which is expected to be in CH_UNIX encoding to UTF16.
218  *
219  * This will be the same as the number of bytes in a string for single
220  * byte strings, but will be different for multibyte.
221  */
222 _PUBLIC_ size_t strlen_m(const char *s)
223 {
224         return strlen_m_ext(s, CH_UNIX, CH_UTF16LE);
225 }
226
227 /**
228    Work out the number of multibyte chars in a string, including the NULL
229    terminator.
230 **/
231 _PUBLIC_ size_t strlen_m_term(const char *s)
232 {
233         if (!s) {
234                 return 0;
235         }
236
237         return strlen_m(s) + 1;
238 }
239
240 /*
241  * Weird helper routine for the winreg pipe: If nothing is around, return 0,
242  * if a string is there, include the terminator.
243  */
244
245 _PUBLIC_ size_t strlen_m_term_null(const char *s)
246 {
247         size_t len;
248         if (!s) {
249                 return 0;
250         }
251         len = strlen_m(s);
252         if (len == 0) {
253                 return 0;
254         }
255
256         return len+1;
257 }
258
259 /**
260  Strchr and strrchr_m are a bit complex on general multi-byte strings.
261 **/
262 _PUBLIC_ char *strchr_m(const char *src, char c)
263 {
264         const char *s;
265         struct smb_iconv_convenience *ic = get_iconv_convenience();
266         if (src == NULL) {
267                 return NULL;
268         }
269         /* characters below 0x3F are guaranteed to not appear in
270            non-initial position in multi-byte charsets */
271         if ((c & 0xC0) == 0) {
272                 return strchr(src, c);
273         }
274
275         /* this is quite a common operation, so we want it to be
276            fast. We optimise for the ascii case, knowing that all our
277            supported multi-byte character sets are ascii-compatible
278            (ie. they match for the first 128 chars) */
279
280         for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
281                 if (*s == c)
282                         return (char *)s;
283         }
284
285         if (!*s)
286                 return NULL;
287
288 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
289         /* With compose characters we must restart from the beginning. JRA. */
290         s = src;
291 #endif
292
293         while (*s) {
294                 size_t size;
295                 codepoint_t c2 = next_codepoint_convenience(ic, s, &size);
296                 if (c2 == c) {
297                         return discard_const_p(char, s);
298                 }
299                 s += size;
300         }
301
302         return NULL;
303 }
304
305 /**
306  * Multibyte-character version of strrchr
307  */
308 _PUBLIC_ char *strrchr_m(const char *s, char c)
309 {
310         struct smb_iconv_convenience *ic = get_iconv_convenience();
311         char *ret = NULL;
312
313         if (s == NULL) {
314                 return NULL;
315         }
316
317         /* characters below 0x3F are guaranteed to not appear in
318            non-initial position in multi-byte charsets */
319         if ((c & 0xC0) == 0) {
320                 return strrchr(s, c);
321         }
322
323         /* this is quite a common operation, so we want it to be
324            fast. We optimise for the ascii case, knowing that all our
325            supported multi-byte character sets are ascii-compatible
326            (ie. they match for the first 128 chars). Also, in Samba
327            we only search for ascii characters in 'c' and that
328            in all mb character sets with a compound character
329            containing c, if 'c' is not a match at position
330            p, then p[-1] > 0x7f. JRA. */
331
332         {
333                 size_t len = strlen(s);
334                 const char *cp = s;
335                 bool got_mb = false;
336
337                 if (len == 0)
338                         return NULL;
339                 cp += (len - 1);
340                 do {
341                         if (c == *cp) {
342                                 /* Could be a match. Part of a multibyte ? */
343                                 if ((cp > s) &&
344                                         (((unsigned char)cp[-1]) & 0x80)) {
345                                         /* Yep - go slow :-( */
346                                         got_mb = true;
347                                         break;
348                                 }
349                                 /* No - we have a match ! */
350                                 return (char *)cp;
351                         }
352                 } while (cp-- != s);
353                 if (!got_mb)
354                         return NULL;
355         }
356
357         while (*s) {
358                 size_t size;
359                 codepoint_t c2 = next_codepoint_convenience(ic, s, &size);
360                 if (c2 == c) {
361                         ret = discard_const_p(char, s);
362                 }
363                 s += size;
364         }
365
366         return ret;
367 }
368
369 /**
370   return True if any (multi-byte) character is lower case
371 */
372 _PUBLIC_ bool strhaslower(const char *string)
373 {
374         struct smb_iconv_convenience *ic = get_iconv_convenience();
375         while (*string) {
376                 size_t c_size;
377                 codepoint_t s;
378                 codepoint_t t;
379
380                 s = next_codepoint_convenience(ic, string, &c_size);
381                 string += c_size;
382
383                 t = toupper_m(s);
384
385                 if (s != t) {
386                         return true; /* that means it has lower case chars */
387                 }
388         }
389
390         return false;
391 }
392
393 /**
394   return True if any (multi-byte) character is upper case
395 */
396 _PUBLIC_ bool strhasupper(const char *string)
397 {
398         struct smb_iconv_convenience *ic = get_iconv_convenience();
399         while (*string) {
400                 size_t c_size;
401                 codepoint_t s;
402                 codepoint_t t;
403
404                 s = next_codepoint_convenience(ic, string, &c_size);
405                 string += c_size;
406
407                 t = tolower_m(s);
408
409                 if (s != t) {
410                         return true; /* that means it has upper case chars */
411                 }
412         }
413
414         return false;
415 }
416