OSDN Git Service

Initial revision
authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Jul 1993 00:11:20 +0000 (00:11 +0000)
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Jul 1993 00:11:20 +0000 (00:11 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@4986 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/fix-header.c [new file with mode: 0644]
gcc/gen-protos.c [new file with mode: 0644]
gcc/scan-decls.c [new file with mode: 0644]
gcc/scan.c [new file with mode: 0644]
gcc/scan.h [new file with mode: 0644]

diff --git a/gcc/fix-header.c b/gcc/fix-header.c
new file mode 100644 (file)
index 0000000..4d3dfef
--- /dev/null
@@ -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 (file)
index 0000000..ace6d12
--- /dev/null
@@ -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 (file)
index 0000000..4e2f194
--- /dev/null
@@ -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 (file)
index 0000000..a4980ea
--- /dev/null
@@ -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 (file)
index 0000000..7106eb0
--- /dev/null
@@ -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;