fix-header.c revision 90075
1/* fix-header.c - Make C header file suitable for C++.
2   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998,
3   1999, 2000, 2001 Free Software Foundation, Inc.
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19/* This program massages a system include file (such as stdio.h),
20   into a form that is compatible with GNU C and GNU C++.
21
22   * extern "C" { ... } braces are added (inside #ifndef __cplusplus),
23   if they seem to be needed.  These prevent C++ compilers from name
24   mangling the functions inside the braces.
25
26   * If an old-style incomplete function declaration is seen (without
27   an argument list), and it is a "standard" function listed in
28   the file sys-protos.h (and with a non-empty argument list), then
29   the declaration is converted to a complete prototype by replacing
30   the empty parameter list with the argument list from sys-protos.h.
31
32   * The program can be given a list of (names of) required standard
33   functions (such as fclose for stdio.h).  If a required function
34   is not seen in the input, then a prototype for it will be
35   written to the output.
36
37   * If all of the non-comment code of the original file is protected
38   against multiple inclusion:
39	#ifndef FOO
40	#define FOO
41	<body of include file>
42	#endif
43   then extra matter added to the include file is placed inside the <body>.
44
45   * If the input file is OK (nothing needs to be done);
46   the output file is not written (nor removed if it exists).
47
48   There are also some special actions that are done for certain
49   well-known standard include files:
50
51   * If argv[1] is "sys/stat.h", the Posix.1 macros
52   S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if
53   they were missing, and the corresponding "traditional" S_IFxxx
54   macros were defined.
55
56   * If argv[1] is "errno.h", errno is declared if it was missing.
57
58   * TODO:  The input file should be read complete into memory, because:
59   a) it needs to be scanned twice anyway, and
60   b) it would be nice to allow update in place.
61
62   Usage:
63	fix-header FOO.H INFILE.H OUTFILE.H [OPTIONS]
64   where:
65   * FOO.H is the relative file name of the include file,
66   as it would be #include'd by a C file.  (E.g. stdio.h)
67   * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h)
68   * OUTFILE.H is the full pathname for where to write the output file,
69   if anything needs to be done.  (e.g. ./include/stdio.h)
70   * OPTIONS are such as you would pass to cpp.
71
72   Written by Per Bothner <bothner@cygnus.com>, July 1993.  */
73
74#include "hconfig.h"
75#include "system.h"
76#include "obstack.h"
77#include "scan.h"
78#include "cpplib.h"
79
80static void v_fatal PARAMS ((const char *, va_list)) ATTRIBUTE_PRINTF (1,0) ATTRIBUTE_NORETURN;
81static void fatal PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
82
83sstring buf;
84
85int verbose = 0;
86int partial_count = 0;
87int warnings = 0;
88
89/* We no longer need to add extern "C", because cpp implicitly
90   forces the standard include files to be treated as C.  */
91/*#define ADD_MISSING_EXTERN_C 1 */
92
93#if ADD_MISSING_EXTERN_C
94int missing_extern_C_count = 0;
95#endif
96
97#include "xsys-protos.h"
98
99#ifdef FIXPROTO_IGNORE_LIST
100/* This is a currently unused feature.  */
101
102/* List of files and directories to ignore.
103   A directory name (ending in '/') means ignore anything in that
104   directory.  (It might be more efficient to do directory pruning
105   earlier in fixproto, but this is simpler and easier to customize.) */
106
107static const char *const files_to_ignore[] = {
108  "X11/",
109  FIXPROTO_IGNORE_LIST
110  0
111};
112#endif
113
114char *inf_buffer;
115char *inf_limit;
116char *inf_ptr;
117static const char *cur_file;
118
119/* Certain standard files get extra treatment */
120
121enum special_file
122{
123  no_special,
124#ifdef errno_h
125#undef errno_h
126#endif
127  errno_h,
128#ifdef stdio_h
129#undef stdio_h
130#endif
131  stdio_h,
132#ifdef stdlib_h
133#undef stdlib_h
134#endif
135  stdlib_h,
136#ifdef sys_stat_h
137#undef sys_stat_h
138#endif
139  sys_stat_h
140};
141
142/* A NAMELIST is a sequence of names, separated by '\0', and terminated
143   by an empty name (i.e. by "\0\0").  */
144
145typedef const char *namelist;
146
147/* The following macros provide the bits for symbol_flags.  */
148typedef int symbol_flags;
149
150/* Used to mark names defined in the ANSI/ISO C standard.  */
151#define ANSI_SYMBOL 1
152
153/* We no longer massage include files for POSIX or XOPEN symbols,
154   as there are now several versions of the POSIX and XOPEN standards,
155   and it would be a maintenance nightmare for us to track them all.
156   Better to be compatible with the system include files.  */
157/*#define ADD_MISSING_POSIX 1 */
158/*#define ADD_MISSING_XOPEN 1 */
159
160#if ADD_MISSING_POSIX
161/* Used to mark names defined in the Posix.1 or Posix.2 standard.  */
162#define POSIX1_SYMBOL 2
163#define POSIX2_SYMBOL 4
164#else
165#define POSIX1_SYMBOL 0
166#define POSIX2_SYMBOL 0
167#endif
168
169#if ADD_MISSING_XOPEN
170/* Used to mark names defined in X/Open Portability Guide.  */
171#define XOPEN_SYMBOL 8
172/* Used to mark names defined in X/Open UNIX Extensions.  */
173#define XOPEN_EXTENDED_SYMBOL 16
174#else
175#define XOPEN_SYMBOL 0
176#define XOPEN_EXTENDED_SYMBOL 0
177#endif
178
179/* Used to indicate names that are not functions */
180#define MACRO_SYMBOL 512
181
182struct symbol_list {
183  symbol_flags flags;
184  namelist names;
185};
186
187#define SYMBOL_TABLE_SIZE 10
188struct symbol_list symbol_table[SYMBOL_TABLE_SIZE];
189int cur_symbol_table_size;
190
191static void add_symbols PARAMS ((symbol_flags, namelist));
192static struct fn_decl *lookup_std_proto PARAMS ((const char *, int));
193static void write_lbrac PARAMS ((void));
194static void recognized_macro PARAMS ((const char *));
195static void check_macro_names PARAMS ((cpp_reader *, namelist));
196static void read_scan_file PARAMS ((char *, int, char **));
197static void write_rbrac PARAMS ((void));
198static int inf_skip_spaces PARAMS ((int));
199static int inf_read_upto PARAMS ((sstring *, int));
200static int inf_scan_ident PARAMS ((sstring *, int));
201static int check_protection PARAMS ((int *, int *));
202static void cb_file_change PARAMS ((cpp_reader *, const struct line_map *));
203
204static void
205add_symbols (flags, names)
206     symbol_flags flags;
207     namelist names;
208{
209  symbol_table[cur_symbol_table_size].flags = flags;
210  symbol_table[cur_symbol_table_size].names = names;
211  cur_symbol_table_size++;
212  if (cur_symbol_table_size >= SYMBOL_TABLE_SIZE)
213    fatal ("too many calls to add_symbols");
214  symbol_table[cur_symbol_table_size].names = NULL; /* Termination.  */
215}
216
217struct std_include_entry {
218  const char *const name;
219  const symbol_flags flags;
220  const namelist names;
221};
222
223const char NONE[] = "";  /* The empty namelist.  */
224
225/* Special name to indicate a continuation line in std_include_table.  */
226const char CONTINUED[] = "";
227
228const struct std_include_entry *include_entry;
229
230const struct std_include_entry std_include_table [] = {
231  { "ctype.h", ANSI_SYMBOL,
232      "isalnum\0isalpha\0iscntrl\0isdigit\0isgraph\0islower\0\
233isprint\0ispunct\0isspace\0isupper\0isxdigit\0tolower\0toupper\0" },
234
235  { "dirent.h", POSIX1_SYMBOL, "closedir\0opendir\0readdir\0rewinddir\0"},
236
237  { "errno.h", ANSI_SYMBOL|MACRO_SYMBOL, "errno\0" },
238
239  /* ANSI_SYMBOL is wrong, but ...  */
240  { "curses.h", ANSI_SYMBOL, "box\0delwin\0endwin\0getcurx\0getcury\0initscr\0\
241mvcur\0mvwprintw\0mvwscanw\0newwin\0overlay\0overwrite\0\
242scroll\0subwin\0touchwin\0waddstr\0wclear\0wclrtobot\0wclrtoeol\0\
243waddch\0wdelch\0wdeleteln\0werase\0wgetch\0wgetstr\0winsch\0winsertln\0\
244wmove\0wprintw\0wrefresh\0wscanw\0wstandend\0wstandout\0" },
245
246  { "fcntl.h", POSIX1_SYMBOL, "creat\0fcntl\0open\0" },
247
248  /* Maybe also "getgrent fgetgrent setgrent endgrent" */
249  { "grp.h", POSIX1_SYMBOL, "getgrgid\0getgrnam\0" },
250
251/*{ "limit.h", ... provided by gcc }, */
252
253  { "locale.h", ANSI_SYMBOL, "localeconv\0setlocale\0" },
254
255  { "math.h", ANSI_SYMBOL,
256      "acos\0asin\0atan\0atan2\0ceil\0cos\0cosh\0exp\0\
257fabs\0floor\0fmod\0frexp\0ldexp\0log10\0log\0modf\0pow\0sin\0sinh\0sqrt\0\
258tan\0tanh\0" },
259
260  { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "HUGE_VAL\0" },
261
262  { "pwd.h", POSIX1_SYMBOL, "getpwnam\0getpwuid\0" },
263
264  /* Left out siglongjmp sigsetjmp - these depend on sigjmp_buf.  */
265  { "setjmp.h", ANSI_SYMBOL, "longjmp\0setjmp\0" },
266
267  /* Left out signal() - its prototype is too complex for us!
268     Also left out "sigaction sigaddset sigdelset sigemptyset
269     sigfillset sigismember sigpending sigprocmask sigsuspend"
270     because these need sigset_t or struct sigaction.
271     Most systems that provide them will also declare them.  */
272  { "signal.h", ANSI_SYMBOL, "kill\0raise\0" },
273
274  { "stdio.h", ANSI_SYMBOL,
275      "clearerr\0fclose\0feof\0ferror\0fflush\0fgetc\0fgetpos\0\
276fgets\0fopen\0fprintf\0fputc\0fputs\0fread\0freopen\0fscanf\0fseek\0\
277fsetpos\0ftell\0fwrite\0getc\0getchar\0gets\0perror\0\
278printf\0putc\0putchar\0puts\0remove\0rename\0rewind\0scanf\0setbuf\0\
279setvbuf\0sprintf\0sscanf\0vprintf\0vsprintf\0vfprintf\0tmpfile\0\
280tmpnam\0ungetc\0" },
281  { CONTINUED, POSIX1_SYMBOL, "fdopen\0fileno\0" },
282  { CONTINUED, POSIX2_SYMBOL, "pclose\0popen\0" },  /* I think ...  */
283/* Should perhaps also handle NULL, EOF, ... ? */
284
285  /* "div ldiv", - ignored because these depend on div_t, ldiv_t
286     ignore these: "mblen mbstowcs mbstowc wcstombs wctomb"
287     Left out getgroups, because SunOS4 has incompatible BSD and SVR4 versions.
288     Should perhaps also add NULL */
289  { "stdlib.h", ANSI_SYMBOL,
290      "abort\0abs\0atexit\0atof\0atoi\0atol\0bsearch\0calloc\0\
291exit\0free\0getenv\0labs\0malloc\0putenv\0qsort\0rand\0realloc\0\
292srand\0strtod\0strtol\0strtoul\0system\0" },
293  { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "EXIT_FAILURE\0EXIT_SUCCESS\0" },
294
295  { "string.h", ANSI_SYMBOL, "memchr\0memcmp\0memcpy\0memmove\0memset\0\
296strcat\0strchr\0strcmp\0strcoll\0strcpy\0strcspn\0strerror\0\
297strlen\0strncat\0strncmp\0strncpy\0strpbrk\0strrchr\0strspn\0strstr\0\
298strtok\0strxfrm\0" },
299/* Should perhaps also add NULL and size_t */
300
301  { "strings.h", XOPEN_EXTENDED_SYMBOL,
302      "bcmp\0bcopy\0bzero\0ffs\0index\0rindex\0strcasecmp\0strncasecmp\0" },
303
304  { "strops.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
305
306  /* Actually, XPG4 does not seem to have <sys/ioctl.h>, but defines
307     ioctl in <strops.h>.  However, many systems have it is sys/ioctl.h,
308     and many systems do have <sys/ioctl.h> but not <strops.h>.  */
309  { "sys/ioctl.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
310
311  { "sys/socket.h", XOPEN_EXTENDED_SYMBOL, "socket\0" },
312
313  { "sys/stat.h", POSIX1_SYMBOL,
314      "chmod\0fstat\0mkdir\0mkfifo\0stat\0lstat\0umask\0" },
315  { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
316      "S_ISDIR\0S_ISBLK\0S_ISCHR\0S_ISFIFO\0S_ISREG\0S_ISLNK\0S_IFDIR\0\
317S_IFBLK\0S_IFCHR\0S_IFIFO\0S_IFREG\0S_IFLNK\0" },
318  { CONTINUED, XOPEN_EXTENDED_SYMBOL, "fchmod\0" },
319
320#if 0
321/* How do we handle fd_set? */
322  { "sys/time.h", XOPEN_EXTENDED_SYMBOL, "select\0" },
323  { "sys/select.h", XOPEN_EXTENDED_SYMBOL /* fake */, "select\0" },
324#endif
325
326  { "sys/times.h", POSIX1_SYMBOL, "times\0" },
327  /* "sys/types.h" add types (not in old g++-include) */
328
329  { "sys/utsname.h", POSIX1_SYMBOL, "uname\0" },
330
331  { "sys/wait.h", POSIX1_SYMBOL, "wait\0waitpid\0" },
332  { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
333      "WEXITSTATUS\0WIFEXITED\0WIFSIGNALED\0WIFSTOPPED\0WSTOPSIG\0\
334WTERMSIG\0WNOHANG\0WNOTRACED\0" },
335
336  { "tar.h", POSIX1_SYMBOL, NONE },
337
338  { "termios.h", POSIX1_SYMBOL,
339      "cfgetispeed\0cfgetospeed\0cfsetispeed\0cfsetospeed\0tcdrain\0tcflow\0tcflush\0tcgetattr\0tcsendbreak\0tcsetattr\0" },
340
341  { "time.h", ANSI_SYMBOL,
342      "asctime\0clock\0ctime\0difftime\0gmtime\0localtime\0mktime\0strftime\0time\0tzset\0" },
343
344  { "unistd.h", POSIX1_SYMBOL,
345      "_exit\0access\0alarm\0chdir\0chown\0close\0ctermid\0cuserid\0\
346dup\0dup2\0execl\0execle\0execlp\0execv\0execve\0execvp\0fork\0fpathconf\0\
347getcwd\0getegid\0geteuid\0getgid\0getlogin\0getpgrp\0getpid\0\
348getppid\0getuid\0isatty\0link\0lseek\0pathconf\0pause\0pipe\0read\0rmdir\0\
349setgid\0setpgid\0setsid\0setuid\0sleep\0sysconf\0tcgetpgrp\0tcsetpgrp\0\
350ttyname\0unlink\0write\0" },
351  { CONTINUED, POSIX2_SYMBOL, "getopt\0" },
352  { CONTINUED, XOPEN_EXTENDED_SYMBOL,
353      "lockf\0gethostid\0gethostname\0readlink\0symlink\0" },
354
355  { "utime.h", POSIX1_SYMBOL, "utime\0" },
356
357  { NULL, 0, NONE }
358};
359
360enum special_file special_file_handling = no_special;
361
362/* They are set if the corresponding macro has been seen.  */
363/* The following are only used when handling sys/stat.h */
364int seen_S_IFBLK = 0, seen_S_ISBLK  = 0;
365int seen_S_IFCHR = 0, seen_S_ISCHR  = 0;
366int seen_S_IFDIR = 0, seen_S_ISDIR  = 0;
367int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
368int seen_S_IFLNK = 0, seen_S_ISLNK  = 0;
369int seen_S_IFREG = 0, seen_S_ISREG  = 0;
370/* The following are only used when handling errno.h */
371int seen_errno = 0;
372/* The following are only used when handling stdlib.h */
373int seen_EXIT_FAILURE = 0, seen_EXIT_SUCCESS = 0;
374
375#define obstack_chunk_alloc xmalloc
376#define obstack_chunk_free free
377struct obstack scan_file_obstack;
378
379/* NOTE:  If you edit this, also edit gen-protos.c !! */
380
381static struct fn_decl *
382lookup_std_proto (name, name_length)
383     const char *name;
384     int name_length;
385{
386  int i = hashstr (name, name_length) % HASH_SIZE;
387  int i0 = i;
388  for (;;)
389    {
390      struct fn_decl *fn;
391      if (hash_tab[i] == 0)
392	return NULL;
393      fn = &std_protos[hash_tab[i]];
394      if ((int) strlen (fn->fname) == name_length
395	  && strncmp (fn->fname, name, name_length) == 0)
396	return fn;
397      i = (i+1) % HASH_SIZE;
398      if (i == i0)
399	abort ();
400    }
401}
402
403char *inc_filename;
404int inc_filename_length;
405const char *progname = "fix-header";
406FILE *outf;
407sstring line;
408
409int lbrac_line, rbrac_line;
410
411int required_unseen_count = 0;
412int required_other = 0;
413
414static void
415write_lbrac ()
416{
417
418#if ADD_MISSING_EXTERN_C
419  if (missing_extern_C_count + required_unseen_count > 0)
420    fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
421#endif
422
423  if (partial_count)
424    {
425      fprintf (outf, "#ifndef _PARAMS\n");
426      fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
427      fprintf (outf, "#define _PARAMS(ARGS) ARGS\n");
428      fprintf (outf, "#else\n");
429      fprintf (outf, "#define _PARAMS(ARGS) ()\n");
430      fprintf (outf, "#endif\n#endif /* _PARAMS */\n");
431    }
432}
433
434struct partial_proto
435{
436  struct partial_proto *next;
437  struct fn_decl *fn;
438  int line_seen;
439};
440
441struct partial_proto *partial_proto_list = NULL;
442
443struct partial_proto required_dummy_proto, seen_dummy_proto;
444#define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
445#define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
446#define SET_SEEN(FN) ((FN)->partial = &seen_dummy_proto)
447#define SEEN(FN) ((FN)->partial == &seen_dummy_proto)
448
449static void
450recognized_macro (fname)
451     const char *fname;
452{
453  /* The original include file defines fname as a macro.  */
454  struct fn_decl *fn = lookup_std_proto (fname, strlen (fname));
455
456  /* Since fname is a macro, don't require a prototype for it.  */
457  if (fn)
458    {
459      if (REQUIRED (fn))
460	required_unseen_count--;
461      SET_SEEN (fn);
462    }
463
464  switch (special_file_handling)
465    {
466    case errno_h:
467      if (strcmp (fname, "errno") == 0 && !seen_errno)
468	seen_errno = 1, required_other--;
469      break;
470    case stdlib_h:
471      if (strcmp (fname, "EXIT_FAILURE") == 0 && !seen_EXIT_FAILURE)
472	seen_EXIT_FAILURE = 1, required_other--;
473      if (strcmp (fname, "EXIT_SUCCESS") == 0 && !seen_EXIT_SUCCESS)
474	seen_EXIT_SUCCESS = 1, required_other--;
475      break;
476    case sys_stat_h:
477      if (fname[0] == 'S' && fname[1] == '_')
478	{
479	  if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++;
480	  else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++;
481	  else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++;
482	  else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++;
483	  else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++;
484	  else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++;
485	  else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++;
486	  else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++;
487	  else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++;
488	  else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++;
489	  else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
490	  else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
491	}
492      break;
493
494    default:
495      break;
496    }
497}
498
499void
500recognized_extern (name)
501     const cpp_token *name;
502{
503  switch (special_file_handling)
504    {
505    case errno_h:
506      if (cpp_ideq (name, "errno"))
507	seen_errno = 1, required_other--;
508      break;
509
510    default:
511      break;
512    }
513}
514
515/* Called by scan_decls if it saw a function definition for a function
516   named FNAME.  KIND is 'I' for an inline function; 'F' if a normal
517   function declaration preceded by 'extern "C"' (or nested inside
518   'extern "C"' braces); or 'f' for other function declarations.  */
519
520void
521recognized_function (fname, line, kind, have_arg_list)
522     const cpp_token *fname;
523     unsigned int line;
524     int kind; /* One of 'f' 'F' or 'I' */
525     int have_arg_list;
526{
527  struct partial_proto *partial;
528  int i;
529  struct fn_decl *fn;
530#if ADD_MISSING_EXTERN_C
531  if (kind == 'f')
532    missing_extern_C_count++;
533#endif
534
535  fn = lookup_std_proto ((const char *) NODE_NAME (fname->val.node),
536			 NODE_LEN (fname->val.node));
537
538  /* Remove the function from the list of required function.  */
539  if (fn)
540    {
541      if (REQUIRED (fn))
542	required_unseen_count--;
543      SET_SEEN (fn);
544    }
545
546  /* If we have a full prototype, we're done.  */
547  if (have_arg_list)
548    return;
549
550  if (kind == 'I')  /* don't edit inline function */
551    return;
552
553  /* If the partial prototype was included from some other file,
554     we don't need to patch it up (in this run).  */
555  i = strlen (cur_file);
556  if (i < inc_filename_length
557      || strcmp (inc_filename, cur_file + (i - inc_filename_length)) != 0)
558    return;
559
560  if (fn == NULL)
561    return;
562  if (fn->params[0] == '\0')
563    return;
564
565  /* We only have a partial function declaration,
566     so remember that we have to add a complete prototype.  */
567  partial_count++;
568  partial = (struct partial_proto *)
569    obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
570  partial->line_seen = line;
571  partial->fn = fn;
572  fn->partial = partial;
573  partial->next = partial_proto_list;
574  partial_proto_list = partial;
575  if (verbose)
576    {
577      fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
578	       inc_filename, fn->fname);
579    }
580}
581
582/* For any name in NAMES that is defined as a macro,
583   call recognized_macro on it.  */
584
585static void
586check_macro_names (pfile, names)
587     cpp_reader *pfile;
588     namelist names;
589{
590  size_t len;
591  while (*names)
592    {
593      len = strlen (names);
594      if (cpp_defined (pfile, (const unsigned char *)names, len))
595	recognized_macro (names);
596      names += len + 1;
597    }
598}
599
600static void
601cb_file_change (pfile, map)
602     cpp_reader *pfile ATTRIBUTE_UNUSED;
603     const struct line_map *map;
604{
605  /* Just keep track of current file name.  */
606  cur_file = map->to_file;
607}
608
609static void
610read_scan_file (in_fname, argc, argv)
611     char *in_fname;
612     int argc;
613     char **argv;
614{
615  cpp_reader *scan_in;
616  cpp_callbacks *cb;
617  cpp_options *options;
618  struct fn_decl *fn;
619  int i;
620  struct symbol_list *cur_symbols;
621
622  obstack_init (&scan_file_obstack);
623
624  scan_in = cpp_create_reader (CLK_GNUC89);
625  cb = cpp_get_callbacks (scan_in);
626  cb->file_change = cb_file_change;
627
628  /* We are going to be scanning a header file out of its proper context,
629     so ignore warnings and errors.  */
630  options = cpp_get_options (scan_in);
631  options->inhibit_warnings = 1;
632  options->inhibit_errors = 1;
633
634  i = cpp_handle_options (scan_in, argc, argv);
635  if (i < argc && ! CPP_FATAL_ERRORS (scan_in))
636    cpp_fatal (scan_in, "Invalid option `%s'", argv[i]);
637  cpp_post_options (scan_in);
638  if (CPP_FATAL_ERRORS (scan_in))
639    exit (FATAL_EXIT_CODE);
640
641  if (! cpp_read_main_file (scan_in, in_fname, NULL))
642    exit (FATAL_EXIT_CODE);
643
644  cpp_finish_options (scan_in);
645
646  /* We are scanning a system header, so mark it as such.  */
647  cpp_make_system_header (scan_in, 1, 0);
648
649  scan_decls (scan_in, argc, argv);
650  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
651    check_macro_names (scan_in, cur_symbols->names);
652
653  /* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf.
654     If so, those functions are also required.  */
655  if (special_file_handling == stdio_h
656      && (fn = lookup_std_proto ("_filbuf", 7)) != NULL)
657    {
658      static const unsigned char getchar_call[] = "getchar();";
659      int seen_filbuf = 0;
660
661      /* Scan the macro expansion of "getchar();".  */
662      cpp_push_buffer (scan_in, getchar_call, sizeof(getchar_call) - 1,
663		       /* from_stage3 */ true, 1);
664      for (;;)
665	{
666	  const cpp_token *t = cpp_get_token (scan_in);
667
668	  if (t->type == CPP_EOF)
669	    break;
670	  else if (cpp_ideq (t, "_filbuf"))
671	    seen_filbuf++;
672	}
673
674      if (seen_filbuf)
675	{
676	  int need_filbuf = !SEEN (fn) && !REQUIRED (fn);
677	  struct fn_decl *flsbuf_fn = lookup_std_proto ("_flsbuf", 7);
678	  int need_flsbuf
679	    = flsbuf_fn && !SEEN (flsbuf_fn) && !REQUIRED (flsbuf_fn);
680
681	  /* Append "_filbuf" and/or "_flsbuf" to the required functions.  */
682	  if (need_filbuf + need_flsbuf)
683	    {
684	      const char *new_list;
685	      if (need_filbuf)
686		SET_REQUIRED (fn);
687	      if (need_flsbuf)
688		SET_REQUIRED (flsbuf_fn);
689	      if (need_flsbuf && need_filbuf)
690		new_list = "_filbuf\0_flsbuf\0";
691	      else if (need_flsbuf)
692		new_list = "_flsbuf\0";
693	      else /* if (need_flsbuf) */
694		new_list = "_filbuf\0";
695	      add_symbols (ANSI_SYMBOL, new_list);
696	      required_unseen_count += need_filbuf + need_flsbuf;
697	    }
698	}
699    }
700
701  if (required_unseen_count + partial_count + required_other
702#if ADD_MISSING_EXTERN_C
703      + missing_extern_C_count
704#endif
705      == 0)
706    {
707      if (verbose)
708	fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
709      exit (SUCCESS_EXIT_CODE);
710    }
711  if (!verbose)
712    fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
713  else
714    {
715      if (required_unseen_count)
716	fprintf (stderr, "%s: %d missing function declarations.\n",
717		 inc_filename, required_unseen_count);
718      if (partial_count)
719	fprintf (stderr, "%s: %d non-prototype function declarations.\n",
720		 inc_filename, partial_count);
721#if ADD_MISSING_EXTERN_C
722      if (missing_extern_C_count)
723	fprintf (stderr,
724		 "%s: %d declarations not protected by extern \"C\".\n",
725		 inc_filename, missing_extern_C_count);
726#endif
727    }
728}
729
730static void
731write_rbrac ()
732{
733  struct fn_decl *fn;
734  const char *cptr;
735  struct symbol_list *cur_symbols;
736
737  if (required_unseen_count)
738    {
739#ifdef NO_IMPLICIT_EXTERN_C
740      fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
741#endif
742    }
743
744  /* Now we print out prototypes for those functions that we haven't seen.  */
745  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
746    {
747      int if_was_emitted = 0;
748      int name_len;
749      cptr = cur_symbols->names;
750      for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
751	{
752	  int macro_protect = 0;
753
754	  if (cur_symbols->flags & MACRO_SYMBOL)
755	    continue;
756
757	  fn = lookup_std_proto (cptr, name_len);
758	  if (fn == NULL || !REQUIRED (fn))
759	    continue;
760
761	  if (!if_was_emitted)
762	    {
763/*	      what about curses. ??? or _flsbuf/_filbuf ??? */
764	      if (cur_symbols->flags & ANSI_SYMBOL)
765		fprintf (outf,
766	 "#if defined(__USE_FIXED_PROTOTYPES__) || defined(__cplusplus) || defined (__STRICT_ANSI__)\n");
767	      else if (cur_symbols->flags & (POSIX1_SYMBOL|POSIX2_SYMBOL))
768		fprintf (outf,
769       "#if defined(__USE_FIXED_PROTOTYPES__) || (defined(__cplusplus) \\\n\
770    ? (!defined(__STRICT_ANSI__) || defined(_POSIX_SOURCE)) \\\n\
771    : (defined(__STRICT_ANSI__) && defined(_POSIX_SOURCE)))\n");
772	      else if (cur_symbols->flags & XOPEN_SYMBOL)
773		{
774		fprintf (outf,
775       "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
776   || (defined(__STRICT_ANSI__) && defined(_XOPEN_SOURCE))\n");
777		}
778	      else if (cur_symbols->flags & XOPEN_EXTENDED_SYMBOL)
779		{
780		fprintf (outf,
781       "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
782   || (defined(__STRICT_ANSI__) && defined(_XOPEN_EXTENDED_SOURCE))\n");
783		}
784	      else
785		{
786		  fatal ("internal error for function %s", fn->fname);
787		}
788	      if_was_emitted = 1;
789	    }
790
791	  /* In the case of memmove, protect in case the application
792	     defines it as a macro before including the header.  */
793	  if (!strcmp (fn->fname, "memmove")
794	      || !strcmp (fn->fname, "putc")
795	      || !strcmp (fn->fname, "getc")
796	      || !strcmp (fn->fname, "vprintf")
797	      || !strcmp (fn->fname, "vfprintf")
798	      || !strcmp (fn->fname, "vsprintf")
799	      || !strcmp (fn->fname, "rewinddir")
800	      || !strcmp (fn->fname, "abort"))
801	    macro_protect = 1;
802
803	  if (macro_protect)
804	    fprintf (outf, "#ifndef %s\n", fn->fname);
805	  fprintf (outf, "extern %s %s (%s);\n",
806		   fn->rtype, fn->fname, fn->params);
807	  if (macro_protect)
808	    fprintf (outf, "#endif\n");
809	}
810      if (if_was_emitted)
811	fprintf (outf,
812		 "#endif /* defined(__USE_FIXED_PROTOTYPES__) || ... */\n");
813    }
814  if (required_unseen_count)
815    {
816#ifdef NO_IMPLICIT_EXTERN_C
817      fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
818#endif
819    }
820
821  switch (special_file_handling)
822    {
823    case errno_h:
824      if (!seen_errno)
825	fprintf (outf, "extern int errno;\n");
826      break;
827    case stdlib_h:
828      if (!seen_EXIT_FAILURE)
829	fprintf (outf, "#define EXIT_FAILURE 1\n");
830      if (!seen_EXIT_SUCCESS)
831	fprintf (outf, "#define EXIT_SUCCESS 0\n");
832      break;
833    case sys_stat_h:
834      if (!seen_S_ISBLK && seen_S_IFBLK)
835	fprintf (outf,
836		 "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
837      if (!seen_S_ISCHR && seen_S_IFCHR)
838	fprintf (outf,
839		 "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
840      if (!seen_S_ISDIR && seen_S_IFDIR)
841	fprintf (outf,
842		 "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
843      if (!seen_S_ISFIFO && seen_S_IFIFO)
844	fprintf (outf,
845		 "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
846      if (!seen_S_ISLNK && seen_S_IFLNK)
847	fprintf (outf,
848		 "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
849      if (!seen_S_ISREG && seen_S_IFREG)
850	fprintf (outf,
851		 "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
852      break;
853
854    default:
855      break;
856    }
857
858
859#if ADD_MISSING_EXTERN_C
860  if (missing_extern_C_count + required_unseen_count > 0)
861    fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
862#endif
863}
864
865/* Returns 1 iff the file is properly protected from multiple inclusion:
866   #ifndef PROTECT_NAME
867   #define PROTECT_NAME
868   #endif
869
870 */
871
872#define INF_GET() (inf_ptr < inf_limit ? *(unsigned char *) inf_ptr++ : EOF)
873#define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
874
875static int
876inf_skip_spaces (c)
877     int c;
878{
879  for (;;)
880    {
881      if (c == ' ' || c == '\t')
882	c = INF_GET ();
883      else if (c == '/')
884	{
885	  c = INF_GET ();
886	  if (c != '*')
887	    {
888	      (void) INF_UNGET (c);
889	      return '/';
890	    }
891	  c = INF_GET ();
892	  for (;;)
893	    {
894	      if (c == EOF)
895		return EOF;
896	      else if (c != '*')
897		{
898		  if (c == '\n')
899		    source_lineno++, lineno++;
900		  c = INF_GET ();
901		}
902	      else if ((c = INF_GET ()) == '/')
903		return INF_GET ();
904	    }
905	}
906      else
907	break;
908    }
909  return c;
910}
911
912/* Read into STR from inf_buffer upto DELIM.  */
913
914static int
915inf_read_upto (str, delim)
916     sstring *str;
917     int delim;
918{
919  int ch;
920  for (;;)
921    {
922      ch = INF_GET ();
923      if (ch == EOF || ch == delim)
924	break;
925      SSTRING_PUT (str, ch);
926    }
927  MAKE_SSTRING_SPACE (str, 1);
928  *str->ptr = 0;
929  return ch;
930}
931
932static int
933inf_scan_ident (s, c)
934     sstring *s;
935     int c;
936{
937  s->ptr = s->base;
938  if (ISIDST (c))
939    {
940      for (;;)
941	{
942	  SSTRING_PUT (s, c);
943	  c = INF_GET ();
944	  if (c == EOF || !(ISIDNUM (c)))
945	    break;
946	}
947    }
948  MAKE_SSTRING_SPACE (s, 1);
949  *s->ptr = 0;
950  return c;
951}
952
953/* Returns 1 if the file is correctly protected against multiple
954   inclusion, setting *ifndef_line to the line number of the initial #ifndef
955   and setting *endif_line to the final #endif.
956   Otherwise return 0.  */
957
958static int
959check_protection (ifndef_line, endif_line)
960     int *ifndef_line, *endif_line;
961{
962  int c;
963  int if_nesting = 1; /* Level of nesting of #if's */
964  char *protect_name = NULL; /* Identifier following initial #ifndef */
965  int define_seen = 0;
966
967  /* Skip initial white space (including comments).  */
968  for (;; lineno++)
969    {
970      c = inf_skip_spaces (' ');
971      if (c == EOF)
972	return 0;
973      if (c != '\n')
974	break;
975    }
976  if (c != '#')
977    return 0;
978  c = inf_scan_ident (&buf, inf_skip_spaces (' '));
979  if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
980    return 0;
981
982  /* So far so good: We've seen an initial #ifndef.  */
983  *ifndef_line = lineno;
984  c = inf_scan_ident (&buf, inf_skip_spaces (c));
985  if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
986    return 0;
987  protect_name = xstrdup (buf.base);
988
989  (void) INF_UNGET (c);
990  c = inf_read_upto (&buf, '\n');
991  if (c == EOF)
992    return 0;
993  lineno++;
994
995  for (;;)
996    {
997      c = inf_skip_spaces (' ');
998      if (c == EOF)
999	return 0;
1000      if (c == '\n')
1001	{
1002	  lineno++;
1003	  continue;
1004	}
1005      if (c != '#')
1006	goto skip_to_eol;
1007      c = inf_scan_ident (&buf, inf_skip_spaces (' '));
1008      if (SSTRING_LENGTH (&buf) == 0)
1009	;
1010      else if (!strcmp (buf.base, "ifndef")
1011	  || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
1012	{
1013	  if_nesting++;
1014	}
1015      else if (!strcmp (buf.base, "endif"))
1016	{
1017	  if_nesting--;
1018	  if (if_nesting == 0)
1019	    break;
1020	}
1021      else if (!strcmp (buf.base, "else"))
1022	{
1023	  if (if_nesting == 1)
1024	    return 0;
1025	}
1026      else if (!strcmp (buf.base, "define"))
1027	{
1028	  c = inf_skip_spaces (c);
1029	  c = inf_scan_ident (&buf, c);
1030	  if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
1031	    define_seen = 1;
1032	}
1033    skip_to_eol:
1034      for (;;)
1035	{
1036	  if (c == '\n' || c == EOF)
1037	    break;
1038	  c = INF_GET ();
1039	}
1040      if (c == EOF)
1041	return 0;
1042      lineno++;
1043    }
1044
1045  if (!define_seen)
1046     return 0;
1047  *endif_line = lineno;
1048  /* Skip final white space (including comments).  */
1049  for (;;)
1050    {
1051      c = inf_skip_spaces (' ');
1052      if (c == EOF)
1053	break;
1054      if (c != '\n')
1055	return 0;
1056    }
1057
1058  return 1;
1059}
1060
1061extern int main			PARAMS ((int, char **));
1062
1063int
1064main (argc, argv)
1065     int argc;
1066     char **argv;
1067{
1068  int inf_fd;
1069  struct stat sbuf;
1070  int c;
1071#ifdef FIXPROTO_IGNORE_LIST
1072  int i;
1073#endif
1074  const char *cptr;
1075  int ifndef_line;
1076  int endif_line;
1077  long to_read;
1078  long int inf_size;
1079  struct symbol_list *cur_symbols;
1080
1081  if (argv[0] && argv[0][0])
1082    {
1083      char *p;
1084
1085      progname = 0;
1086      for (p = argv[0]; *p; p++)
1087        if (*p == '/')
1088          progname = p;
1089      progname = progname ? progname+1 : argv[0];
1090    }
1091
1092  if (argc < 4)
1093    {
1094      fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h options\n",
1095	       progname);
1096      exit (FATAL_EXIT_CODE);
1097    }
1098
1099  inc_filename = argv[1];
1100  inc_filename_length = strlen (inc_filename);
1101
1102#ifdef FIXPROTO_IGNORE_LIST
1103  for (i = 0; files_to_ignore[i] != NULL; i++)
1104    {
1105      const char *const ignore_name = files_to_ignore[i];
1106      int ignore_len = strlen (ignore_name);
1107      if (strncmp (inc_filename, ignore_name, ignore_len) == 0)
1108	{
1109	  if (ignore_name[ignore_len-1] == '/'
1110	      || inc_filename[ignore_len] == '\0')
1111	    {
1112	      if (verbose)
1113		fprintf (stderr, "%s: ignoring %s\n", progname, inc_filename);
1114	      exit (SUCCESS_EXIT_CODE);
1115	    }
1116	}
1117
1118    }
1119#endif
1120
1121  if (strcmp (inc_filename, "sys/stat.h") == 0)
1122    special_file_handling = sys_stat_h;
1123  else if (strcmp (inc_filename, "errno.h") == 0)
1124    special_file_handling = errno_h, required_other++;
1125  else if (strcmp (inc_filename, "stdlib.h") == 0)
1126    special_file_handling = stdlib_h, required_other+=2;
1127  else if (strcmp (inc_filename, "stdio.h") == 0)
1128    special_file_handling = stdio_h;
1129  include_entry = std_include_table;
1130  while (include_entry->name != NULL
1131	 && ((strcmp (include_entry->name, CONTINUED) == 0)
1132	     || strcmp (inc_filename, include_entry->name) != 0))
1133    include_entry++;
1134
1135  if (include_entry->name != NULL)
1136    {
1137      const struct std_include_entry *entry;
1138      cur_symbol_table_size = 0;
1139      for (entry = include_entry; ;)
1140	{
1141	  if (entry->flags)
1142	    add_symbols (entry->flags, entry->names);
1143	  entry++;
1144	  if (!entry->name || strcmp (entry->name, CONTINUED) != 0)
1145	    break;
1146	}
1147    }
1148  else
1149    symbol_table[0].names = NULL;
1150
1151  /* Count and mark the prototypes required for this include file.  */
1152  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
1153    {
1154      int name_len;
1155      if (cur_symbols->flags & MACRO_SYMBOL)
1156	continue;
1157      cptr = cur_symbols->names;
1158      for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
1159	{
1160	  struct fn_decl *fn = lookup_std_proto (cptr, name_len);
1161	  required_unseen_count++;
1162	  if (fn == NULL)
1163	    fprintf (stderr, "Internal error:  No prototype for %s\n", cptr);
1164	  else
1165	    SET_REQUIRED (fn);
1166	}
1167    }
1168
1169  read_scan_file (argv[2], argc - 4, argv + 4);
1170
1171  inf_fd = open (argv[2], O_RDONLY, 0666);
1172  if (inf_fd < 0)
1173    {
1174      fprintf (stderr, "%s: Cannot open '%s' for reading -",
1175	       progname, argv[2]);
1176      perror (NULL);
1177      exit (FATAL_EXIT_CODE);
1178    }
1179  if (fstat (inf_fd, &sbuf) < 0)
1180    {
1181      fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
1182      perror (NULL);
1183      exit (FATAL_EXIT_CODE);
1184    }
1185  inf_size = sbuf.st_size;
1186  inf_buffer = (char *) xmalloc (inf_size + 2);
1187  inf_ptr = inf_buffer;
1188
1189  to_read = inf_size;
1190  while (to_read > 0)
1191    {
1192      long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
1193      if (i < 0)
1194	{
1195	  fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
1196	  perror (NULL);
1197	  exit (FATAL_EXIT_CODE);
1198	}
1199      if (i == 0)
1200	{
1201	  inf_size -= to_read;
1202	  break;
1203	}
1204      to_read -= i;
1205    }
1206
1207  close (inf_fd);
1208
1209  /* Inf_size may have changed if read was short (as on VMS) */
1210  inf_buffer[inf_size] = '\n';
1211  inf_buffer[inf_size + 1] = '\0';
1212  inf_limit = inf_buffer + inf_size;
1213
1214  /* If file doesn't end with '\n', add one.  */
1215  if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
1216    inf_limit++;
1217
1218  unlink (argv[3]);
1219  outf = fopen (argv[3], "w");
1220  if (outf == NULL)
1221    {
1222      fprintf (stderr, "%s: Cannot open '%s' for writing -",
1223	       progname, argv[3]);
1224      perror (NULL);
1225      exit (FATAL_EXIT_CODE);
1226    }
1227
1228  lineno = 1;
1229
1230  if (check_protection (&ifndef_line, &endif_line))
1231    {
1232      lbrac_line = ifndef_line+1;
1233      rbrac_line = endif_line;
1234    }
1235  else
1236    {
1237      lbrac_line = 1;
1238      rbrac_line = -1;
1239    }
1240
1241  /* Reset input file.  */
1242  inf_ptr = inf_buffer;
1243  lineno = 1;
1244
1245  for (;;)
1246    {
1247      if (lineno == lbrac_line)
1248	write_lbrac ();
1249      if (lineno == rbrac_line)
1250	write_rbrac ();
1251      for (;;)
1252	{
1253	  struct fn_decl *fn;
1254	  c = INF_GET ();
1255	  if (c == EOF)
1256	    break;
1257	  if (ISIDST (c))
1258	    {
1259	      c = inf_scan_ident (&buf, c);
1260	      (void) INF_UNGET (c);
1261	      fputs (buf.base, outf);
1262	      fn = lookup_std_proto (buf.base, strlen (buf.base));
1263	      /* We only want to edit the declaration matching the one
1264		 seen by scan-decls, as there can be multiple
1265		 declarations, selected by #ifdef __STDC__ or whatever.  */
1266	      if (fn && fn->partial && fn->partial->line_seen == lineno)
1267		{
1268		  c = inf_skip_spaces (' ');
1269		  if (c == EOF)
1270		    break;
1271		  if (c == '(')
1272		    {
1273		      c = inf_skip_spaces (' ');
1274		      if (c == ')')
1275			{
1276			  fprintf (outf, " _PARAMS((%s))", fn->params);
1277			}
1278		      else
1279			{
1280			  putc ('(', outf);
1281			  (void) INF_UNGET (c);
1282			}
1283		    }
1284		  else
1285		    fprintf (outf, " %c", c);
1286		}
1287	    }
1288	  else
1289	    {
1290	      putc (c, outf);
1291	      if (c == '\n')
1292		break;
1293	    }
1294	}
1295      if (c == EOF)
1296	break;
1297      lineno++;
1298    }
1299  if (rbrac_line < 0)
1300    write_rbrac ();
1301
1302  fclose (outf);
1303
1304  return 0;
1305}
1306
1307
1308static void
1309v_fatal (str, ap)
1310  const char * str;
1311  va_list ap;
1312{
1313  fprintf (stderr, "%s: %s: ", progname, inc_filename);
1314  vfprintf (stderr, str, ap);
1315  fprintf (stderr, "\n");
1316
1317  exit (FATAL_EXIT_CODE);
1318}
1319
1320static void
1321fatal VPARAMS ((const char *str, ...))
1322{
1323  VA_OPEN (ap, str);
1324  VA_FIXEDARG (ap, const char *, str);
1325
1326  v_fatal (str, ap);
1327  VA_CLOSE (ap);
1328}
1329