source: trunk/third/gcc/fix-header.c @ 8834

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