]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - wcwidth.c
RDB's Unicode patch. Fonts are now used in Unicode mode where
[PuTTY.git] / wcwidth.c
1 /*
2  * This is an implementation of wcwidth() and wcswidth() as defined in
3  * "The Single UNIX Specification, Version 2, The Open Group, 1997"
4  * <http://www.UNIX-systems.org/online.html>
5  *
6  * Markus Kuhn -- 2000-02-08 -- public domain
7  */
8
9 #include <wchar.h>
10
11 /* These functions define the column width of an ISO 10646 character
12  * as follows:
13  *
14  *    - The null character (U+0000) has a column width of 0.
15  *
16  *    - Other C0/C1 control characters and DEL will lead to a return
17  *      value of -1.
18  *
19  *    - Non-spacing and enclosing combining characters (general
20  *      category code Mn or Me in the Unicode database) have a
21  *      column width of 0.
22  *
23  *    - Spacing characters in the East Asian Wide (W) or East Asian
24  *      FullWidth (F) category as defined in Unicode Technical
25  *      Report #11 have a column width of 2.
26  *
27  *    - All remaining characters (including all printable
28  *      ISO 8859-1 and WGL4 characters, Unicode control characters,
29  *      etc.) have a column width of 1.
30  *
31  * This implementation assumes that wchar_t characters are encoded
32  * in ISO 10646.
33  */
34
35 int wcwidth(wchar_t ucs)
36 {
37     /* sorted list of non-overlapping intervals of non-spacing characters */
38     static const struct interval {
39         unsigned short first;
40         unsigned short last;
41     } combining[] = {
42         {
43         0x0300, 0x034E}, {
44         0x0360, 0x0362}, {
45         0x0483, 0x0486}, {
46         0x0488, 0x0489}, {
47         0x0591, 0x05A1}, {
48         0x05A3, 0x05B9}, {
49         0x05BB, 0x05BD}, {
50         0x05BF, 0x05BF}, {
51         0x05C1, 0x05C2}, {
52         0x05C4, 0x05C4}, {
53         0x064B, 0x0655}, {
54         0x0670, 0x0670}, {
55         0x06D6, 0x06E4}, {
56         0x06E7, 0x06E8}, {
57         0x06EA, 0x06ED}, {
58         0x0711, 0x0711}, {
59         0x0730, 0x074A}, {
60         0x07A6, 0x07B0}, {
61         0x0901, 0x0902}, {
62         0x093C, 0x093C}, {
63         0x0941, 0x0948}, {
64         0x094D, 0x094D}, {
65         0x0951, 0x0954}, {
66         0x0962, 0x0963}, {
67         0x0981, 0x0981}, {
68         0x09BC, 0x09BC}, {
69         0x09C1, 0x09C4}, {
70         0x09CD, 0x09CD}, {
71         0x09E2, 0x09E3}, {
72         0x0A02, 0x0A02}, {
73         0x0A3C, 0x0A3C}, {
74         0x0A41, 0x0A42}, {
75         0x0A47, 0x0A48}, {
76         0x0A4B, 0x0A4D}, {
77         0x0A70, 0x0A71}, {
78         0x0A81, 0x0A82}, {
79         0x0ABC, 0x0ABC}, {
80         0x0AC1, 0x0AC5}, {
81         0x0AC7, 0x0AC8}, {
82         0x0ACD, 0x0ACD}, {
83         0x0B01, 0x0B01}, {
84         0x0B3C, 0x0B3C}, {
85         0x0B3F, 0x0B3F}, {
86         0x0B41, 0x0B43}, {
87         0x0B4D, 0x0B4D}, {
88         0x0B56, 0x0B56}, {
89         0x0B82, 0x0B82}, {
90         0x0BC0, 0x0BC0}, {
91         0x0BCD, 0x0BCD}, {
92         0x0C3E, 0x0C40}, {
93         0x0C46, 0x0C48}, {
94         0x0C4A, 0x0C4D}, {
95         0x0C55, 0x0C56}, {
96         0x0CBF, 0x0CBF}, {
97         0x0CC6, 0x0CC6}, {
98         0x0CCC, 0x0CCD}, {
99         0x0D41, 0x0D43}, {
100         0x0D4D, 0x0D4D}, {
101         0x0DCA, 0x0DCA}, {
102         0x0DD2, 0x0DD4}, {
103         0x0DD6, 0x0DD6}, {
104         0x0E31, 0x0E31}, {
105         0x0E34, 0x0E3A}, {
106         0x0E47, 0x0E4E}, {
107         0x0EB1, 0x0EB1}, {
108         0x0EB4, 0x0EB9}, {
109         0x0EBB, 0x0EBC}, {
110         0x0EC8, 0x0ECD}, {
111         0x0F18, 0x0F19}, {
112         0x0F35, 0x0F35}, {
113         0x0F37, 0x0F37}, {
114         0x0F39, 0x0F39}, {
115         0x0F71, 0x0F7E}, {
116         0x0F80, 0x0F84}, {
117         0x0F86, 0x0F87}, {
118         0x0F90, 0x0F97}, {
119         0x0F99, 0x0FBC}, {
120         0x0FC6, 0x0FC6}, {
121         0x102D, 0x1030}, {
122         0x1032, 0x1032}, {
123         0x1036, 0x1037}, {
124         0x1039, 0x1039}, {
125         0x1058, 0x1059}, {
126         0x17B7, 0x17BD}, {
127         0x17C6, 0x17C6}, {
128         0x17C9, 0x17D3}, {
129         0x18A9, 0x18A9}, {
130         0x20D0, 0x20E3}, {
131         0x302A, 0x302F}, {
132         0x3099, 0x309A}, {
133         0xFB1E, 0xFB1E}, {
134         0xFE20, 0xFE23}
135     };
136     int min = 0;
137     int max = sizeof(combining) / sizeof(struct interval) - 1;
138     int mid;
139
140     /* test for 8-bit control characters */
141     if (ucs == 0)
142         return 0;
143     if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
144         return -1;
145
146     /* first quick check for Latin-1 etc. characters */
147     if (ucs < combining[0].first)
148         return 1;
149
150     /* binary search in table of non-spacing characters */
151     while (max >= min) {
152         mid = (min + max) / 2;
153         if (combining[mid].last < ucs)
154             min = mid + 1;
155         else if (combining[mid].first > ucs)
156             max = mid - 1;
157         else if (combining[mid].first <= ucs && combining[mid].last >= ucs)
158             return 0;
159     }
160
161     /* if we arrive here, ucs is not a combining or C0/C1 control character */
162
163     /* fast test for majority of non-wide scripts */
164     if (ucs < 0x1100)
165         return 1;
166
167     return 1 + ((ucs >= 0x1100 && ucs <= 0x115f) ||     /* Hangul Jamo */
168                 
169                 (ucs >= 0x2e80 && ucs <= 0xa4cf
170                  && (ucs & ~0x0011) != 0x300a && ucs != 0x303f) ||      /* CJK ... Yi */
171                 (ucs >= 0xac00 && ucs <= 0xd7a3) ||     /* Hangul Syllables */
172                 (ucs >= 0xf900 && ucs <= 0xfaff) ||     /* CJK Compatibility Ideographs */
173                 (ucs >= 0xfe30 && ucs <= 0xfe6f) ||     /* CJK Compatibility Forms */
174                 (ucs >= 0xff00 && ucs <= 0xff5f) ||     /* Fullwidth Forms */
175                 (ucs >= 0xffe0 && ucs <= 0xffe6));
176 }
177
178
179 int wcswidth(const wchar_t * pwcs, size_t n)
180 {
181     int w, width = 0;
182
183     for (; *pwcs && n-- > 0; pwcs++)
184         if ((w = wcwidth(*pwcs)) < 0)
185             return -1;
186         else
187             width += w;
188
189     return width;
190 }