]> git.deb.at Git - pkg/abook.git/blob - mbswidth.c
Upload 0.6.1-2 to unstable
[pkg/abook.git] / mbswidth.c
1 /* Determine the number of screen columns needed for a string.
2    Copyright (C) 2000-2002 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Bruno Haible <haible@clisp.cons.org>.  */
19 /*
20  * Adapted for abook by JH <jheinonen@users.sourceforge.net>
21  */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 /* Specification.  */
28 #include "mbswidth.h"
29
30 #ifdef HANDLE_MULTIBYTE /* for abook */
31
32 /* Get MB_CUR_MAX.  */
33 #include <stdlib.h>
34
35 #include <string.h>
36
37 /* Get isprint().  */
38 #include <ctype.h>
39
40 /* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth().  */
41 #if HAVE_WCHAR_H
42 # include <wchar.h>
43 #endif
44
45 /* Get iswprint(), iswcntrl().  */
46 #if HAVE_WCTYPE_H
47 # include <wctype.h>
48 #endif
49 #if !defined iswprint && !HAVE_ISWPRINT
50 # define iswprint(wc) 1
51 #endif
52 #if !defined iswcntrl && !HAVE_ISWCNTRL
53 # define iswcntrl(wc) 0
54 #endif
55
56 #ifndef mbsinit
57 # if !HAVE_MBSINIT
58 #  define mbsinit(ps) 1
59 # endif
60 #endif
61
62 #ifndef HAVE_DECL_WCWIDTH
63 #       warn "this configure-time declaration test was not run"
64 #endif
65 #if !HAVE_DECL_WCWIDTH
66 int wcwidth ();
67 #endif
68
69 #ifndef wcwidth
70 # if !HAVE_WCWIDTH
71 /* wcwidth doesn't exist, so assume all printable characters have
72    width 1.  */
73 #  define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
74 # endif
75 #endif
76
77 /* Get ISPRINT.  */
78 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
79 # define IN_CTYPE_DOMAIN(c) 1
80 #else
81 # define IN_CTYPE_DOMAIN(c) isascii(c)
82 #endif
83 /* Undefine to protect against the definition in wctype.h of solaris2.6.   */
84 #undef ISPRINT
85 #define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
86 #undef ISCNTRL
87 #define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
88
89 /* Returns the number of columns needed to represent the multibyte
90    character string pointed to by STRING.  If a non-printable character
91    occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned.
92    With flags = MBSW_REJECT_INVALID | MBSW_REJECT_UNPRINTABLE, this is
93    the multibyte analogon of the wcswidth function.  */
94 int
95 mbswidth (const char *string, int flags)
96 {
97   return mbsnwidth (string, strlen (string), flags);
98 }
99
100 /* Returns the number of columns needed to represent the multibyte
101    character string pointed to by STRING of length NBYTES.  If a
102    non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is
103    specified, -1 is returned.  */
104 int
105 mbsnwidth (const char *string, size_t nbytes, int flags)
106 {
107   const char *p = string;
108   const char *plimit = p + nbytes;
109   int width;
110
111   width = 0;
112 #if HAVE_MBRTOWC
113   if (MB_CUR_MAX > 1)
114     {
115       while (p < plimit)
116         switch (*p)
117           {
118             case ' ': case '!': case '"': case '#': case '%':
119             case '&': case '\'': case '(': case ')': case '*':
120             case '+': case ',': case '-': case '.': case '/':
121             case '0': case '1': case '2': case '3': case '4':
122             case '5': case '6': case '7': case '8': case '9':
123             case ':': case ';': case '<': case '=': case '>':
124             case '?':
125             case 'A': case 'B': case 'C': case 'D': case 'E':
126             case 'F': case 'G': case 'H': case 'I': case 'J':
127             case 'K': case 'L': case 'M': case 'N': case 'O':
128             case 'P': case 'Q': case 'R': case 'S': case 'T':
129             case 'U': case 'V': case 'W': case 'X': case 'Y':
130             case 'Z':
131             case '[': case '\\': case ']': case '^': case '_':
132             case 'a': case 'b': case 'c': case 'd': case 'e':
133             case 'f': case 'g': case 'h': case 'i': case 'j':
134             case 'k': case 'l': case 'm': case 'n': case 'o':
135             case 'p': case 'q': case 'r': case 's': case 't':
136             case 'u': case 'v': case 'w': case 'x': case 'y':
137             case 'z': case '{': case '|': case '}': case '~':
138               /* These characters are printable ASCII characters.  */
139               p++;
140               width++;
141               break;
142             default:
143               /* If we have a multibyte sequence, scan it up to its end.  */
144               {
145                 mbstate_t mbstate;
146                 memset (&mbstate, 0, sizeof mbstate);
147                 do
148                   {
149                     wchar_t wc;
150                     size_t bytes;
151                     int w;
152
153                     bytes = mbrtowc (&wc, p, plimit - p, &mbstate);
154
155                     if (bytes == (size_t) -1)
156                       /* An invalid multibyte sequence was encountered.  */
157                       {
158                         if (!(flags & MBSW_REJECT_INVALID))
159                           {
160                             p++;
161                             width++;
162                             break;
163                           }
164                         else
165                           return -1;
166                       }
167
168                     if (bytes == (size_t) -2)
169                       /* An incomplete multibyte character at the end.  */
170                       {
171                         if (!(flags & MBSW_REJECT_INVALID))
172                           {
173                             p = plimit;
174                             width++;
175                             break;
176                           }
177                         else
178                           return -1;
179                       }
180
181                     if (bytes == 0)
182                       /* A null wide character was encountered.  */
183                       bytes = 1;
184
185                     w = wcwidth (wc);
186                     if (w >= 0)
187                       /* A printable multibyte character.  */
188                       width += w;
189                     else
190                       /* An unprintable multibyte character.  */
191                       if (!(flags & MBSW_REJECT_UNPRINTABLE))
192                         width += (iswcntrl (wc) ? 0 : 1);
193                       else
194                         return -1;
195
196                     p += bytes;
197                   }
198                 while (! mbsinit (&mbstate));
199               }
200               break;
201           }
202       return width;
203     }
204 #endif
205
206   while (p < plimit)
207     {
208       unsigned char c = (unsigned char) *p++;
209
210       if (ISPRINT (c))
211         width++;
212       else if (!(flags & MBSW_REJECT_UNPRINTABLE))
213         width += (ISCNTRL (c) ? 0 : 1);
214       else
215         return -1;
216     }
217   return width;
218 }
219
220 int
221 mbsnbytes (const char *string, size_t nbytes, int maxwidth, int flags)
222 {
223   const char *p = string, *old_p = string;
224   const char *plimit = p + nbytes;
225   int width;
226
227   width = 0;
228 #if HAVE_MBRTOWC
229   if (MB_CUR_MAX > 1)
230     {
231       while (p < plimit && width < maxwidth)
232         {
233         old_p = p;
234         switch (*p)
235           {
236             case ' ': case '!': case '"': case '#': case '%':
237             case '&': case '\'': case '(': case ')': case '*':
238             case '+': case ',': case '-': case '.': case '/':
239             case '0': case '1': case '2': case '3': case '4':
240             case '5': case '6': case '7': case '8': case '9':
241             case ':': case ';': case '<': case '=': case '>':
242             case '?':
243             case 'A': case 'B': case 'C': case 'D': case 'E':
244             case 'F': case 'G': case 'H': case 'I': case 'J':
245             case 'K': case 'L': case 'M': case 'N': case 'O':
246             case 'P': case 'Q': case 'R': case 'S': case 'T':
247             case 'U': case 'V': case 'W': case 'X': case 'Y':
248             case 'Z':
249             case '[': case '\\': case ']': case '^': case '_':
250             case 'a': case 'b': case 'c': case 'd': case 'e':
251             case 'f': case 'g': case 'h': case 'i': case 'j':
252             case 'k': case 'l': case 'm': case 'n': case 'o':
253             case 'p': case 'q': case 'r': case 's': case 't':
254             case 'u': case 'v': case 'w': case 'x': case 'y':
255             case 'z': case '{': case '|': case '}': case '~':
256               /* These characters are printable ASCII characters.  */
257               p++;
258               width++;
259               break;
260             default:
261               /* If we have a multibyte sequence, scan it up to its end.  */
262               {
263                 mbstate_t mbstate;
264                 memset (&mbstate, 0, sizeof mbstate);
265                 do
266                   {
267                     wchar_t wc;
268                     size_t bytes;
269                     int w;
270
271                     bytes = mbrtowc (&wc, p, plimit - p, &mbstate);
272
273                     if (bytes == (size_t) -1)
274                       /* An invalid multibyte sequence was encountered.  */
275                       {
276                         if (!(flags & MBSW_REJECT_INVALID))
277                           {
278                             p++;
279                             width++;
280                             break;
281                           }
282                         else
283                           return -1;
284                       }
285
286                     if (bytes == (size_t) -2)
287                       /* An incomplete multibyte character at the end.  */
288                       {
289                         if (!(flags & MBSW_REJECT_INVALID))
290                           {
291                             p = plimit;
292                             width++;
293                             break;
294                           }
295                         else
296                           return -1;
297                       }
298
299                     if (bytes == 0)
300                       /* A null wide character was encountered.  */
301                       bytes = 1;
302
303                     w = wcwidth (wc);
304                     if (w >= 0)
305                       /* A printable multibyte character.  */
306                       width += w;
307                     else
308                       /* An unprintable multibyte character.  */
309                       if (!(flags & MBSW_REJECT_UNPRINTABLE))
310                         width += (iswcntrl (wc) ? 0 : 1);
311                       else
312                         return -1;
313
314                     p += bytes;
315                   }
316                 while (! mbsinit (&mbstate));
317               }
318               break;
319           }
320       }
321
322       return (width > maxwidth) ? (old_p - string) : (p - string);
323     }
324 #endif
325
326   return maxwidth;
327 }
328
329 #else /* HANDLE_MULTIBYTE */
330
331 #include <string.h>
332 int
333 mbswidth (const char *string, int flags)
334 {
335   return strlen(string);
336 }
337 #endif /* HANDLE_MULTIBYTE */
338