Fix access after end of search string in regex matcher
[platform/upstream/glibc.git] / posix / annexc.c
1 /* Copyright (C) 1998, 2000, 2002, 2004 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, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <ctype.h>
20 #include <fnmatch.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <sys/wait.h>
27
28 #define HEADER_MAX          256
29
30 static const char *macrofile;
31
32 /* <aio.h>.  */
33 static const char *const aio_syms[] =
34 {
35   "AIO_ALLDONE", "AIO_CANCELED", "AIO_NOTCANCELED", "LIO_NOP", "LIO_NOWAIT",
36   "LIO_READ", "LIO_WAIT", "LIO_WRITE",
37   /* From <fcntl.h>.  */
38   "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
39   "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
40   "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
41   "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
42   "O_WRONLY",
43   /* From <signal.h>.  */
44   "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
45   "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_SIGNAL", "SIGEV_THREAD",
46   "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
47   "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
48   "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
49   "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
50   "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
51 };
52 static const char *const aio_maybe[] =
53 {
54   "aio_cancel", "aio_error", "aio_fsync", "aio_read", "aio_return",
55   "aio_suspend", "aio_write", "lio_listio",
56   /* From <fcntl.h>.  */
57   "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
58   "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
59   "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
60   "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR",
61   /* From <signal.h>.  */
62   "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
63   "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
64   "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
65 };
66
67 /* <assert.h>.  */
68 static const char *const assert_syms[] =
69 {
70   "assert"
71 };
72 static const char *const assert_maybe[] =
73 {
74 };
75
76 /* <ctype.h>.   */
77 static const char *const ctype_syms[] =
78 {
79 };
80 static const char *const ctype_maybe[] =
81 {
82   "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
83   "isprint", "ispunct", "isspace", "isupper", "isxdigit", "tolower",
84   "toupper"
85 };
86
87 /* <dirent.h>.  */
88 static const char *const dirent_syms[] =
89 {
90 };
91 static const char *const dirent_maybe[] =
92 {
93   "closedir", "opendir", "readdir", "readdir_r", "rewinddir"
94 };
95
96 /* <errno.h>.  */
97 static const char *const errno_syms[] =
98 {
99   "E2BIG", "EACCES", "EAGAIN", "EBADF", "EBADMSG", "EBUSY", "ECANCELED",
100   "ECHILD", "EDEADLK", "EDOM", "EEXIST", "EFAULT", "EFBIG", "EINPROGRESS",
101   "EINTR", "EINVAL", "EIO", "EISDIR", "EMFILE", "EMLINK", "EMSGSIZE",
102   "ENAMETOOLONG", "ENFILE", "ENODEV", "ENOENT", "ENOEXEC", "ENOLCK",
103   "ENOMEM", "ENOSPC", "ENOSYS", "ENOTDIR", "ENOTEMPTY", "ENOTSUP",
104   "ENOTTY", "ENXIO", "EPERM", "EPIPE", "ERANGE", "EROFS", "ESPIPE",
105   "ESRCH", "ETIMEDOUT", "EXDEV"
106 };
107 static const char *const errno_maybe[] =
108 {
109   "errno", "E*"
110 };
111
112 /* <fcntl.h>.  */
113 static const char *const fcntl_syms[] =
114 {
115   "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
116   "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
117   "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
118   "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
119   "O_WRONLY"
120 };
121 static const char *const fcntl_maybe[] =
122 {
123   "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
124   "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
125   "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
126   "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR"
127 };
128
129 /* <float.h>.  */
130 static const char *const float_syms[] =
131 {
132   "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX", "DBL_MAX_10_EXP",
133   "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP", "DBL_MIN_EXP", "FLT_DIG",
134   "FLT_EPSILON", "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
135   "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX", "FLT_ROUNDS",
136   "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX", "LDBL_MAX_10_EXP",
137   "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP", "LDBL_MIN_EXP"
138 };
139 static const char *const float_maybe[] =
140 {
141 };
142
143 /* <grp.h>.  */
144 static const char *const grp_syms[] =
145 {
146 };
147 static const char *const grp_maybe[] =
148 {
149   "getgrgid", "getgrgid_r", "getgrnam", "getgrnam_r"
150 };
151
152 /* <limits.h>.  */
153 static const char *const limits_syms[] =
154 {
155   "_POSIX_AIO_LISTIO_MAX", "_POSIX_AIO_MAX", "_POSIX_ARG_MAX",
156   "_POSIX_CHILD_MAX", "_POSIX_CLOCKRES_MAX", "_POSIX_DELAYTIMER_MAX",
157   "_POSIX_LINK_MAX", "_POSIX_LOGIN_NAME_MAX", "_POSIX_MAX_CANON",
158   "_POSIX_MAX_INPUT", "_POSIX_MQ_OPEN_MAX", "_POSIX_MQ_PRIO_MAX",
159   "_POSIX_NAME_MAX", "_POSIX_NGROUPS_MAX", "_POSIX_OPEN_MAX",
160   "_POSIX_PATH_MAX", "_POSIX_PIPE_BUF", "_POSIX_RTSIG_MAX",
161   "_POSIX_SEM_NSEMS_MAX", "_POSIX_SEM_VALUE_MAX", "_POSIX_SIGQUEUE_MAX",
162   "_POSIX_SSIZE_MAX", "_POSIX_STREAM_MAX",
163   "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", "_POSIX_THREAD_KEYS_MAX",
164   "_POSIX_THREAD_THREADS_MAX", "_POSIX_TIMER_MAX", "_POSIX_TTY_NAME_MAX",
165   "_POSIX_TZNAME_MAX", "_POSIX_THREAD_DESTRUCTOR_ITERATIONS",
166   "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "INT_MAX", "INT_MIN", "LONG_MAX",
167   "LONG_MIN", "MB_LEN_MAX", "NGROUPS_MAX", "PAGESIZE", "SCHAR_MAX",
168   "SCHAR_MIN", "SHRT_MAX", "SHRT_MIN", "UCHAR_MAX", "UINT_MAX",
169   "ULONG_MAX", "USHRT_MAX"
170 };
171 static const char *const limits_maybe[] =
172 {
173   "AIO_LISTIO_MAX", "AIO_MAX", "ARG_MAX", "CHILD_MAX", "DELAYTIMER_MAX",
174   "LINK_MAX", "LOGIN_NAME_MAX", "LONG_MAX", "LONG_MIN", "MAX_CANON",
175   "MAX_INPUT", "MQ_OPEN_MAX", "MQ_PRIO_MAX", "NAME_MAX", "OPEN_MAX",
176   "PATH_MAX", "PIPE_BUF", "RTSIG_MAX", "PTHREAD_DESTRUCTOR_ITERATIONS",
177   "PTHREAD_KEYS_MAX", "PTHREAD_STACK_MIN", "PTHREAD_THREADS_MAX"
178 };
179
180 /* <locale.h>.  */
181 static const char *const locale_syms[] =
182 {
183   "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
184   "LC_TIME", "NULL"
185 };
186 static const char *const locale_maybe[] =
187 {
188   "LC_*", "localeconv", "setlocale"
189 };
190
191 /* <math.h>.  */
192 static const char *const math_syms[] =
193 {
194   "HUGE_VAL"
195 };
196 static const char *const math_maybe[] =
197 {
198   "acos", "asin", "atan2", "atan", "ceil", "cos", "cosh", "exp",
199   "fabs", "floor", "fmod", "frexp", "ldexp", "log10", "log", "modf",
200   "pow", "sin", "sinh", "sqrt", "tan", "tanh",
201   "acosf", "asinf", "atan2f", "atanf", "ceilf", "cosf", "coshf", "expf",
202   "fabsf", "floorf", "fmodf", "frexpf", "ldexpf", "log10f", "logf", "modff",
203   "powf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf",
204   "acosl", "asinl", "atan2l", "atanl", "ceill", "cosl", "coshl", "expl",
205   "fabsl", "floorl", "fmodl", "frexpl", "ldexpl", "log10l", "logl", "modfl",
206   "powl", "sinl", "sinhl", "sqrtl", "tanl", "tanhl"
207 };
208
209 /* <mqueue.h>.  */
210 static const char *const mqueue_syms[] =
211 {
212 };
213 static const char *const mqueue_maybe[] =
214 {
215   "mq_close", "mq_getattr", "mq_notify", "mq_open", "mq_receive",
216   "mq_send", "mq_setattr", "mq_unlink"
217 };
218
219 /* <pthread.h>.  */
220 static const char *const pthread_syms[] =
221 {
222   "PTHREAD_CANCELED", "PTHREAD_CANCEL_ASYNCHRONOUS",
223   "PTHREAD_CANCEL_DEFERRED", "PTHREAD_CANCEL_DISABLE", "PTHREAD_CANCEL_ENABLE",
224   "PTHREAD_COND_INITIALIZER", "PTHREAD_CREATE_DETACHED",
225   "PTHREAD_CREATE_JOINABLE", "PTHREAD_EXPLICIT_SCHED",
226   "PTHREAD_INHERIT_SCHED", "PTHREAD_MUTEX_INITIALIZER",
227   "PTHREAD_ONCE_INIT", "PTHREAD_PRIO_INHERIT", "PTHREAD_PRIO_NONE",
228   "PTHREAD_PRIO_PROTECT", "PTHREAD_PROCESS_PRIVATE",
229   "PTHREAD_PROCESS_SHARED", "PTHREAD_SCOPE_PROCESS", "PTHREAD_SCOPE_SYSTEM",
230   /* These come from <sched.h>.  */
231   "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
232   /* These come from <time.h>.  */
233   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
234 };
235 static const char *const pthread_maybe[] =
236 {
237   "pthread_atfork", "pthread_attr_destroy", "pthread_attr_getdetachstate",
238   "pthread_attr_getinheritsched", "pthread_attr_getschedparam",
239   "pthread_attr_getschedpolicy", "pthread_attr_getscope",
240   "pthread_attr_getstackaddr", "pthread_attr_getstacksize",
241   "pthread_attr_init", "pthread_attr_setdetachstate",
242   "pthread_attr_setinheritsched", "pthread_attr_setschedparam",
243   "pthread_attr_setschedpolicy", "pthread_attr_setscope",
244   "pthread_attr_setstackaddr", "pthread_attr_setstacksize",
245   "pthread_cleanup_pop", "pthread_cleanup_push", "pthread_cond_broadcast",
246   "pthread_cond_destroy", "pthread_cond_init", "pthread_cond_signal",
247   "pthread_cond_timedwait", "pthread_cond_wait", "pthread_condattr_destroy",
248   "pthread_condattr_getpshared", "pthread_condattr_init",
249   "pthread_condattr_setpshared", "pthread_create", "pthread_detach",
250   "pthread_equal", "pthread_exit", "pthread_getspecific", "pthread_join",
251   "pthread_key_create", "pthread_key_destroy", "pthread_kill",
252   "pthread_mutex_destroy", "pthread_mutex_getprioceiling",
253   "pthread_mutex_init", "pthread_mutex_lock", "pthread_mutex_setprioceiling",
254   "pthread_mutex_trylock", "pthread_mutex_unlock", "pthread_mutexattr_destroy",
255   "pthread_mutexattr_getprioceiling", "pthread_mutexattr_getprotocol",
256   "pthread_mutexattr_getpshared", "pthread_mutexattr_init",
257   "pthread_mutexattr_setprioceiling", "pthread_mutexattr_setprotocol",
258   "pthread_mutexattr_setpshared", "pthread_once", "pthread_self",
259   "pthread_setcancelstate", "pthread_setcanceltype", "pthread_setspecific",
260   "pthread_sigmask", "pthread_testcancel"
261   /* These come from <sched.h>.  */
262   "sched_get_priority_max", "sched_get_priority_min",
263   "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
264   "sched_setparam", "sched_setscheduler", "sched_yield",
265   /* These come from <time.h>.  */
266   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
267   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
268   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
269   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
270   "timer_settime", "tzset"
271 };
272
273 /* <pwd.h>.  */
274 static const char *const pwd_syms[] =
275 {
276 };
277 static const char *const pwd_maybe[] =
278 {
279   "getpwnam", "getpwnam_r", "getpwuid", "getpwuid_r"
280 };
281
282 /* <sched.h>.  */
283 static const char *const sched_syms[] =
284 {
285   "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
286 };
287 static const char *const sched_maybe[] =
288 {
289   "sched_get_priority_max", "sched_get_priority_min",
290   "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
291   "sched_setparam", "sched_setscheduler", "sched_yield",
292   /* These come from <time.h>.  */
293   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
294   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
295   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
296   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
297   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
298   "timer_settime", "tzset"
299 };
300
301 /* <semaphore.h>.  */
302 static const char *const semaphore_syms[] =
303 {
304 };
305 static const char *const semaphore_maybe[] =
306 {
307   "sem_close", "sem_destroy", "sem_getvalue", "sem_init", "sem_open",
308   "sen_post", "sem_trywait", "sem_unlink", "sem_wait"
309 };
310
311 /* <setjmp.h>.  */
312 static const char *const setjmp_syms[] =
313 {
314 };
315 static const char *const setjmp_maybe[] =
316 {
317   "longjmp", "setjmp", "siglongjmp", "sigsetjmp"
318 };
319
320 /* <signal.h>.  */
321 static const char *const signal_syms[] =
322 {
323   "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
324   "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_THREAD",
325   "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
326   "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
327   "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
328   "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
329   "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
330 };
331 static const char *const signal_maybe[] =
332 {
333   "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
334   "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
335   "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
336 };
337
338 /* <stdarg.h>.  */
339 static const char *const stdarg_syms[] =
340 {
341   "va_arg", "va_end", "va_start"
342 };
343 static const char *const stdarg_maybe[] =
344 {
345   "va_list"
346 };
347
348 /* <stddef.h>.  */
349 static const char *const stddef_syms[] =
350 {
351   "NULL", "offsetof"
352 };
353 static const char *const stddef_maybe[] =
354 {
355 };
356
357 /* <stdio.h>.  */
358 static const char *const stdio_syms[] =
359 {
360   "BUFSIZ", "EOF", "FILENAME_MAX", "FOPEN_MAX", "L_ctermid", "L_cuserid",
361   "L_tmpnam", "NULL", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STREAM_MAX",
362   "TMP_MAX", "stderr", "stdin", "stdout", "_IOFBF", "_IOLBF", "_IONBF"
363 };
364 static const char *const stdio_maybe[] =
365 {
366   "clearerr", "fclose", "fdopen", "feof", "ferror", "fflush", "fgetc",
367   "fgetpos", "fgets", "fileno", "flockfile", "fopen", "fprintf", "fputc",
368   "fputs", "fread", "freopen", "fscanf", "fseek", "fsetpos", "ftell",
369   "ftrylockfile", "funlockfile", "fwrite", "getc", "getchar",
370   "getchar_unlocked", "getc_unlocked", "gets", "perror", "printf", "putc",
371   "putchar", "putchar_unlocked", "putc_unlocked", "puts", "remove", "rename",
372   "rewind", "scanf", "setbuf", "setvbuf", "sprintf", "sscanf", "tmpfile",
373   "tmpnam", "ungetc", "vfprintf", "vprintf", "vsprintf"
374 };
375
376 /* <stdlib.h>.  */
377 static const char *const stdlib_syms[] =
378 {
379   "EXIT_FAILURE", "EXIT_SUCCESS", "MB_CUR_MAX", "NULL", "RAND_MAX"
380 };
381 static const char *const stdlib_maybe[] =
382 {
383   "abort", "abs", "atexit", "atof", "atoi", "atol", "bsearch", "calloc",
384   "div", "exit", "free", "getenv", "labs", "ldiv", "malloc", "mblen",
385   "mbstowcs", "mbtowc", "qsort", "rand", "rand_r", "realloc", "srand",
386   "strtod", "strtol", "strtoul", "system", "wcstombs", "wctomb"
387 };
388
389 /* <string.h>.  */
390 static const char *const string_syms[] =
391 {
392   "NULL"
393 };
394 static const char *const string_maybe[] =
395 {
396   "memchr", "memcmp", "memcpy", "memmove", "memset", "strcat", "strchr",
397   "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen",
398   "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn",
399   "strstr", "strtok", "strtok_r", "strxfrm"
400 };
401
402 /* <sys/mman.h>.  */
403 static const char *const mman_syms[] =
404 {
405   "MAP_FAILED", "MAP_FIXED", "MAP_PRIVATE", "MAP_SHARED", "MCL_CURRENT",
406   "MCL_FUTURE", "MS_ASYNC", "MS_INVALIDATE", "MS_SYNC", "PROT_EXEC",
407   "PROT_NONE", "PROT_READ", "PROT_WRITE"
408 };
409 static const char *const mman_maybe[] =
410 {
411   "mlock", "mlockall", "mmap", "mprotect", "msync", "munlock", "munlockall",
412   "munmap", "shm_open", "shm_unlock"
413 };
414
415 /* <sys/stat.h>.  */
416 static const char *const stat_syms[] =
417 {
418   "S_IRGRP", "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU",
419   "S_ISBLK", "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG",
420   "S_ISUID", "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH",
421   "S_IXUSR", "S_TYPEISMQ", "S_TYPEISSEM", "S_TYPEISSHM"
422 };
423 static const char *const stat_maybe[] =
424 {
425   "chmod", "fchmod", "fstat", "mkdir", "mkfifo", "stat", "umask"
426 };
427
428 /* <sys/times.h>.  */
429 static const char *const times_syms[] =
430 {
431 };
432 static const char *const times_maybe[] =
433 {
434   "times"
435 };
436
437 /* <sys/types.h>.  */
438 static const char *const types_syms[] =
439 {
440 };
441 static const char *const types_maybe[] =
442 {
443 };
444
445 /* <sys/utsname.h>.  */
446 static const char *const utsname_syms[] =
447 {
448 };
449 static const char *const utsname_maybe[] =
450 {
451   "uname"
452 };
453
454 /* <sys/wait.h>.  */
455 static const char *const wait_syms[] =
456 {
457   "WEXITSTATUS", "WIFEXITED", "WIFSIGNALED", "WIFSTOPPED", "WNOHANG",
458   "WSTOPSIG", "WTERMSIG", "WUNTRACED"
459 };
460 static const char *const wait_maybe[] =
461 {
462   "wait", "waitpid"
463 };
464
465 /* <termios.h>.  */
466 static const char *const termios_syms[] =
467 {
468   "B0", "B110", "B1200", "B134", "B150", "B1800", "B19200", "B200", "B2400",
469   "B300", "B38400", "B4800", "B50", "B600", "B75", "B9600", "BRKINT", "CLOCAL",
470   "CREAD", "CS5", "CS6", "CS7", "CS8", "CSIZE", "CSTOPN", "ECHO", "ECHOE",
471   "ECHOK", "ECHONL", "HUPCL", "ICANON", "ICRNL", "IEXTEN", "IGNBRK", "IGNCR",
472   "IGNPAR", "INCLR", "INPCK", "ISIG", "ISTRIP", "IXOFF", "IXON", "NCCS",
473   "NOFLSH", "OPOST", "PARENB", "PARMRK", "PARODD", "TCIFLUSH", "TCIOFF",
474   "TCIOFLUSH", "TCOFLUSH", "TCOOFF", "TCOON", "TCSADRAIN", "TCSAFLUSH",
475   "TCSANOW", "TOSTOP", "VEOF", "VEOL", "VERASE", "VINTR", "VKILL", "VMIN",
476   "VQUIT", "VSTART", "VSTOP", "VSUSP", "VTIME"
477 };
478 static const char *const termios_maybe[] =
479 {
480   "cfgetispeed", "cfgetospeed", "cfsetispeed", "cfsetospeed", "tcdrain",
481   "tcflow", "tcflush", "tcgetattr", "tcsendbrk", "tcsetattr"
482 };
483
484 /* <time.h>.  */
485 static const char *const time_syms[] =
486 {
487   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
488 };
489 static const char *const time_maybe[] =
490 {
491   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
492   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
493   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
494   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
495   "timer_settime", "tzset"
496 };
497
498 /* <unistd.h>.  */
499 static const char *const unistd_syms[] =
500 {
501   "F_OK", "NULL", "R_OK", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STDERR_FILENO",
502   "STDIN_FILENO", "STDOUT_FILENO", "W_OK", "X_OK",
503   "_PC_ASYNC_IO", "_PC_CHOWN_RESTRICTED", "_PC_LINK_MAX", "_PC_MAX_CANON",
504   "_PC_MAX_INPUT", "_PC_NAME_MAX", "_PC_NO_TRUNC", "_PC_PATH_MAX",
505   "_PC_PIPE_BUF", "_PC_PRIO_IO", "_PC_SYNC_IO", "_PC_VDISABLE",
506   "_SC_AIO_LISTIO_MAX", "_SC_AIO_MAX", "_SC_AIO_PRIO_DELTA_MAX",
507   "_SC_ARG_MAX", "_SC_ASYNCHRONOUS_IO", "_SC_CHILD_MAX", "_SC_CLK_TCK",
508   "_SC_DELAYTIMER_MAX", "_SC_FSYNC", "_SC_GETGR_R_SIZE_MAX",
509   "_SC_GETPW_R_SIZE_MAX", "_SC_JOB_CONTROL", "_SC_LOGIN_NAME_MAX",
510   "_SC_MAPPED_FILES", "_SC_MEMLOCK", "_SC_MEMLOCK_RANGE",
511   "_SC_MEMORY_PROTECTION", "_SC_MESSAGE_PASSING", "_SC_MQ_OPEN_MAX",
512   "_SC_MQ_PRIO_MAX", "_SC_NGROUPS_MAX", "_SC_OPEN_MAX", "_SC_PAGESIZE",
513   "_SC_PRIORITIZED_IO", "_SC_PRIORITY_SCHEDULING", "_SC_REALTIME_SIGNALS",
514   "_SC_RTSIG_MAX", "_SC_SAVED_IDS", "_SC_SEMAPHORES", "_SC_SEM_NSEMS_MAX",
515   "_SC_SEM_VALUE_MAX", "_SC_SHARED_MEMORY_OBJECTS", "_SC_SIGQUEUE_MAX",
516   "_SC_STREAM_MAX", "_SC_SYNCHRONIZED_IO", "_SC_THREADS",
517   "_SC_THREAD_ATTR_STACKADDR", "_SC_THREAD_ATTR_STACKSIZE",
518   "_SC_THREAD_DESTRUCTOR_ITERATIONS", "_SC_THREAD_PRIO_INHERIT",
519   "_SC_THREAD_PRIORITY_SCHEDULING", "_SC_THREAD_PRIO_PROTECT",
520   "_SC_THREAD_PROCESS_SHARED", "_SC_THREAD_SAFE_FUNCTIONS",
521   "_SC_THREAD_STACK_MIN", "_SC_THREAD_THREADS_MAX", "_SC_TIMERS",
522   "_SC_TIMER_MAX", "_SC_TTY_NAME_MAX", "_SC_TZNAME_MAX", "_SC_VERSION"
523 };
524 static const char *const unistd_maybe[] =
525 {
526   "_POSIX_ASYNCHRONOUS_IO", "_POSIX_ASYNC_IO", "_POSIX_CHOWN_RESTRICTED",
527   "_POSIX_FSYNC", "_POSIX_JOB_CONTROL", "_POSIX_MAPPED_FILES",
528   "_POSIX_MEMLOCK", "_POSIX_MEMLOCK_RANGE", "_MEMORY_PROTECTION",
529   "_POSIX_MESSAGE_PASSING", "_POSIX_NO_TRUNC", "_POSIX_PRIORITIZED_IO",
530   "_POSIX_PRIORITY_SCHEDULING", "_POSIX_PRIO_IO", "_POSIX_REATIME_SIGNALS",
531   "_POSIX_SAVED_IDS", "_POSIX_SEMAPHORES", "_POSIX_SHARED_MEMORY_OBJECTS",
532   "_POSIX_SYNCHRONIZED_IO", "_POSIX_SYNC_IO", "_POSIX_THREADS",
533   "_POSIX_THREAD_ATTR_STACKADDR", "_POSIX_THREAD_ATTR_STACKSIZE",
534   "_POSIX_THREAD_PRIO_INHERIT", "_POSIX_THREAD_PRIO_PROTECT",
535   "_POSIX_THREAD_PROCESS_SHARED", "_POSIX_THREAD_SAFE_FUNCTIONS",
536   "_POSIX_THREAD_PRIORITY_SCHEDULING", "_POSIX_TIMERS",
537   "_POSIX_VDISABLE", "_POSIX_VERSION",
538   "_exit", "access", "alarm", "chdir", "chown", "close", "ctermid", "cuserid",
539   "dup2", "dup", "execl", "execle", "execlp", "execv", "execve", "execvp",
540   "fdatasync", "fork", "fpathconf", "fsync", "ftruncate", "getcwd", "getegid",
541   "geteuid", "getgid", "getgroups", "getlogin", "getlogin_r", "getpgrp",
542   "getpid", "getppid", "getuid", "isatty", "link", "lseek", "pathconf",
543   "pause", "pipe", "read", "rmdir", "setgid", "setgpid", "setsid", "setuid",
544   "sleep", "sleep", "sysconf", "tcgetpgrp", "tcsetpgrp", "ttyname",
545   "ttyname_r", "unlink", "write"
546 };
547
548 /* <utime.h>.  */
549 static const char *const utime_syms[] =
550 {
551 };
552 static const char *const utime_maybe[] =
553 {
554   "utime"
555 };
556
557
558 static struct header
559 {
560   const char *name;
561   const char *const *syms;
562   size_t nsyms;
563   const char *const *maybe;
564   size_t nmaybe;
565   const char *subset;
566 } headers[] =
567 {
568 #define H(n) \
569   { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
570     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
571 #define Hc(n, s) \
572   { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
573     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), s }
574 #define Hs(n) \
575   { "sys/" #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
576     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
577   H(aio),
578   H(assert),
579   H(ctype),
580   H(dirent),
581   H(errno),
582   H(fcntl),
583   H(float),
584   H(grp),
585   H(limits),
586   H(locale),
587   H(math),
588   Hc(mqueue, "_POSIX_MESSAGE_PASSING"),
589   H(pthread),
590   H(pwd),
591   H(sched),
592   H(semaphore),
593   H(setjmp),
594   H(signal),
595   H(stdarg),
596   H(stddef),
597   H(stdio),
598   H(stdlib),
599   H(string),
600   Hs(mman),
601   Hs(stat),
602   Hs(times),
603   Hs(types),
604   Hs(utsname),
605   Hs(wait),
606   H(termios),
607   H(time),
608   H(unistd),
609   H(utime)
610 };
611
612 #define NUMBER_OF_HEADERS              (sizeof headers / sizeof *headers)
613
614
615 /* Format string to build command to invoke compiler.  */
616 static const char fmt[] = "\
617 echo \"#include <%s>\" |\
618 %s -E -dM -D_POSIX_SOURCE %s \
619 -isystem `%s --print-prog-name=include` - > %s";
620
621 static const char testfmt[] = "\
622 echo \"#include <unistd.h>\n#if !defined %s || %s == -1\n#error not defined\n#endif\n\" |\
623 %s -E -dM -D_POSIX_SOURCE %s \
624 -isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
625
626
627 /* The compiler we use (given on the command line).  */
628 const char *CC;
629 /* The -I parameters for CC to find all headers.  */
630 const char *INC;
631
632 static char *xstrndup (const char *, size_t);
633 static const char **get_null_defines (void);
634 static int check_header (const struct header *, const char **);
635 static int xsystem (const char *);
636
637 int
638 main (int argc, char *argv[])
639 {
640   int h;
641   int result = 0;
642   const char **ignore_list;
643
644   CC = argc > 1 ? argv[1] : "gcc";
645   INC = argc > 2 ? argv[2] : "";
646
647   if (system (NULL) == 0)
648     {
649       puts ("Sorry, no command processor.");
650       return EXIT_FAILURE;
651     }
652
653   /* First get list of symbols which are defined by the compiler.  */
654   ignore_list = get_null_defines ();
655
656   fputs ("Tested files:\n", stdout);
657
658   for (h = 0; h < NUMBER_OF_HEADERS; ++h)
659     result |= check_header (&headers[h], ignore_list);
660
661   /* The test suite should return errors but for now this is not
662      practical.  Give a warning and ask the user to correct the bugs.  */
663   return result;
664 }
665
666
667 static char *
668 xstrndup (const char *s, size_t n)
669 {
670   size_t len = n;
671   char *new = malloc (len + 1);
672
673   if (new == NULL)
674     return NULL;
675
676   new[len] = '\0';
677   return memcpy (new, s, len);
678 }
679
680
681 /* Like system but propagate interrupt and quit signals.  */
682 int
683 xsystem (const char *cmd)
684 {
685   int status;
686
687   status = system (cmd);
688   if (status != -1)
689     {
690       if (WIFSIGNALED (status))
691         {
692           if (WTERMSIG (status) == SIGINT || WTERMSIG (status) == SIGQUIT)
693             raise (WTERMSIG (status));
694         }
695       else if (WIFEXITED (status))
696         {
697           if (WEXITSTATUS (status) == SIGINT + 128
698               || WEXITSTATUS (status) == SIGQUIT + 128)
699             raise (WEXITSTATUS (status) - 128);
700         }
701     }
702   return status;
703 }
704
705
706 static const char **
707 get_null_defines (void)
708 {
709   char line[BUFSIZ], *command;
710   char **result = NULL;
711   size_t result_len = 0;
712   size_t result_max = 0;
713   FILE *input;
714   int first = 1;
715
716   macrofile = tmpnam (NULL);
717
718   command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
719                     + strlen (INC) + strlen (macrofile));
720
721   if (command == NULL)
722     {
723       puts ("No more memory.");
724       exit (1);
725     }
726
727   sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
728
729   if (xsystem (command))
730     {
731       puts ("system() returned nonzero");
732       return NULL;
733     }
734   free (command);
735   input = fopen (macrofile, "r");
736
737   if (input == NULL)
738     {
739       printf ("Could not read %s: ", macrofile);
740       perror (NULL);
741       return NULL;
742     }
743
744   while (fgets (line, sizeof line, input) != NULL)
745     {
746       char *start;
747       if (strlen (line) < 9 || line[7] != ' ')
748         { /* "#define A" */
749           printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
750                   line);
751           continue;
752         }
753       if (line[8] == '_')
754         /* It's a safe identifier.  */
755         continue;
756       if (result_len == result_max)
757         {
758           result_max += 10;
759           result = realloc (result, result_max * sizeof (char **));
760           if (result == NULL)
761             {
762               puts ("No more memory.");
763               exit (1);
764             }
765         }
766       start = &line[8];
767       result[result_len++] = xstrndup (start, strcspn (start, " ("));
768
769       if (first)
770         {
771           fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
772           first = 0;
773         }
774       puts (result[result_len - 1]);
775     }
776   if (result_len == result_max)
777     {
778       result_max += 1;
779       result = realloc (result, result_max * sizeof (char **));
780       if (result == NULL)
781         {
782           puts ("No more memory.");
783           exit (1);
784         }
785     }
786   result[result_len] = NULL;
787   fclose (input);
788   remove (macrofile);
789
790   return (const char **) result;
791 }
792
793
794 static int
795 check_header (const struct header *header, const char **except)
796 {
797   char line[BUFSIZ], command[sizeof fmt + strlen (header->name)
798                              + 2 * strlen (CC)
799                              + strlen (INC) + strlen (macrofile)];
800   FILE *input;
801   int result = 0;
802   int found[header->nsyms];
803   int i;
804
805   memset (found, '\0', header->nsyms * sizeof (int));
806
807   printf ("=== %s ===\n", header->name);
808   sprintf (command, fmt, header->name, CC, INC, CC, macrofile);
809
810   /* First see whether this subset is supported at all.  */
811   if (header->subset != NULL)
812     {
813       sprintf (line, testfmt, header->subset, header->subset, CC, INC, CC,
814                macrofile);
815       if (xsystem (line))
816         {
817           printf ("!! not available\n");
818           return 0;
819         }
820     }
821
822   if (xsystem (command))
823     {
824       puts ("system() returned nonzero");
825       result = 1;
826     }
827   input = fopen (macrofile, "r");
828
829   if (input == NULL)
830     {
831       printf ("Could not read %s: ", macrofile);
832       perror (NULL);
833       return 1;
834     }
835
836   while (fgets (line, sizeof line, input) != NULL)
837     {
838       const char **ignore;
839       if (strlen (line) < 9 || line[7] != ' ')
840         { /* "#define A" */
841           printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
842                   line);
843           result = 1;
844           continue;
845         }
846
847       /* Find next char after the macro identifier; this can be either
848          a space or an open parenthesis.  */
849       line[8 + strcspn (&line[8], " (")] = '\0';
850
851       /* Now check whether it's one of the required macros.  */
852       for (i = 0; i < header->nsyms; ++i)
853         if (!strcmp (&line[8], header->syms[i]))
854           break;
855       if (i < header->nsyms)
856         {
857           found[i] = 1;
858           continue;
859         }
860
861       /* Symbols starting with "_" are ok.  */
862       if (line[8] == '_')
863         continue;
864
865       /* Maybe one of the symbols which are always defined.  */
866       for (ignore = except; *ignore != NULL; ++ignore)
867         if (! strcmp (&line[8], *ignore))
868           break;
869       if (*ignore != NULL)
870         continue;
871
872       /* Otherwise the symbol better should match one of the following.  */
873       for (i = 0; i < header->nmaybe; ++i)
874         if (fnmatch (header->maybe[i], &line[8], 0) == 0)
875           break;
876       if (i < header->nmaybe)
877         continue;
878
879       printf ("*  invalid macro `%s'\n", &line[8]);
880       result |= 1;
881     }
882   fclose (input);
883   remove (macrofile);
884
885   for (i = 0; i < header->nsyms; ++i)
886     if (found[i] == 0)
887       printf ("** macro `%s' not defined\n", header->syms[i]);
888
889   return result;
890 }