1cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Determine the number of screen columns needed for a string.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2000-2012 Free Software Foundation, Inc.
3cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
5cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   it under the terms of the GNU General Public License as published by
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
8cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
9cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   This program is distributed in the hope that it will be useful,
10cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   but WITHOUT ANY WARRANTY; without even the implied warranty of
11cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   GNU General Public License for more details.
13cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
14cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   You should have received a copy of the GNU General Public License
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
17cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Written by Bruno Haible <haible@clisp.cons.org>.  */
18cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
20cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
21cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Specification.  */
22cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include "mbswidth.h"
23cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
24cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Get MB_CUR_MAX.  */
25cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include <stdlib.h>
26cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
27cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include <string.h>
28cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
29cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Get isprint().  */
30cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include <ctype.h>
31cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
32cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth().  */
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <wchar.h>
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get iswcntrl().  */
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <wctype.h>
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get INT_MAX.  */
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <limits.h>
40cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
41cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Returns the number of columns needed to represent the multibyte
42cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   character string pointed to by STRING.  If a non-printable character
43cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned.
44cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   With flags = MBSW_REJECT_INVALID | MBSW_REJECT_UNPRINTABLE, this is
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the multibyte analogue of the wcswidth function.  */
46cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Projectint
47cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Projectmbswidth (const char *string, int flags)
48cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project{
49cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  return mbsnwidth (string, strlen (string), flags);
50cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project}
51cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
52cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Returns the number of columns needed to represent the multibyte
53cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   character string pointed to by STRING of length NBYTES.  If a
54cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   specified, -1 is returned.  */
56cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Projectint
57cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Projectmbsnwidth (const char *string, size_t nbytes, int flags)
58cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project{
59cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  const char *p = string;
60cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  const char *plimit = p + nbytes;
61cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  int width;
62cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
63cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  width = 0;
64cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  if (MB_CUR_MAX > 1)
65cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project    {
66cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project      while (p < plimit)
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        switch (*p)
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case ' ': case '!': case '"': case '#': case '%':
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '&': case '\'': case '(': case ')': case '*':
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '+': case ',': case '-': case '.': case '/':
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '0': case '1': case '2': case '3': case '4':
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '5': case '6': case '7': case '8': case '9':
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case ':': case ';': case '<': case '=': case '>':
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '?':
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'A': case 'B': case 'C': case 'D': case 'E':
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'F': case 'G': case 'H': case 'I': case 'J':
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'K': case 'L': case 'M': case 'N': case 'O':
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'P': case 'Q': case 'R': case 'S': case 'T':
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'U': case 'V': case 'W': case 'X': case 'Y':
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'Z':
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case '[': case '\\': case ']': case '^': case '_':
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'a': case 'b': case 'c': case 'd': case 'e':
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'f': case 'g': case 'h': case 'i': case 'j':
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'k': case 'l': case 'm': case 'n': case 'o':
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'p': case 'q': case 'r': case 's': case 't':
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'u': case 'v': case 'w': case 'x': case 'y':
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case 'z': case '{': case '|': case '}': case '~':
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* These characters are printable ASCII characters.  */
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              p++;
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              width++;
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              break;
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            default:
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* If we have a multibyte sequence, scan it up to its end.  */
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                mbstate_t mbstate;
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                memset (&mbstate, 0, sizeof mbstate);
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                do
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  {
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    wchar_t wc;
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    size_t bytes;
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    int w;
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    bytes = mbrtowc (&wc, p, plimit - p, &mbstate);
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (bytes == (size_t) -1)
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* An invalid multibyte sequence was encountered.  */
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      {
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        if (!(flags & MBSW_REJECT_INVALID))
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          {
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            p++;
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            width++;
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            break;
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          }
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        else
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          return -1;
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      }
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (bytes == (size_t) -2)
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* An incomplete multibyte character at the end.  */
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      {
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        if (!(flags & MBSW_REJECT_INVALID))
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          {
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            p = plimit;
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            width++;
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            break;
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          }
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        else
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          return -1;
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      }
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (bytes == 0)
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* A null wide character was encountered.  */
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      bytes = 1;
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    w = wcwidth (wc);
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (w >= 0)
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* A printable multibyte character.  */
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      {
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        if (w > INT_MAX - width)
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          goto overflow;
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        width += w;
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      }
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    else
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* An unprintable multibyte character.  */
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (!(flags & MBSW_REJECT_UNPRINTABLE))
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          if (!iswcntrl (wc))
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            {
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              if (width == INT_MAX)
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                goto overflow;
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              width++;
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            }
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        return -1;
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    p += bytes;
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  }
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                while (! mbsinit (&mbstate));
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              break;
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
164cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project      return width;
165cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project    }
166cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
167cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  while (p < plimit)
168cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project    {
169cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project      unsigned char c = (unsigned char) *p++;
170cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (isprint (c))
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (width == INT_MAX)
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            goto overflow;
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          width++;
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
177cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project      else if (!(flags & MBSW_REJECT_UNPRINTABLE))
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (!iscntrl (c))
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (width == INT_MAX)
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                goto overflow;
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              width++;
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
186cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project      else
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return -1;
188cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project    }
189cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  return width;
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang overflow:
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return INT_MAX;
193cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project}
194