|
|
1.1 root 1: /* fix-header.c - Make C header file suitable for C++.
1.1.1.3 root 2: Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
1.1 root 3:
4: This program is free software; you can redistribute it and/or modify it
5: under the terms of the GNU General Public License as published by the
6: Free Software Foundation; either version 2, or (at your option) any
7: later version.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
1.1.1.3 root 16: Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1.1 root 17:
18: /* This program massages a system include file (such as stdio.h),
1.1.1.3 root 19: into a form more conforming with ANSI/POSIX, and more suitable for C++:
1.1 root 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
1.1.1.3 root 32: functions (such as fclose for stdio.h). If a required function
1.1 root 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:
1.1.1.3 root 62: fix-header FOO.H INFILE.H OUTFILE.H [OPTIONS]
1.1 root 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)
1.1.1.3 root 69: * OPTIONS are such as you would pass to cpp.
1.1 root 70:
71: Written by Per Bothner <[email protected]>, July 1993. */
72:
73: #include <stdio.h>
74: #include <ctype.h>
75: #include "hconfig.h"
76: #include "obstack.h"
77: #include "scan.h"
1.1.1.3 root 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
1.1 root 86:
1.1.1.3 root 87: sstring buf;
1.1.1.2 root 88:
1.1 root 89: int verbose = 0;
90: int partial_count = 0;
1.1.1.3 root 91: int 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
1.1 root 98: int missing_extern_C_count = 0;
1.1.1.2 root 99: #endif
1.1 root 100: int missing_errno = 0;
101:
102: #include "xsys-protos.h"
103:
1.1.1.3 root 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:
112: static char *files_to_ignore[] = {
113: "X11/",
114: FIXPROTO_IGNORE_LIST
115: 0
116: };
117: #endif
118:
1.1 root 119: char *inf_buffer;
120: char *inf_limit;
121: char *inf_ptr;
122:
123: /* Certain standard files get extra treatment */
124:
125: enum special_file
126: {
127: no_special,
1.1.1.3 root 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:
136: typedef const char* namelist;
137:
138: struct std_include_entry {
139: const char *name;
140: namelist required;
141: namelist extra;
142: int special;
143: };
144:
145: /* End of namelist NAMES. */
146:
147: namelist
148: namelist_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:
163: const char NONE[] = "";
164:
165: struct std_include_entry *include_entry;
166:
167: struct std_include_entry std_include_table [] = {
168: { "ctype.h",
169: "isalnum\0isalpha\0iscntrl\0isdigit\0isgraph\0islower\0\
170: isprint\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\
177: mvcur\0mvwprintw\0mvwscanw\0newwin\0overlay\0overwrite\0\
178: scroll\0subwin\0touchwin\0waddstr\0wclear\0wclrtobot\0wclrtoeol\0\
179: waddch\0wdelch\0wdeleteln\0werase\0wgetch\0wgetstr\0winsch\0winsertln\0\
180: wmove\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\
192: fabs\0floor\0fmod\0frexp\0ldexp\0log10\0log\0modf\0pow\0sin\0sinh\0sqrt\0\
193: tan\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\
208: fgets\0fopen\0fprintf\0fputc\0fputs\0fread\0freopen\0fscanf\0fseek\0\
209: fsetpos\0ftell\0fwrite\0getc\0getchar\0gets\0pclose\0perror\0popen\0\
210: printf\0putc\0putchar\0puts\0remove\0rename\0rewind\0scanf\0setbuf\0\
211: setvbuf\0sprintf\0sscanf\0vprintf\0vsprintf\0vfprintf\0tmpfile\0\
212: tmpnam\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\
220: exit\0free\0getenv\0labs\0malloc\0putenv\0qsort\0rand\0realloc\0\
221: srand\0strtod\0strtol\0strtoul\0system\0", NONE },
222:
223: { "string.h", "memchr\0memcmp\0memcpy\0memmove\0memset\0\
224: strcat\0strchr\0strcmp\0strcoll\0strcpy\0strcspn\0strerror\0\
225: strlen\0strncat\0strncmp\0strncpy\0strpbrk\0strrchr\0strspn\0strstr\0\
226: strtok\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\
231: S_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\
240: WTERMSIG\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\
249: dup\0dup2\0execl\0execle\0execlp\0execv\0execve\0execvp\0fork\0fpathconf\0\
250: getcwd\0getegid\0geteuid\0getgid\0getlogin\0getopt\0getpgrp\0getpid\0\
251: getppid\0getuid\0isatty\0link\0lseek\0pathconf\0pause\0pipe\0read\0rmdir\0\
252: setgid\0setpgid\0setsid\0setuid\0sleep\0sysconf\0tcgetpgrp\0tcsetpgrp\0\
253: ttyname\0unlink\0write\0", NONE },
254:
255: { 0, NONE, NONE }
1.1 root 256: };
257:
258: enum 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. */
262: int seen_S_IFBLK = 0, seen_S_ISBLK = 0;
263: int seen_S_IFCHR = 0, seen_S_ISCHR = 0;
264: int seen_S_IFDIR = 0, seen_S_ISDIR = 0;
265: int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
266: int seen_S_IFLNK = 0, seen_S_ISLNK = 0;
267: int seen_S_IFREG = 0, seen_S_ISREG = 0;
268:
269: /* Wrapper around free, to avoid prototype clashes. */
270:
271: void
272: xfree (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:
282: void
283: fancy_abort ()
284: {
285: abort ();
286: }
287:
288: #define obstack_chunk_alloc xmalloc
289: #define obstack_chunk_free xfree
290: struct obstack scan_file_obstack;
291:
292: /* NOTE: If you edit this, also edit gen-protos.c !! */
293: struct fn_decl *
1.1.1.3 root 294: lookup_std_proto (name, name_length)
295: const char *name;
296: int name_length;
1.1 root 297: {
1.1.1.3 root 298: int i = hashf (name, name_length, HASH_SIZE);
1.1 root 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]];
1.1.1.3 root 306: if (strlen (fn->fname) == name_length
307: && strncmp (fn->fname, name, name_length) == 0)
1.1 root 308: return fn;
309: i = (i+1) % HASH_SIZE;
310: if (i == i0)
311: abort ();
312: }
313: }
314:
315: char *inc_filename;
316: int inc_filename_length;
317: char *progname = "fix-header";
318: FILE *outf;
319: sstring line;
320:
321: int lbrac_line, rbrac_line;
322:
1.1.1.3 root 323: namelist required_functions_list;
324: int required_unseen_count = 0;
1.1 root 325:
1.1.1.2 root 326: void
1.1 root 327: write_lbrac ()
328: {
329:
1.1.1.3 root 330: #if ADD_MISSING_EXTERN_C
1.1 root 331: if (missing_extern_C_count + required_unseen_count > 0)
332: fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
1.1.1.2 root 333: #endif
1.1 root 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:
346: struct 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:
355: struct partial_proto *partial_proto_list = NULL;
356:
1.1.1.3 root 357: struct partial_proto required_dummy_proto, seen_dummy_proto;
1.1 root 358: #define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
359: #define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
1.1.1.3 root 360: #define SET_SEEN(FN) ((FN)->partial = &seen_dummy_proto)
361: #define SEEN(FN) ((FN)->partial == &seen_dummy_proto)
1.1 root 362:
363: void
364: recognized_macro (fname)
365: char *fname;
366: {
367: /* The original include file defines fname as a macro. */
1.1.1.3 root 368: struct fn_decl *fn = lookup_std_proto (fname, strlen (fname));
1.1 root 369:
370: /* Since fname is a macro, don't require a prototype for it. */
1.1.1.3 root 371: if (fn)
1.1 root 372: {
1.1.1.3 root 373: if (REQUIRED (fn))
374: required_unseen_count--;
375: SET_SEEN (fn);
1.1 root 376: }
377:
378: switch (special_file_handling)
379: {
1.1.1.3 root 380: case errno_h:
1.1 root 381: if (strcmp (fname, "errno") == 0) missing_errno = 0;
382: break;
1.1.1.3 root 383: case sys_stat_h:
1.1 root 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:
402: void
1.1.1.3 root 403: recognized_extern (name, name_length, type, type_length)
1.1 root 404: char *name;
405: char *type;
1.1.1.3 root 406: int name_length, type_length;
1.1 root 407: {
408: switch (special_file_handling)
409: {
1.1.1.3 root 410: case errno_h:
411: if (strncmp (name, "errno", name_length) == 0) missing_errno = 0;
1.1 root 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:
424: void
1.1.1.3 root 425: recognized_function (fname, fname_length,
426: kind, rtype, rtype_length,
427: have_arg_list, file_seen, line_seen)
1.1 root 428: char *fname;
1.1.1.3 root 429: int fname_length;
1.1 root 430: int kind; /* One of 'f' 'F' or 'I' */
431: char *rtype;
1.1.1.3 root 432: int rtype_length;
433: int have_arg_list;
1.1 root 434: char *file_seen;
435: int line_seen;
436: {
437: struct partial_proto *partial;
438: int i;
439: struct fn_decl *fn;
1.1.1.3 root 440: #if ADD_MISSING_EXTERN_C
1.1 root 441: if (kind == 'f')
442: missing_extern_C_count++;
1.1.1.2 root 443: #endif
1.1 root 444:
1.1.1.3 root 445: fn = lookup_std_proto (fname, fname_length);
1.1 root 446:
447: /* Remove the function from the list of required function. */
1.1.1.3 root 448: if (fn)
1.1 root 449: {
1.1.1.3 root 450: if (REQUIRED (fn))
451: required_unseen_count--;
452: SET_SEEN (fn);
1.1 root 453: }
454:
455: /* If we have a full prototype, we're done. */
1.1.1.3 root 456: if (have_arg_list)
1.1 root 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));
1.1.1.3 root 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);
1.1 root 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",
1.1.1.3 root 492: inc_filename, partial->fname);
1.1 root 493: }
494: }
495:
1.1.1.3 root 496: /* For any name in NAMES that is defined as a macro,
497: call recognized_macro on it. */
498:
1.1 root 499: void
1.1.1.3 root 500: check_macro_names (pfile, names)
501: struct parse_file *pfile;
502: namelist names;
1.1 root 503: {
1.1.1.3 root 504: while (*names)
505: {
506: if (cpp_lookup (pfile, names, -1, -1))
507: recognized_macro (names);
508: names += strlen (names) + 1;
509: }
510: }
511:
512: void
513: read_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:
1.1 root 523: obstack_init (&scan_file_obstack);
524:
1.1.1.3 root 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:
1.1.1.4 ! root 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. */
1.1.1.3 root 544: scan_decls (&scan_in, argc, argv);
1.1.1.4 ! root 545:
1.1.1.3 root 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: }
1.1 root 616:
1.1.1.2 root 617: if (required_unseen_count + partial_count + missing_errno
1.1.1.3 root 618: #if ADD_MISSING_EXTERN_C
1.1.1.2 root 619: + missing_extern_C_count
620: #endif
621: == 0)
1.1 root 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);
1.1.1.3 root 637: #if ADD_MISSING_EXTERN_C
1.1 root 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);
1.1.1.2 root 642: #endif
1.1 root 643: }
644: }
645:
1.1.1.2 root 646: void
1.1 root 647: write_rbrac ()
648: {
649: struct fn_decl *fn;
1.1.1.3 root 650: const char *cptr;
1.1 root 651:
652: if (required_unseen_count)
1.1.1.2 root 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: }
1.1 root 660:
661: /* Now we print out prototypes for those functions that we haven't seen. */
1.1.1.3 root 662: for (cptr = required_functions_list; *cptr!= '\0'; )
1.1 root 663: {
664: int macro_protect = 0;
1.1.1.3 root 665: int name_len = strlen (cptr);
1.1 root 666:
1.1.1.3 root 667: fn = lookup_std_proto (cptr, name_len);
668: cptr+= name_len + 1;
1.1 root 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)
1.1.1.2 root 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: }
1.1 root 696:
697: switch (special_file_handling)
698: {
1.1.1.3 root 699: case errno_h:
1.1 root 700: if (missing_errno)
701: fprintf (outf, "extern int errno;\n");
702: break;
1.1.1.3 root 703: case sys_stat_h:
1.1 root 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:
1.1.1.3 root 726: #if ADD_MISSING_EXTERN_C
1.1 root 727: if (missing_extern_C_count + required_unseen_count > 0)
728: fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
1.1.1.2 root 729: #endif
1.1 root 730: }
731:
732: char *
1.1.1.2 root 733: xstrdup (str)
1.1 root 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:
751: int
752: inf_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:
790: int
791: inf_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:
808: int
809: inf_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:
834: int
835: check_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;
1.1.1.2 root 863: protect_name = xstrdup (buf.base);
1.1 root 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:
939: int
940: main (argc, argv)
941: int argc;
942: char **argv;
943: {
944: int inf_fd;
945: struct stat sbuf;
946: int c;
947: int i, done;
1.1.1.3 root 948: const char *cptr, **pptr;
1.1 root 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: {
1.1.1.3 root 967: fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h options\n",
1.1 root 968: progname);
969: exit (-1);
970: }
971:
972: inc_filename = argv[1];
973: inc_filename_length = strlen (inc_filename);
974:
1.1.1.3 root 975: #ifdef FIXPROTO_IGNORE_LIST
976: for (i = 0; files_to_ignore[i] != NULL; i++)
1.1 root 977: {
1.1.1.3 root 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)
1.1 root 981: {
1.1.1.3 root 982: if (ignore_name[ignore_len-1] == '/'
983: || inc_filename[ignore_len] == '\0')
1.1 root 984: {
1.1.1.3 root 985: if (verbose)
986: fprintf (stderr, "%s: ignoring %s\n", progname, inc_filename);
987: exit (0);
1.1 root 988: }
989: }
1.1.1.3 root 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;
1.1 root 1018: }
1019:
1.1.1.3 root 1020: read_scan_file (argv[2], argc - 4, argv + 4);
1.1 root 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);
1.1.1.3 root 1111: fn = lookup_std_proto (buf.base, strlen (buf.base));
1.1 root 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: }
1.1.1.3 root 1155:
1156: /* Stub error functions. These replace cpperror.c,
1157: because we want to suppress error messages. */
1158:
1159: void
1160: cpp_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:
1173: void
1174: cpp_print_containing_files (pfile)
1175: cpp_reader *pfile;
1176: {
1177: }
1178:
1179: /* IS_ERROR is 1 for error, 0 for warning */
1180: void 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:
1196: void
1197: fatal (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:
1206: void
1207: cpp_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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.