summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/fix-header.c674
-rw-r--r--gcc/gen-protos.c141
-rw-r--r--gcc/scan-decls.c170
-rw-r--r--gcc/scan.c274
-rw-r--r--gcc/scan.h75
5 files changed, 1334 insertions, 0 deletions
diff --git a/gcc/fix-header.c b/gcc/fix-header.c
new file mode 100644
index 00000000000..4d3dfefb549
--- /dev/null
+++ b/gcc/fix-header.c
@@ -0,0 +1,674 @@
+/* patch-header.c - Make C header file suitable for C++.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This program massages a system include file (such as stdio.h),
+ into a form more conformant with ANSI/POSIX, and more suitable for C++:
+
+ * extern "C" { ... } braces are added (inside #ifndef __cplusplus),
+ if they seem to be needed. These prevcnt C++ compilers from name
+ mangling the functions inside the braces.
+
+ * If an old-style incomplete function declaration is seen (without
+ an argument list), and it is a "standard" function listed in
+ the file sys-protos.h (and with a non-empty argument list), then
+ the declaration is converted to a complete prototype by replacing
+ the empty parameter list with the argument lust from sys-protos.h.
+
+ * The program can be given a list of (names of) required standard
+ functions (such as fclose for stdio.h). If a reqquired function
+ is not seen in the input, then a prototype for it will be
+ written to the output.
+
+ * If all of the non-comment code of the original file is protected
+ against multiple inclusion:
+ #ifndef FOO
+ #define FOO
+ <body of include file>
+ #endif
+ then extra matter added to the include file is placed inside the <body>.
+
+ * If the input file is OK (nothing needs to be done);
+ the output file is not written (nor removed if it exists).
+
+ There are also some special actions that are done for certain
+ well-known standard include files:
+
+ * If argv[1] is "sys/stat.h", the Posix.1 macros
+ S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if
+ they were missing, and the corresponding "traditional" S_IFxxx
+ macros were defined.
+
+ * If argv[1] is "errno.h", errno is declared if it was missing.
+
+ * TODO: The input file should be read complete into memory, because:
+ a) it needs to be scanned twice anyway, and
+ b) it would be nice to allow update in place.
+
+ Usage:
+ patch-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE
+ where:
+ * FOO.H is the relative file name of the include file,
+ as it would be #include'd by a C file. (E.g. stdio.h)
+ * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h)
+ * OUTFILE.H is the full pathname for where to write the output file,
+ if anything needs to be done. (e.g. ./include/stdio.h)
+ * SCAN-FILE is the output of the scan-decls program.
+ * REQUIRED_FUNCS is a list of required function (e.g. fclose for stdio.h).
+
+ Written by Per Bothner <bothner@cygnus.com>, July 1993. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "obstack.h"
+#include "scan.h"
+
+extern char *strcpy();
+sstring buf;
+int verbose = 0;
+int partial_count = 0;
+int missing_extern_C_count = 0;
+int missing_extra_stuff = 0;
+
+#include "xsys-protos.h"
+
+/* Certain standard files get extra treatment */
+
+enum special_file
+{
+ no_special,
+ errno_special,
+ sys_stat_special
+};
+
+enum special_file special_file_handling = no_special;
+
+/* The following are only used when handling sys/stat.h */
+/* They are set if the corresponding macro has been seen. */
+int seen_S_IFBLK = 0, seen_S_ISBLK = 0;
+int seen_S_IFCHR = 0, seen_S_ISCHR = 0;
+int seen_S_IFDIR = 0, seen_S_ISDIR = 0;
+int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
+int seen_S_IFLNK = 0, seen_S_ISLNK = 0;
+int seen_S_IFREG = 0, seen_S_ISREG = 0;
+
+/* The following are only used when handling errno.h */
+int seen_errno = 0;
+
+/* Wrapper around free, to avoid prototype clashes. */
+
+void xfree (ptr)
+ char *ptr;
+{
+ free(ptr);
+}
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free xfree
+struct obstack scan_file_obstack;
+
+/* NOTE: If you edit this, also edit gen-protos.c !! */
+struct fn_decl *
+lookup_std_proto (name)
+ char *name;
+{
+ int i = hash(name) % HASH_SIZE;
+ int i0 = i;
+ for (;;)
+ {
+ struct fn_decl *fn;
+ if (hash_tab[i] == 0)
+ return NULL;
+ fn = &std_protos[hash_tab[i]];
+ if (strcmp (fn->fname, name) == 0)
+ return fn;
+ i = (i+1) % HASH_SIZE;
+ if (i == i0)
+ abort();
+ }
+}
+
+char *inc_filename;
+int inc_filename_length;
+char *progname = "patch-header";
+FILE *outf;
+sstring buf;
+sstring line;
+
+int lbrac_line, rbrac_line;
+
+char **required_functions;
+int required_unseen_count;
+
+int
+write_lbrac ()
+{
+ fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
+
+ if (partial_count)
+ {
+ fprintf (outf, "#ifndef _PARAMS\n");
+ fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
+ fprintf (outf, "#define _PARAMS(ARGS) ARGS\n");
+ fprintf (outf, "#else\n");
+ fprintf (outf, "#define _PARAMS(ARGS) ()\n");
+ fprintf (outf, "#endif\n#endif /* _PARAMS */\n");
+ }
+}
+
+struct partial_proto
+{
+ struct partial_proto *next;
+ char *fname; /* name of function */
+ char *rtype; /* return type */
+ struct fn_decl *fn;
+ int line_seen;
+};
+
+struct partial_proto *partial_proto_list = NULL;
+
+struct partial_proto required_dummy_proto;
+#define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
+#define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
+#define CLEAR_REQUIRED(FN) ((FN)->partial = 0)
+
+void
+read_scan_file (scan_file)
+ FILE *scan_file;
+{
+ char **rptr;
+ int i;
+ obstack_init(&scan_file_obstack);
+
+ for (;;)
+ {
+ struct partial_proto *partial;
+ struct fn_decl *fn;
+ int ch;
+ char *ptr, *fname, *extern_C, *rtype, *args, *file_seen, *line_seen;
+ line.ptr = line.base;
+ ch = read_upto (scan_file, &line, '\n');
+ if (ch == EOF)
+ break;
+
+ fname = line.base;
+ for (ptr = fname; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+ extern_C = ptr + 1;
+ for (ptr = extern_C; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+
+ if (*extern_C == 'X')
+ {
+ switch (special_file_handling)
+ {
+ case errno_special:
+ if (strcmp (fname, "errno") == 0) seen_errno++;
+ break;
+ }
+ continue;
+ }
+
+ if (*extern_C == 'M')
+ {
+ /* The original include file defines fname as a macro. */
+ fn = lookup_std_proto (fname);
+
+ /* Since fname is a macro, don't require a prototype for it. */
+ if (fn && REQUIRED (fn))
+ {
+ CLEAR_REQUIRED(fn);
+ required_unseen_count--;
+ }
+
+ switch (special_file_handling)
+ {
+ case errno_special:
+ if (strcmp (fname, "errno") == 0) seen_errno++;
+ break;
+ case sys_stat_special:
+ if (fname[0] == 'S' && fname[1] == '_')
+ {
+ if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++;
+ else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++;
+ else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++;
+ else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++;
+ else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++;
+ else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++;
+ else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++;
+ else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++;
+ else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++;
+ else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++;
+ else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
+ else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
+ }
+ break;
+ }
+ continue;
+ }
+
+ rtype = ptr + 1;
+ for (ptr = rtype; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+ args = ptr + 1;
+ for (ptr = args; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+ file_seen = ptr + 1;
+ for (ptr = file_seen; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+ line_seen = ptr + 1;
+ for (ptr = line_seen; *ptr != ';'; ) ptr++;
+ *ptr = 0;
+
+ if (extern_C[0] == 'f')
+ missing_extern_C_count++;
+
+ fn = lookup_std_proto (fname);
+
+ /* Remove the function from the list of required function. */
+ if (fn && REQUIRED (fn))
+ {
+ CLEAR_REQUIRED(fn);
+ required_unseen_count--;
+ }
+
+ /* If we have a full prototype, we're done. */
+ if (args[0] != '\0')
+ continue;
+
+ /* If the partial prototype was included from some other file,
+ we don't need to patch it up (in this run). */
+ i = strlen (file_seen);
+ if (i < inc_filename_length
+ || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0)
+ continue;
+
+ if (fn == NULL)
+ continue;
+ if (fn->fname[0] == '\0' || strcmp(fn->fname, "void") == 0)
+ continue;
+
+ /* We only have a partial function declaration,
+ so remember that we have to add a complete prototype. */
+ partial_count++;
+ partial = (struct partial_proto*)
+ obstack_alloc (&scan_file_obstack, sizeof(struct partial_proto));
+ partial->fname
+ = obstack_copy0 (&scan_file_obstack, fname, strlen (fname));
+ partial->rtype
+ = obstack_copy0 (&scan_file_obstack, rtype, strlen (rtype));
+ partial->line_seen = atoi(line_seen);
+ partial->fn = fn;
+ fn->partial = partial;
+ partial->next = partial_proto_list;
+ partial_proto_list = partial;
+ if (verbose)
+ {
+ fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
+ inc_filename, fname);
+ }
+ }
+
+ if (missing_extern_C_count + required_unseen_count + partial_count
+ + missing_extra_stuff == 0)
+ {
+ if (verbose)
+ fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
+ exit (0);
+ }
+ if (required_unseen_count)
+ fprintf (stderr, "%s: %d missing function declarations.\n",
+ inc_filename, required_unseen_count);
+ if (partial_count)
+ fprintf (stderr, "%s: %d non-prototype function declarations.\n",
+ inc_filename, partial_count);
+ if (missing_extern_C_count)
+ fprintf (stderr, "%s: %d declarations not protected by extern \"C\".\n",
+ inc_filename, missing_extern_C_count);
+}
+
+write_rbrac ()
+{
+ struct fn_decl *fn;
+ char **rptr;
+ register struct partial_proto *partial;
+
+ if (required_unseen_count)
+ fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
+
+ /* Now we print out prototypes for those functions that we haven't seen. */
+ for (rptr = required_functions; *rptr; rptr++)
+ {
+ fn = lookup_std_proto (*rptr);
+ if (fn == NULL || !REQUIRED (fn))
+ continue;
+ fprintf (outf, "extern %s %s (%s);\n",
+ fn->rtype, fn->fname, fn->params);
+ }
+ if (required_unseen_count)
+ fprintf (outf,
+ "#endif /* defined(__STDC__) || defined(__cplusplus) */\n");
+
+ switch (special_file_handling)
+ {
+ case errno_special:
+ if (!seen_errno)
+ fprintf (outf, "extern int errno;\n");
+ break;
+ case sys_stat_special:
+ if (!seen_S_ISBLK && seen_S_IFBLK)
+ fprintf (outf,
+ "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
+ if (!seen_S_ISCHR && seen_S_IFCHR)
+ fprintf (outf,
+ "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
+ if (!seen_S_ISDIR && seen_S_IFDIR)
+ fprintf (outf,
+ "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
+ if (!seen_S_ISFIFO && seen_S_IFIFO)
+ fprintf (outf,
+ "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
+ if (!seen_S_ISLNK && seen_S_IFLNK)
+ fprintf (outf,
+ "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
+ if (!seen_S_ISREG && seen_S_IFREG)
+ fprintf (outf,
+ "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
+ break;
+ }
+
+
+ fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
+}
+
+char *
+strdup (str)
+ char *str;
+{
+ return strcpy((char*)malloc (strlen (str) + 1), str);
+}
+
+/* Returns 1 iff the file is properly protected from multiple inclusion:
+ #ifndef PROTECT_NAME
+ #define PROTECT_NAME
+ #endif
+
+ */
+
+int
+check_protection (inf, ifndef_line, endif_line)
+ FILE *inf;
+ int *ifndef_line, *endif_line;
+{
+ int c;
+ int if_nesting = 1; /* Level of nesting of #if's */
+ char *protect_name = NULL; /* Identifier following initial #ifndef */
+ int define_seen = 0;
+
+ /* Skip initial white space (including comments). */
+ for (;; lineno++)
+ {
+ c = skip_spaces (inf, ' ');
+ if (c == EOF)
+ return 0;
+ if (c != '\n')
+ break;
+ }
+ if (c != '#')
+ return 0;
+ c = scan_ident (inf, &buf, skip_spaces (inf, ' '));
+ if (SSTRING_LENGTH(&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
+ return 0;
+
+ /* So far so good: We've seen an initial #ifndef. */
+ *ifndef_line = lineno;
+ c = scan_ident (inf, &buf, skip_spaces (inf, c));
+ if (SSTRING_LENGTH(&buf) == 0 || c == EOF)
+ return 0;
+ protect_name = strdup (buf.base);
+
+ ungetc (c, inf);
+ c = read_upto (inf, &buf, '\n');
+ if (c == EOF)
+ return 0;
+ lineno++;
+
+ for (;;)
+ {
+ c = skip_spaces(inf, ' ');
+ if (c == EOF)
+ return 0;
+ if (c == '\n')
+ {
+ lineno++;
+ continue;
+ }
+ if (c != '#')
+ goto skip_to_eol;
+ c = scan_ident (inf, &buf, skip_spaces (inf, ' '));
+ if (SSTRING_LENGTH(&buf) == 0)
+ ;
+ else if (!strcmp (buf.base, "ifndef")
+ || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
+ {
+ if_nesting++;
+ }
+ else if (!strcmp (buf.base, "endif"))
+ {
+ if_nesting--;
+ if (if_nesting == 0)
+ break;
+ }
+ else if (!strcmp (buf.base, "else"))
+ {
+ if (if_nesting == 1)
+ return 0;
+ }
+ else if (!strcmp (buf.base, "define"))
+ {
+ if (if_nesting != 1)
+ goto skip_to_eol;
+ c = skip_spaces (inf, c);
+ c = scan_ident (inf, &buf, c);
+ if (buf.base[0] > 0 && strcmp(buf.base, protect_name) == 0)
+ define_seen = 1;
+ }
+ skip_to_eol:
+ for (;;)
+ {
+ if (c == '\n' || c == EOF)
+ break;
+ c = getc (inf);
+ }
+ if (c == EOF)
+ return 0;
+ lineno++;
+ }
+
+ if (!define_seen)
+ return 0;
+ *endif_line = lineno;
+ /* Skip final white space (including comments). */
+ for (;;)
+ {
+ c = skip_spaces (inf, ' ');
+ if (c == EOF)
+ break;
+ if (c != '\n')
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *inf;
+ int c;
+ int i, done;
+ char *cptr, *cptr0, **pptr;
+ int ifndef_line;
+ int endif_line;;
+
+
+ if (argv[0] && argv[0][0])
+ progname = argv[0];
+
+ if (argc < 4)
+ {
+ fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n",
+ progname);
+ exit (-1);
+ }
+
+ inc_filename = argv[1];
+ inc_filename_length = strlen (inc_filename);
+ if (strcmp (inc_filename, "sys/stat.h") == 0)
+ special_file_handling = sys_stat_special;
+ else if (strcmp (inc_filename, "errno.h") == 0)
+ special_file_handling = errno_special, missing_extra_stuff++;
+
+ /* Calculate an upper bound of the number of function names in argv[4] */
+ for (i = 1, cptr = argv[4]; *cptr; cptr++)
+ if (*cptr == ' ') i++;
+ /* Find the list of prototypes required for this include file. */
+ required_functions = (char**)xmalloc((i+1) * sizeof(char*));
+ for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0;
+ !done; cptr++)
+ {
+ done = *cptr == '\0';
+ if (*cptr == ' ' || done)
+ {
+ *cptr = '\0';
+ if (cptr > cptr0)
+ {
+ struct fn_decl *fn = lookup_std_proto(cptr0);
+ *pptr++ = cptr0;
+ if (fn == NULL)
+ fprintf (stderr, "Internal error: No prototype for %s\n",
+ cptr0);
+ else
+ SET_REQUIRED(fn);
+ }
+ cptr0 = cptr + 1;
+ }
+ }
+ required_unseen_count = pptr - required_functions;
+ *pptr = 0;
+
+ read_scan_file (stdin);
+
+ inf = fopen (argv[2], "r");
+ if (inf == NULL)
+ {
+ fprintf (stderr, "%s: Cannot open '%s' for reading -",
+ progname, argv[2]);
+ perror (NULL);
+ exit (-1);
+ }
+
+ outf = fopen (argv[3], "w");
+ if (outf == NULL)
+ {
+ fprintf (stderr, "%s: Cannot open '%s' for writing -",
+ progname, argv[3]);
+ perror (NULL);
+ exit (-1);
+ }
+
+ if (check_protection (inf, &ifndef_line, &endif_line))
+ {
+#if 0
+ fprintf(stderr, "#ifndef %s on line %d; #endif on line %d\n",
+ protect_name, ifndef_line, endif_line);
+#endif
+ lbrac_line = ifndef_line+1;
+ rbrac_line = endif_line;
+ }
+ else
+ {
+ lbrac_line = 1;
+ rbrac_line = -1;
+ }
+
+ fseek(inf, 0, 0);
+ lineno = 1;
+
+ for (;;)
+ {
+ if (lineno == lbrac_line)
+ write_lbrac ();
+ if (lineno == rbrac_line)
+ write_rbrac ();
+ for (;;)
+ {
+ struct fn_decl *fn;
+ c = getc (inf);
+ if (c == EOF)
+ break;
+ if (isalpha (c) || c == '_')
+ {
+ struct partial_proto *partial;
+ ungetc (c, inf);
+ if (get_token (inf, &buf) != IDENTIFIER_TOKEN)
+ abort ();
+ fputs (buf.base, outf);
+ fn = lookup_std_proto (buf.base);
+ /* We only want to edit the declaration matching the one
+ seen by scan-decls, as there can be multiple
+ declarations, selected by #ifdef __STDC__ or whatever. */
+ if (fn && fn->partial && fn->partial->line_seen == lineno)
+ {
+ c = skip_spaces (inf, ' ');
+ if (c == EOF)
+ break;
+ if (c == '(')
+ {
+ c = skip_spaces (inf, ' ');
+ if (c == ')')
+ {
+ fprintf (outf, " _PARAMS((%s))", fn->params);
+ }
+ else
+ {
+ putc ('(', outf);
+ ungetc (c, inf);
+ }
+ }
+ else
+ putc (c, outf);
+ }
+ }
+ else
+ putc (c, outf);
+ if (c == '\n')
+ break;
+ }
+ if (c == EOF)
+ break;
+ lineno++;
+ }
+ if (rbrac_line < 0)
+ write_rbrac ();
+
+ fclose (inf);
+ fclose (outf);
+
+ return 0;
+}
diff --git a/gcc/gen-protos.c b/gcc/gen-protos.c
new file mode 100644
index 00000000000..ace6d1267d8
--- /dev/null
+++ b/gcc/gen-protos.c
@@ -0,0 +1,141 @@
+/* gen-protos.c - massages a list of prototypes, for use by fixproto.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "scan.h"
+
+#define HASH_SIZE 2503 /* a prime */
+
+int hash_tab[HASH_SIZE];
+
+sstring linebuf;
+
+int
+main (argc, argv)
+ int argc;
+ char** argv;
+{
+ FILE *inf = stdin;
+ FILE *outf = stdout;
+ int next_index = 0;
+ int i, i0;
+
+ fprintf (outf, "struct fn_decl std_protos[] = {\n");
+
+ for (;;)
+ {
+ int c = skip_spaces (inf, ' ');
+ int param_nesting = 1;
+ char *param_start, *param_end, *decl_start,
+ *name_start, *name_end;
+ register char *ptr;
+ if (c == EOF)
+ break;
+ linebuf.ptr = linebuf.base;
+ ungetc (c, inf);
+ c = read_upto (inf, &linebuf, '\n');
+ if (linebuf.base[0] == '#') /* skip cpp command */
+ continue;
+ if (linebuf.base[0] == '\0') /* skip empty line */
+ continue;
+
+ ptr = linebuf.ptr - 1;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ if (*ptr-- != ';')
+ {
+ fprintf (stderr, "Funny input line: %s\n", linebuf.base);
+ continue;
+ }
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ if (*ptr != ')')
+ {
+ fprintf (stderr, "Funny input line: %s\n", linebuf.base);
+ continue;
+ }
+ param_end = ptr;
+ for (;;)
+ {
+ int c = *--ptr;
+ if (c == '(' && --param_nesting == 0)
+ break;
+ else if (c == ')')
+ param_nesting++;
+ }
+ param_start = ptr+1;
+
+ ptr--;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+
+ if (!isalnum (*ptr))
+ {
+ fprintf (stderr, "%s: Can't handle this complex prototype: %s\n",
+ argv[0], linebuf.base);
+ continue;
+ }
+ name_end = ptr+1;
+
+ while (isalnum (*ptr) || *ptr == '_') --ptr;
+ name_start = ptr+1;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ ptr[1] = 0;
+ *name_end = 0;
+ *param_end = 0;
+ *name_end = 0;
+
+ decl_start = linebuf.base;
+ if (strncmp (decl_start, "typedef ", 8) == 0)
+ continue;
+ if (strncmp (decl_start, "extern ", 7) == 0)
+ decl_start += 7;
+
+
+ /* NOTE: If you edit this,
+ also edit lookup_std_proto in patch-header.c !! */
+ i = hash(name_start) % HASH_SIZE;
+ i0 = i;
+ if (hash_tab[i] != 0)
+ {
+ for (;;)
+ {
+ i = (i+1) % HASH_SIZE;
+ if (i == i0)
+ abort();
+ if (hash_tab[i] == 0)
+ break;
+ }
+ }
+ hash_tab[i] = next_index;
+
+ fprintf (outf, " {\"%s\", \"%s\", \"%s\" }, /* ix: %d, i0: %d */\n",
+ name_start, decl_start, param_start, i, i0);
+
+ next_index++;
+
+ if (c == EOF)
+ break;
+ }
+ fprintf (outf, "{0, 0, 0}\n};\n");
+
+
+ fprintf (outf, "#define HASH_SIZE %d\n", HASH_SIZE);
+ fprintf (outf, "short hash_tab[HASH_SIZE] = {\n");
+ for (i = 0; i < HASH_SIZE; i++)
+ fprintf (outf, " %d,\n", hash_tab[i]);
+ fprintf (outf, "};\n");
+
+ return 0;
+}
diff --git a/gcc/scan-decls.c b/gcc/scan-decls.c
new file mode 100644
index 00000000000..4e2f1943005
--- /dev/null
+++ b/gcc/scan-decls.c
@@ -0,0 +1,170 @@
+/* scan-decls.c - Extracts declarations from cpp output.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This filter scans a C source file (actually, the output of cpp).
+ It looks for function declaration. For each declaration, it prints:
+
+ NAME;C;RTYPE;ARGS;FILENAME;LINENO;
+
+ NAME is the function's name.
+ C is "F" if the declaration is nested inside 'extern "C"' braces;
+ otherwise "f".
+ RTYPE is the function's return type.
+ ARGS is the function's argument list.
+ FILENAME and LINENO is where the declarations was seen
+ (taking #-directives into account).
+
+ Also:
+
+ NAME;M;
+ indicates that the macro NAME was seen (when invoked from fixproto).
+ NAME;X;TYPE;
+ indicates that 'extern TYPE NAME;' was seen.
+
+ Written by Per Bothner <bothner@cygnus.com>, July 1993.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "scan.h"
+
+sstring buf;
+sstring rtype;
+
+int brace_nesting = 0;
+
+/* The first extern_C_braces_length elements of extern_C_braces
+ indicate the (brace nesting levels of) left braces that were
+ prefixed by extern "C". */
+int extern_C_braces_length = 0;
+char extern_C_braces[20];
+#define in_extern_C_brace (extern_C_braces_length>0)
+
+/* True if the function declaration currently being scanned is
+ prefixed by extern "C". */
+int current_extern_C = 0;
+
+int
+main ()
+{
+ FILE *fp = stdin;
+ int c;
+ int saw_extern;
+
+ new_statement:
+ c = get_token (fp, &buf);
+ handle_statement:
+ current_extern_C = 0;
+ saw_extern = 0;
+ if (c == '}')
+ {
+ /* pop an 'extern "C"' nesting level, if appropriate */
+ if (extern_C_braces_length
+ && extern_C_braces[extern_C_braces_length - 1] == brace_nesting)
+ extern_C_braces_length--;
+ brace_nesting--;
+ goto new_statement;
+ }
+ if (c == '{')
+ {
+ brace_nesting++;
+ goto new_statement;
+ }
+ if (c == EOF)
+ return 0;
+ if (c == ';')
+ goto new_statement;
+ if (c != IDENTIFIER_TOKEN)
+ goto new_statement;
+ rtype.ptr = rtype.base;
+ if (SSTRING_LENGTH (&buf) > 16
+ && strncmp (buf.base, "__DEFINED_MACRO_", 16) == 0)
+ {
+ fprintf (stdout, "%s;M;\n", buf.base+16);
+ goto new_statement;
+ }
+ if (strcmp (buf.base, "extern") == 0)
+ {
+ saw_extern = 1;
+ c = get_token (fp, &buf);
+ if (c == STRING_TOKEN && strcmp (buf.base, "C") == 0)
+ {
+ current_extern_C = 1;
+ c = get_token (fp, &buf);
+ if (c == '{')
+ {
+ brace_nesting++;
+ extern_C_braces[extern_C_braces_length++] = brace_nesting;
+ goto new_statement;
+ }
+ c = get_token (fp, &buf);
+ }
+ }
+ for (;;)
+ {
+ int followingc = getc (fp); /* char following token in buf */
+ if (c == IDENTIFIER_TOKEN)
+ {
+ int nextc = skip_spaces (fp, followingc);
+ if (nextc == '(')
+ {
+ int nesting = 1;
+
+ MAKE_SSTRING_SPACE(&rtype, 1);
+ *rtype.ptr = 0;
+
+ fprintf (stdout, "%s;%s;%s;",
+ buf.base,
+ in_extern_C_brace || current_extern_C ? "F" : "f",
+ rtype.base);
+ c = skip_spaces (fp, ' ');
+ for (;;)
+ {
+ if (c == '(')
+ nesting++;
+ else if (c == ')')
+ if (--nesting == 0)
+ break;
+ if (c == EOF)
+ break;
+ if (c == '\n')
+ c = ' ';
+ putc (c, stdout);
+ c = getc (fp);
+ }
+ fprintf (stdout, ";%s;%d;\n",
+ source_filename.base, source_lineno);
+ goto new_statement;
+ }
+ else if (nextc == ';' && saw_extern)
+ {
+ fprintf (stdout, "%s;X;%s;\n", buf.base, rtype.base);
+ goto handle_statement;
+ }
+ else
+ ungetc (nextc, fp);
+ }
+ else if (followingc != EOF)
+ ungetc (followingc, fp);
+ if (c == ';' || c == '{' || c == '}' || c == EOF)
+ goto handle_statement;
+ sstring_append (&rtype, &buf);
+ if (followingc == ' ' || followingc == '\t' || followingc == '\n')
+ SSTRING_PUT(&rtype, ' ');
+ c = get_token (fp, &buf);
+ }
+}
diff --git a/gcc/scan.c b/gcc/scan.c
new file mode 100644
index 00000000000..a4980ea76f5
--- /dev/null
+++ b/gcc/scan.c
@@ -0,0 +1,274 @@
+/* scan.c - Utility functions for scan-decls and patch-header programs.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "scan.h"
+#include <ctype.h>
+
+int lineno = 1;
+int source_lineno = 1;
+sstring source_filename;
+
+void
+make_sstring_space (str, count)
+ sstring *str;
+ int count;
+{
+ int cur_pos = str->ptr - str->base;
+ int cur_size = str->limit - str->base;
+ int new_size = cur_pos + count + 100;
+
+ if (new_size <= cur_size)
+ return;
+
+ if (str->base == NULL)
+ str->base = xmalloc (new_size);
+ else
+ str->base = xrealloc (str->base, new_size);
+ str->ptr = str->base + cur_size;
+ str->limit = str->base + new_size;
+}
+
+void
+sstring_append (dst, src)
+ sstring *dst;
+ sstring *src;
+{
+ register char *d, *s;
+ register count = SSTRING_LENGTH(src);
+ MAKE_SSTRING_SPACE(dst, count + 1);
+ d = dst->ptr;
+ s = src->base;
+ while (--count >= 0) *d++ = *s++;
+ dst->ptr = d;
+ *d = 0;
+}
+
+memory_full ()
+{
+ abort();
+}
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *ptr = (char *) malloc (size);
+ if (ptr != 0) return (ptr);
+ memory_full ();
+ /*NOTREACHED*/
+ return 0;
+}
+
+
+char *
+xrealloc (old, size)
+ char *old;
+ unsigned size;
+{
+ register char *ptr = (char *) realloc (old, size);
+ if (ptr != 0) return (ptr);
+ memory_full ();
+ /*NOTREACHED*/
+ return 0;
+}
+
+int
+scan_ident (fp, s, c)
+ register FILE *fp;
+ register sstring *s;
+ int c;
+{
+ s->ptr = s->base;
+ if (isalpha(c) || c == '_')
+ {
+ for (;;)
+ {
+ SSTRING_PUT(s, c);
+ c = getc (fp);
+ if (c == EOF || !(isalnum(c) || c == '_'))
+ break;
+ }
+ }
+ MAKE_SSTRING_SPACE(s, 1);
+ *s->ptr = 0;
+ return c;
+}
+
+int scan_string (fp, s, init)
+ register FILE *fp;
+ register sstring *s;
+{
+ int c;
+ for (;;)
+ {
+ c = getc (fp);
+ if (c == EOF || c == '\n')
+ break;
+ if (c == init)
+ {
+ c = getc (fp);
+ break;
+ }
+ if (c == '\\')
+ {
+ c = getc (fp);
+ if (c == EOF)
+ break;
+ if (c == '\n')
+ continue;
+ }
+ SSTRING_PUT(s, c);
+ }
+ MAKE_SSTRING_SPACE(s, 1);
+ *s->ptr = 0;
+ return c;
+}
+
+/* Skip horizontal white spaces (spaces, tabs, and C-style comments). */
+
+int skip_spaces (fp, c)
+ register FILE *fp;
+ int c;
+{
+ for (;;)
+ {
+ if (c == ' ' || c == '\t')
+ c = getc (fp);
+ else if (c == '/')
+ {
+ c = getc (fp);
+ if (c != '*')
+ {
+ ungetc (c, fp);
+ return '/';
+ }
+ c = getc (fp);
+ for (;;)
+ {
+ if (c == EOF)
+ return EOF;
+ else if (c != '*')
+ {
+ if (c == '\n')
+ source_lineno++, lineno++;
+ c = getc (fp);
+ }
+ else if ((c = getc (fp)) == '/')
+ return getc (fp);
+ }
+ }
+ else
+ break;
+ }
+ return c;
+}
+
+int
+read_upto (fp, str, delim)
+ FILE *fp;
+ sstring *str;
+ int delim;
+{
+ int ch;
+ for (;;)
+ {
+ ch = getc (fp);
+ if (ch == EOF || ch == delim)
+ break;
+ SSTRING_PUT(str, ch);
+ }
+ MAKE_SSTRING_SPACE(str, 1);
+ *str->ptr = 0;
+ return ch;
+}
+
+int
+get_token (fp, s)
+ register FILE *fp;
+ register sstring *s;
+{
+ int c;
+ s->ptr = s->base;
+ retry:
+ c = ' ';
+ again:
+ c = skip_spaces (fp, c);
+ if (c == '\n')
+ {
+ source_lineno++;
+ lineno++;
+ goto retry;
+ }
+ if (c == '#')
+ {
+ c = get_token (fp, s);
+ if (c == INT_TOKEN)
+ {
+ source_lineno = atoi (s->base);
+ get_token (fp, &source_filename);
+ }
+ for (;;)
+ {
+ c = getc (fp);
+ if (c == EOF)
+ return EOF;
+ if (c == '\n')
+ goto retry;
+ }
+ }
+ if (c == EOF)
+ return EOF;
+ if (isdigit (c))
+ {
+ do
+ {
+ SSTRING_PUT(s, c);
+ c = getc (fp);
+ } while (c != EOF && isdigit(c));
+ ungetc (c, fp);
+ c = INT_TOKEN;
+ goto done;
+ }
+ if (isalpha (c) || c == '_')
+ {
+ c = scan_ident (fp, s, c);
+ ungetc (c, fp);
+ return IDENTIFIER_TOKEN;
+ }
+ if (c == '\'' || c == '"')
+ {
+ int quote = c;
+ c = scan_string (fp, s, c);
+ ungetc (c, fp);
+ return c == '\'' ? CHAR_TOKEN : STRING_TOKEN;
+ }
+ SSTRING_PUT(s, c);
+ done:
+ MAKE_SSTRING_SPACE(s, 1);
+ *s->ptr = 0;
+ return c;
+}
+
+unsigned long
+hash (str)
+ char *str;
+{
+ int h = 0;
+ /* Replace this with something faster/better! FIXME! */
+ while (*str) h = (h << 3) + *str++;
+ return h & 0x7FFFFFFF;
+}
diff --git a/gcc/scan.h b/gcc/scan.h
new file mode 100644
index 00000000000..7106eb0bf79
--- /dev/null
+++ b/gcc/scan.h
@@ -0,0 +1,75 @@
+/* scan.h - Utility declarations for scan-decls and patch-header programs.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+typedef struct sstring
+{
+ char *base;
+ char *ptr;
+ char *limit;
+} sstring;
+
+#define INIT_SSTRING(STR) ((STR)->base = 0, (STR)->ptr = 0, (STR)->limit = 0)
+#define FREE_SSTRING(STR) do { if ((STR)->base) free (STR)->base; } while(0)
+#define SSTRING_PUT(STR, C) do {\
+ if ((STR)->limit <= (STR)->ptr) make_sstring_space (STR, 1); \
+ *(STR)->ptr++ = (C); } while (0)
+#define SSTRING_LENGTH(STR) ((STR)->ptr - (STR)->base)
+#define MAKE_SSTRING_SPACE(STR, COUNT) \
+ if ((STR)->limit - (STR)->ptr < (COUNT)) make_sstring_space (STR, COUNT);
+
+#ifndef _PARAMS
+#if defined(__STDC__) || defined(__cplusplus)
+#define _PARAMS(args) args
+#else
+#define _PARAMS(args) ()
+#endif
+#endif
+
+struct partial_proto;
+struct fn_decl
+{
+ char *fname;
+ char *rtype;
+ char *params;
+ struct partial_proto *partial;
+};
+
+extern int lineno;
+extern void sstring_append _PARAMS((sstring*, sstring*));
+extern void make_sstring_space _PARAMS((sstring*, int));
+extern int skip_spaces _PARAMS((FILE*, int));
+extern int scan_ident _PARAMS((FILE *, sstring *, int));
+extern int scan_string _PARAMS((FILE*, sstring *, int));
+extern int read_upto _PARAMS((FILE*, sstring*, int));
+extern char *xmalloc _PARAMS((unsigned));
+extern char *xrealloc _PARAMS((char *, unsigned));
+extern unsigned long hash _PARAMS((char*));
+
+/* get_token is a simple C lexer. */
+#define IDENTIFIER_TOKEN 300
+#define CHAR_TOKEN 301
+#define STRING_TOKEN 302
+#define INT_TOKEN 303
+extern int get_token _PARAMS ((FILE*, sstring*));
+
+/* Current file and line numer, taking #-directives into account */
+extern int source_lineno;
+extern sstring source_filename;
+/* Current physical line number */
+extern int lineno;