Remove 'grp' and merge into 'nss' and 'posix'
[platform/upstream/glibc.git] / stdlib / isomac.c
1 /* Check system header files for ISO 9899:1990 (ISO C) compliance.
2    Copyright (C) 1996-2023 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18
19 /* This is a simple minded program that tries to find illegal macro
20    definitions in system header files. Illegal macro definitions are
21    those not from the implementation namespace (i.e. not starting with
22    an underscore) or not matching any identifier mandated by The
23    Standard. Some common macro names are considered okay, e.g. all those
24    beginning with E (which may be defined in <errno.h>) or ending in
25    _MAX. See the arrays prefix[] and suffix[] below for details.
26
27    In a compliant implementation no other macros can be defined, because
28    you could write strictly conforming programs that may fail to compile
29    due to syntax errors: suppose <stdio.h> defines PIPE_BUF, then the
30    conforming
31
32    #include <assert.h>
33    #include <stdio.h>      <- or where the bogus macro is defined
34    #include <string.h>
35    #define STR(x) #x
36    #define XSTR(x) STR(x)
37    int main (void)
38    {
39      int PIPE_BUF = 0;
40      assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
41      return 0;
42    }
43
44    is expected to compile and meet the assertion. If it does not, your
45    compiler compiles some other language than Standard C.
46
47    REQUIREMENTS:
48      This program calls ${1-gcc} to get the list of defined macros. If you
49      don't have gcc you're probably out of luck unless your compiler or
50      preprocessor has something similar to gcc's -dM option. This program
51      assumes headers are found in the default search path (pass -I... in
52      $2 if this is not the case) and that there is a writable /tmp directory.
53
54    OUTPUT:
55      Each header file name is printed, followed by illegal macro names
56      and their definition. For the above example, you would see
57      ...
58      /usr/include/stdio.h
59      #define PIPE_BUF 5120
60      ...
61      If your implementation does not yet incorporate Amendment 1 you
62      will see messages about iso646.h, wctype.h and wchar.h not being
63      found.  */
64
65 #ifndef _GNU_SOURCE
66 # define _GNU_SOURCE 1
67 #endif
68
69 #include <ctype.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74
75 #define HEADER_MAX          256
76
77 static char macrofile[] = "/tmp/isomac.XXXXXX";
78
79 /* ISO C header names including Amendment 1 (without ".h" suffix).  */
80 static char *header[] =
81 {
82   "assert", "ctype", "errno", "float", "iso646", "limits", "locale",
83   "math", "setjmp", "signal", "stdarg", "stddef", "stdio", "stdlib",
84   "string", "time", "wchar", "wctype"
85 };
86
87 /* Macros with these prefixes are considered okay.  */
88 static char *prefix[] =
89 {
90   "_", "E", "is", "str", "mem", "SIG", "FLT_", "DBL_", "LDBL_",
91   "LC_", "wmem", "wcs"
92 };
93
94 /* Macros with these suffixes are considered okay.  Will not work for
95    parametrized macros with arguments.  */
96 static char *suffix[] =
97 {
98   "_MAX", "_MIN"
99 };
100
101 /* These macros are considered okay. In fact, these are just more prefixes.  */
102 static char *macros[] =
103 {
104   "BUFSIZ", "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "CLOCKS_PER_SEC",
105   "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX",
106   "DBL_MAX_10_EXP", "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP",
107   "DBL_MIN_EXP", "EDOM", "EILSEQ", "EOF", "ERANGE", "EXIT_FAILURE",
108   "EXIT_SUCCESS", "FILENAME_MAX", "FLT_DIG", "FLT_EPSILON",
109   "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
110   "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX",
111   "FLT_ROUNDS", "FOPEN_MAX", "HUGE_VAL", "INT_MAX", "INT_MIN",
112   "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
113   "LC_TIME", "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX",
114   "LDBL_MAX_10_EXP", "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP",
115   "LDBL_MIN_EXP", "LONG_MAX", "LONG_MIN", "L_tmpnam", "MB_CUR_MAX",
116   "MB_LEN_MAX", "NDEBUG", "NULL", "RAND_MAX", "SCHAR_MAX",
117   "SCHAR_MIN", "SEEK_CUR", "SEEK_END", "SEEK_SET", "SHRT_MAX",
118   "SHRT_MIN", "SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV",
119   "SIGTERM", "SIG_DFL", "SIG_ERR", "SIG_IGN", "TMP_MAX", "UCHAR_MAX",
120   "UINT_MAX", "ULONG_MAX", "USHRT_MAX", "WCHAR_MAX", "WCHAR_MIN",
121   "WEOF", "_IOFBF", "_IOLBF", "_IONBF", "abort", "abs", "acos",
122   "acosf", "acosl", "and", "and_eq", "asctime", "asin", "asinf",
123   "asinl", "assert", "atan", "atan2", "atan2f", "atan2l", "atanf",
124   "atanl", "atexit", "atof", "atoi", "atol", "bitand", "bitor",
125   "bsearch", "btowc", "calloc", "ceil", "ceilf", "ceill", "clearerr",
126   "clock", "clock_t", "compl", "cos", "cosf", "cosh", "coshf",
127   "coshl", "cosl", "ctime", "difftime", "div", "div_t", "errno",
128   "exit", "exp", "expf", "expl", "fabs", "fabsf", "fabsl", "fclose",
129   "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets", "fgetwc",
130   "fgetws", "floor", "floorf", "floorl", "fmod", "fmodf", "fmodl",
131   "fopen", "fprintf", "fputc", "fputs", "fputwc", "fputws", "fread",
132   "free", "freopen", "frexp", "frexpf", "frexpl", "fscanf", "fseek",
133   "fsetpos", "ftell", "fwide", "fwprintf", "fwrite", "fwscanf",
134   "getc", "getchar", "getenv", "gets", "getwc", "getwchar", "gmtime",
135   "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
136   "isprint", "ispunct", "isspace", "isupper", "iswalnum", "iswalpha",
137   "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower",
138   "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit",
139   "isxdigit", "labs", "ldexp", "ldexpf", "ldexpl", "ldiv", "ldiv_t",
140   "localeconv", "localtime", "log", "log10", "log10f", "log10l",
141   "logf", "logl", "longjmp", "malloc", "mblen", "mbrlen", "mbrtowc",
142   "mbsinit", "mbsrtowcs", "mbstate_t", "mbstowcs", "mbtowc", "memchr",
143   "memcmp", "memcpy", "memmove", "memset", "mktime", "modf", "modff",
144   "modfl", "not", "not_eq", "offsetof", "or", "or_eq", "perror",
145   "pow", "powf", "powl", "printf", "ptrdiff_t", "putc", "putchar",
146   "puts", "putwc", "putwchar", "qsort", "raise", "rand", "realloc",
147   "remove", "rename", "rewind", "scanf", "setbuf", "setjmp",
148   "setlocale", "setvbuf", "sig_atomic_t", "signal", "sin", "sinf",
149   "sinh", "sinhf", "sinhl", "sinl", "size_t", "sprintf", "sqrt",
150   "sqrtf", "sqrtl", "srand", "sscanf", "stderr", "stdin", "stdout",
151   "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn",
152   "strerror", "strftime", "strlen", "strncat", "strncmp", "strncpy",
153   "strpbrk", "strrchr", "strspn", "strstr", "strtod", "strtok",
154   "strtol", "strtoul", "strxfrm", "swprintf", "swscanf", "system",
155   "tan", "tanf", "tanh", "tanhf", "tanhl", "tanl", "time", "time_t",
156   "tmpfile", "tmpnam", "tolower", "toupper", "towctrans", "towlower",
157   "towupper", "ungetc", "ungetwc", "va_arg", "va_copy", "va_end", "va_start",
158   "vfprintf", "vfwprintf", "vprintf", "vsprintf", "vswprintf",
159   "vwprintf", "wchar_t", "wcrtomb", "wcscat", "wcschr", "wcscmp",
160   "wcscoll", "wcscpy", "wcscspn", "wcsftime", "wcslen", "wcsncat",
161   "wcsncmp", "wcsncpy", "wcspbrk", "wcsrchr", "wcsrtombs", "wcsspn",
162   "wcsstr", "wcstod", "wcstok", "wcstol", "wcstombs", "wcstoul",
163   "wcsxfrm", "wctob", "wctomb", "wctrans", "wctrans_t", "wctype",
164   "wctype_t", "wint_t", "wmemchr", "wmemcmp", "wmemcpy", "wmemmove",
165   "wmemset", "wprintf", "wscanf", "xor", "xor_eq"
166 };
167
168 #define NUMBER_OF_HEADERS              (sizeof header / sizeof *header)
169 #define NUMBER_OF_PREFIXES             (sizeof prefix / sizeof *prefix)
170 #define NUMBER_OF_SUFFIXES             (sizeof suffix / sizeof *suffix)
171 #define NUMBER_OF_MACROS               (sizeof macros / sizeof *macros)
172
173
174 /* Format string to build command to invoke compiler.  */
175 static const char fmt[] = "\
176 echo \"#include <%s>\" |\
177 %s -E -dM -ansi -pedantic %s -D_LIBC -D_ISOMAC \
178 -DIN_MODULE=MODULE_extramodules -I. \
179 -isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
180
181
182 /* The compiler we use (given on the command line).  */
183 char *CC;
184 /* The -I parameters for CC to find all headers.  */
185 char *INC;
186
187 static char *xstrndup (const char *, size_t);
188 static const char **get_null_defines (void);
189 static int check_header (const char *, const char **);
190
191 int
192 main (int argc, char *argv[])
193 {
194   int h;
195   int result = 0;
196   const char **ignore_list;
197
198   CC = argc > 1 ? argv[1] : "gcc";
199   INC = argc > 2 ? argv[2] : "";
200
201   if (system (NULL) == 0)
202     {
203       puts ("Sorry, no command processor.");
204       return EXIT_FAILURE;
205     }
206
207   /* First get list of symbols which are defined by the compiler.  */
208   ignore_list = get_null_defines ();
209
210   fputs ("Tested files:\n", stdout);
211
212   for (h = 0; h < NUMBER_OF_HEADERS; ++h)
213     {
214       char file_name[HEADER_MAX];
215       sprintf (file_name, "%s.h", header[h]);
216       result |= check_header (file_name, ignore_list);
217     }
218
219   remove (macrofile);
220
221   /* The test suite should return errors but for now this is not
222      practical.  Give a warning and ask the user to correct the bugs.  */
223   return result;
224 }
225
226
227 static char *
228 xstrndup (const char *s, size_t n)
229 {
230   size_t len = n;
231   char *new = malloc (len + 1);
232
233   if (new == NULL)
234     return NULL;
235
236   new[len] = '\0';
237   return memcpy (new, s, len);
238 }
239
240
241 static const char **
242 get_null_defines (void)
243 {
244   char line[BUFSIZ], *command;
245   char **result = NULL;
246   size_t result_len = 0;
247   size_t result_max = 0;
248   FILE *input;
249   int first = 1;
250
251   int fd = mkstemp (macrofile);
252   if (fd == -1)
253     {
254       printf ("mkstemp failed: %m\n");
255       exit (1);
256     }
257   close (fd);
258
259   command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
260                     + strlen (INC) + strlen (macrofile));
261
262   if (command == NULL)
263     {
264       puts ("No more memory.");
265       exit (1);
266     }
267
268   sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
269
270   if (system (command))
271     {
272       puts ("system() returned nonzero");
273       free (command);
274       return NULL;
275     }
276   free (command);
277   input = fopen (macrofile, "r");
278
279   if (input == NULL)
280     {
281       printf ("Could not read %s: ", macrofile);
282       perror (NULL);
283       return NULL;
284     }
285
286   while (fgets (line, sizeof line, input) != NULL)
287     {
288       int i, okay = 0;
289       size_t endmac;
290       char *start, *end;
291       if (strlen (line) < 9 || line[7] != ' ')
292         { /* "#define A" */
293           printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
294                   line);
295           continue;
296         }
297       if (line[8] == '_')
298         /* It's a safe identifier.  */
299         continue;
300       if (result_len == result_max)
301         {
302           result_max += 10;
303           result = realloc (result, result_max * sizeof (char **));
304           if (result == NULL)
305             {
306               puts ("No more memory.");
307               exit (1);
308             }
309         }
310       start = &line[8];
311       for (end = start + 1; !isspace (*end) && *end != '\0'; ++end)
312         ;
313       result[result_len] = xstrndup (start, end - start);
314
315       if (strcmp (result[result_len], "IN_MODULE") != 0)
316         {
317           if (first)
318             {
319               fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
320               first = 0;
321             }
322           puts (result[result_len]);
323         }
324       ++result_len;
325     }
326   if (result_len == result_max)
327     {
328       result_max += 1;
329       result = realloc (result, result_max * sizeof (char **));
330       if (result == NULL)
331         {
332           puts ("No more memory.");
333           exit (1);
334         }
335     }
336   result[result_len] = NULL;
337   fclose (input);
338
339   return (const char **) result;
340 }
341
342
343 static int
344 check_header (const char *file_name, const char **except)
345 {
346   char line[BUFSIZ], *command;
347   FILE *input;
348   int result = 0;
349
350   command = malloc (sizeof fmt + strlen (file_name) + 2 * strlen (CC)
351                     + strlen (INC) + strlen (macrofile));
352
353   if (command == NULL)
354     {
355       puts ("No more memory.");
356       exit (1);
357     }
358
359   puts (file_name);
360   sprintf (command, fmt, file_name, CC, INC, CC, macrofile);
361
362   if (system (command))
363     {
364       puts ("system() returned nonzero");
365       result = 1;
366     }
367   free (command);
368   input = fopen (macrofile, "r");
369
370   if (input == NULL)
371     {
372       printf ("Could not read %s: ", macrofile);
373       perror (NULL);
374       return 1;
375     }
376
377   while (fgets (line, sizeof line, input) != NULL)
378     {
379       int i, okay = 0;
380       size_t endmac;
381       const char **cpp;
382       if (strlen (line) < 9 || line[7] != ' ')
383         { /* "#define A" */
384           printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
385                   line);
386           result = 1;
387           continue;
388         }
389       for (i = 0; i < NUMBER_OF_PREFIXES; ++i)
390         {
391           if (!strncmp (line+8, prefix[i], strlen (prefix[i]))) {
392             ++okay;
393             break;
394           }
395         }
396       if (okay)
397         continue;
398       for (i = 0; i < NUMBER_OF_MACROS; ++i)
399         {
400           if (!strncmp (line + 8, macros[i], strlen (macros[i])))
401             {
402               ++okay;
403               break;
404             }
405         }
406       if (okay)
407         continue;
408       /* Find next char after the macro identifier; this can be either
409          a space or an open parenthesis.  */
410       endmac = strcspn (line + 8, " (");
411       if (line[8+endmac] == '\0')
412         {
413           printf ("malformed input, expected '#define MACRO VALUE'\n"
414                   "got '%s'\n", line);
415           result = 1;
416           continue;
417         }
418       for (i = 0; i < NUMBER_OF_SUFFIXES; ++i)
419         {
420           size_t len = strlen (suffix[i]);
421           if (!strncmp (line + 8 + endmac - len, suffix[i], len))
422             {
423               ++okay;
424               break;
425             }
426         }
427       if (okay)
428         continue;
429       if (except != NULL)
430         for (cpp = except; *cpp != NULL; ++cpp)
431           {
432             size_t len = strlen (*cpp);
433             if (!strncmp (line + 8, *cpp, len) && isspace (line[8 + len]))
434               {
435                 ++okay;
436                 break;
437               }
438           }
439       if (!okay)
440         {
441           fputs (line, stdout);
442           result = 2;
443         }
444     }
445   fclose (input);
446
447   return result;
448 }
449
450 /* EOF */