1*a7c91847Schristos /* Iterating through multibyte strings: macros for multi-byte encodings.
2*a7c91847Schristos Copyright (C) 2001, 2005 Free Software Foundation, Inc.
3*a7c91847Schristos
4*a7c91847Schristos This program is free software; you can redistribute it and/or modify
5*a7c91847Schristos it under the terms of the GNU General Public License as published by
6*a7c91847Schristos the Free Software Foundation; either version 2, or (at your option)
7*a7c91847Schristos any later version.
8*a7c91847Schristos
9*a7c91847Schristos This program is distributed in the hope that it will be useful,
10*a7c91847Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
11*a7c91847Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*a7c91847Schristos GNU General Public License for more details.
13*a7c91847Schristos
14*a7c91847Schristos You should have received a copy of the GNU General Public License
15*a7c91847Schristos along with this program; if not, write to the Free Software Foundation,
16*a7c91847Schristos Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17*a7c91847Schristos
18*a7c91847Schristos /* Written by Bruno Haible <bruno@clisp.org>. */
19*a7c91847Schristos
20*a7c91847Schristos /* The macros in this file implement forward iteration through a
21*a7c91847Schristos multi-byte string, without knowing its length a-priori.
22*a7c91847Schristos
23*a7c91847Schristos With these macros, an iteration loop that looks like
24*a7c91847Schristos
25*a7c91847Schristos char *iter;
26*a7c91847Schristos for (iter = buf; *iter != '\0'; iter++)
27*a7c91847Schristos {
28*a7c91847Schristos do_something (*iter);
29*a7c91847Schristos }
30*a7c91847Schristos
31*a7c91847Schristos becomes
32*a7c91847Schristos
33*a7c91847Schristos mbui_iterator_t iter;
34*a7c91847Schristos for (mbui_init (iter, buf); mbui_avail (iter); mbui_advance (iter))
35*a7c91847Schristos {
36*a7c91847Schristos do_something (mbui_cur_ptr (iter), mb_len (mbui_cur (iter)));
37*a7c91847Schristos }
38*a7c91847Schristos
39*a7c91847Schristos The benefit of these macros over plain use of mbrtowc is:
40*a7c91847Schristos - Handling of invalid multibyte sequences is possible without
41*a7c91847Schristos making the code more complicated, while still preserving the
42*a7c91847Schristos invalid multibyte sequences.
43*a7c91847Schristos
44*a7c91847Schristos Compared to mbiter.h, the macros here don't need to know the string's
45*a7c91847Schristos length a-priori. The downside is that at each step, the look-ahead
46*a7c91847Schristos that guards against overrunning the terminating '\0' is more expensive.
47*a7c91847Schristos The mbui_* macros are therefore suitable when there is a high probability
48*a7c91847Schristos that only the first few multibyte characters need to be inspected.
49*a7c91847Schristos Whereas the mbi_* macros are better if usually the iteration runs
50*a7c91847Schristos through the entire string.
51*a7c91847Schristos
52*a7c91847Schristos mbui_iterator_t
53*a7c91847Schristos is a type usable for variable declarations.
54*a7c91847Schristos
55*a7c91847Schristos mbui_init (iter, startptr)
56*a7c91847Schristos initializes the iterator, starting at startptr.
57*a7c91847Schristos
58*a7c91847Schristos mbui_avail (iter)
59*a7c91847Schristos returns true if there are more multibyte chracters available before
60*a7c91847Schristos the end of string is reached. In this case, mbui_cur (iter) is
61*a7c91847Schristos initialized to the next multibyte chracter.
62*a7c91847Schristos
63*a7c91847Schristos mbui_advance (iter)
64*a7c91847Schristos advances the iterator by one multibyte character.
65*a7c91847Schristos
66*a7c91847Schristos mbui_cur (iter)
67*a7c91847Schristos returns the current multibyte character, of type mbchar_t. All the
68*a7c91847Schristos macros defined in mbchar.h can be used on it.
69*a7c91847Schristos
70*a7c91847Schristos mbui_cur_ptr (iter)
71*a7c91847Schristos return a pointer to the beginning of the current multibyte character.
72*a7c91847Schristos
73*a7c91847Schristos mbui_reloc (iter, ptrdiff)
74*a7c91847Schristos relocates iterator when the string is moved by ptrdiff bytes.
75*a7c91847Schristos
76*a7c91847Schristos Here are the function prototypes of the macros.
77*a7c91847Schristos
78*a7c91847Schristos extern void mbui_init (mbui_iterator_t iter, const char *startptr);
79*a7c91847Schristos extern bool mbui_avail (mbui_iterator_t iter);
80*a7c91847Schristos extern void mbui_advance (mbui_iterator_t iter);
81*a7c91847Schristos extern mbchar_t mbui_cur (mbui_iterator_t iter);
82*a7c91847Schristos extern const char * mbui_cur_ptr (mbui_iterator_t iter);
83*a7c91847Schristos extern void mbui_reloc (mbui_iterator_t iter, ptrdiff_t ptrdiff);
84*a7c91847Schristos */
85*a7c91847Schristos
86*a7c91847Schristos #ifndef _MBUITER_H
87*a7c91847Schristos #define _MBUITER_H 1
88*a7c91847Schristos
89*a7c91847Schristos #include <assert.h>
90*a7c91847Schristos #include <stdbool.h>
91*a7c91847Schristos #include <stdlib.h>
92*a7c91847Schristos
93*a7c91847Schristos /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
94*a7c91847Schristos <wchar.h>.
95*a7c91847Schristos BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
96*a7c91847Schristos <wchar.h>. */
97*a7c91847Schristos #include <stdio.h>
98*a7c91847Schristos #include <time.h>
99*a7c91847Schristos #include <wchar.h>
100*a7c91847Schristos
101*a7c91847Schristos #include "mbchar.h"
102*a7c91847Schristos #include "strnlen1.h"
103*a7c91847Schristos
104*a7c91847Schristos struct mbuiter_multi
105*a7c91847Schristos {
106*a7c91847Schristos bool in_shift; /* true if next byte may not be interpreted as ASCII */
107*a7c91847Schristos mbstate_t state; /* if in_shift: current shift state */
108*a7c91847Schristos bool next_done; /* true if mbui_avail has already filled the following */
109*a7c91847Schristos struct mbchar cur; /* the current character:
110*a7c91847Schristos const char *cur.ptr pointer to current character
111*a7c91847Schristos The following are only valid after mbui_avail.
112*a7c91847Schristos size_t cur.bytes number of bytes of current character
113*a7c91847Schristos bool cur.wc_valid true if wc is a valid wide character
114*a7c91847Schristos wchar_t cur.wc if wc_valid: the current character
115*a7c91847Schristos */
116*a7c91847Schristos };
117*a7c91847Schristos
118*a7c91847Schristos static inline void
mbuiter_multi_next(struct mbuiter_multi * iter)119*a7c91847Schristos mbuiter_multi_next (struct mbuiter_multi *iter)
120*a7c91847Schristos {
121*a7c91847Schristos if (iter->next_done)
122*a7c91847Schristos return;
123*a7c91847Schristos if (iter->in_shift)
124*a7c91847Schristos goto with_shift;
125*a7c91847Schristos /* Handle most ASCII characters quickly, without calling mbrtowc(). */
126*a7c91847Schristos if (is_basic (*iter->cur.ptr))
127*a7c91847Schristos {
128*a7c91847Schristos /* These characters are part of the basic character set. ISO C 99
129*a7c91847Schristos guarantees that their wide character code is identical to their
130*a7c91847Schristos char code. */
131*a7c91847Schristos iter->cur.bytes = 1;
132*a7c91847Schristos iter->cur.wc = *iter->cur.ptr;
133*a7c91847Schristos iter->cur.wc_valid = true;
134*a7c91847Schristos }
135*a7c91847Schristos else
136*a7c91847Schristos {
137*a7c91847Schristos assert (mbsinit (&iter->state));
138*a7c91847Schristos iter->in_shift = true;
139*a7c91847Schristos with_shift:
140*a7c91847Schristos iter->cur.bytes = mbrtowc (&iter->cur.wc, iter->cur.ptr,
141*a7c91847Schristos strnlen1 (iter->cur.ptr, MB_CUR_MAX),
142*a7c91847Schristos &iter->state);
143*a7c91847Schristos if (iter->cur.bytes == (size_t) -1)
144*a7c91847Schristos {
145*a7c91847Schristos /* An invalid multibyte sequence was encountered. */
146*a7c91847Schristos iter->cur.bytes = 1;
147*a7c91847Schristos iter->cur.wc_valid = false;
148*a7c91847Schristos /* Whether to set iter->in_shift = false and reset iter->state
149*a7c91847Schristos or not is not very important; the string is bogus anyway. */
150*a7c91847Schristos }
151*a7c91847Schristos else if (iter->cur.bytes == (size_t) -2)
152*a7c91847Schristos {
153*a7c91847Schristos /* An incomplete multibyte character at the end. */
154*a7c91847Schristos iter->cur.bytes = strlen (iter->cur.ptr);
155*a7c91847Schristos iter->cur.wc_valid = false;
156*a7c91847Schristos /* Whether to set iter->in_shift = false and reset iter->state
157*a7c91847Schristos or not is not important; the string end is reached anyway. */
158*a7c91847Schristos }
159*a7c91847Schristos else
160*a7c91847Schristos {
161*a7c91847Schristos if (iter->cur.bytes == 0)
162*a7c91847Schristos {
163*a7c91847Schristos /* A null wide character was encountered. */
164*a7c91847Schristos iter->cur.bytes = 1;
165*a7c91847Schristos assert (*iter->cur.ptr == '\0');
166*a7c91847Schristos assert (iter->cur.wc == 0);
167*a7c91847Schristos }
168*a7c91847Schristos iter->cur.wc_valid = true;
169*a7c91847Schristos
170*a7c91847Schristos /* When in the initial state, we can go back treating ASCII
171*a7c91847Schristos characters more quickly. */
172*a7c91847Schristos if (mbsinit (&iter->state))
173*a7c91847Schristos iter->in_shift = false;
174*a7c91847Schristos }
175*a7c91847Schristos }
176*a7c91847Schristos iter->next_done = true;
177*a7c91847Schristos }
178*a7c91847Schristos
179*a7c91847Schristos static inline void
mbuiter_multi_reloc(struct mbuiter_multi * iter,ptrdiff_t ptrdiff)180*a7c91847Schristos mbuiter_multi_reloc (struct mbuiter_multi *iter, ptrdiff_t ptrdiff)
181*a7c91847Schristos {
182*a7c91847Schristos iter->cur.ptr += ptrdiff;
183*a7c91847Schristos }
184*a7c91847Schristos
185*a7c91847Schristos /* Iteration macros. */
186*a7c91847Schristos typedef struct mbuiter_multi mbui_iterator_t;
187*a7c91847Schristos #define mbui_init(iter, startptr) \
188*a7c91847Schristos ((iter).cur.ptr = (startptr), \
189*a7c91847Schristos (iter).in_shift = false, memset (&(iter).state, '\0', sizeof (mbstate_t)), \
190*a7c91847Schristos (iter).next_done = false)
191*a7c91847Schristos #define mbui_avail(iter) \
192*a7c91847Schristos (mbuiter_multi_next (&(iter)), !mb_isnul ((iter).cur))
193*a7c91847Schristos #define mbui_advance(iter) \
194*a7c91847Schristos ((iter).cur.ptr += (iter).cur.bytes, (iter).next_done = false)
195*a7c91847Schristos
196*a7c91847Schristos /* Access to the current character. */
197*a7c91847Schristos #define mbui_cur(iter) (iter).cur
198*a7c91847Schristos #define mbui_cur_ptr(iter) (iter).cur.ptr
199*a7c91847Schristos
200*a7c91847Schristos /* Relocation. */
201*a7c91847Schristos #define mbui_reloc(iter, ptrdiff) mbuiter_multi_reloc (&iter, ptrdiff)
202*a7c91847Schristos
203*a7c91847Schristos #endif /* _MBUITER_H */
204