1 /* Copyright (C) 2000-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library 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 GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <ctype.h>
19 #include <locale.h>
20 #include <langinfo.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 
25 static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
26 static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
27 static const char digits[] = "0123456789";
28 static const char cntrl[] = "\
29 \x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
30 \x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ";
31 
32 
33 static struct classes
34 {
35   const char *name;
36   int mask;
37 } classes[] =
38 {
39 #define ENTRY(name) { #name, _IS##name }
40   ENTRY (upper),
41   ENTRY (lower),
42   ENTRY (alpha),
43   ENTRY (digit),
44   ENTRY (xdigit),
45   ENTRY (space),
46   ENTRY (print),
47   ENTRY (graph),
48   ENTRY (blank),
49   ENTRY (cntrl),
50   ENTRY (punct),
51   ENTRY (alnum)
52 };
53 #define nclasses (sizeof (classes) / sizeof (classes[0]))
54 
55 
56 #define FAIL(str, args...) \
57   {									      \
58     printf ("      " str "\n", ##args);					      \
59     ++errors;								      \
60   }
61 
62 
63 static int
do_test(void)64 do_test (void)
65 {
66   const char *cp;
67   const char *cp2;
68   int errors = 0;
69   char *inpline = NULL;
70   size_t inplinelen = 0;
71   char *resline = NULL;
72   size_t reslinelen = 0;
73   size_t n;
74   const unsigned short int *__ctype_b;
75 
76   setlocale (LC_ALL, "");
77 
78   printf ("Testing the ctype data of the `%s' locale\n",
79 	  setlocale (LC_CTYPE, NULL));
80 
81   __ctype_b = ((const unsigned short *) nl_langinfo (_NL_CTYPE_CLASS)) + 128;
82 
83 #if 0
84   /* Just for debugging.  */
85 
86   /* Contents of the class array.  */
87   printf ("\
88 upper = %04x  lower = %04x  alpha = %04x  digit = %04x  xdigit = %04x\n\
89 space = %04x  print = %04x  graph = %04x  blank = %04x  cntrl  = %04x\n\
90 punct = %04x  alnum = %04x\n",
91 	  _ISupper, _ISlower, _ISalpha, _ISdigit, _ISxdigit,
92 	  _ISspace, _ISprint, _ISgraph, _ISblank, _IScntrl,
93 	  _ISpunct, _ISalnum);
94 
95   while (n < 256)
96     {
97       if (n % 8 == 0)
98 	printf ("%02x: ", n);
99       printf ("%04x%s", __ctype_b[n], (n + 1) % 8 == 0 ? "\n" : " ");
100       ++n;
101     }
102 #endif
103 
104   puts ("  Test of ASCII character range\n    special NUL byte handling");
105   if (isupper ('\0'))
106     FAIL ("isupper ('\\0') is true");
107   if (islower ('\0'))
108     FAIL ("islower ('\\0') is true");
109   if (isalpha ('\0'))
110     FAIL ("isalpha ('\\0') is true");
111   if (isdigit ('\0'))
112     FAIL ("isdigit ('\\0') is true");
113   if (isxdigit ('\0'))
114     FAIL ("isxdigit ('\\0') is true");
115   if (isspace ('\0'))
116     FAIL ("isspace ('\\0') is true");
117   if (isprint ('\0'))
118     FAIL ("isprint ('\\0') is true");
119   if (isgraph ('\0'))
120     FAIL ("isgraph ('\\0') is true");
121   if (isblank ('\0'))
122     FAIL ("isblank ('\\0') is true");
123   if (! iscntrl ('\0'))
124     FAIL ("iscntrl ('\\0') not true");
125   if (ispunct ('\0'))
126     FAIL ("ispunct ('\\0') is true");
127   if (isalnum ('\0'))
128     FAIL ("isalnum ('\\0') is true");
129 
130   puts ("    islower()");
131   for (cp = lower; *cp != '\0'; ++cp)
132     if (! islower (*cp))
133       FAIL ("islower ('%c') not true", *cp);
134   for (cp = upper; *cp != '\0'; ++cp)
135     if (islower (*cp))
136       FAIL ("islower ('%c') is true", *cp);
137   for (cp = digits; *cp != '\0'; ++cp)
138     if (islower (*cp))
139       FAIL ("islower ('%c') is true", *cp);
140   for (cp = cntrl; *cp != '\0'; ++cp)
141     if (islower (*cp))
142       FAIL ("islower ('\\x%02x') is true", *cp);
143 
144   puts ("    isupper()");
145   for (cp = lower; *cp != '\0'; ++cp)
146     if (isupper (*cp))
147       FAIL ("isupper ('%c') is true", *cp);
148   for (cp = upper; *cp != '\0'; ++cp)
149     if (! isupper (*cp))
150       FAIL ("isupper ('%c') not true", *cp);
151   for (cp = digits; *cp != '\0'; ++cp)
152     if (isupper (*cp))
153       FAIL ("isupper ('%c') is true", *cp);
154   for (cp = cntrl; *cp != '\0'; ++cp)
155     if (isupper (*cp))
156       FAIL ("isupper ('\\x%02x') is true", *cp);
157 
158   puts ("    isalpha()");
159   for (cp = lower; *cp != '\0'; ++cp)
160     if (! isalpha (*cp))
161       FAIL ("isalpha ('%c') not true", *cp);
162   for (cp = upper; *cp != '\0'; ++cp)
163     if (! isalpha (*cp))
164       FAIL ("isalpha ('%c') not true", *cp);
165   for (cp = digits; *cp != '\0'; ++cp)
166     if (isalpha (*cp))
167       FAIL ("isalpha ('%c') is true", *cp);
168   for (cp = cntrl; *cp != '\0'; ++cp)
169     if (isalpha (*cp))
170       FAIL ("isalpha ('\\x%02x') is true", *cp);
171 
172   puts ("    isdigit()");
173   for (cp = lower; *cp != '\0'; ++cp)
174     if (isdigit (*cp))
175       FAIL ("isdigit ('%c') is true", *cp);
176   for (cp = upper; *cp != '\0'; ++cp)
177     if (isdigit (*cp))
178       FAIL ("isdigit ('%c') is true", *cp);
179   for (cp = digits; *cp != '\0'; ++cp)
180     if (! isdigit (*cp))
181       FAIL ("isdigit ('%c') not true", *cp);
182   for (cp = cntrl; *cp != '\0'; ++cp)
183     if (isdigit (*cp))
184       FAIL ("isdigit ('\\x%02x') is true", *cp);
185 
186   puts ("    isxdigit()");
187   for (cp = lower; *cp != '\0'; ++cp)
188     if ((! isxdigit (*cp) && cp - lower < 6)
189 	|| (isxdigit (*cp) && cp - lower >= 6))
190       FAIL ("isxdigit ('%c') %s true", *cp, cp - upper < 6 ? "not" : "is");
191   for (cp = upper; *cp != '\0'; ++cp)
192     if ((! isxdigit (*cp) && cp - upper < 6)
193 	|| (isxdigit (*cp) && cp - upper >= 6))
194       FAIL ("isxdigit ('%c') %s true", *cp, cp - upper < 6 ? "not" : "is");
195   for (cp = digits; *cp != '\0'; ++cp)
196     if (! isxdigit (*cp))
197       FAIL ("isxdigit ('%c') not true", *cp);
198   for (cp = cntrl; *cp != '\0'; ++cp)
199     if (isxdigit (*cp))
200       FAIL ("isxdigit ('\\x%02x') is true", *cp);
201 
202   puts ("    isspace()");
203   for (cp = lower; *cp != '\0'; ++cp)
204     if (isspace (*cp))
205       FAIL ("isspace ('%c') is true", *cp);
206   for (cp = upper; *cp != '\0'; ++cp)
207     if (isspace (*cp))
208       FAIL ("isspace ('%c') is true", *cp);
209   for (cp = digits; *cp != '\0'; ++cp)
210     if (isspace (*cp))
211       FAIL ("isspace ('%c') is true", *cp);
212   for (cp = cntrl; *cp != '\0'; ++cp)
213     if ((isspace (*cp) && ((*cp < '\x09' || *cp > '\x0d') && *cp != ' '))
214 	|| (! isspace (*cp)
215 	    && ((*cp >= '\x09' && *cp <= '\x0d') || *cp == ' ')))
216       FAIL ("isspace ('\\x%02x') %s true", *cp,
217 	    (*cp < '\x09' || *cp > '\x0d') ? "is" : "not");
218 
219   puts ("    isprint()");
220   for (cp = lower; *cp != '\0'; ++cp)
221     if (! isprint (*cp))
222       FAIL ("isprint ('%c') not true", *cp);
223   for (cp = upper; *cp != '\0'; ++cp)
224     if (! isprint (*cp))
225       FAIL ("isprint ('%c') not true", *cp);
226   for (cp = digits; *cp != '\0'; ++cp)
227     if (! isprint (*cp))
228       FAIL ("isprint ('%c') not true", *cp);
229   for (cp = cntrl; *cp != '\0'; ++cp)
230     if ((isprint (*cp) && *cp != ' ')
231 	|| (! isprint (*cp) && *cp == ' '))
232       FAIL ("isprint ('\\x%02x') is true", *cp);
233 
234   puts ("    isgraph()");
235   for (cp = lower; *cp != '\0'; ++cp)
236     if (! isgraph (*cp))
237       FAIL ("isgraph ('%c') not true", *cp);
238   for (cp = upper; *cp != '\0'; ++cp)
239     if (! isgraph (*cp))
240       FAIL ("isgraph ('%c') not true", *cp);
241   for (cp = digits; *cp != '\0'; ++cp)
242     if (! isgraph (*cp))
243       FAIL ("isgraph ('%c') not true", *cp);
244   for (cp = cntrl; *cp != '\0'; ++cp)
245     if (isgraph (*cp))
246       FAIL ("isgraph ('\\x%02x') is true", *cp);
247 
248   puts ("    isblank()");
249   for (cp = lower; *cp != '\0'; ++cp)
250     if (isblank (*cp))
251       FAIL ("isblank ('%c') is true", *cp);
252   for (cp = upper; *cp != '\0'; ++cp)
253     if (isblank (*cp))
254       FAIL ("isblank ('%c') is true", *cp);
255   for (cp = digits; *cp != '\0'; ++cp)
256     if (isblank (*cp))
257       FAIL ("isblank ('%c') is true", *cp);
258   for (cp = cntrl; *cp != '\0'; ++cp)
259     if ((isblank (*cp) && *cp != '\x09' && *cp != ' ')
260 	|| (! isblank (*cp) && (*cp == '\x09' || *cp == ' ')))
261       FAIL ("isblank ('\\x%02x') %s true", *cp, *cp != '\x09' ? "is" : "not");
262 
263   puts ("    iscntrl()");
264   for (cp = lower; *cp != '\0'; ++cp)
265     if (iscntrl (*cp))
266       FAIL ("iscntrl ('%c') is true", *cp);
267   for (cp = upper; *cp != '\0'; ++cp)
268     if (iscntrl (*cp))
269       FAIL ("iscntrl ('%c') is true", *cp);
270   for (cp = digits; *cp != '\0'; ++cp)
271     if (iscntrl (*cp))
272       FAIL ("iscntrl ('%c') is true", *cp);
273   for (cp = cntrl; *cp != '\0'; ++cp)
274     if ((iscntrl (*cp) && *cp == ' ')
275 	|| (! iscntrl (*cp) && *cp != ' '))
276       FAIL ("iscntrl ('\\x%02x') not true", *cp);
277 
278   puts ("    ispunct()");
279   for (cp = lower; *cp != '\0'; ++cp)
280     if (ispunct (*cp))
281       FAIL ("ispunct ('%c') is true", *cp);
282   for (cp = upper; *cp != '\0'; ++cp)
283     if (ispunct (*cp))
284       FAIL ("ispunct ('%c') is true", *cp);
285   for (cp = digits; *cp != '\0'; ++cp)
286     if (ispunct (*cp))
287       FAIL ("ispunct ('%c') is true", *cp);
288   for (cp = cntrl; *cp != '\0'; ++cp)
289     if (ispunct (*cp))
290       FAIL ("ispunct ('\\x%02x') is true", *cp);
291 
292   puts ("    isalnum()");
293   for (cp = lower; *cp != '\0'; ++cp)
294     if (! isalnum (*cp))
295       FAIL ("isalnum ('%c') not true", *cp);
296   for (cp = upper; *cp != '\0'; ++cp)
297     if (! isalnum (*cp))
298       FAIL ("isalnum ('%c') not true", *cp);
299   for (cp = digits; *cp != '\0'; ++cp)
300     if (! isalnum (*cp))
301       FAIL ("isalnum ('%c') not true", *cp);
302   for (cp = cntrl; *cp != '\0'; ++cp)
303     if (isalnum (*cp))
304       FAIL ("isalnum ('\\x%02x') is true", *cp);
305 
306 
307   puts ("    tolower()");
308   for (cp = lower; *cp != '\0'; ++cp)
309     if (tolower (*cp) != *cp)
310       FAIL ("tolower ('%c') != '%c'", *cp, *cp);
311   for (cp = upper, cp2 = lower; *cp != '\0'; ++cp, ++cp2)
312     if (tolower (*cp) != *cp2)
313       FAIL ("tolower ('%c') != '%c'", *cp, *cp2);
314   for (cp = digits; *cp != '\0'; ++cp)
315     if (tolower (*cp) != *cp)
316       FAIL ("tolower ('%c') != '%c'", *cp, *cp);
317   for (cp = cntrl; *cp != '\0'; ++cp)
318     if (tolower (*cp) != *cp)
319       FAIL ("tolower ('\\x%02x') != '\\x%02x'", *cp, *cp);
320 
321   puts ("    toupper()");
322   for (cp = lower, cp2 = upper; *cp != '\0'; ++cp, ++cp2)
323     if (toupper (*cp) != *cp2)
324       FAIL ("toupper ('%c') != '%c'", *cp, *cp2);
325   for (cp = upper; *cp != '\0'; ++cp)
326     if (toupper (*cp) != *cp)
327       FAIL ("toupper ('%c') != '%c'", *cp, *cp);
328   for (cp = digits; *cp != '\0'; ++cp)
329     if (toupper (*cp) != *cp)
330       FAIL ("toupper ('%c') != '%c'", *cp, *cp);
331   for (cp = cntrl; *cp != '\0'; ++cp)
332     if (toupper (*cp) != *cp)
333       FAIL ("toupper ('\\x%02x') != '\\x%02x'", *cp, *cp);
334 
335 
336   /* Now some locale specific tests.  */
337   while (! feof (stdin))
338     {
339       unsigned char *inp;
340       unsigned char *resp;
341 
342       if (getline (&inpline, &inplinelen, stdin) <= 0
343 	  || getline (&resline, &reslinelen, stdin) <= 0)
344 	break;
345 
346       inp = (unsigned char *) strchr (inpline, '\n');
347       if (inp != NULL)
348 	*inp = '\0';
349       resp = (unsigned char *) strchr (resline, '\n');
350       if (resp != NULL)
351 	*resp = '\0';
352 
353       inp = (unsigned char *) inpline;
354       while (*inp != ' ' && *inp != '\t' && *inp && *inp != '\n'
355 	     && *inp != '\0')
356 	++inp;
357 
358       if (*inp == '\0')
359 	{
360 	  printf ("line \"%s\" is without content\n", inpline);
361 	  continue;
362 	}
363       *inp++ = '\0';
364       while (*inp == ' ' || *inp == '\t')
365 	++inp;
366 
367       /* Try all classes.  */
368       for (n = 0; n < nclasses; ++n)
369 	if (strcmp (inpline, classes[n].name) == 0)
370 	  break;
371 
372       resp = (unsigned char *) resline;
373       while (*resp == ' ' || *resp == '\t')
374 	++resp;
375 
376       if (strlen ((char *) inp) != strlen ((char *) resp))
377 	{
378 	  printf ("lines \"%.20s\"... and \"%.20s\" have not the same length\n",
379 		  inp, resp);
380 	  continue;
381 	}
382 
383       if (n < nclasses)
384 	{
385 	  if (strspn ((char *) resp, "01") != strlen ((char *) resp))
386 	    {
387 	      printf ("result string \"%s\" malformed\n", resp);
388 	      continue;
389 	    }
390 
391 	  printf ("  Locale-specific tests for `%s'\n", inpline);
392 
393 	  while (*inp != '\0' && *inp != '\n')
394 	    {
395 	      if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
396 		  != (*resp != '0'))
397 		{
398 		  printf ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
399 			  *inp, *inp, *resp == '1' ? "not" : "is");
400 		  ++errors;
401 		}
402 	      ++inp;
403 	      ++resp;
404 	    }
405 	}
406       else if (strcmp (inpline, "tolower") == 0)
407 	{
408 	  while (*inp != '\0')
409 	    {
410 	      if (tolower (*inp) != *resp)
411 		{
412 		  printf ("    tolower('%c' = '\\x%02x') != '%c'\n",
413 			  *inp, *inp, *resp);
414 		  ++errors;
415 		}
416 	      ++inp;
417 	      ++resp;
418 	    }
419 	}
420       else if (strcmp (inpline, "toupper") == 0)
421 	{
422 	  while (*inp != '\0')
423 	    {
424 	      if (toupper (*inp) != *resp)
425 		{
426 		  printf ("    toupper('%c' = '\\x%02x') != '%c'\n",
427 			  *inp, *inp, *resp);
428 		  ++errors;
429 		}
430 	      ++inp;
431 	      ++resp;
432 	    }
433 	}
434       else
435 	printf ("\"%s\": unknown class or map\n", inpline);
436     }
437 
438 
439   if (errors != 0)
440     {
441       printf ("  %d error%s for `%s' locale\n\n\n", errors,
442 	      errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
443       return 1;
444     }
445 
446   printf ("  No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
447   return 0;
448 }
449 
450 #define TEST_FUNCTION do_test ()
451 #include "../test-skeleton.c"
452