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