1 /* fix-header.c - Make C header file suitable for C++.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
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
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.
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
16 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* This program massages a system include file (such as stdio.h),
19 into a form more conformant with ANSI/POSIX, and more suitable for C++:
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.
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.
31 * The program can be given a list of (names of) required standard
32 functions (such as fclose for stdio.h). If a reqquired function
33 is not seen in the input, then a prototype for it will be
34 written to the output.
36 * If all of the non-comment code of the original file is protected
37 against multiple inclusion:
40 <body of include file>
42 then extra matter added to the include file is placed inside the <body>.
44 * If the input file is OK (nothing needs to be done);
45 the output file is not written (nor removed if it exists).
47 There are also some special actions that are done for certain
48 well-known standard include files:
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
55 * If argv[1] is "errno.h", errno is declared if it was missing.
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.
62 fix-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE
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 * SCAN-FILE is the output of the scan-decls program.
70 * REQUIRED_FUNCS is a list of required function (e.g. fclose for stdio.h).
72 Written by Per Bothner <bothner@cygnus.com>, July 1993. */
76 #include <sys/types.h>
88 int partial_count = 0;
90 /* All uses of this are ifdefed out. This is no longer needed, because
91 cccp.c implicitly forces the standard include files to be treated as C.
92 Adding an explicit extern "C" is undesireable as it breaks the SunOS 4.x
93 sun4c/romvec.h file. */
94 int missing_extern_C_count = 0;
96 int missing_errno = 0;
98 #include "xsys-protos.h"
104 /* Certain standard files get extra treatment */
113 enum special_file special_file_handling = no_special;
115 /* The following are only used when handling sys/stat.h */
116 /* They are set if the corresponding macro has been seen. */
117 int seen_S_IFBLK = 0, seen_S_ISBLK = 0;
118 int seen_S_IFCHR = 0, seen_S_ISCHR = 0;
119 int seen_S_IFDIR = 0, seen_S_ISDIR = 0;
120 int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
121 int seen_S_IFLNK = 0, seen_S_ISLNK = 0;
122 int seen_S_IFREG = 0, seen_S_ISREG = 0;
124 /* Wrapper around free, to avoid prototype clashes. */
133 /* Avoid error if config defines abort as fancy_abort.
134 It's not worth "really" implementing this because ordinary
135 compiler users never run fix-header. */
143 #define obstack_chunk_alloc xmalloc
144 #define obstack_chunk_free xfree
145 struct obstack scan_file_obstack;
147 /* NOTE: If you edit this, also edit gen-protos.c !! */
149 lookup_std_proto (name)
152 int i = hash (name) % HASH_SIZE;
157 if (hash_tab[i] == 0)
159 fn = &std_protos[hash_tab[i]];
160 if (strcmp (fn->fname, name) == 0)
162 i = (i+1) % HASH_SIZE;
169 int inc_filename_length;
170 char *progname = "fix-header";
174 int lbrac_line, rbrac_line;
176 char **required_functions;
177 int required_unseen_count;
184 if (missing_extern_C_count + required_unseen_count > 0)
185 fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
190 fprintf (outf, "#ifndef _PARAMS\n");
191 fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
192 fprintf (outf, "#define _PARAMS(ARGS) ARGS\n");
193 fprintf (outf, "#else\n");
194 fprintf (outf, "#define _PARAMS(ARGS) ()\n");
195 fprintf (outf, "#endif\n#endif /* _PARAMS */\n");
201 struct partial_proto *next;
202 char *fname; /* name of function */
203 char *rtype; /* return type */
208 struct partial_proto *partial_proto_list = NULL;
210 struct partial_proto required_dummy_proto;
211 #define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
212 #define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
213 #define CLEAR_REQUIRED(FN) ((FN)->partial = 0)
216 recognized_macro (fname)
219 /* The original include file defines fname as a macro. */
220 struct fn_decl *fn = lookup_std_proto (fname);
222 /* Since fname is a macro, don't require a prototype for it. */
223 if (fn && REQUIRED (fn))
226 required_unseen_count--;
229 switch (special_file_handling)
232 if (strcmp (fname, "errno") == 0) missing_errno = 0;
234 case sys_stat_special:
235 if (fname[0] == 'S' && fname[1] == '_')
237 if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++;
238 else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++;
239 else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++;
240 else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++;
241 else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++;
242 else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++;
243 else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++;
244 else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++;
245 else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++;
246 else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++;
247 else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
248 else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
254 recognized_extern (name, type)
258 switch (special_file_handling)
261 if (strcmp (name, "errno") == 0) missing_errno = 0;
266 /* Called by scan_decls if it saw a function definition for a function
267 named FNAME, with return type RTYPE, and argument list ARGS,
268 in source file FILE_SEEN on line LINE_SEEN.
269 KIND is 'I' for an inline function;
270 'F' if a normal function declaration preceded by 'extern "C"'
271 (or nested inside 'extern "C"' braces); or
272 'f' for other function declarations. */
275 recognized_function (fname, kind, rtype, args, file_seen, line_seen)
277 int kind; /* One of 'f' 'F' or 'I' */
283 struct partial_proto *partial;
288 missing_extern_C_count++;
291 fn = lookup_std_proto (fname);
293 /* Remove the function from the list of required function. */
294 if (fn && REQUIRED (fn))
297 required_unseen_count--;
300 /* If we have a full prototype, we're done. */
304 if (kind == 'I') /* don't edit inline function */
307 /* If the partial prototype was included from some other file,
308 we don't need to patch it up (in this run). */
309 i = strlen (file_seen);
310 if (i < inc_filename_length
311 || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0)
316 if (fn->params[0] == '\0' || strcmp (fn->params, "void") == 0)
319 /* We only have a partial function declaration,
320 so remember that we have to add a complete prototype. */
322 partial = (struct partial_proto*)
323 obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
324 partial->fname = obstack_alloc (&scan_file_obstack, strlen (fname) + 1);
325 strcpy (partial->fname, fname);
326 partial->rtype = obstack_alloc (&scan_file_obstack, strlen (rtype) + 1);
327 strcpy (partial->rtype, rtype);
328 partial->line_seen = line_seen;
330 fn->partial = partial;
331 partial->next = partial_proto_list;
332 partial_proto_list = partial;
335 fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
336 inc_filename, fname);
341 read_scan_file (scan_file)
344 obstack_init (&scan_file_obstack);
346 scan_decls (scan_file);
348 if (required_unseen_count + partial_count + missing_errno
350 + missing_extern_C_count
355 fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
359 fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
362 if (required_unseen_count)
363 fprintf (stderr, "%s: %d missing function declarations.\n",
364 inc_filename, required_unseen_count);
366 fprintf (stderr, "%s: %d non-prototype function declarations.\n",
367 inc_filename, partial_count);
369 if (missing_extern_C_count)
371 "%s: %d declarations not protected by extern \"C\".\n",
372 inc_filename, missing_extern_C_count);
383 if (required_unseen_count)
385 "#if defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__)\n");
387 /* Now we print out prototypes for those functions that we haven't seen. */
388 for (rptr = required_functions; *rptr; rptr++)
390 int macro_protect = 0;
392 fn = lookup_std_proto (*rptr);
393 if (fn == NULL || !REQUIRED (fn))
396 /* In the case of memmove, protect in case the application
397 defines it as a macro before including the header. */
398 if (!strcmp (fn->fname, "memmove")
399 || !strcmp (fn->fname, "vprintf")
400 || !strcmp (fn->fname, "vfprintf")
401 || !strcmp (fn->fname, "vsprintf")
402 || !strcmp (fn->fname, "rewinddir"))
406 fprintf (outf, "#ifndef %s\n", fn->fname);
407 fprintf (outf, "extern %s %s (%s);\n",
408 fn->rtype, fn->fname, fn->params);
410 fprintf (outf, "#endif\n");
412 if (required_unseen_count)
414 "#endif /* defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__*/\n");
416 switch (special_file_handling)
420 fprintf (outf, "extern int errno;\n");
422 case sys_stat_special:
423 if (!seen_S_ISBLK && seen_S_IFBLK)
425 "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
426 if (!seen_S_ISCHR && seen_S_IFCHR)
428 "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
429 if (!seen_S_ISDIR && seen_S_IFDIR)
431 "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
432 if (!seen_S_ISFIFO && seen_S_IFIFO)
434 "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
435 if (!seen_S_ISLNK && seen_S_IFLNK)
437 "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
438 if (!seen_S_ISREG && seen_S_IFREG)
440 "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
446 if (missing_extern_C_count + required_unseen_count > 0)
447 fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
455 char *copy = (char *) xmalloc (strlen (str) + 1);
460 /* Returns 1 iff the file is properly protected from multiple inclusion:
467 #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF)
468 #define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
476 if (c == ' ' || c == '\t')
494 source_lineno++, lineno++;
497 else if ((c = INF_GET ()) == '/')
507 /* Read into STR from inf_buffer upto DELIM. */
510 inf_read_upto (str, delim)
518 if (ch == EOF || ch == delim)
520 SSTRING_PUT (str, ch);
522 MAKE_SSTRING_SPACE (str, 1);
528 inf_scan_ident (s, c)
533 if (isalpha (c) || c == '_')
539 if (c == EOF || !(isalnum (c) || c == '_'))
543 MAKE_SSTRING_SPACE (s, 1);
548 /* Returns 1 if the file is correctly protected against multiple
549 inclusion, setting *ifndef_line to the line number of the initial #ifndef
550 and setting *endif_line to the final #endif.
551 Otherwise return 0. */
554 check_protection (ifndef_line, endif_line)
555 int *ifndef_line, *endif_line;
558 int if_nesting = 1; /* Level of nesting of #if's */
559 char *protect_name = NULL; /* Identifier following initial #ifndef */
562 /* Skip initial white space (including comments). */
565 c = inf_skip_spaces (' ');
573 c = inf_scan_ident (&buf, inf_skip_spaces (' '));
574 if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
577 /* So far so good: We've seen an initial #ifndef. */
578 *ifndef_line = lineno;
579 c = inf_scan_ident (&buf, inf_skip_spaces (c));
580 if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
582 protect_name = xstrdup (buf.base);
585 c = inf_read_upto (&buf, '\n');
592 c = inf_skip_spaces (' ');
602 c = inf_scan_ident (&buf, inf_skip_spaces (' '));
603 if (SSTRING_LENGTH (&buf) == 0)
605 else if (!strcmp (buf.base, "ifndef")
606 || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
610 else if (!strcmp (buf.base, "endif"))
616 else if (!strcmp (buf.base, "else"))
621 else if (!strcmp (buf.base, "define"))
625 c = inf_skip_spaces (c);
626 c = inf_scan_ident (&buf, c);
627 if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
633 if (c == '\n' || c == EOF)
644 *endif_line = lineno;
645 /* Skip final white space (including comments). */
648 c = inf_skip_spaces (' ');
667 char *cptr, *cptr0, **pptr;
673 if (argv[0] && argv[0][0])
678 for (p = argv[0]; *p; p++)
681 progname = progname ? progname+1 : argv[0];
686 fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n",
691 inc_filename = argv[1];
692 inc_filename_length = strlen (inc_filename);
693 if (strcmp (inc_filename, "sys/stat.h") == 0)
694 special_file_handling = sys_stat_special;
695 else if (strcmp (inc_filename, "errno.h") == 0)
696 special_file_handling = errno_special, missing_errno = 1;
698 /* Calculate an upper bound of the number of function names in argv[4] */
699 for (i = 1, cptr = argv[4]; *cptr; cptr++)
700 if (*cptr == ' ') i++;
701 /* Find the list of prototypes required for this include file. */
702 required_functions = (char**)xmalloc ((i+1) * sizeof (char*));
703 for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0;
706 done = *cptr == '\0';
707 if (*cptr == ' ' || done)
712 struct fn_decl *fn = lookup_std_proto (cptr0);
715 fprintf (stderr, "Internal error: No prototype for %s\n",
723 required_unseen_count = pptr - required_functions;
726 read_scan_file (stdin);
728 inf_fd = open (argv[2], O_RDONLY, 0666);
731 fprintf (stderr, "%s: Cannot open '%s' for reading -",
736 if (fstat (inf_fd, &sbuf) < 0)
738 fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
742 inf_size = sbuf.st_size;
743 inf_buffer = (char*) xmalloc (inf_size + 2);
744 inf_buffer[inf_size] = '\n';
745 inf_buffer[inf_size + 1] = '\0';
746 inf_limit = inf_buffer + inf_size;
747 inf_ptr = inf_buffer;
752 long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
755 fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
769 /* If file doesn't end with '\n', add one. */
770 if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
774 outf = fopen (argv[3], "w");
777 fprintf (stderr, "%s: Cannot open '%s' for writing -",
785 if (check_protection (&ifndef_line, &endif_line))
788 fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n",
789 protect_name, ifndef_line, endif_line);
791 lbrac_line = ifndef_line+1;
792 rbrac_line = endif_line;
800 /* Reset input file. */
801 inf_ptr = inf_buffer;
806 if (lineno == lbrac_line)
808 if (lineno == rbrac_line)
816 if (isalpha (c) || c == '_')
818 c = inf_scan_ident (&buf, c);
820 fputs (buf.base, outf);
821 fn = lookup_std_proto (buf.base);
822 /* We only want to edit the declaration matching the one
823 seen by scan-decls, as there can be multiple
824 declarations, selected by #ifdef __STDC__ or whatever. */
825 if (fn && fn->partial && fn->partial->line_seen == lineno)
827 c = inf_skip_spaces (' ');
832 c = inf_skip_spaces (' ');
835 fprintf (outf, " _PARAMS((%s))", fn->params);
844 fprintf (outf, " %c", c);