blob: 7730e46eea2a441e04fbb60dc385630f7fa26a68 [file] [log] [blame]
Chet Ramey495aee42011-11-22 19:11:26 -05001/* mbschr.c - strchr(3) that handles multibyte characters. */
2
3/* Copyright (C) 2002 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
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.
11
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.
16
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/>.
19*/
20
21#include <config.h>
22
23#ifdef HAVE_STDLIB_H
24# include <stdlib.h>
25#endif
26
27#include "bashansi.h"
28#include "shmbutil.h"
29
Chet Rameyac50fba2014-02-26 09:36:43 -050030extern int locale_mb_cur_max;
31
Chet Ramey495aee42011-11-22 19:11:26 -050032#undef mbschr
33
34/* In some locales, the non-first byte of some multibyte characters have
35 the same value as some ascii character. Faced with these strings, a
36 legacy strchr() might return the wrong value. */
37
38char *
39#if defined (PROTOTYPES)
40mbschr (const char *s, int c)
41#else
42mbschr (s, c)
43 const char *s;
44 int c;
45#endif
46{
47#if HANDLE_MULTIBYTE
48 char *pos;
49 mbstate_t state;
50 size_t strlength, mblength;
51
52 /* The locale encodings with said weird property are BIG5, BIG5-HKSCS,
53 GBK, GB18030, SHIFT_JIS, and JOHAB. They exhibit the problem only
54 when c >= 0x30. We can therefore use the faster bytewise search if
55 c <= 0x30. */
Chet Rameyac50fba2014-02-26 09:36:43 -050056 if ((unsigned char)c >= '0' && locale_mb_cur_max > 1)
Chet Ramey495aee42011-11-22 19:11:26 -050057 {
58 pos = (char *)s;
59 memset (&state, '\0', sizeof(mbstate_t));
60 strlength = strlen (s);
61
62 while (strlength > 0)
63 {
Chet Rameyac50fba2014-02-26 09:36:43 -050064 if (is_basic (*pos))
Chet Ramey495aee42011-11-22 19:11:26 -050065 mblength = 1;
Chet Rameyac50fba2014-02-26 09:36:43 -050066 else
67 {
68 mblength = mbrlen (pos, strlength, &state);
69 if (mblength == (size_t)-2 || mblength == (size_t)-1 || mblength == (size_t)0)
70 mblength = 1;
71 }
Chet Ramey495aee42011-11-22 19:11:26 -050072
73 if (mblength == 1 && c == (unsigned char)*pos)
74 return pos;
75
76 strlength -= mblength;
77 pos += mblength;
78 }
79
80 return ((char *)NULL);
81 }
82 else
83#endif
84 return (strchr (s, c));
85}