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