unifont-6.3.20131020.tar.gz
[unifont.git] / src / unigenwidth.c
1 /*
2    unigenwidth - IEEE 1003.1-2008 setup to calculate wchar_t string widths.
3
4    Author: Paul Hardy, 2013
5
6    LICENSE:
7
8       This program is free software: you can redistribute it and/or modify
9       it under the terms of the GNU General Public License as published by
10       the Free Software Foundation, either version 2 of the License, or
11       (at your option) any later version.
12
13       This program is distributed in the hope that it will be useful,
14       but WITHOUT ANY WARRANTY; without even the implied warranty of
15       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16       GNU General Public License for more details.
17
18       You should have received a copy of the GNU General Public License
19       along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #define MAXSTRING       256
28
29
30 int main(int argc, char **argv) {
31
32    int i; /* loop variable */
33
34    char teststring[MAXSTRING];
35    int  loc;
36    char *gstart;
37
38    char plane0width[0x10000];
39
40    FILE *infilefp;
41
42    /*
43       if (argc != 3) {
44          fprintf(stderr, "\n\nUsage: %s <unifont-file.hex> <combining.txt>\n\n");
45          exit(EXIT_FAILURE);
46       }
47    */
48
49    /*
50       Read the collection of hex glyphs.
51    */
52    if ((infilefp = fopen(argv[1],"r")) == NULL) {
53       fprintf(stderr,"ERROR - hex input file %s not found.\n\n", argv[1]);
54       exit(EXIT_FAILURE);
55    }
56
57    memset(plane0width, 0, 0x10000 * sizeof(char));
58
59    teststring[MAXSTRING] = '\0';
60    while (fgets(teststring, MAXSTRING-1, infilefp) != NULL) {
61       sscanf(teststring, "%X", &loc);
62       gstart = index(teststring,':') + 1;
63       plane0width[loc] = strlen(gstart) <= 34 ? 1 : 2;
64    }
65
66    fclose(infilefp);
67
68    /*
69       Now read the combining character code points.  These have width of 0.
70    */
71    if ((infilefp = fopen(argv[2],"r")) == NULL) {
72       fprintf(stderr,"ERROR - combining characters file %s not found.\n\n", argv[2]);
73       exit(EXIT_FAILURE);
74    }
75
76    while (fscanf(infilefp, "%X", &loc) != EOF) plane0width[loc] = 0;
77
78    fclose(infilefp);
79
80    /*
81       Code Points with Unusual Properties (Unicode Standard, Chapter 4)
82    */
83    plane0width[0]=0; /* NULL character */
84    for (i = 0x0001; i <= 0x001F; i++) plane0width[i]=-1; /* Control Characters */
85    for (i = 0x007F; i <= 0x009F; i++) plane0width[i]=-1; /* Control Characters */
86
87    plane0width[0x034F]=0; /* combining grapheme joiner               */
88    plane0width[0x180B]=0; /* Mongolian free variation selector one   */
89    plane0width[0x180C]=0; /* Mongolian free variation selector two   */
90    plane0width[0x180D]=0; /* Mongolian free variation selector three */
91    plane0width[0x180E]=0; /* Mongolian vowel separator               */
92    plane0width[0x200B]=0; /* zero width space                        */
93    plane0width[0x200C]=0; /* zero width non-joiner                   */
94    plane0width[0x200D]=0; /* zero width joiner                       */
95    plane0width[0x200E]=0; /* left-to-right mark                      */
96    plane0width[0x200F]=0; /* right-to-left mark                      */
97    plane0width[0x202A]=0; /* left-to-right embedding                 */
98    plane0width[0x202B]=0; /* right-to-left embedding                 */
99    plane0width[0x202C]=0; /* pop directional formatting              */
100    plane0width[0x202D]=0; /* left-to-right override                  */
101    plane0width[0x202E]=0; /* right-to-left override                  */
102    plane0width[0x2060]=0; /* word joiner                             */
103    plane0width[0x2061]=0; /* function application                    */
104    plane0width[0x2062]=0; /* invisible times                         */
105    plane0width[0x2063]=0; /* invisible separator                     */
106    plane0width[0x2064]=0; /* invisible plus                          */
107    plane0width[0x206A]=0; /* inhibit symmetric swapping              */
108    plane0width[0x206B]=0; /* activate symmetric swapping             */
109    plane0width[0x206C]=0; /* inhibit arabic form shaping             */
110    plane0width[0x206D]=0; /* activate arabic form shaping            */
111    plane0width[0x206E]=0; /* national digit shapes                   */
112    plane0width[0x206F]=0; /* nominal digit shapes                    */
113
114    /*
115       Ideographic Description Character Left to Right..
116       Ideographic Description Character Overlaid
117    */
118    for (i = 0x2FF0; i <= 0x2FFB; i++) plane0width[i] = 0;
119
120    plane0width[0x303E] = 0; /* ideographic variation indicator */
121
122    /* Variation Selector-1 to Variation Selector-16 */
123    for (i = 0xFE00; i <= 0xFE0F; i++) plane0width[i] = 0;
124
125    plane0width[0xFEFF]=0; /* zero width no-break space         */
126    plane0width[0xFFF9]=0; /* interlinear annotation anchor     */
127    plane0width[0xFFFA]=0; /* interlinear annotation separator  */
128    plane0width[0xFFFB]=0; /* interlinear annotation terminator */
129    /*
130       Let glyph widths represent 0xFFFC (object replacement character)
131       and 0xFFFD (replacement character).
132    */
133
134    /*
135       Hangul Jamo:
136
137          Leading Consonant (Choseong): leave spacing as is.
138
139          Hangul Choseong Filler (U+115F): set width to 2.
140
141          Hangul Jungseong Filler, Hangul Vowel (Jungseong), and
142          Final Consonant (Jongseong): set width to 0, because these
143          combine with the leading consonant as one composite syllabic
144          glyph.  As of Unicode 5.2, the Hangul Jamo block (U+1100..U+11FF)
145          is completely filled.
146    */
147    for (i = 0x1160; i <= 0x11FF; i++) plane0width[i]=0; /* Vowels & Final Consonants */
148
149    /*
150       Private Use Area -- the width is undefined, but likely
151       to be 2 charcells wide either from a graphic glyph or
152       from a four-digit hexadecimal glyph representing the
153       code point.  Therefore if any PUA glyph does not have
154       a non-zero width yet, assign it a default width of 2.
155       The Unicode Standard allows giving PUA characters
156       default property values; see for example The Unicode
157       Standard Version 5.0, p. 91.  This same default is
158       used for higher plane PUA code points below.
159    */
160    for (i = 0xE000; i <= 0xF8FF; i++) {
161       if (plane0width[i] == 0) plane0width[i]=2;
162    }
163
164    /*
165       <not a character>
166    */
167    for (i = 0xFDD0; i <= 0xFDEF; i++) plane0width[i] = -1;
168    plane0width[0xFFFE] = -1; /* Byte Order Mark */
169    plane0width[0xFFFF] = -1; /* Byte Order Mark */
170
171    /* Surrogate Code Points */
172    for (i = 0xD800; i <= 0xDFFF; i++) plane0width[i]=-1;
173
174
175    /*
176       Now generate the output file.
177    */
178    printf("/*\n");
179    printf("   wcwidth() and wcswidth() functions, as per IEEE 1003.1-2008\n");
180    printf("   System Interfaces, pp. 2241 and 2251.\n\n");
181    printf("   Author: Paul Hardy, 2013\n\n");
182    printf("   Copyright (c) 2013 Paul Hardy\n\n");
183    printf("   LICENSE:\n");
184    printf("\n");
185    printf("      This program is free software: you can redistribute it and/or modify\n");
186    printf("      it under the terms of the GNU General Public License as published by\n");
187    printf("      the Free Software Foundation, either version 2 of the License, or\n");
188    printf("      (at your option) any later version.\n");
189    printf("\n");
190    printf("      This program is distributed in the hope that it will be useful,\n");
191    printf("      but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
192    printf("      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
193    printf("      GNU General Public License for more details.\n");
194    printf("\n");
195    printf("      You should have received a copy of the GNU General Public License\n");
196    printf("      along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
197    printf("*/\n\n");
198
199    printf("#include <wchar.h>\n\n");
200    printf("#define PLANE1_ZEROES 177\n\n");
201    printf("\n\n");
202    printf("/* wcwidth() -- return charcell positions of one code point */\n");
203    printf("inline int wcwidth(wchar_t wc) {\n");
204    printf("   return(wcswidth(&wc, 1));\n");
205    printf("}\n");
206    printf("\n\n");
207    printf("int wcswidth(const wchar_t *pwcs, size_t n) {\n\n");
208    printf("   int i;                    /* loop variable                                      */\n");
209    printf("   unsigned codept;          /* Unicode code point of current character            */\n");
210    printf("   unsigned plane;           /* Unicode plane, 0x00..0x10                          */\n");
211    printf("   unsigned lower16;         /* lower 16 bits of Unicode code point                */\n");
212    printf("   int lowpt, midpt, highpt; /* for binary searching in plane1zeroes[]             */\n");
213    printf("   int found;                /* for binary searching in plane1zeroes[]             */\n");
214    printf("   int totalwidth;           /* total width of string, in charcells (1 or 2/glyph) */\n");
215    printf("   int illegalchar;          /* Whether or not tihs code point is illegal          */\n");
216    putchar('\n');
217
218    /*
219       Print the plane0width[] array for glyphs widths in the
220       Basic Multilingual Plane (Plane 0).
221    */
222    printf("   char plane0width[0x10000] = {");
223    for (i = 0; i < 0x10000; i++) {
224       if ((i & 0x1F) == 0)
225          printf("\n      /* U+%04X */ ", i);
226       printf("%d,", plane0width[i]);
227    }
228    printf("};\n\n");
229
230    /*
231       Print wide zero-width glyph code points in the
232       Supplemental Lingual Plane (Plane 1).
233    */
234    printf("\n");
235    printf("   /*\n");
236    printf("      Zero-width code points in Supplemental Multilingual Plane\n");
237    printf("   */\n");
238    printf("   int plane1zeroes[PLANE1_ZEROES] = {\n");
239    printf("      /* Phaistos Disc */\n");
240    printf("      0x0101FD,\n");
241    printf("      /* Kharoshthi Combining Glyphs */\n");
242    printf("      0x010A01,0x010A02,0x010A03,0x010A05,0x010A06,0x010A0C,0x010A0D,\n");
243    printf("      0x010A0E,0x010A0F,0x010A38,0x010A39,0x010A3A,0x010A3F,\n");
244    printf("      /* Brahmi Combining Glyphs */\n");
245    printf("      0x011000,0x011001,0x011002,0x011038,0x011039,0x01103A,0x01103B,\n");
246    printf("      0x01103C,0x01103D,0x01103E,0x01103F,0x011040,0x011041,0x011042,\n");
247    printf("      0x011043,0x011044,0x011045,0x011046,\n");
248    printf("      /* Kaithi Combining Glyphs */\n");
249    printf("      0x011080,0x011081,0x011082,0x0110B0,0x0110B1,0x0110B2,0x0110B3,\n");
250    printf("      0x0110B4,0x0110B5,0x0110B6,0x0110B7,0x0110B8,0x0110B9,0x0110BA,\n");
251    printf("      /* Chakma Combining Glyphs */\n");
252    printf("      0x011100,0x011101,0x011102,0x011127,0x011128,0x011129,0x01112A,\n");
253    printf("      0x01112B,0x01112C,0x01112D,0x01112E,0x01112F,0x011130,0x011131,\n");
254    printf("      0x011132,0x011133,0x011134,\n");
255    printf("      /* Sharada Combining Glyphs */\n");
256    printf("      0x011180,0x011181,0x011182,0x0111B3,0x0111B4,0x0111B5,0x0111B6,\n");
257    printf("      0x0111B7,0x0111B8,0x0111B9,0x0111BA,0x0111BB,0x0111BC,0x0111BD,\n");
258    printf("      0x0111BE,0x0111BF,0x0111C0,\n");
259    printf("      /* Takri Combining Glyphs */\n");
260    printf("      0x0116AB,0x0116AC,0x0116AD,0x0116AE,0x0116AF,0x0116B0,0x0116B1,\n");
261    printf("      0x0116B2,0x0116B3,0x0116B4,0x0116B5,0x0116B6,0x0116B7,\n");
262    printf("      /* Miao Combining Glyphs */\n");
263    printf("      0x016F51,0x016F52,0x016F53,0x016F54,0x016F55,0x016F56,0x016F57,\n");
264    printf("      0x016F58,0x016F59,0x016F5A,0x016F5B,0x016F5C,0x016F5D,0x016F5E,\n");
265    printf("      0x016F5F,0x016F60,0x016F61,0x016F62,0x016F63,0x016F64,0x016F65,\n");
266    printf("      0x016F66,0x016F67,0x016F68,0x016F69,0x016F6A,0x016F6B,0x016F6C,\n");
267    printf("      0x016F6D,0x016F6E,0x016F6F,0x016F70,0x016F71,0x016F72,0x016F73,\n");
268    printf("      0x016F74,0x016F75,0x016F76,0x016F77,0x016F78,0x016F79,0x016F7A,\n");
269    printf("      0x016F7B,0x016F7C,0x016F7D,0x016F7E,\n");
270    printf("      0x016F8F,0x016F90,0x016F91,0x016F92,\n");
271    printf("      /* Musical Symbols Combining Glyphs */\n");
272    printf("      0x01D159,0x01D165,0x01D166,0x01D167,0x01D168,0x01D169,0x01D16D,\n");
273    printf("      0x01D16E,0x01D16F,0x01D170,0x01D171,0x01D172,0x01D17B,0x01D17C,\n");
274    printf("      0x01D17D,0x01D17E,0x01D17F,0x01D180,0x01D181,0x01D182,0x01D185,\n");
275    printf("      0x01D186,0x01D187,0x01D188,0x01D189,0x01D18A,0x01D18B,0x01D1AA,\n");
276    printf("      0x01D1AB,0x01D1AC,0x01D1AD,\n");
277    printf("      /* Ancient Greek Musical Notation */\n");
278    printf("      0x01D242,0x01D243,0x01D244\n");
279    printf("   };\n\n");
280
281    /*
282       Execution part of wcswidth().
283    */
284    printf("\n");
285    printf("   illegalchar = totalwidth = 0;\n");
286    printf("   for (i = 0; !illegalchar && i < n; i++) {\n");
287    printf("      codept  = pwcs[i];\n");
288    printf("      plane   = codept >> 16;\n");
289    printf("      lower16 = codept & 0xFFFF;\n");
290    printf("      if (plane == 0) { /* the most common case */\n");
291    printf("         if (plane0width[lower16] < 0) illegalchar = 1;\n");
292    printf("         else totalwidth += plane0width[lower16];\n");
293    printf("      }\n");
294    printf("      else { /* a higher plane or beyond Unicode range */\n");
295    printf("         if (lower16 == 0xFFFE || lower16 == 0xFFFF) {\n");
296    printf("            illegalchar = 1;\n");
297    printf("         }\n");
298    printf("         else if (plane > 0x10) {\n");
299    printf("            illegalchar = 1;\n");
300    printf("         }\n");
301    printf("         else if (plane == 1) { /* Supplementary Multilingual Plane */\n");
302    printf("            /*\n");
303    printf("               Perform a binary search in plane1zeroes[] sparse list for\n");
304    printf("               combining code points and other zero-width code points.\n");
305    printf("            */\n");
306    printf("            lowpt  = 0;\n");
307    printf("            highpt = PLANE1_ZEROES - 1;\n");
308    printf("\n");
309    printf("            while (lowpt < highpt) {\n");
310    printf("               midpt  = (lowpt + highpt) >> 1;\n");
311    printf("               if (plane1zeroes[midpt] < codept)\n");
312    printf("                  lowpt = midpt + 1;\n");
313    printf("               else if (plane1zeroes[midpt] > codept)\n");
314    printf("                  highpt = midpt - 1;\n");
315    printf("               else\n");
316    printf("                  lowpt = highpt = midpt; /* found the match */\n");
317    printf("            }\n");
318    printf("\n");
319    printf("            if (lowpt >= 0 && codept == plane1zeroes[lowpt]) {\n");
320    printf("               found = 1;\n");
321    printf("            }\n");
322    printf("            else if (highpt < PLANE1_ZEROES && codept == plane1zeroes[highpt]) {\n");
323    printf("               found = 1;\n");
324    printf("            }\n");
325    printf("            else {\n");
326    printf("               found = 0;\n");
327    printf("            }\n");
328    printf("\n");
329    printf("            if (!found) totalwidth += 2; /* default for SMP glyphs */\n");
330    printf("         }\n");
331    printf("         /* Other non-printing in higher planes; return -1 as per IEEE 1003.1-2008. */\n");
332    printf("         else if (/* language tags */\n");
333    printf("                  codept == 0x0E0001 || (codept >= 0x0E0020 && codept <= 0x0E007F) ||\n");
334    printf("                  /* variation selectors, 0x0E0100..0x0E01EF */\n");
335    printf("                  (codept >= 0x0E0100 && codept <= 0x0E01EF)) {\n");
336    printf("            illegalchar = 1;\n");
337    printf("         }\n");
338    printf("         /*\n");
339    printf("            Unicode plane 0x02..0x10 printing character\n");
340    printf("         */\n");
341    printf("         else {\n");
342    printf("            totalwidth += 2; /* default width of 2 charcells for legal glyphs */\n");
343    printf("         }\n");
344    printf("\n");
345    printf("      }\n");
346    printf("   }\n");
347    printf("   if (illegalchar) totalwidth = -1;\n");
348    printf("\n");
349    printf("   return(totalwidth);\n");
350    printf("\n");
351    printf("}\n");
352
353    exit(EXIT_SUCCESS);
354 }