118334Speter/* fix-header.c - Make C header file suitable for C++.
290075Sobrien   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
418334Speter
518334SpeterThis program is free software; you can redistribute it and/or modify it
618334Speterunder the terms of the GNU General Public License as published by the
718334SpeterFree Software Foundation; either version 2, or (at your option) any
818334Speterlater version.
918334Speter
1018334SpeterThis program is distributed in the hope that it will be useful,
1118334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1218334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1318334SpeterGNU General Public License for more details.
1418334Speter
1518334SpeterYou should have received a copy of the GNU General Public License
1618334Speteralong with this program; if not, write to the Free Software
17169689SkanFoundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
1818334Speter
1918334Speter/* This program massages a system include file (such as stdio.h),
2050397Sobrien   into a form that is compatible with GNU C and GNU C++.
2118334Speter
2218334Speter   * extern "C" { ... } braces are added (inside #ifndef __cplusplus),
2318334Speter   if they seem to be needed.  These prevent C++ compilers from name
2418334Speter   mangling the functions inside the braces.
2518334Speter
2618334Speter   * If an old-style incomplete function declaration is seen (without
2718334Speter   an argument list), and it is a "standard" function listed in
2818334Speter   the file sys-protos.h (and with a non-empty argument list), then
2918334Speter   the declaration is converted to a complete prototype by replacing
3050397Sobrien   the empty parameter list with the argument list from sys-protos.h.
3118334Speter
3218334Speter   * The program can be given a list of (names of) required standard
3318334Speter   functions (such as fclose for stdio.h).  If a required function
3418334Speter   is not seen in the input, then a prototype for it will be
3518334Speter   written to the output.
3618334Speter
3718334Speter   * If all of the non-comment code of the original file is protected
3818334Speter   against multiple inclusion:
3918334Speter	#ifndef FOO
4018334Speter	#define FOO
4118334Speter	<body of include file>
4218334Speter	#endif
4318334Speter   then extra matter added to the include file is placed inside the <body>.
4418334Speter
4518334Speter   * If the input file is OK (nothing needs to be done);
4618334Speter   the output file is not written (nor removed if it exists).
4718334Speter
4818334Speter   There are also some special actions that are done for certain
4918334Speter   well-known standard include files:
5018334Speter
5118334Speter   * If argv[1] is "sys/stat.h", the Posix.1 macros
5218334Speter   S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if
5318334Speter   they were missing, and the corresponding "traditional" S_IFxxx
5418334Speter   macros were defined.
5518334Speter
5618334Speter   * If argv[1] is "errno.h", errno is declared if it was missing.
5718334Speter
5818334Speter   * TODO:  The input file should be read complete into memory, because:
5918334Speter   a) it needs to be scanned twice anyway, and
6018334Speter   b) it would be nice to allow update in place.
6118334Speter
6218334Speter   Usage:
6318334Speter	fix-header FOO.H INFILE.H OUTFILE.H [OPTIONS]
6418334Speter   where:
6518334Speter   * FOO.H is the relative file name of the include file,
6618334Speter   as it would be #include'd by a C file.  (E.g. stdio.h)
6718334Speter   * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h)
6818334Speter   * OUTFILE.H is the full pathname for where to write the output file,
6918334Speter   if anything needs to be done.  (e.g. ./include/stdio.h)
70132718Skan   * OPTIONS can be -D or -I switches as you would pass to cpp.
7118334Speter
7250397Sobrien   Written by Per Bothner <bothner@cygnus.com>, July 1993.  */
7318334Speter
74132718Skan#include "bconfig.h"
7550397Sobrien#include "system.h"
76132718Skan#include "coretypes.h"
77132718Skan#include "tm.h"
7818334Speter#include "obstack.h"
7918334Speter#include "scan.h"
8018334Speter#include "cpplib.h"
81132718Skan#include "c-incpath.h"
82169689Skan#include "errors.h"
8318334Speter
84169689Skan#ifdef TARGET_EXTRA_INCLUDES
85169689Skanvoid
86169689SkanTARGET_EXTRA_INCLUDES (const char *sysroot ATTRIBUTE_UNUSED,
87169689Skan		       const char *iprefix ATTRIBUTE_UNUSED,
88169689Skan		       int stdinc ATTRIBUTE_UNUSED)
89169689Skan{
90169689Skan}
91169689Skan#endif
9218334Speter
93169689Skan#ifdef TARGET_EXTRA_PRE_INCLUDES
94169689Skanvoid
95169689SkanTARGET_EXTRA_PRE_INCLUDES (const char *sysroot ATTRIBUTE_UNUSED,
96169689Skan			   const char *iprefix ATTRIBUTE_UNUSED,
97169689Skan			   int stdinc ATTRIBUTE_UNUSED)
98169689Skan{
99169689Skan}
100169689Skan#endif
101169689Skan
102169689Skanstruct line_maps line_table;
103169689Skan
10418334Spetersstring buf;
10518334Speter
10618334Speterint verbose = 0;
10718334Speterint partial_count = 0;
10818334Speterint warnings = 0;
10918334Speter
11018334Speter#if ADD_MISSING_EXTERN_C
11118334Speterint missing_extern_C_count = 0;
11218334Speter#endif
11318334Speter
11418334Speter#include "xsys-protos.h"
11518334Speter
11618334Speter#ifdef FIXPROTO_IGNORE_LIST
11750397Sobrien/* This is a currently unused feature.  */
11818334Speter
11918334Speter/* List of files and directories to ignore.
12018334Speter   A directory name (ending in '/') means ignore anything in that
12118334Speter   directory.  (It might be more efficient to do directory pruning
12218334Speter   earlier in fixproto, but this is simpler and easier to customize.) */
12318334Speter
12490075Sobrienstatic const char *const files_to_ignore[] = {
12518334Speter  "X11/",
12618334Speter  FIXPROTO_IGNORE_LIST
12718334Speter  0
12818334Speter};
12918334Speter#endif
13018334Speter
13118334Speterchar *inf_buffer;
13218334Speterchar *inf_limit;
13318334Speterchar *inf_ptr;
13490075Sobrienstatic const char *cur_file;
13518334Speter
13618334Speter/* Certain standard files get extra treatment */
13718334Speter
13818334Speterenum special_file
13918334Speter{
14018334Speter  no_special,
14150397Sobrien#ifdef errno_h
14250397Sobrien#undef errno_h
14350397Sobrien#endif
14418334Speter  errno_h,
14550397Sobrien#ifdef stdio_h
14650397Sobrien#undef stdio_h
14750397Sobrien#endif
14818334Speter  stdio_h,
14950397Sobrien#ifdef stdlib_h
15050397Sobrien#undef stdlib_h
15150397Sobrien#endif
15250397Sobrien  stdlib_h,
15350397Sobrien#ifdef sys_stat_h
15450397Sobrien#undef sys_stat_h
15550397Sobrien#endif
15618334Speter  sys_stat_h
15718334Speter};
15818334Speter
15918334Speter/* A NAMELIST is a sequence of names, separated by '\0', and terminated
16050397Sobrien   by an empty name (i.e. by "\0\0").  */
16118334Speter
16250397Sobrientypedef const char *namelist;
16318334Speter
16450397Sobrien/* The following macros provide the bits for symbol_flags.  */
16550397Sobrientypedef int symbol_flags;
16650397Sobrien
16750397Sobrien/* Used to mark names defined in the ANSI/ISO C standard.  */
16850397Sobrien#define ANSI_SYMBOL 1
16950397Sobrien
17050397Sobrien/* We no longer massage include files for POSIX or XOPEN symbols,
17150397Sobrien   as there are now several versions of the POSIX and XOPEN standards,
17250397Sobrien   and it would be a maintenance nightmare for us to track them all.
17350397Sobrien   Better to be compatible with the system include files.  */
17450397Sobrien/*#define ADD_MISSING_POSIX 1 */
17550397Sobrien/*#define ADD_MISSING_XOPEN 1 */
17650397Sobrien
17750397Sobrien#if ADD_MISSING_POSIX
17850397Sobrien/* Used to mark names defined in the Posix.1 or Posix.2 standard.  */
17950397Sobrien#define POSIX1_SYMBOL 2
18050397Sobrien#define POSIX2_SYMBOL 4
18150397Sobrien#else
18250397Sobrien#define POSIX1_SYMBOL 0
18350397Sobrien#define POSIX2_SYMBOL 0
18450397Sobrien#endif
18550397Sobrien
18650397Sobrien#if ADD_MISSING_XOPEN
18750397Sobrien/* Used to mark names defined in X/Open Portability Guide.  */
18850397Sobrien#define XOPEN_SYMBOL 8
18950397Sobrien/* Used to mark names defined in X/Open UNIX Extensions.  */
19050397Sobrien#define XOPEN_EXTENDED_SYMBOL 16
19150397Sobrien#else
19250397Sobrien#define XOPEN_SYMBOL 0
19350397Sobrien#define XOPEN_EXTENDED_SYMBOL 0
19450397Sobrien#endif
19550397Sobrien
19650397Sobrien/* Used to indicate names that are not functions */
19750397Sobrien#define MACRO_SYMBOL 512
19850397Sobrien
19950397Sobrienstruct symbol_list {
20050397Sobrien  symbol_flags flags;
20150397Sobrien  namelist names;
20218334Speter};
20318334Speter
20450397Sobrien#define SYMBOL_TABLE_SIZE 10
20550397Sobrienstruct symbol_list symbol_table[SYMBOL_TABLE_SIZE];
20650397Sobrienint cur_symbol_table_size;
20718334Speter
208132718Skanstatic void add_symbols (symbol_flags, namelist);
209132718Skanstatic struct fn_decl *lookup_std_proto (const char *, int);
210132718Skanstatic void write_lbrac (void);
211132718Skanstatic void recognized_macro (const char *);
212132718Skanstatic void check_macro_names (cpp_reader *, namelist);
213132718Skanstatic void read_scan_file (char *, int, char **);
214132718Skanstatic void write_rbrac (void);
215132718Skanstatic int inf_skip_spaces (int);
216132718Skanstatic int inf_read_upto (sstring *, int);
217132718Skanstatic int inf_scan_ident (sstring *, int);
218132718Skanstatic int check_protection (int *, int *);
219132718Skanstatic void cb_file_change (cpp_reader *, const struct line_map *);
22090075Sobrien
22190075Sobrienstatic void
222132718Skanadd_symbols (symbol_flags flags, namelist names)
22318334Speter{
22450397Sobrien  symbol_table[cur_symbol_table_size].flags = flags;
22550397Sobrien  symbol_table[cur_symbol_table_size].names = names;
22650397Sobrien  cur_symbol_table_size++;
22750397Sobrien  if (cur_symbol_table_size >= SYMBOL_TABLE_SIZE)
22850397Sobrien    fatal ("too many calls to add_symbols");
22950397Sobrien  symbol_table[cur_symbol_table_size].names = NULL; /* Termination.  */
23018334Speter}
23118334Speter
23250397Sobrienstruct std_include_entry {
23390075Sobrien  const char *const name;
23490075Sobrien  const symbol_flags flags;
23590075Sobrien  const namelist names;
23650397Sobrien};
23718334Speter
23850397Sobrienconst char NONE[] = "";  /* The empty namelist.  */
23950397Sobrien
24050397Sobrien/* Special name to indicate a continuation line in std_include_table.  */
24150397Sobrienconst char CONTINUED[] = "";
24250397Sobrien
24390075Sobrienconst struct std_include_entry *include_entry;
24418334Speter
24590075Sobrienconst struct std_include_entry std_include_table [] = {
24650397Sobrien  { "ctype.h", ANSI_SYMBOL,
24718334Speter      "isalnum\0isalpha\0iscntrl\0isdigit\0isgraph\0islower\0\
24850397Sobrienisprint\0ispunct\0isspace\0isupper\0isxdigit\0tolower\0toupper\0" },
24918334Speter
25050397Sobrien  { "dirent.h", POSIX1_SYMBOL, "closedir\0opendir\0readdir\0rewinddir\0"},
25118334Speter
25250397Sobrien  { "errno.h", ANSI_SYMBOL|MACRO_SYMBOL, "errno\0" },
25318334Speter
25450397Sobrien  /* ANSI_SYMBOL is wrong, but ...  */
25550397Sobrien  { "curses.h", ANSI_SYMBOL, "box\0delwin\0endwin\0getcurx\0getcury\0initscr\0\
25618334Spetermvcur\0mvwprintw\0mvwscanw\0newwin\0overlay\0overwrite\0\
25718334Speterscroll\0subwin\0touchwin\0waddstr\0wclear\0wclrtobot\0wclrtoeol\0\
25818334Speterwaddch\0wdelch\0wdeleteln\0werase\0wgetch\0wgetstr\0winsch\0winsertln\0\
25950397Sobrienwmove\0wprintw\0wrefresh\0wscanw\0wstandend\0wstandout\0" },
26018334Speter
26150397Sobrien  { "fcntl.h", POSIX1_SYMBOL, "creat\0fcntl\0open\0" },
26218334Speter
26318334Speter  /* Maybe also "getgrent fgetgrent setgrent endgrent" */
26450397Sobrien  { "grp.h", POSIX1_SYMBOL, "getgrgid\0getgrnam\0" },
26518334Speter
26618334Speter/*{ "limit.h", ... provided by gcc }, */
26718334Speter
26850397Sobrien  { "locale.h", ANSI_SYMBOL, "localeconv\0setlocale\0" },
26918334Speter
27050397Sobrien  { "math.h", ANSI_SYMBOL,
27150397Sobrien      "acos\0asin\0atan\0atan2\0ceil\0cos\0cosh\0exp\0\
27218334Speterfabs\0floor\0fmod\0frexp\0ldexp\0log10\0log\0modf\0pow\0sin\0sinh\0sqrt\0\
27350397Sobrientan\0tanh\0" },
27418334Speter
27550397Sobrien  { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "HUGE_VAL\0" },
27618334Speter
27750397Sobrien  { "pwd.h", POSIX1_SYMBOL, "getpwnam\0getpwuid\0" },
27818334Speter
27950397Sobrien  /* Left out siglongjmp sigsetjmp - these depend on sigjmp_buf.  */
28050397Sobrien  { "setjmp.h", ANSI_SYMBOL, "longjmp\0setjmp\0" },
28150397Sobrien
28218334Speter  /* Left out signal() - its prototype is too complex for us!
28318334Speter     Also left out "sigaction sigaddset sigdelset sigemptyset
28418334Speter     sigfillset sigismember sigpending sigprocmask sigsuspend"
28518334Speter     because these need sigset_t or struct sigaction.
28650397Sobrien     Most systems that provide them will also declare them.  */
287169689Skan  { "signal.h", ANSI_SYMBOL, "raise\0" },
288169689Skan  { CONTINUED, POSIX1_SYMBOL, "kill\0" },
28918334Speter
29050397Sobrien  { "stdio.h", ANSI_SYMBOL,
29150397Sobrien      "clearerr\0fclose\0feof\0ferror\0fflush\0fgetc\0fgetpos\0\
29218334Speterfgets\0fopen\0fprintf\0fputc\0fputs\0fread\0freopen\0fscanf\0fseek\0\
29350397Sobrienfsetpos\0ftell\0fwrite\0getc\0getchar\0gets\0perror\0\
29418334Speterprintf\0putc\0putchar\0puts\0remove\0rename\0rewind\0scanf\0setbuf\0\
29518334Spetersetvbuf\0sprintf\0sscanf\0vprintf\0vsprintf\0vfprintf\0tmpfile\0\
29650397Sobrientmpnam\0ungetc\0" },
29750397Sobrien  { CONTINUED, POSIX1_SYMBOL, "fdopen\0fileno\0" },
29850397Sobrien  { CONTINUED, POSIX2_SYMBOL, "pclose\0popen\0" },  /* I think ...  */
29918334Speter/* Should perhaps also handle NULL, EOF, ... ? */
30018334Speter
30118334Speter  /* "div ldiv", - ignored because these depend on div_t, ldiv_t
30218334Speter     ignore these: "mblen mbstowcs mbstowc wcstombs wctomb"
30318334Speter     Left out getgroups, because SunOS4 has incompatible BSD and SVR4 versions.
30418334Speter     Should perhaps also add NULL */
30550397Sobrien  { "stdlib.h", ANSI_SYMBOL,
30650397Sobrien      "abort\0abs\0atexit\0atof\0atoi\0atol\0bsearch\0calloc\0\
307169689Skanexit\0free\0getenv\0labs\0malloc\0qsort\0rand\0realloc\0\
30850397Sobriensrand\0strtod\0strtol\0strtoul\0system\0" },
30950397Sobrien  { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "EXIT_FAILURE\0EXIT_SUCCESS\0" },
310169689Skan  { CONTINUED, POSIX1_SYMBOL, "putenv\0" },
31118334Speter
31250397Sobrien  { "string.h", ANSI_SYMBOL, "memchr\0memcmp\0memcpy\0memmove\0memset\0\
31318334Speterstrcat\0strchr\0strcmp\0strcoll\0strcpy\0strcspn\0strerror\0\
31418334Speterstrlen\0strncat\0strncmp\0strncpy\0strpbrk\0strrchr\0strspn\0strstr\0\
31550397Sobrienstrtok\0strxfrm\0" },
31618334Speter/* Should perhaps also add NULL and size_t */
31718334Speter
31850397Sobrien  { "strings.h", XOPEN_EXTENDED_SYMBOL,
31950397Sobrien      "bcmp\0bcopy\0bzero\0ffs\0index\0rindex\0strcasecmp\0strncasecmp\0" },
32050397Sobrien
32150397Sobrien  { "strops.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
32250397Sobrien
32350397Sobrien  /* Actually, XPG4 does not seem to have <sys/ioctl.h>, but defines
32450397Sobrien     ioctl in <strops.h>.  However, many systems have it is sys/ioctl.h,
32550397Sobrien     and many systems do have <sys/ioctl.h> but not <strops.h>.  */
32650397Sobrien  { "sys/ioctl.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
32750397Sobrien
32850397Sobrien  { "sys/socket.h", XOPEN_EXTENDED_SYMBOL, "socket\0" },
32950397Sobrien
33050397Sobrien  { "sys/stat.h", POSIX1_SYMBOL,
33150397Sobrien      "chmod\0fstat\0mkdir\0mkfifo\0stat\0lstat\0umask\0" },
33250397Sobrien  { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
33318334Speter      "S_ISDIR\0S_ISBLK\0S_ISCHR\0S_ISFIFO\0S_ISREG\0S_ISLNK\0S_IFDIR\0\
33418334SpeterS_IFBLK\0S_IFCHR\0S_IFIFO\0S_IFREG\0S_IFLNK\0" },
33550397Sobrien  { CONTINUED, XOPEN_EXTENDED_SYMBOL, "fchmod\0" },
33618334Speter
33750397Sobrien#if 0
33850397Sobrien/* How do we handle fd_set? */
33950397Sobrien  { "sys/time.h", XOPEN_EXTENDED_SYMBOL, "select\0" },
34050397Sobrien  { "sys/select.h", XOPEN_EXTENDED_SYMBOL /* fake */, "select\0" },
34150397Sobrien#endif
34250397Sobrien
34350397Sobrien  { "sys/times.h", POSIX1_SYMBOL, "times\0" },
34418334Speter  /* "sys/types.h" add types (not in old g++-include) */
34518334Speter
34650397Sobrien  { "sys/utsname.h", POSIX1_SYMBOL, "uname\0" },
34718334Speter
34850397Sobrien  { "sys/wait.h", POSIX1_SYMBOL, "wait\0waitpid\0" },
34950397Sobrien  { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
35018334Speter      "WEXITSTATUS\0WIFEXITED\0WIFSIGNALED\0WIFSTOPPED\0WSTOPSIG\0\
35118334SpeterWTERMSIG\0WNOHANG\0WNOTRACED\0" },
35218334Speter
35350397Sobrien  { "tar.h", POSIX1_SYMBOL, NONE },
35418334Speter
35550397Sobrien  { "termios.h", POSIX1_SYMBOL,
35650397Sobrien      "cfgetispeed\0cfgetospeed\0cfsetispeed\0cfsetospeed\0tcdrain\0tcflow\0tcflush\0tcgetattr\0tcsendbreak\0tcsetattr\0" },
35718334Speter
35850397Sobrien  { "time.h", ANSI_SYMBOL,
359169689Skan      "asctime\0clock\0ctime\0difftime\0gmtime\0localtime\0mktime\0strftime\0time\0" },
360169689Skan  { CONTINUED, POSIX1_SYMBOL, "tzset\0" },
36118334Speter
36250397Sobrien  { "unistd.h", POSIX1_SYMBOL,
36350397Sobrien      "_exit\0access\0alarm\0chdir\0chown\0close\0ctermid\0cuserid\0\
36418334Speterdup\0dup2\0execl\0execle\0execlp\0execv\0execve\0execvp\0fork\0fpathconf\0\
36550397Sobriengetcwd\0getegid\0geteuid\0getgid\0getlogin\0getpgrp\0getpid\0\
36618334Spetergetppid\0getuid\0isatty\0link\0lseek\0pathconf\0pause\0pipe\0read\0rmdir\0\
36718334Spetersetgid\0setpgid\0setsid\0setuid\0sleep\0sysconf\0tcgetpgrp\0tcsetpgrp\0\
36850397Sobrienttyname\0unlink\0write\0" },
36950397Sobrien  { CONTINUED, POSIX2_SYMBOL, "getopt\0" },
37050397Sobrien  { CONTINUED, XOPEN_EXTENDED_SYMBOL,
37152284Sobrien      "lockf\0gethostid\0gethostname\0readlink\0symlink\0" },
37218334Speter
37350397Sobrien  { "utime.h", POSIX1_SYMBOL, "utime\0" },
37450397Sobrien
37550397Sobrien  { NULL, 0, NONE }
37618334Speter};
37718334Speter
37818334Speterenum special_file special_file_handling = no_special;
37918334Speter
38050397Sobrien/* They are set if the corresponding macro has been seen.  */
38118334Speter/* The following are only used when handling sys/stat.h */
38218334Speterint seen_S_IFBLK = 0, seen_S_ISBLK  = 0;
38318334Speterint seen_S_IFCHR = 0, seen_S_ISCHR  = 0;
38418334Speterint seen_S_IFDIR = 0, seen_S_ISDIR  = 0;
38518334Speterint seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
38618334Speterint seen_S_IFLNK = 0, seen_S_ISLNK  = 0;
38718334Speterint seen_S_IFREG = 0, seen_S_ISREG  = 0;
38850397Sobrien/* The following are only used when handling errno.h */
38950397Sobrienint seen_errno = 0;
39050397Sobrien/* The following are only used when handling stdlib.h */
39150397Sobrienint seen_EXIT_FAILURE = 0, seen_EXIT_SUCCESS = 0;
39218334Speter
39318334Speterstruct obstack scan_file_obstack;
39418334Speter
39518334Speter/* NOTE:  If you edit this, also edit gen-protos.c !! */
39650397Sobrien
39790075Sobrienstatic struct fn_decl *
398132718Skanlookup_std_proto (const char *name, int name_length)
39918334Speter{
40090075Sobrien  int i = hashstr (name, name_length) % HASH_SIZE;
40118334Speter  int i0 = i;
40218334Speter  for (;;)
40318334Speter    {
40418334Speter      struct fn_decl *fn;
40518334Speter      if (hash_tab[i] == 0)
40618334Speter	return NULL;
40718334Speter      fn = &std_protos[hash_tab[i]];
40852284Sobrien      if ((int) strlen (fn->fname) == name_length
40918334Speter	  && strncmp (fn->fname, name, name_length) == 0)
41018334Speter	return fn;
41118334Speter      i = (i+1) % HASH_SIZE;
412169689Skan      gcc_assert (i != i0);
41318334Speter    }
41418334Speter}
41518334Speter
41618334Speterchar *inc_filename;
41718334Speterint inc_filename_length;
41818334SpeterFILE *outf;
41918334Spetersstring line;
42018334Speter
42118334Speterint lbrac_line, rbrac_line;
42218334Speter
42318334Speterint required_unseen_count = 0;
42450397Sobrienint required_other = 0;
42518334Speter
426117395Skanstatic void
427132718Skanwrite_lbrac (void)
42818334Speter{
42918334Speter  if (partial_count)
43018334Speter    {
43118334Speter      fprintf (outf, "#ifndef _PARAMS\n");
43218334Speter      fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
43318334Speter      fprintf (outf, "#define _PARAMS(ARGS) ARGS\n");
43418334Speter      fprintf (outf, "#else\n");
43518334Speter      fprintf (outf, "#define _PARAMS(ARGS) ()\n");
43618334Speter      fprintf (outf, "#endif\n#endif /* _PARAMS */\n");
43718334Speter    }
43818334Speter}
43918334Speter
44018334Speterstruct partial_proto
44118334Speter{
44218334Speter  struct partial_proto *next;
44318334Speter  struct fn_decl *fn;
44418334Speter  int line_seen;
44518334Speter};
44618334Speter
44718334Speterstruct partial_proto *partial_proto_list = NULL;
44818334Speter
44918334Speterstruct partial_proto required_dummy_proto, seen_dummy_proto;
45018334Speter#define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
45118334Speter#define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
45218334Speter#define SET_SEEN(FN) ((FN)->partial = &seen_dummy_proto)
45318334Speter#define SEEN(FN) ((FN)->partial == &seen_dummy_proto)
45418334Speter
45590075Sobrienstatic void
456132718Skanrecognized_macro (const char *fname)
45718334Speter{
45850397Sobrien  /* The original include file defines fname as a macro.  */
45918334Speter  struct fn_decl *fn = lookup_std_proto (fname, strlen (fname));
46018334Speter
46150397Sobrien  /* Since fname is a macro, don't require a prototype for it.  */
46218334Speter  if (fn)
46318334Speter    {
46418334Speter      if (REQUIRED (fn))
46518334Speter	required_unseen_count--;
46618334Speter      SET_SEEN (fn);
46718334Speter    }
46818334Speter
46918334Speter  switch (special_file_handling)
47018334Speter    {
47118334Speter    case errno_h:
47250397Sobrien      if (strcmp (fname, "errno") == 0 && !seen_errno)
47350397Sobrien	seen_errno = 1, required_other--;
47418334Speter      break;
47550397Sobrien    case stdlib_h:
47650397Sobrien      if (strcmp (fname, "EXIT_FAILURE") == 0 && !seen_EXIT_FAILURE)
47750397Sobrien	seen_EXIT_FAILURE = 1, required_other--;
47850397Sobrien      if (strcmp (fname, "EXIT_SUCCESS") == 0 && !seen_EXIT_SUCCESS)
47950397Sobrien	seen_EXIT_SUCCESS = 1, required_other--;
48050397Sobrien      break;
48118334Speter    case sys_stat_h:
48218334Speter      if (fname[0] == 'S' && fname[1] == '_')
48318334Speter	{
48418334Speter	  if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++;
48518334Speter	  else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++;
48618334Speter	  else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++;
48718334Speter	  else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++;
48818334Speter	  else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++;
48918334Speter	  else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++;
49018334Speter	  else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++;
49118334Speter	  else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++;
49218334Speter	  else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++;
49318334Speter	  else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++;
49418334Speter	  else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
49518334Speter	  else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
49618334Speter	}
49750397Sobrien      break;
49850397Sobrien
49950397Sobrien    default:
50050397Sobrien      break;
50118334Speter    }
50218334Speter}
50318334Speter
50418334Spetervoid
505132718Skanrecognized_extern (const cpp_token *name)
50618334Speter{
50718334Speter  switch (special_file_handling)
50818334Speter    {
50918334Speter    case errno_h:
51090075Sobrien      if (cpp_ideq (name, "errno"))
51150397Sobrien	seen_errno = 1, required_other--;
51218334Speter      break;
51350397Sobrien
51450397Sobrien    default:
51550397Sobrien      break;
51618334Speter    }
51718334Speter}
51818334Speter
51918334Speter/* Called by scan_decls if it saw a function definition for a function
52090075Sobrien   named FNAME.  KIND is 'I' for an inline function; 'F' if a normal
52190075Sobrien   function declaration preceded by 'extern "C"' (or nested inside
52290075Sobrien   'extern "C"' braces); or 'f' for other function declarations.  */
52318334Speter
52418334Spetervoid
525132718Skanrecognized_function (const cpp_token *fname, unsigned int line, int kind,
526132718Skan		     int have_arg_list)
52718334Speter{
52818334Speter  struct partial_proto *partial;
52918334Speter  int i;
53018334Speter  struct fn_decl *fn;
53118334Speter
53290075Sobrien  fn = lookup_std_proto ((const char *) NODE_NAME (fname->val.node),
53390075Sobrien			 NODE_LEN (fname->val.node));
53418334Speter
53550397Sobrien  /* Remove the function from the list of required function.  */
53618334Speter  if (fn)
53718334Speter    {
53818334Speter      if (REQUIRED (fn))
53918334Speter	required_unseen_count--;
54018334Speter      SET_SEEN (fn);
54118334Speter    }
54218334Speter
54350397Sobrien  /* If we have a full prototype, we're done.  */
54418334Speter  if (have_arg_list)
54518334Speter    return;
546117395Skan
54718334Speter  if (kind == 'I')  /* don't edit inline function */
54818334Speter    return;
54918334Speter
55018334Speter  /* If the partial prototype was included from some other file,
55150397Sobrien     we don't need to patch it up (in this run).  */
55290075Sobrien  i = strlen (cur_file);
55318334Speter  if (i < inc_filename_length
55490075Sobrien      || strcmp (inc_filename, cur_file + (i - inc_filename_length)) != 0)
55518334Speter    return;
55618334Speter
55718334Speter  if (fn == NULL)
55818334Speter    return;
55990075Sobrien  if (fn->params[0] == '\0')
56018334Speter    return;
56118334Speter
56218334Speter  /* We only have a partial function declaration,
56350397Sobrien     so remember that we have to add a complete prototype.  */
56418334Speter  partial_count++;
565132718Skan  partial = obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
56690075Sobrien  partial->line_seen = line;
56718334Speter  partial->fn = fn;
56818334Speter  fn->partial = partial;
56918334Speter  partial->next = partial_proto_list;
57018334Speter  partial_proto_list = partial;
57118334Speter  if (verbose)
57218334Speter    {
57318334Speter      fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
57490075Sobrien	       inc_filename, fn->fname);
57518334Speter    }
57618334Speter}
57718334Speter
57818334Speter/* For any name in NAMES that is defined as a macro,
57950397Sobrien   call recognized_macro on it.  */
58018334Speter
58190075Sobrienstatic void
582132718Skancheck_macro_names (cpp_reader *pfile, namelist names)
58318334Speter{
58490075Sobrien  size_t len;
58518334Speter  while (*names)
58618334Speter    {
58790075Sobrien      len = strlen (names);
58890075Sobrien      if (cpp_defined (pfile, (const unsigned char *)names, len))
58918334Speter	recognized_macro (names);
59090075Sobrien      names += len + 1;
59118334Speter    }
59218334Speter}
59318334Speter
59490075Sobrienstatic void
595132718Skancb_file_change (cpp_reader *pfile ATTRIBUTE_UNUSED,
596132718Skan		const struct line_map *map)
59790075Sobrien{
59890075Sobrien  /* Just keep track of current file name.  */
599132718Skan  cur_file = map == NULL ? NULL : map->to_file;
60090075Sobrien}
60190075Sobrien
60290075Sobrienstatic void
603132718Skanread_scan_file (char *in_fname, int argc, char **argv)
60418334Speter{
60590075Sobrien  cpp_reader *scan_in;
60690075Sobrien  cpp_callbacks *cb;
60790075Sobrien  cpp_options *options;
60818334Speter  struct fn_decl *fn;
609132718Skan  int i, strings_processed;
61090075Sobrien  struct symbol_list *cur_symbols;
61118334Speter
612117395Skan  obstack_init (&scan_file_obstack);
61318334Speter
614169689Skan  linemap_init (&line_table);
615169689Skan  scan_in = cpp_create_reader (CLK_GNUC89, NULL, &line_table);
61690075Sobrien  cb = cpp_get_callbacks (scan_in);
61790075Sobrien  cb->file_change = cb_file_change;
61890075Sobrien
61990075Sobrien  /* We are going to be scanning a header file out of its proper context,
62090075Sobrien     so ignore warnings and errors.  */
62190075Sobrien  options = cpp_get_options (scan_in);
62290075Sobrien  options->inhibit_warnings = 1;
62390075Sobrien  options->inhibit_errors = 1;
624132718Skan  cpp_post_options (scan_in);
62590075Sobrien
626132718Skan  if (!cpp_read_main_file (scan_in, in_fname))
627132718Skan    exit (FATAL_EXIT_CODE);
628132718Skan
629132718Skan  cpp_change_file (scan_in, LC_RENAME, "<built-in>");
630132718Skan  cpp_init_builtins (scan_in, true);
631132718Skan  cpp_change_file (scan_in, LC_RENAME, in_fname);
632132718Skan
633132718Skan  /* Process switches after builtins so -D can override them.  */
634132718Skan  for (i = 0; i < argc; i += strings_processed)
635132718Skan    {
636132718Skan      strings_processed = 0;
637132718Skan      if (argv[i][0] == '-')
638132718Skan	{
639132718Skan	  if (argv[i][1] == 'I')
640132718Skan	    {
641132718Skan	      if (argv[i][2] != '\0')
642132718Skan		{
643132718Skan		  strings_processed = 1;
644169689Skan		  add_path (xstrdup (argv[i] + 2), BRACKET, false, false);
645132718Skan		}
646132718Skan	      else if (i + 1 != argc)
647132718Skan		{
648132718Skan		  strings_processed = 2;
649169689Skan		  add_path (xstrdup (argv[i + 1]), BRACKET, false, false);
650132718Skan		}
651132718Skan	    }
652132718Skan	  else if (argv[i][1] == 'D')
653132718Skan	    {
654132718Skan	      if (argv[i][2] != '\0')
655132718Skan		strings_processed = 1, cpp_define (scan_in, argv[i] + 2);
656132718Skan	      else if (i + 1 != argc)
657132718Skan		strings_processed = 2, cpp_define (scan_in, argv[i + 1]);
658132718Skan	    }
659132718Skan	}
660132718Skan
661132718Skan      if (strings_processed == 0)
662132718Skan	break;
663132718Skan    }
664132718Skan
665117395Skan  if (i < argc)
666132718Skan    cpp_error (scan_in, CPP_DL_ERROR, "invalid option `%s'", argv[i]);
667117395Skan  if (cpp_errors (scan_in))
66850397Sobrien    exit (FATAL_EXIT_CODE);
66950397Sobrien
670132718Skan  register_include_chains (scan_in, NULL /* sysroot */, NULL /* iprefix */,
671169689Skan			   NULL /* imultilib */, true /* stdinc */,
672169689Skan			   false /* cxx_stdinc */, false /* verbose */);
67318334Speter
67490075Sobrien  /* We are scanning a system header, so mark it as such.  */
67590075Sobrien  cpp_make_system_header (scan_in, 1, 0);
67690075Sobrien
67790075Sobrien  scan_decls (scan_in, argc, argv);
67850397Sobrien  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
67990075Sobrien    check_macro_names (scan_in, cur_symbols->names);
68018336Speter
68118334Speter  /* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf.
68250397Sobrien     If so, those functions are also required.  */
68318334Speter  if (special_file_handling == stdio_h
68418334Speter      && (fn = lookup_std_proto ("_filbuf", 7)) != NULL)
68518334Speter    {
686132718Skan      unsigned char getchar_call[] = "getchar();\n";
68718334Speter      int seen_filbuf = 0;
68818334Speter
68950397Sobrien      /* Scan the macro expansion of "getchar();".  */
69090075Sobrien      cpp_push_buffer (scan_in, getchar_call, sizeof(getchar_call) - 1,
691132718Skan		       /* from_stage3 */ true);
69218334Speter      for (;;)
69318334Speter	{
69490075Sobrien	  const cpp_token *t = cpp_get_token (scan_in);
69590075Sobrien
69690075Sobrien	  if (t->type == CPP_EOF)
69718334Speter	    break;
69890075Sobrien	  else if (cpp_ideq (t, "_filbuf"))
69918334Speter	    seen_filbuf++;
70018334Speter	}
70190075Sobrien
70218334Speter      if (seen_filbuf)
70318334Speter	{
70418334Speter	  int need_filbuf = !SEEN (fn) && !REQUIRED (fn);
70518334Speter	  struct fn_decl *flsbuf_fn = lookup_std_proto ("_flsbuf", 7);
70618334Speter	  int need_flsbuf
70718334Speter	    = flsbuf_fn && !SEEN (flsbuf_fn) && !REQUIRED (flsbuf_fn);
70818334Speter
70950397Sobrien	  /* Append "_filbuf" and/or "_flsbuf" to the required functions.  */
71018334Speter	  if (need_filbuf + need_flsbuf)
71118334Speter	    {
71252284Sobrien	      const char *new_list;
71318334Speter	      if (need_filbuf)
71450397Sobrien		SET_REQUIRED (fn);
71518334Speter	      if (need_flsbuf)
71650397Sobrien		SET_REQUIRED (flsbuf_fn);
71790075Sobrien	      if (need_flsbuf && need_filbuf)
71850397Sobrien		new_list = "_filbuf\0_flsbuf\0";
71950397Sobrien	      else if (need_flsbuf)
72050397Sobrien		new_list = "_flsbuf\0";
72150397Sobrien	      else /* if (need_flsbuf) */
72250397Sobrien		new_list = "_filbuf\0";
72350397Sobrien	      add_symbols (ANSI_SYMBOL, new_list);
72418334Speter	      required_unseen_count += need_filbuf + need_flsbuf;
72518334Speter	    }
72618334Speter	}
72718334Speter    }
72818334Speter
729132718Skan  if (required_unseen_count + partial_count + required_other == 0)
73018334Speter    {
73118334Speter      if (verbose)
73218334Speter	fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
73350397Sobrien      exit (SUCCESS_EXIT_CODE);
73418334Speter    }
73518334Speter  if (!verbose)
73618334Speter    fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
73718334Speter  else
73818334Speter    {
73918334Speter      if (required_unseen_count)
74018334Speter	fprintf (stderr, "%s: %d missing function declarations.\n",
74118334Speter		 inc_filename, required_unseen_count);
74218334Speter      if (partial_count)
74318334Speter	fprintf (stderr, "%s: %d non-prototype function declarations.\n",
74418334Speter		 inc_filename, partial_count);
74518334Speter    }
74618334Speter}
74718334Speter
74890075Sobrienstatic void
749132718Skanwrite_rbrac (void)
75018334Speter{
75118334Speter  struct fn_decl *fn;
75218334Speter  const char *cptr;
75390075Sobrien  struct symbol_list *cur_symbols;
75418334Speter
75518334Speter  if (required_unseen_count)
75618334Speter    {
75718334Speter#ifdef NO_IMPLICIT_EXTERN_C
75818334Speter      fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
75918334Speter#endif
76018334Speter    }
76118334Speter
76250397Sobrien  /* Now we print out prototypes for those functions that we haven't seen.  */
76350397Sobrien  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
76418334Speter    {
76550397Sobrien      int if_was_emitted = 0;
76650397Sobrien      int name_len;
76750397Sobrien      cptr = cur_symbols->names;
76850397Sobrien      for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
76950397Sobrien	{
77050397Sobrien	  int macro_protect = 0;
77118334Speter
77250397Sobrien	  if (cur_symbols->flags & MACRO_SYMBOL)
77350397Sobrien	    continue;
77418334Speter
77550397Sobrien	  fn = lookup_std_proto (cptr, name_len);
77650397Sobrien	  if (fn == NULL || !REQUIRED (fn))
77750397Sobrien	    continue;
77818334Speter
77950397Sobrien	  if (!if_was_emitted)
78050397Sobrien	    {
78150397Sobrien/*	      what about curses. ??? or _flsbuf/_filbuf ??? */
78250397Sobrien	      if (cur_symbols->flags & ANSI_SYMBOL)
78350397Sobrien		fprintf (outf,
78450397Sobrien	 "#if defined(__USE_FIXED_PROTOTYPES__) || defined(__cplusplus) || defined (__STRICT_ANSI__)\n");
78550397Sobrien	      else if (cur_symbols->flags & (POSIX1_SYMBOL|POSIX2_SYMBOL))
78650397Sobrien		fprintf (outf,
78750397Sobrien       "#if defined(__USE_FIXED_PROTOTYPES__) || (defined(__cplusplus) \\\n\
78850397Sobrien    ? (!defined(__STRICT_ANSI__) || defined(_POSIX_SOURCE)) \\\n\
78950397Sobrien    : (defined(__STRICT_ANSI__) && defined(_POSIX_SOURCE)))\n");
79050397Sobrien	      else if (cur_symbols->flags & XOPEN_SYMBOL)
79150397Sobrien		{
79250397Sobrien		fprintf (outf,
79350397Sobrien       "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
79450397Sobrien   || (defined(__STRICT_ANSI__) && defined(_XOPEN_SOURCE))\n");
79550397Sobrien		}
79650397Sobrien	      else if (cur_symbols->flags & XOPEN_EXTENDED_SYMBOL)
79750397Sobrien		{
79850397Sobrien		fprintf (outf,
79950397Sobrien       "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
80050397Sobrien   || (defined(__STRICT_ANSI__) && defined(_XOPEN_EXTENDED_SOURCE))\n");
80150397Sobrien		}
80250397Sobrien	      else
80350397Sobrien		{
80450397Sobrien		  fatal ("internal error for function %s", fn->fname);
80550397Sobrien		}
80650397Sobrien	      if_was_emitted = 1;
80750397Sobrien	    }
80850397Sobrien
80950397Sobrien	  /* In the case of memmove, protect in case the application
81050397Sobrien	     defines it as a macro before including the header.  */
81150397Sobrien	  if (!strcmp (fn->fname, "memmove")
81290075Sobrien	      || !strcmp (fn->fname, "putc")
81390075Sobrien	      || !strcmp (fn->fname, "getc")
81450397Sobrien	      || !strcmp (fn->fname, "vprintf")
81550397Sobrien	      || !strcmp (fn->fname, "vfprintf")
81650397Sobrien	      || !strcmp (fn->fname, "vsprintf")
81750397Sobrien	      || !strcmp (fn->fname, "rewinddir")
81850397Sobrien	      || !strcmp (fn->fname, "abort"))
81950397Sobrien	    macro_protect = 1;
82050397Sobrien
82150397Sobrien	  if (macro_protect)
82250397Sobrien	    fprintf (outf, "#ifndef %s\n", fn->fname);
82350397Sobrien	  fprintf (outf, "extern %s %s (%s);\n",
82450397Sobrien		   fn->rtype, fn->fname, fn->params);
82550397Sobrien	  if (macro_protect)
82650397Sobrien	    fprintf (outf, "#endif\n");
82750397Sobrien	}
82850397Sobrien      if (if_was_emitted)
82950397Sobrien	fprintf (outf,
83050397Sobrien		 "#endif /* defined(__USE_FIXED_PROTOTYPES__) || ... */\n");
83118334Speter    }
83218334Speter  if (required_unseen_count)
83318334Speter    {
83418334Speter#ifdef NO_IMPLICIT_EXTERN_C
83518334Speter      fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
83618334Speter#endif
83718334Speter    }
83818334Speter
83918334Speter  switch (special_file_handling)
84018334Speter    {
84118334Speter    case errno_h:
84250397Sobrien      if (!seen_errno)
84318334Speter	fprintf (outf, "extern int errno;\n");
84418334Speter      break;
84550397Sobrien    case stdlib_h:
84650397Sobrien      if (!seen_EXIT_FAILURE)
84750397Sobrien	fprintf (outf, "#define EXIT_FAILURE 1\n");
84850397Sobrien      if (!seen_EXIT_SUCCESS)
84950397Sobrien	fprintf (outf, "#define EXIT_SUCCESS 0\n");
85050397Sobrien      break;
85118334Speter    case sys_stat_h:
85218334Speter      if (!seen_S_ISBLK && seen_S_IFBLK)
85318334Speter	fprintf (outf,
85418334Speter		 "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
85518334Speter      if (!seen_S_ISCHR && seen_S_IFCHR)
85618334Speter	fprintf (outf,
85718334Speter		 "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
85818334Speter      if (!seen_S_ISDIR && seen_S_IFDIR)
85918334Speter	fprintf (outf,
86018334Speter		 "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
86118334Speter      if (!seen_S_ISFIFO && seen_S_IFIFO)
86218334Speter	fprintf (outf,
86318334Speter		 "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
86418334Speter      if (!seen_S_ISLNK && seen_S_IFLNK)
86518334Speter	fprintf (outf,
86618334Speter		 "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
86718334Speter      if (!seen_S_ISREG && seen_S_IFREG)
86818334Speter	fprintf (outf,
86918334Speter		 "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
87018334Speter      break;
87150397Sobrien
87250397Sobrien    default:
87350397Sobrien      break;
87418334Speter    }
87518334Speter
87618334Speter}
87718334Speter
87818334Speter/* Returns 1 iff the file is properly protected from multiple inclusion:
87918334Speter   #ifndef PROTECT_NAME
88018334Speter   #define PROTECT_NAME
88118334Speter   #endif
88218334Speter
88318334Speter */
88418334Speter
88550397Sobrien#define INF_GET() (inf_ptr < inf_limit ? *(unsigned char *) inf_ptr++ : EOF)
88618334Speter#define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
88718334Speter
88890075Sobrienstatic int
889132718Skaninf_skip_spaces (int c)
89018334Speter{
89118334Speter  for (;;)
89218334Speter    {
89318334Speter      if (c == ' ' || c == '\t')
89418334Speter	c = INF_GET ();
89518334Speter      else if (c == '/')
89618334Speter	{
89718334Speter	  c = INF_GET ();
89818334Speter	  if (c != '*')
89918334Speter	    {
90050397Sobrien	      (void) INF_UNGET (c);
90118334Speter	      return '/';
90218334Speter	    }
90318334Speter	  c = INF_GET ();
90418334Speter	  for (;;)
90518334Speter	    {
90618334Speter	      if (c == EOF)
90718334Speter		return EOF;
90818334Speter	      else if (c != '*')
90918334Speter		{
91018334Speter		  if (c == '\n')
91118334Speter		    source_lineno++, lineno++;
91218334Speter		  c = INF_GET ();
91318334Speter		}
91418334Speter	      else if ((c = INF_GET ()) == '/')
91518334Speter		return INF_GET ();
91618334Speter	    }
91718334Speter	}
91818334Speter      else
91918334Speter	break;
92018334Speter    }
92118334Speter  return c;
92218334Speter}
92318334Speter
92450397Sobrien/* Read into STR from inf_buffer upto DELIM.  */
92518334Speter
92690075Sobrienstatic int
927132718Skaninf_read_upto (sstring *str, int delim)
92818334Speter{
92918334Speter  int ch;
93018334Speter  for (;;)
93118334Speter    {
93218334Speter      ch = INF_GET ();
93318334Speter      if (ch == EOF || ch == delim)
93418334Speter	break;
93518334Speter      SSTRING_PUT (str, ch);
93618334Speter    }
93718334Speter  MAKE_SSTRING_SPACE (str, 1);
93818334Speter  *str->ptr = 0;
93918334Speter  return ch;
94018334Speter}
94118334Speter
94290075Sobrienstatic int
943132718Skaninf_scan_ident (sstring *s, int c)
94418334Speter{
94518334Speter  s->ptr = s->base;
94690075Sobrien  if (ISIDST (c))
94718334Speter    {
94818334Speter      for (;;)
94918334Speter	{
95018334Speter	  SSTRING_PUT (s, c);
95118334Speter	  c = INF_GET ();
95290075Sobrien	  if (c == EOF || !(ISIDNUM (c)))
95318334Speter	    break;
95418334Speter	}
95518334Speter    }
95618334Speter  MAKE_SSTRING_SPACE (s, 1);
95718334Speter  *s->ptr = 0;
95818334Speter  return c;
95918334Speter}
96018334Speter
96118334Speter/* Returns 1 if the file is correctly protected against multiple
96218334Speter   inclusion, setting *ifndef_line to the line number of the initial #ifndef
96318334Speter   and setting *endif_line to the final #endif.
96450397Sobrien   Otherwise return 0.  */
96518334Speter
96690075Sobrienstatic int
967132718Skancheck_protection (int *ifndef_line, int *endif_line)
96818334Speter{
96918334Speter  int c;
97018334Speter  int if_nesting = 1; /* Level of nesting of #if's */
97118334Speter  char *protect_name = NULL; /* Identifier following initial #ifndef */
97218334Speter  int define_seen = 0;
97318334Speter
97450397Sobrien  /* Skip initial white space (including comments).  */
97518334Speter  for (;; lineno++)
97618334Speter    {
97718334Speter      c = inf_skip_spaces (' ');
97818334Speter      if (c == EOF)
97918334Speter	return 0;
98018334Speter      if (c != '\n')
98118334Speter	break;
98218334Speter    }
98318334Speter  if (c != '#')
98418334Speter    return 0;
98518334Speter  c = inf_scan_ident (&buf, inf_skip_spaces (' '));
98618334Speter  if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
98718334Speter    return 0;
98818334Speter
98950397Sobrien  /* So far so good: We've seen an initial #ifndef.  */
99018334Speter  *ifndef_line = lineno;
99118334Speter  c = inf_scan_ident (&buf, inf_skip_spaces (c));
99218334Speter  if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
99318334Speter    return 0;
99418334Speter  protect_name = xstrdup (buf.base);
99518334Speter
99650397Sobrien  (void) INF_UNGET (c);
99718334Speter  c = inf_read_upto (&buf, '\n');
99818334Speter  if (c == EOF)
99918334Speter    return 0;
100018334Speter  lineno++;
100118334Speter
100218334Speter  for (;;)
100318334Speter    {
100418334Speter      c = inf_skip_spaces (' ');
100518334Speter      if (c == EOF)
100618334Speter	return 0;
100718334Speter      if (c == '\n')
100818334Speter	{
100918334Speter	  lineno++;
101018334Speter	  continue;
101118334Speter	}
101218334Speter      if (c != '#')
101318334Speter	goto skip_to_eol;
101418334Speter      c = inf_scan_ident (&buf, inf_skip_spaces (' '));
101518334Speter      if (SSTRING_LENGTH (&buf) == 0)
101618334Speter	;
101718334Speter      else if (!strcmp (buf.base, "ifndef")
101818334Speter	  || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
101918334Speter	{
102018334Speter	  if_nesting++;
102118334Speter	}
102218334Speter      else if (!strcmp (buf.base, "endif"))
102318334Speter	{
102418334Speter	  if_nesting--;
102518334Speter	  if (if_nesting == 0)
102618334Speter	    break;
102718334Speter	}
102818334Speter      else if (!strcmp (buf.base, "else"))
102918334Speter	{
103018334Speter	  if (if_nesting == 1)
103118334Speter	    return 0;
103218334Speter	}
103318334Speter      else if (!strcmp (buf.base, "define"))
103418334Speter	{
103518334Speter	  c = inf_skip_spaces (c);
103618334Speter	  c = inf_scan_ident (&buf, c);
103718334Speter	  if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
103818334Speter	    define_seen = 1;
103918334Speter	}
104018334Speter    skip_to_eol:
104118334Speter      for (;;)
104218334Speter	{
104318334Speter	  if (c == '\n' || c == EOF)
104418334Speter	    break;
104518334Speter	  c = INF_GET ();
104618334Speter	}
104718334Speter      if (c == EOF)
104818334Speter	return 0;
104918334Speter      lineno++;
105018334Speter    }
105118334Speter
105218334Speter  if (!define_seen)
105318334Speter     return 0;
105418334Speter  *endif_line = lineno;
105550397Sobrien  /* Skip final white space (including comments).  */
105618334Speter  for (;;)
105718334Speter    {
105818334Speter      c = inf_skip_spaces (' ');
105918334Speter      if (c == EOF)
106018334Speter	break;
106118334Speter      if (c != '\n')
106218334Speter	return 0;
106318334Speter    }
106418334Speter
106518334Speter  return 1;
106618334Speter}
106718334Speter
1068132718Skanextern int main (int, char **);
106990075Sobrien
107018334Speterint
1071132718Skanmain (int argc, char **argv)
107218334Speter{
107318334Speter  int inf_fd;
107418334Speter  struct stat sbuf;
107518334Speter  int c;
107650397Sobrien#ifdef FIXPROTO_IGNORE_LIST
107750397Sobrien  int i;
107850397Sobrien#endif
107950397Sobrien  const char *cptr;
108018334Speter  int ifndef_line;
108118334Speter  int endif_line;
108218334Speter  long to_read;
108318334Speter  long int inf_size;
108490075Sobrien  struct symbol_list *cur_symbols;
108518334Speter
1086169689Skan  progname = "fix-header";
108718334Speter  if (argv[0] && argv[0][0])
108818334Speter    {
108990075Sobrien      char *p;
109018334Speter
109118334Speter      progname = 0;
109218334Speter      for (p = argv[0]; *p; p++)
1093117395Skan	if (*p == '/')
1094117395Skan	  progname = p;
109518334Speter      progname = progname ? progname+1 : argv[0];
109618334Speter    }
109718334Speter
109818334Speter  if (argc < 4)
109918334Speter    {
110018334Speter      fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h options\n",
110118334Speter	       progname);
110250397Sobrien      exit (FATAL_EXIT_CODE);
110318334Speter    }
110418334Speter
110518334Speter  inc_filename = argv[1];
110618334Speter  inc_filename_length = strlen (inc_filename);
110718334Speter
110818334Speter#ifdef FIXPROTO_IGNORE_LIST
110918334Speter  for (i = 0; files_to_ignore[i] != NULL; i++)
111018334Speter    {
111190075Sobrien      const char *const ignore_name = files_to_ignore[i];
111218334Speter      int ignore_len = strlen (ignore_name);
111318334Speter      if (strncmp (inc_filename, ignore_name, ignore_len) == 0)
111418334Speter	{
111518334Speter	  if (ignore_name[ignore_len-1] == '/'
111618334Speter	      || inc_filename[ignore_len] == '\0')
111718334Speter	    {
111818334Speter	      if (verbose)
111918334Speter		fprintf (stderr, "%s: ignoring %s\n", progname, inc_filename);
112050397Sobrien	      exit (SUCCESS_EXIT_CODE);
112118334Speter	    }
112218334Speter	}
1123117395Skan
112418334Speter    }
112518334Speter#endif
112618334Speter
112718334Speter  if (strcmp (inc_filename, "sys/stat.h") == 0)
112818334Speter    special_file_handling = sys_stat_h;
112918334Speter  else if (strcmp (inc_filename, "errno.h") == 0)
113050397Sobrien    special_file_handling = errno_h, required_other++;
113150397Sobrien  else if (strcmp (inc_filename, "stdlib.h") == 0)
113250397Sobrien    special_file_handling = stdlib_h, required_other+=2;
113318334Speter  else if (strcmp (inc_filename, "stdio.h") == 0)
113418334Speter    special_file_handling = stdio_h;
113518334Speter  include_entry = std_include_table;
113618334Speter  while (include_entry->name != NULL
113752284Sobrien	 && ((strcmp (include_entry->name, CONTINUED) == 0)
113850397Sobrien	     || strcmp (inc_filename, include_entry->name) != 0))
113918334Speter    include_entry++;
114018334Speter
114150397Sobrien  if (include_entry->name != NULL)
114250397Sobrien    {
114390075Sobrien      const struct std_include_entry *entry;
114450397Sobrien      cur_symbol_table_size = 0;
114550397Sobrien      for (entry = include_entry; ;)
114650397Sobrien	{
114750397Sobrien	  if (entry->flags)
114850397Sobrien	    add_symbols (entry->flags, entry->names);
114950397Sobrien	  entry++;
115052750Sobrien	  if (!entry->name || strcmp (entry->name, CONTINUED) != 0)
115150397Sobrien	    break;
115250397Sobrien	}
115350397Sobrien    }
115450397Sobrien  else
115550397Sobrien    symbol_table[0].names = NULL;
115618334Speter
1157117395Skan  /* Count and mark the prototypes required for this include file.  */
115850397Sobrien  for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
115918334Speter    {
116050397Sobrien      int name_len;
116150397Sobrien      if (cur_symbols->flags & MACRO_SYMBOL)
116250397Sobrien	continue;
116350397Sobrien      cptr = cur_symbols->names;
116450397Sobrien      for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
116550397Sobrien	{
116650397Sobrien	  struct fn_decl *fn = lookup_std_proto (cptr, name_len);
116750397Sobrien	  required_unseen_count++;
116850397Sobrien	  if (fn == NULL)
116950397Sobrien	    fprintf (stderr, "Internal error:  No prototype for %s\n", cptr);
117050397Sobrien	  else
117150397Sobrien	    SET_REQUIRED (fn);
117250397Sobrien	}
117318334Speter    }
117418334Speter
117518334Speter  read_scan_file (argv[2], argc - 4, argv + 4);
117618334Speter
117718334Speter  inf_fd = open (argv[2], O_RDONLY, 0666);
117818334Speter  if (inf_fd < 0)
117918334Speter    {
118018334Speter      fprintf (stderr, "%s: Cannot open '%s' for reading -",
118118334Speter	       progname, argv[2]);
118218334Speter      perror (NULL);
118350397Sobrien      exit (FATAL_EXIT_CODE);
118418334Speter    }
118518334Speter  if (fstat (inf_fd, &sbuf) < 0)
118618334Speter    {
118718334Speter      fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
118818334Speter      perror (NULL);
118950397Sobrien      exit (FATAL_EXIT_CODE);
119018334Speter    }
119118334Speter  inf_size = sbuf.st_size;
1192169689Skan  inf_buffer = XNEWVEC (char, inf_size + 2);
119318334Speter  inf_ptr = inf_buffer;
119418334Speter
119518334Speter  to_read = inf_size;
119618334Speter  while (to_read > 0)
119718334Speter    {
119818334Speter      long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
119918334Speter      if (i < 0)
120018334Speter	{
120118334Speter	  fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
120218334Speter	  perror (NULL);
120350397Sobrien	  exit (FATAL_EXIT_CODE);
120418334Speter	}
120518334Speter      if (i == 0)
120618334Speter	{
120718334Speter	  inf_size -= to_read;
120818334Speter	  break;
120918334Speter	}
121018334Speter      to_read -= i;
121118334Speter    }
121218334Speter
121318334Speter  close (inf_fd);
121418334Speter
121590075Sobrien  /* Inf_size may have changed if read was short (as on VMS) */
121690075Sobrien  inf_buffer[inf_size] = '\n';
121790075Sobrien  inf_buffer[inf_size + 1] = '\0';
121890075Sobrien  inf_limit = inf_buffer + inf_size;
121990075Sobrien
122050397Sobrien  /* If file doesn't end with '\n', add one.  */
122118334Speter  if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
122218334Speter    inf_limit++;
122318334Speter
122418334Speter  unlink (argv[3]);
122518334Speter  outf = fopen (argv[3], "w");
122618334Speter  if (outf == NULL)
122718334Speter    {
122818334Speter      fprintf (stderr, "%s: Cannot open '%s' for writing -",
122918334Speter	       progname, argv[3]);
123018334Speter      perror (NULL);
123150397Sobrien      exit (FATAL_EXIT_CODE);
123218334Speter    }
123318334Speter
123418334Speter  lineno = 1;
123518334Speter
123618334Speter  if (check_protection (&ifndef_line, &endif_line))
123718334Speter    {
123818334Speter      lbrac_line = ifndef_line+1;
123918334Speter      rbrac_line = endif_line;
124018334Speter    }
124118334Speter  else
124218334Speter    {
124318334Speter      lbrac_line = 1;
124418334Speter      rbrac_line = -1;
124518334Speter    }
124618334Speter
124750397Sobrien  /* Reset input file.  */
124818334Speter  inf_ptr = inf_buffer;
124918334Speter  lineno = 1;
125018334Speter
125118334Speter  for (;;)
125218334Speter    {
125318334Speter      if (lineno == lbrac_line)
125418334Speter	write_lbrac ();
125518334Speter      if (lineno == rbrac_line)
125618334Speter	write_rbrac ();
125718334Speter      for (;;)
125818334Speter	{
125918334Speter	  struct fn_decl *fn;
126018334Speter	  c = INF_GET ();
126118334Speter	  if (c == EOF)
126218334Speter	    break;
126390075Sobrien	  if (ISIDST (c))
126418334Speter	    {
126518334Speter	      c = inf_scan_ident (&buf, c);
126650397Sobrien	      (void) INF_UNGET (c);
126718334Speter	      fputs (buf.base, outf);
126818334Speter	      fn = lookup_std_proto (buf.base, strlen (buf.base));
126918334Speter	      /* We only want to edit the declaration matching the one
127018334Speter		 seen by scan-decls, as there can be multiple
127150397Sobrien		 declarations, selected by #ifdef __STDC__ or whatever.  */
127218334Speter	      if (fn && fn->partial && fn->partial->line_seen == lineno)
127318334Speter		{
127418334Speter		  c = inf_skip_spaces (' ');
127518334Speter		  if (c == EOF)
127618334Speter		    break;
127718334Speter		  if (c == '(')
127818334Speter		    {
127918334Speter		      c = inf_skip_spaces (' ');
128018334Speter		      if (c == ')')
128118334Speter			{
128218334Speter			  fprintf (outf, " _PARAMS((%s))", fn->params);
128318334Speter			}
128418334Speter		      else
128518334Speter			{
128618334Speter			  putc ('(', outf);
128750397Sobrien			  (void) INF_UNGET (c);
128818334Speter			}
128918334Speter		    }
129018334Speter		  else
129118334Speter		    fprintf (outf, " %c", c);
129218334Speter		}
129318334Speter	    }
129418334Speter	  else
129518334Speter	    {
129618334Speter	      putc (c, outf);
129718334Speter	      if (c == '\n')
129818334Speter		break;
129918334Speter	    }
130018334Speter	}
130118334Speter      if (c == EOF)
130218334Speter	break;
130318334Speter      lineno++;
130418334Speter    }
130518334Speter  if (rbrac_line < 0)
130618334Speter    write_rbrac ();
130718334Speter
130818334Speter  fclose (outf);
130918334Speter
131018334Speter  return 0;
131118334Speter}
1312