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