OSDN Git Service

Fix to previous check-in.
[pf3gnuchains/gcc-fork.git] / gcc / fix-header.c
1 /* fix-header.c - Make C header file suitable for C++.
2    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
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
16 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
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++:
20
21    * extern "C" { ... } braces are added (inside #ifndef __cplusplus),
22    if they seem to be needed.  These prevent C++ compilers from name
23    mangling the functions inside the braces.
24
25    * If an old-style incomplete function declaration is seen (without
26    an argument list), and it is a "standard" function listed in
27    the file sys-protos.h (and with a non-empty argument list), then
28    the declaration is converted to a complete prototype by replacing
29    the empty parameter list with the argument lust from sys-protos.h.
30
31    * The program can be given a list of (names of) required standard
32    functions (such as fclose for stdio.h).  If a reqquired function
33    is not seen in the input, then a prototype for it will be
34    written to the output.
35
36    * If all of the non-comment code of the original file is protected
37    against multiple inclusion:
38         #ifndef FOO
39         #define FOO
40         <body of include file>
41         #endif
42    then extra matter added to the include file is placed inside the <body>.
43
44    * If the input file is OK (nothing needs to be done);
45    the output file is not written (nor removed if it exists).
46
47    There are also some special actions that are done for certain
48    well-known standard include files:
49
50    * If argv[1] is "sys/stat.h", the Posix.1 macros
51    S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if
52    they were missing, and the corresponding "traditional" S_IFxxx
53    macros were defined.
54
55    * If argv[1] is "errno.h", errno is declared if it was missing.
56
57    * TODO:  The input file should be read complete into memory, because:
58    a) it needs to be scanned twice anyway, and
59    b) it would be nice to allow update in place.
60
61    Usage:
62         fix-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE
63    where:
64    * FOO.H is the relative file name of the include file,
65    as it would be #include'd by a C file.  (E.g. stdio.h)
66    * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h)
67    * OUTFILE.H is the full pathname for where to write the output file,
68    if anything needs to be done.  (e.g. ./include/stdio.h)
69    * 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).
71
72    Written by Per Bothner <bothner@cygnus.com>, July 1993. */
73
74 #include <stdio.h>
75 #include <ctype.h>
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #ifndef O_RDONLY
79 #define O_RDONLY 0
80 #endif
81 #include "hconfig.h"
82 #include "obstack.h"
83 #include "scan.h"
84
85 extern sstring buf;
86
87 int verbose = 0;
88 int partial_count = 0;
89 #if 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;
95 #endif
96 int missing_errno = 0;
97
98 #include "xsys-protos.h"
99
100 char *inf_buffer;
101 char *inf_limit;
102 char *inf_ptr;
103
104 /* Certain standard files get extra treatment */
105
106 enum special_file
107 {
108   no_special,
109   errno_special,
110   sys_stat_special
111 };
112
113 enum special_file special_file_handling = no_special;
114
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;
123 \f
124 /* Wrapper around free, to avoid prototype clashes. */
125
126 void
127 xfree (ptr)
128      char *ptr;
129 {
130   free (ptr);
131 }
132
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.  */
136
137 void
138 fancy_abort ()
139 {
140   abort ();
141 }
142 \f
143 #define obstack_chunk_alloc xmalloc
144 #define obstack_chunk_free xfree
145 struct obstack scan_file_obstack;
146
147 /* NOTE:  If you edit this, also edit gen-protos.c !! */
148 struct fn_decl *
149 lookup_std_proto (name)
150      char *name;
151 {
152   int i = hash (name) % HASH_SIZE;
153   int i0 = i;
154   for (;;)
155     {
156       struct fn_decl *fn;
157       if (hash_tab[i] == 0)
158         return NULL;
159       fn = &std_protos[hash_tab[i]];
160       if (strcmp (fn->fname, name) == 0)
161         return fn;
162       i = (i+1) % HASH_SIZE;
163       if (i == i0)
164         abort ();
165     }
166 }
167
168 char *inc_filename;
169 int inc_filename_length;
170 char *progname = "fix-header";
171 FILE *outf;
172 sstring line;
173
174 int lbrac_line, rbrac_line;
175
176 char **required_functions;
177 int required_unseen_count;
178
179 void 
180 write_lbrac ()
181 {
182   
183 #if 0
184   if (missing_extern_C_count + required_unseen_count > 0)
185     fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
186 #endif
187
188   if (partial_count)
189     {
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");
196     }
197 }
198
199 struct partial_proto
200 {
201   struct partial_proto *next;
202   char *fname;  /* name of function */
203   char *rtype;  /* return type */
204   struct fn_decl *fn;
205   int line_seen;
206 };
207
208 struct partial_proto *partial_proto_list = NULL;
209
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)
214
215 void
216 recognized_macro (fname)
217      char *fname;
218 {
219   /* The original include file defines fname as a macro. */
220   struct fn_decl *fn = lookup_std_proto (fname);
221
222   /* Since fname is a macro, don't require a prototype for it. */
223   if (fn && REQUIRED (fn))
224     {
225       CLEAR_REQUIRED (fn);
226       required_unseen_count--;
227     }
228
229   switch (special_file_handling)
230     {
231     case errno_special:
232       if (strcmp (fname, "errno") == 0) missing_errno = 0;
233       break;
234     case sys_stat_special:
235       if (fname[0] == 'S' && fname[1] == '_')
236         {
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++;
249         }
250     }
251 }
252
253 void
254 recognized_extern (name, type)
255      char *name;
256      char *type;
257 {
258   switch (special_file_handling)
259     {
260     case errno_special:
261       if (strcmp (name, "errno") == 0) missing_errno = 0;
262       break;
263     }
264 }
265
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. */
273
274 void
275 recognized_function (fname, kind, rtype, args, file_seen, line_seen)
276      char *fname;
277      int kind; /* One of 'f' 'F' or 'I' */
278      char *rtype;
279      char *args;
280      char *file_seen;
281      int line_seen;
282 {
283   struct partial_proto *partial;
284   int i;
285   struct fn_decl *fn;
286 #if 0
287   if (kind == 'f')
288     missing_extern_C_count++;
289 #endif
290
291   fn = lookup_std_proto (fname);
292
293   /* Remove the function from the list of required function. */
294   if (fn && REQUIRED (fn))
295     {
296       CLEAR_REQUIRED (fn);
297       required_unseen_count--;
298     }
299
300   /* If we have a full prototype, we're done. */
301   if (args[0] != '\0')
302     return;
303       
304   if (kind == 'I')  /* don't edit inline function */
305     return;
306
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)
312     return;
313
314   if (fn == NULL)
315     return;
316   if (fn->params[0] == '\0' || strcmp (fn->params, "void") == 0)
317     return;
318
319   /* We only have a partial function declaration,
320      so remember that we have to add a complete prototype. */
321   partial_count++;
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;
329   partial->fn = fn;
330   fn->partial = partial;
331   partial->next = partial_proto_list;
332   partial_proto_list = partial;
333   if (verbose)
334     {
335       fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
336                inc_filename, fname);
337     }
338 }
339
340 void
341 read_scan_file (scan_file)
342      FILE *scan_file;
343 {
344   obstack_init (&scan_file_obstack); 
345
346   scan_decls (scan_file);
347
348   if (required_unseen_count + partial_count + missing_errno
349 #if 0
350       + missing_extern_C_count
351 #endif      
352       == 0)
353     {
354       if (verbose)
355         fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
356       exit (0);
357     }
358   if (!verbose)
359     fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
360   else
361     {
362       if (required_unseen_count)
363         fprintf (stderr, "%s: %d missing function declarations.\n",
364                  inc_filename, required_unseen_count);
365       if (partial_count)
366         fprintf (stderr, "%s: %d non-prototype function declarations.\n",
367                  inc_filename, partial_count);
368 #if 0
369       if (missing_extern_C_count)
370         fprintf (stderr,
371                  "%s: %d declarations not protected by extern \"C\".\n",
372                  inc_filename, missing_extern_C_count);
373 #endif
374     }
375 }
376
377 void
378 write_rbrac ()
379 {
380   struct fn_decl *fn;
381   char **rptr;
382
383   if (required_unseen_count)
384     {
385       fprintf (outf,
386         "#if defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__)\n");
387 #ifdef NO_IMPLICIT_EXTERN_C
388       fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
389 #endif
390     }
391
392   /* Now we print out prototypes for those functions that we haven't seen. */
393   for (rptr = required_functions; *rptr; rptr++)
394     {
395       int macro_protect = 0;
396
397       fn = lookup_std_proto (*rptr);
398       if (fn == NULL || !REQUIRED (fn))
399         continue;
400
401       /* In the case of memmove, protect in case the application
402          defines it as a macro before including the header.  */
403       if (!strcmp (fn->fname, "memmove")
404           || !strcmp (fn->fname, "vprintf")
405           || !strcmp (fn->fname, "vfprintf")
406           || !strcmp (fn->fname, "vsprintf")
407           || !strcmp (fn->fname, "rewinddir"))
408         macro_protect = 1;
409
410       if (macro_protect)
411         fprintf (outf, "#ifndef %s\n", fn->fname);
412       fprintf (outf, "extern %s %s (%s);\n",
413                fn->rtype, fn->fname, fn->params);
414       if (macro_protect)
415         fprintf (outf, "#endif\n");
416     }
417   if (required_unseen_count)
418     {
419 #ifdef NO_IMPLICIT_EXTERN_C
420       fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
421 #endif
422       fprintf (outf,
423         "#endif /* defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__*/\n");
424     }
425
426   switch (special_file_handling)
427     {
428     case errno_special:
429       if (missing_errno)
430         fprintf (outf, "extern int errno;\n");
431       break;
432     case sys_stat_special:
433       if (!seen_S_ISBLK && seen_S_IFBLK)
434         fprintf (outf,
435                  "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
436       if (!seen_S_ISCHR && seen_S_IFCHR)
437         fprintf (outf,
438                  "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
439       if (!seen_S_ISDIR && seen_S_IFDIR)
440         fprintf (outf,
441                  "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
442       if (!seen_S_ISFIFO && seen_S_IFIFO)
443         fprintf (outf,
444                  "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
445       if (!seen_S_ISLNK && seen_S_IFLNK)
446         fprintf (outf,
447                  "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
448       if (!seen_S_ISREG && seen_S_IFREG)
449         fprintf (outf,
450                  "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
451       break;
452     }
453
454
455 #if 0
456   if (missing_extern_C_count + required_unseen_count > 0)
457     fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
458 #endif
459 }
460
461 char *
462 xstrdup (str)
463      char *str;
464 {
465   char *copy = (char *) xmalloc (strlen (str) + 1);
466   strcpy (copy, str);
467   return copy;
468 }
469
470 /* Returns 1 iff the file is properly protected from multiple inclusion:
471    #ifndef PROTECT_NAME
472    #define PROTECT_NAME
473    #endif
474
475  */
476
477 #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF)
478 #define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
479
480 int
481 inf_skip_spaces (c)
482      int c;
483 {
484   for (;;)
485     {
486       if (c == ' ' || c == '\t')
487         c = INF_GET ();
488       else if (c == '/')
489         {
490           c = INF_GET ();
491           if (c != '*')
492             {
493               INF_UNGET (c);
494               return '/';
495             }
496           c = INF_GET ();
497           for (;;)
498             {
499               if (c == EOF)
500                 return EOF;
501               else if (c != '*')
502                 {
503                   if (c == '\n')
504                     source_lineno++, lineno++;
505                   c = INF_GET ();
506                 }
507               else if ((c = INF_GET ()) == '/')
508                 return INF_GET ();
509             }
510         }
511       else
512         break;
513     }
514   return c;
515 }
516
517 /* Read into STR from inf_buffer upto DELIM. */
518
519 int
520 inf_read_upto (str, delim)
521      sstring *str;
522      int delim;
523 {
524   int ch;
525   for (;;)
526     {
527       ch = INF_GET ();
528       if (ch == EOF || ch == delim)
529         break;
530       SSTRING_PUT (str, ch);
531     }
532   MAKE_SSTRING_SPACE (str, 1);
533   *str->ptr = 0;
534   return ch;
535 }
536
537 int
538 inf_scan_ident (s, c)
539      register sstring *s;
540      int c;
541 {
542   s->ptr = s->base;
543   if (isalpha (c) || c == '_')
544     {
545       for (;;)
546         {
547           SSTRING_PUT (s, c);
548           c = INF_GET ();
549           if (c == EOF || !(isalnum (c) || c == '_'))
550             break;
551         }
552     }
553   MAKE_SSTRING_SPACE (s, 1);
554   *s->ptr = 0;
555   return c;
556 }
557
558 /* Returns 1 if the file is correctly protected against multiple
559    inclusion, setting *ifndef_line to the line number of the initial #ifndef
560    and setting *endif_line to the final #endif.
561    Otherwise return 0. */
562
563 int
564 check_protection (ifndef_line, endif_line)
565      int *ifndef_line, *endif_line;
566 {
567   int c;
568   int if_nesting = 1; /* Level of nesting of #if's */
569   char *protect_name = NULL; /* Identifier following initial #ifndef */
570   int define_seen = 0;
571
572   /* Skip initial white space (including comments). */
573   for (;; lineno++)
574     {
575       c = inf_skip_spaces (' ');
576       if (c == EOF)
577         return 0;
578       if (c != '\n')
579         break;
580     }
581   if (c != '#')
582     return 0;
583   c = inf_scan_ident (&buf, inf_skip_spaces (' '));
584   if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
585     return 0;
586
587   /* So far so good: We've seen an initial #ifndef. */
588   *ifndef_line = lineno;
589   c = inf_scan_ident (&buf, inf_skip_spaces (c));
590   if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
591     return 0;
592   protect_name = xstrdup (buf.base);
593
594   INF_UNGET (c);
595   c = inf_read_upto (&buf, '\n');
596   if (c == EOF)
597     return 0;
598   lineno++;
599
600   for (;;)
601     {
602       c = inf_skip_spaces (' ');
603       if (c == EOF)
604         return 0;
605       if (c == '\n')
606         {
607           lineno++;
608           continue;
609         }
610       if (c != '#')
611         goto skip_to_eol;
612       c = inf_scan_ident (&buf, inf_skip_spaces (' '));
613       if (SSTRING_LENGTH (&buf) == 0)
614         ;
615       else if (!strcmp (buf.base, "ifndef")
616           || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
617         {
618           if_nesting++;
619         }
620       else if (!strcmp (buf.base, "endif"))
621         {
622           if_nesting--;
623           if (if_nesting == 0)
624             break;
625         }
626       else if (!strcmp (buf.base, "else"))
627         {
628           if (if_nesting == 1)
629             return 0;
630         }
631       else if (!strcmp (buf.base, "define"))
632         {
633           if (if_nesting != 1)
634             goto skip_to_eol;
635           c = inf_skip_spaces (c);
636           c = inf_scan_ident (&buf, c);
637           if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
638             define_seen = 1;
639         }
640     skip_to_eol:
641       for (;;)
642         {
643           if (c == '\n' || c == EOF)
644             break;
645           c = INF_GET ();
646         }
647       if (c == EOF)
648         return 0;
649       lineno++;
650     }
651
652   if (!define_seen)
653      return 0;
654   *endif_line = lineno;
655   /* Skip final white space (including comments). */
656   for (;;)
657     {
658       c = inf_skip_spaces (' ');
659       if (c == EOF)
660         break;
661       if (c != '\n')
662         return 0;
663     }
664
665   return 1;
666 }
667
668 int
669 main (argc, argv)
670      int argc;
671      char **argv;
672 {
673   int inf_fd;
674   struct stat sbuf;
675   int c;
676   int i, done;
677   char *cptr, *cptr0, **pptr;
678   int ifndef_line;
679   int endif_line;
680   long to_read;
681   long int inf_size;
682
683   if (argv[0] && argv[0][0])
684     {
685       register char *p;
686
687       progname = 0;
688       for (p = argv[0]; *p; p++)
689         if (*p == '/')
690           progname = p;
691       progname = progname ? progname+1 : argv[0];
692     }
693
694   if (argc < 4)
695     {
696       fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n",
697                progname);
698       exit (-1);
699     }
700
701   inc_filename = argv[1];
702   inc_filename_length = strlen (inc_filename);
703   if (strcmp (inc_filename, "sys/stat.h") == 0)
704     special_file_handling = sys_stat_special;
705   else if (strcmp (inc_filename, "errno.h") == 0)
706     special_file_handling = errno_special, missing_errno = 1;
707
708   /* Calculate an upper bound of the number of function names in argv[4] */
709   for (i = 1, cptr = argv[4]; *cptr; cptr++)
710     if (*cptr == ' ') i++;
711   /* Find the list of prototypes required for this include file. */ 
712   required_functions = (char**)xmalloc ((i+1) * sizeof (char*));
713   for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; 
714        !done; cptr++)
715     {
716       done = *cptr == '\0';
717       if (*cptr == ' ' || done)
718         {
719           *cptr = '\0';
720           if (cptr > cptr0)
721             {
722               struct fn_decl *fn = lookup_std_proto (cptr0);
723               *pptr++ = cptr0;
724               if (fn == NULL)
725                 fprintf (stderr, "Internal error:  No prototype for %s\n",
726                          cptr0);
727               else
728                 SET_REQUIRED (fn);
729             }
730           cptr0 = cptr + 1;
731         }
732     }
733   required_unseen_count = pptr - required_functions;
734   *pptr = 0;
735
736   read_scan_file (stdin);
737
738   inf_fd = open (argv[2], O_RDONLY, 0666);
739   if (inf_fd < 0)
740     {
741       fprintf (stderr, "%s: Cannot open '%s' for reading -",
742                progname, argv[2]);
743       perror (NULL);
744       exit (-1);
745     }
746   if (fstat (inf_fd, &sbuf) < 0)
747     {
748       fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
749       perror (NULL);
750       exit (-1);
751     }
752   inf_size = sbuf.st_size;
753   inf_buffer = (char*) xmalloc (inf_size + 2);
754   inf_buffer[inf_size] = '\n';
755   inf_buffer[inf_size + 1] = '\0';
756   inf_limit = inf_buffer + inf_size;
757   inf_ptr = inf_buffer;
758
759   to_read = inf_size;
760   while (to_read > 0)
761     {
762       long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
763       if (i < 0)
764         {
765           fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
766           perror (NULL);
767           exit (-1);
768         }
769       if (i == 0)
770         {
771           inf_size -= to_read;
772           break;
773         }
774       to_read -= i;
775     }
776
777   close (inf_fd);
778
779   /* If file doesn't end with '\n', add one. */
780   if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
781     inf_limit++;
782
783   unlink (argv[3]);
784   outf = fopen (argv[3], "w");
785   if (outf == NULL)
786     {
787       fprintf (stderr, "%s: Cannot open '%s' for writing -",
788                progname, argv[3]);
789       perror (NULL);
790       exit (-1);
791     }
792
793   lineno = 1;
794
795   if (check_protection (&ifndef_line, &endif_line))
796     {
797 #if 0
798       fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n",
799                protect_name, ifndef_line, endif_line);
800 #endif
801       lbrac_line = ifndef_line+1;
802       rbrac_line = endif_line;
803     }
804   else
805     {
806       lbrac_line = 1;
807       rbrac_line = -1;
808     }
809
810   /* Reset input file. */
811   inf_ptr = inf_buffer;
812   lineno = 1;
813
814   for (;;)
815     {
816       if (lineno == lbrac_line)
817         write_lbrac ();
818       if (lineno == rbrac_line)
819         write_rbrac ();
820       for (;;)
821         {
822           struct fn_decl *fn;
823           c = INF_GET ();
824           if (c == EOF)
825             break;
826           if (isalpha (c) || c == '_')
827             {
828               c = inf_scan_ident (&buf, c);
829               INF_UNGET (c);
830               fputs (buf.base, outf);
831               fn = lookup_std_proto (buf.base);
832               /* We only want to edit the declaration matching the one
833                  seen by scan-decls, as there can be multiple
834                  declarations, selected by #ifdef __STDC__ or whatever. */
835               if (fn && fn->partial && fn->partial->line_seen == lineno)
836                 {
837                   c = inf_skip_spaces (' ');
838                   if (c == EOF)
839                     break;
840                   if (c == '(')
841                     {
842                       c = inf_skip_spaces (' ');
843                       if (c == ')')
844                         {
845                           fprintf (outf, " _PARAMS((%s))", fn->params);
846                         }
847                       else
848                         {
849                           putc ('(', outf);
850                           INF_UNGET (c);
851                         }
852                     }
853                   else
854                     fprintf (outf, " %c", c);
855                 }
856             }
857           else
858             {
859               putc (c, outf);
860               if (c == '\n')
861                 break;
862             }
863         }
864       if (c == EOF)
865         break;
866       lineno++;
867     }
868   if (rbrac_line < 0)
869     write_rbrac ();
870
871   fclose (outf);
872
873   return 0;
874 }