testsuite: fix g++.dg/pr112822.C
[official-gcc.git] / libcpp / makeucnid.cc
blob5ce17b7f7809e5a8daa8d734f631d9e1cc86039a
1 /* Make ucnid.h from various sources.
2 Copyright (C) 2005-2023 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3, or (at your option) any
7 later version.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING3. If not see
16 <http://www.gnu.org/licenses/>. */
18 /* Run this program as
19 ./makeucnid ucnid.tab UnicodeData.txt DerivedNormalizationProps.txt \
20 DerivedCoreProperties.txt > ucnid.h
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <stdbool.h>
27 #include <stdlib.h>
29 enum {
30 C99 = 1,
31 CXX = 2,
32 N99 = 4,
33 C11 = 8,
34 N11 = 16,
35 CXX23 = 32,
36 NXX23 = 64,
37 all_languages = C99 | CXX | C11 | CXX23 | NXX23,
38 not_NFC = 128,
39 not_NFKC = 256,
40 maybe_not_NFC = 512
43 #define NUM_CODE_POINTS 0x110000
44 #define MAX_CODE_POINT 0x10ffff
46 static unsigned flags[NUM_CODE_POINTS];
47 static unsigned int all_decomp[NUM_CODE_POINTS][2];
48 static unsigned int decomp[NUM_CODE_POINTS][2];
49 static unsigned char combining_value[NUM_CODE_POINTS];
51 /* Die! */
53 static void
54 fail (const char *s)
56 fprintf (stderr, "%s\n", s);
57 exit (1);
60 /* Read ucnid.tab and set the flags for language versions in header[]. */
62 static void
63 read_ucnid (const char *fname)
65 FILE *f = fopen (fname, "r");
66 unsigned fl = 0;
68 if (!f)
69 fail ("opening ucnid.tab");
70 for (;;)
72 char line[256];
74 if (!fgets (line, sizeof (line), f))
75 break;
76 if (strcmp (line, "[C99]\n") == 0)
77 fl = C99;
78 else if (strcmp (line, "[C99DIG]\n") == 0)
79 fl = C99|N99;
80 else if (strcmp (line, "[CXX]\n") == 0)
81 fl = CXX;
82 else if (strcmp (line, "[C11]\n") == 0)
83 fl = C11;
84 else if (strcmp (line, "[C11NOSTART]\n") == 0)
85 fl = C11|N11;
86 else if (isxdigit (line[0]))
88 char *l = line;
89 while (*l)
91 unsigned long start, end;
92 char *endptr;
93 start = strtoul (l, &endptr, 16);
94 if (endptr == l || (*endptr != '-' && ! isspace (*endptr)))
95 fail ("parsing ucnid.tab [1]");
96 l = endptr;
97 if (*l != '-')
98 end = start;
99 else
101 end = strtoul (l + 1, &endptr, 16);
102 if (end < start)
103 fail ("parsing ucnid.tab, end before start");
104 l = endptr;
105 if (! isspace (*l))
106 fail ("parsing ucnid.tab, junk after range");
108 while (isspace (*l))
109 l++;
110 if (end > MAX_CODE_POINT)
111 fail ("parsing ucnid.tab, end too large");
112 while (start <= end)
113 flags[start++] |= fl;
117 if (ferror (f))
118 fail ("reading ucnid.tab");
119 fclose (f);
122 /* Read UnicodeData.txt and fill in the 'decomp' table to be the
123 decompositions of characters for which both the character
124 decomposed and all the code points in the decomposition are valid
125 for some supported language version, and the 'all_decomp' table to
126 be the decompositions of all characters without those
127 constraints. */
129 static void
130 read_table (char *fname)
132 FILE * f = fopen (fname, "r");
134 if (!f)
135 fail ("opening UnicodeData.txt");
136 for (;;)
138 char line[256];
139 unsigned long codepoint, this_decomp[4];
140 char *l;
141 int i, j;
142 int decomp_useful;
144 if (!fgets (line, sizeof (line), f))
145 break;
146 codepoint = strtoul (line, &l, 16);
147 if (l == line || *l != ';')
148 fail ("parsing UnicodeData.txt, reading code point");
149 if (codepoint > MAX_CODE_POINT)
150 fail ("parsing UnicodeData.txt, code point too large");
152 do {
153 l++;
154 } while (*l != ';');
155 /* Category value. */
156 do {
157 l++;
158 } while (*l != ';');
159 /* Canonical combining class; in NFC/NFKC, they must be increasing
160 (or zero). */
161 if (! isdigit (*++l))
162 fail ("parsing UnicodeData.txt, combining class not number");
163 combining_value[codepoint] = strtoul (l, &l, 10);
164 if (*l++ != ';')
165 fail ("parsing UnicodeData.txt, junk after combining class");
167 /* Skip over bidi value. */
168 do {
169 l++;
170 } while (*l != ';');
172 /* Decomposition mapping. */
173 decomp_useful = flags[codepoint];
174 if (*++l == '<') /* Compatibility mapping. */
175 continue;
176 for (i = 0; i < 4; i++)
178 if (*l == ';')
179 break;
180 if (!isxdigit (*l))
181 fail ("parsing UnicodeData.txt, decomposition format");
182 this_decomp[i] = strtoul (l, &l, 16);
183 decomp_useful &= flags[this_decomp[i]];
184 while (isspace (*l))
185 l++;
187 if (i > 2) /* Decomposition too long. */
188 fail ("parsing UnicodeData.txt, decomposition too long");
189 for (j = 0; j < i; j++)
190 all_decomp[codepoint][j] = this_decomp[j];
191 if ((flags[codepoint] & all_languages) && decomp_useful)
192 while (--i >= 0)
193 decomp[codepoint][i] = this_decomp[i];
195 if (ferror (f))
196 fail ("reading UnicodeData.txt");
197 fclose (f);
200 /* Read DerivedNormalizationProps.txt and set the flags that say whether
201 a character is in NFC, NFKC, or is context-dependent. */
203 static void
204 read_derived (const char *fname)
206 FILE * f = fopen (fname, "r");
208 if (!f)
209 fail ("opening DerivedNormalizationProps.txt");
210 for (;;)
212 char line[256];
213 unsigned long start, end;
214 char *l;
215 bool not_NFC_p, not_NFKC_p, maybe_not_NFC_p;
217 if (!fgets (line, sizeof (line), f))
218 break;
219 not_NFC_p = (strstr (line, "; NFC_QC; N") != NULL);
220 not_NFKC_p = (strstr (line, "; NFKC_QC; N") != NULL);
221 maybe_not_NFC_p = (strstr (line, "; NFC_QC; M") != NULL);
222 if (! not_NFC_p && ! not_NFKC_p && ! maybe_not_NFC_p)
223 continue;
225 start = strtoul (line, &l, 16);
226 if (l == line)
227 fail ("parsing DerivedNormalizationProps.txt, reading start");
228 if (start > MAX_CODE_POINT)
229 fail ("parsing DerivedNormalizationProps.txt, code point too large");
230 if (*l == '.' && l[1] == '.')
231 end = strtoul (l + 2, &l, 16);
232 else
233 end = start;
235 while (start <= end)
236 flags[start++] |= ((not_NFC_p ? not_NFC : 0)
237 | (not_NFKC_p ? not_NFKC : 0)
238 | (maybe_not_NFC_p ? maybe_not_NFC : 0)
241 if (ferror (f))
242 fail ("reading DerivedNormalizationProps.txt");
243 fclose (f);
246 /* Read DerivedCoreProperties.txt and fill in languages version in
247 flags from the XID_Start and XID_Continue properties. */
249 static void
250 read_derivedcore (char *fname)
252 FILE * f = fopen (fname, "r");
254 if (!f)
255 fail ("opening DerivedCoreProperties.txt");
256 for (;;)
258 char line[256];
259 unsigned long codepoint_start, codepoint_end;
260 char *l;
261 int i, j;
263 if (!fgets (line, sizeof (line), f))
264 break;
265 if (line[0] == '#' || line[0] == '\n' || line[0] == '\r')
266 continue;
267 codepoint_start = strtoul (line, &l, 16);
268 if (l == line)
269 fail ("parsing DerivedCoreProperties.txt, reading code point");
270 if (codepoint_start > MAX_CODE_POINT)
271 fail ("parsing DerivedCoreProperties.txt, code point too large");
273 if (*l == '.' && l[1] == '.')
275 char *l2 = l + 2;
276 codepoint_end = strtoul (l + 2, &l, 16);
277 if (l == l2 || codepoint_end < codepoint_start)
278 fail ("parsing DerivedCoreProperties.txt, reading code point");
279 if (codepoint_end > MAX_CODE_POINT)
280 fail ("parsing DerivedCoreProperties.txt, code point too large");
282 else
283 codepoint_end = codepoint_start;
285 while (*l == ' ')
286 l++;
287 if (*l++ != ';')
288 fail ("parsing DerivedCoreProperties.txt, reading code point");
290 while (*l == ' ')
291 l++;
293 if (codepoint_end < 0x80)
294 continue;
296 if (strncmp (l, "XID_Start ", 10) == 0)
298 for (; codepoint_start <= codepoint_end; codepoint_start++)
299 flags[codepoint_start]
300 = (flags[codepoint_start] | CXX23) & ~NXX23;
302 else if (strncmp (l, "XID_Continue ", 13) == 0)
304 for (; codepoint_start <= codepoint_end; codepoint_start++)
305 if ((flags[codepoint_start] & CXX23) == 0)
306 flags[codepoint_start] |= CXX23 | NXX23;
309 if (ferror (f))
310 fail ("reading DerivedCoreProperties.txt");
311 fclose (f);
314 /* Write out the table.
315 The table consists of two words per entry. The first word is the flags
316 for the unicode code points up to and including the second word. */
318 static void
319 write_table (void)
321 unsigned i;
322 unsigned last_flag = flags[0];
323 bool really_safe = decomp[0][0] == 0;
324 unsigned char last_combine = combining_value[0];
326 printf ("static const struct ucnrange ucnranges[] = {\n");
328 for (i = 1; i <= NUM_CODE_POINTS; i++)
329 if (i == NUM_CODE_POINTS
330 || (flags[i] != last_flag && ((flags[i] | last_flag) & all_languages))
331 || really_safe != (decomp[i][0] == 0)
332 || combining_value[i] != last_combine)
334 printf ("{ %s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s, %3d, %#06x },\n",
335 last_flag & C99 ? "C99" : " 0",
336 last_flag & N99 ? "N99" : " 0",
337 last_flag & CXX ? "CXX" : " 0",
338 last_flag & C11 ? "C11" : " 0",
339 last_flag & N11 ? "N11" : " 0",
340 last_flag & CXX23 ? "CXX23" : " 0",
341 last_flag & NXX23 ? "NXX23" : " 0",
342 really_safe ? "CID" : " 0",
343 last_flag & not_NFC ? " 0" : "NFC",
344 last_flag & not_NFKC ? " 0" : "NKC",
345 last_flag & maybe_not_NFC ? "CTX" : " 0",
346 combining_value[i - 1],
347 i - 1);
348 last_flag = flags[i];
349 last_combine = combining_value[i];
350 really_safe = decomp[i][0] == 0;
353 printf ("};\n");
356 /* Return whether a given character is valid in an identifier for some
357 supported language, either as itself or as a UCN. */
359 static bool
360 char_id_valid (unsigned int c)
362 return ((flags[c] & all_languages)
363 || (c == 0x24)
364 || (c >= 0x30 && c <= 0x39)
365 || (c >= 0x41 && c <= 0x5a)
366 || (c >= 0x61 && c <= 0x7a));
369 /* Write out the switch statement over characters for which it is
370 context-dependent whether they are in NFC. */
372 static void
373 write_context_switch (void)
375 unsigned i;
376 printf ("static bool\n"
377 "check_nfc (cpp_reader *pfile, cppchar_t c, cppchar_t p)\n"
378 "{\n"
379 " switch (c)\n"
380 " {\n");
381 for (i = 0; i < NUM_CODE_POINTS; i++)
383 bool found_case = false;
384 unsigned j;
385 if (!(flags[i] & all_languages) || !(flags[i] & maybe_not_NFC))
386 continue;
387 if ((i >= 0x1161 && i <= 0x1175) || (i >= 0x11A8 && i <= 0x11C2))
388 continue; /* Hangul handled algorithmically. */
389 printf (" case %#06x:\n"
390 " switch (p)\n"
391 "\t{\n", i);
392 /* If an NFC starter character decomposes with this character I
393 as the second character and an NFC starter character S as the
394 first character, that latter character as a previous
395 character means this character is not NFC. Furthermore, any
396 NFC starter character K made by a series of compositions of S
397 with combining characters whose combining class is greater
398 than that of I also means this character is not NFC. */
399 for (j = 0; j < NUM_CODE_POINTS; j++)
401 unsigned s, k;
402 if (all_decomp[j][1] != i)
403 continue;
404 s = all_decomp[j][0];
405 if (combining_value[s] != 0 || (flags[s] & not_NFC) != 0)
406 continue;
407 if (char_id_valid (s))
409 found_case = true;
410 printf ("\tcase %#06x:\n", s);
412 for (k = 0; k < NUM_CODE_POINTS; k++)
414 unsigned t = k;
415 if (k == s || !char_id_valid (k))
416 continue;
417 while (all_decomp[t][1] != 0
418 && combining_value[all_decomp[t][1]] > combining_value[i])
420 if (combining_value[t] != 0 || (flags[t] & not_NFC) != 0)
421 break;
422 t = all_decomp[t][0];
424 if (t == s)
426 found_case = true;
427 printf ("\tcase %#06x:\n", k);
431 if (found_case)
432 printf ("\t return false;\n");
433 else
434 printf ("\t/* Non-NFC cases not applicable to C/C++. */\n");
435 printf ("\tdefault:\n"
436 "\t return true;\n"
437 "\t}\n\n");
439 printf (" default:\n"
440 " cpp_error (pfile, CPP_DL_ICE, \"Character %%x might not be NFKC\", c);\n"
441 " return true;\n"
442 " }\n"
443 "}\n");
446 /* Print out the huge copyright notice. */
448 static void
449 write_copyright (void)
451 static const char copyright[] = "\
452 /* Unicode characters and various properties.\n\
453 Copyright (C) 2003-2023 Free Software Foundation, Inc.\n\
455 This program is free software; you can redistribute it and/or modify it\n\
456 under the terms of the GNU General Public License as published by the\n\
457 Free Software Foundation; either version 3, or (at your option) any\n\
458 later version.\n\
460 This program is distributed in the hope that it will be useful,\n\
461 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
462 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
463 GNU General Public License for more details.\n\
465 You should have received a copy of the GNU General Public License\n\
466 along with this program; see the file COPYING3. If not see\n\
467 <http://www.gnu.org/licenses/>.\n\
470 Copyright (C) 1991-2023 Unicode, Inc. All rights reserved.\n\
471 Distributed under the Terms of Use in\n\
472 http://www.unicode.org/copyright.html.\n\
474 Permission is hereby granted, free of charge, to any person\n\
475 obtaining a copy of the Unicode data files and any associated\n\
476 documentation (the \"Data Files\") or Unicode software and any\n\
477 associated documentation (the \"Software\") to deal in the Data Files\n\
478 or Software without restriction, including without limitation the\n\
479 rights to use, copy, modify, merge, publish, distribute, and/or\n\
480 sell copies of the Data Files or Software, and to permit persons to\n\
481 whom the Data Files or Software are furnished to do so, provided\n\
482 that (a) the above copyright notice(s) and this permission notice\n\
483 appear with all copies of the Data Files or Software, (b) both the\n\
484 above copyright notice(s) and this permission notice appear in\n\
485 associated documentation, and (c) there is clear notice in each\n\
486 modified Data File or in the Software as well as in the\n\
487 documentation associated with the Data File(s) or Software that the\n\
488 data or software has been modified.\n\
490 THE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY\n\
491 OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n\
492 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n\
493 NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE\n\
494 COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR\n\
495 ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY\n\
496 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\n\
497 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n\
498 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\n\
499 OF THE DATA FILES OR SOFTWARE.\n\
501 Except as contained in this notice, the name of a copyright holder\n\
502 shall not be used in advertising or otherwise to promote the sale,\n\
503 use or other dealings in these Data Files or Software without prior\n\
504 written authorization of the copyright holder. */\n";
506 puts (copyright);
509 /* Main program. */
512 main(int argc, char ** argv)
514 if (argc != 5)
515 fail ("too few arguments to makeucn");
516 read_ucnid (argv[1]);
517 read_table (argv[2]);
518 read_derived (argv[3]);
519 read_derivedcore (argv[4]);
521 write_copyright ();
522 write_table ();
523 write_context_switch ();
524 return 0;