source: trunk/third/gettext/lib/mbswidth.c @ 16931

Revision 16931, 5.6 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16930, which included commits to RCS files with non-trunk default branches.
Line 
1/* Determine the number of screen columns needed for a string.
2   Copyright (C) 2000-2001 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#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24/* Get MB_CUR_MAX.  */
25#include <stdlib.h>
26
27#include <string.h>
28
29/* Get isprint().  */
30#include <ctype.h>
31
32/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth().  */
33#if HAVE_WCHAR_H
34# include <wchar.h>
35#endif
36
37/* Get iswprint(), iswcntrl().  */
38#if HAVE_WCTYPE_H
39# include <wctype.h>
40#endif
41#if !defined iswprint && !HAVE_ISWPRINT
42# define iswprint(wc) 1
43#endif
44#if !defined iswcntrl && !HAVE_ISWCNTRL
45# define iswcntrl(wc) 0
46#endif
47
48#ifndef mbsinit
49# if !HAVE_MBSINIT
50#  define mbsinit(ps) 1
51# endif
52#endif
53
54#ifndef HAVE_DECL_WCWIDTH
55"this configure-time declaration test was not run"
56#endif
57#if !HAVE_DECL_WCWIDTH
58int wcwidth ();
59#endif
60
61#ifndef wcwidth
62# if !HAVE_WCWIDTH
63/* wcwidth doesn't exist, so assume all printable characters have
64   width 1.  */
65#  define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
66# endif
67#endif
68
69/* Get ISPRINT.  */
70#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
71# define IN_CTYPE_DOMAIN(c) 1
72#else
73# define IN_CTYPE_DOMAIN(c) isascii(c)
74#endif
75/* Undefine to protect against the definition in wctype.h of solaris2.6.   */
76#undef ISPRINT
77#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
78#undef ISCNTRL
79#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
80
81#include "mbswidth.h"
82
83/* Returns the number of columns needed to represent the multibyte
84   character string pointed to by STRING.  If a non-printable character
85   occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned.
86   With flags = MBSW_REJECT_INVALID | MBSW_REJECT_UNPRINTABLE, this is
87   the multibyte analogon of the wcswidth function.  */
88int
89mbswidth (string, flags)
90     const char *string;
91     int flags;
92{
93  return mbsnwidth (string, strlen (string), flags);
94}
95
96/* Returns the number of columns needed to represent the multibyte
97   character string pointed to by STRING of length NBYTES.  If a
98   non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is
99   specified, -1 is returned.  */
100int
101mbsnwidth (string, nbytes, flags)
102     const char *string;
103     size_t nbytes;
104     int flags;
105{
106  const char *p = string;
107  const char *plimit = p + nbytes;
108  int width;
109
110  width = 0;
111#if HAVE_MBRTOWC
112  if (MB_CUR_MAX > 1)
113    {
114      while (p < plimit)
115        switch (*p)
116          {
117            case ' ': case '!': case '"': case '#': case '%':
118            case '&': case '\'': case '(': case ')': case '*':
119            case '+': case ',': case '-': case '.': case '/':
120            case '0': case '1': case '2': case '3': case '4':
121            case '5': case '6': case '7': case '8': case '9':
122            case ':': case ';': case '<': case '=': case '>':
123            case '?':
124            case 'A': case 'B': case 'C': case 'D': case 'E':
125            case 'F': case 'G': case 'H': case 'I': case 'J':
126            case 'K': case 'L': case 'M': case 'N': case 'O':
127            case 'P': case 'Q': case 'R': case 'S': case 'T':
128            case 'U': case 'V': case 'W': case 'X': case 'Y':
129            case 'Z':
130            case '[': case '\\': case ']': case '^': case '_':
131            case 'a': case 'b': case 'c': case 'd': case 'e':
132            case 'f': case 'g': case 'h': case 'i': case 'j':
133            case 'k': case 'l': case 'm': case 'n': case 'o':
134            case 'p': case 'q': case 'r': case 's': case 't':
135            case 'u': case 'v': case 'w': case 'x': case 'y':
136            case 'z': case '{': case '|': case '}': case '~':
137              /* These characters are printable ASCII characters.  */
138              p++;
139              width++;
140              break;
141            default:
142              /* If we have a multibyte sequence, scan it up to its end.  */
143              {
144                mbstate_t mbstate;
145                memset (&mbstate, 0, sizeof mbstate);
146                do
147                  {
148                    wchar_t wc;
149                    size_t bytes;
150                    int w;
151
152                    bytes = mbrtowc (&wc, p, plimit - p, &mbstate);
153
154                    if (bytes == (size_t) -1)
155                      /* An invalid multibyte sequence was encountered.  */
156                      {
157                        if (!(flags & MBSW_REJECT_INVALID))
158                          {
159                            p++;
160                            width++;
161                            break;
162                          }
163                        else
164                          return -1;
165                      }
166
167                    if (bytes == (size_t) -2)
168                      /* An incomplete multibyte character at the end.  */
169                      {
170                        if (!(flags & MBSW_REJECT_INVALID))
171                          {
172                            p = plimit;
173                            width++;
174                            break;
175                          }
176                        else
177                          return -1;
178                      }
179
180                    if (bytes == 0)
181                      /* A null wide character was encountered.  */
182                      bytes = 1;
183
184                    w = wcwidth (wc);
185                    if (w >= 0)
186                      /* A printable multibyte character.  */
187                      width += w;
188                    else
189                      /* An unprintable multibyte character.  */
190                      if (!(flags & MBSW_REJECT_UNPRINTABLE))
191                        width += (iswcntrl (wc) ? 0 : 1);
192                      else
193                        return -1;
194
195                    p += bytes;
196                  }
197                while (! mbsinit (&mbstate));
198              }
199              break;
200          }
201      return width;
202    }
203#endif
204
205  while (p < plimit)
206    {
207      unsigned char c = (unsigned char) *p++;
208
209      if (ISPRINT (c))
210        width++;
211      else if (!(flags & MBSW_REJECT_UNPRINTABLE))
212        width += (ISCNTRL (c) ? 0 : 1);
213      else
214        return -1;
215    }
216  return width;
217}
Note: See TracBrowser for help on using the repository browser.