OSDN Git Service

(write_rbrac): Set up to use fixed headers if __USE_FIXED_HEADERS__ is
[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     fprintf (outf,
385              "#if defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__)\n");
386
387   /* Now we print out prototypes for those functions that we haven't seen. */
388   for (rptr = required_functions; *rptr; rptr++)
389     {
390       int macro_protect = 0;
391
392       fn = lookup_std_proto (*rptr);
393       if (fn == NULL || !REQUIRED (fn))
394         continue;
395
396       /* In the case of memmove, protect in case the application
397          defines it as a macro before including the header.  */
398       if (!strcmp (fn->fname, "memmove")
399           || !strcmp (fn->fname, "vprintf")
400           || !strcmp (fn->fname, "vfprintf")
401           || !strcmp (fn->fname, "vsprintf")
402           || !strcmp (fn->fname, "rewinddir"))
403         macro_protect = 1;
404
405       if (macro_protect)
406         fprintf (outf, "#ifndef %s\n", fn->fname);
407       fprintf (outf, "extern %s %s (%s);\n",
408                fn->rtype, fn->fname, fn->params);
409       if (macro_protect)
410         fprintf (outf, "#endif\n");
411     }
412   if (required_unseen_count)
413     fprintf (outf,
414              "#endif /* defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__*/\n");
415
416   switch (special_file_handling)
417     {
418     case errno_special:
419       if (missing_errno)
420         fprintf (outf, "extern int errno;\n");
421       break;
422     case sys_stat_special:
423       if (!seen_S_ISBLK && seen_S_IFBLK)
424         fprintf (outf,
425                  "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
426       if (!seen_S_ISCHR && seen_S_IFCHR)
427         fprintf (outf,
428                  "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
429       if (!seen_S_ISDIR && seen_S_IFDIR)
430         fprintf (outf,
431                  "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
432       if (!seen_S_ISFIFO && seen_S_IFIFO)
433         fprintf (outf,
434                  "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
435       if (!seen_S_ISLNK && seen_S_IFLNK)
436         fprintf (outf,
437                  "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
438       if (!seen_S_ISREG && seen_S_IFREG)
439         fprintf (outf,
440                  "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
441       break;
442     }
443
444
445 #if 0
446   if (missing_extern_C_count + required_unseen_count > 0)
447     fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
448 #endif
449 }
450
451 char *
452 xstrdup (str)
453      char *str;
454 {
455   char *copy = (char *) xmalloc (strlen (str) + 1);
456   strcpy (copy, str);
457   return copy;
458 }
459
460 /* Returns 1 iff the file is properly protected from multiple inclusion:
461    #ifndef PROTECT_NAME
462    #define PROTECT_NAME
463    #endif
464
465  */
466
467 #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF)
468 #define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
469
470 int
471 inf_skip_spaces (c)
472      int c;
473 {
474   for (;;)
475     {
476       if (c == ' ' || c == '\t')
477         c = INF_GET ();
478       else if (c == '/')
479         {
480           c = INF_GET ();
481           if (c != '*')
482             {
483               INF_UNGET (c);
484               return '/';
485             }
486           c = INF_GET ();
487           for (;;)
488             {
489               if (c == EOF)
490                 return EOF;
491               else if (c != '*')
492                 {
493                   if (c == '\n')
494                     source_lineno++, lineno++;
495                   c = INF_GET ();
496                 }
497               else if ((c = INF_GET ()) == '/')
498                 return INF_GET ();
499             }
500         }
501       else
502         break;
503     }
504   return c;
505 }
506
507 /* Read into STR from inf_buffer upto DELIM. */
508
509 int
510 inf_read_upto (str, delim)
511      sstring *str;
512      int delim;
513 {
514   int ch;
515   for (;;)
516     {
517       ch = INF_GET ();
518       if (ch == EOF || ch == delim)
519         break;
520       SSTRING_PUT (str, ch);
521     }
522   MAKE_SSTRING_SPACE (str, 1);
523   *str->ptr = 0;
524   return ch;
525 }
526
527 int
528 inf_scan_ident (s, c)
529      register sstring *s;
530      int c;
531 {
532   s->ptr = s->base;
533   if (isalpha (c) || c == '_')
534     {
535       for (;;)
536         {
537           SSTRING_PUT (s, c);
538           c = INF_GET ();
539           if (c == EOF || !(isalnum (c) || c == '_'))
540             break;
541         }
542     }
543   MAKE_SSTRING_SPACE (s, 1);
544   *s->ptr = 0;
545   return c;
546 }
547
548 /* Returns 1 if the file is correctly protected against multiple
549    inclusion, setting *ifndef_line to the line number of the initial #ifndef
550    and setting *endif_line to the final #endif.
551    Otherwise return 0. */
552
553 int
554 check_protection (ifndef_line, endif_line)
555      int *ifndef_line, *endif_line;
556 {
557   int c;
558   int if_nesting = 1; /* Level of nesting of #if's */
559   char *protect_name = NULL; /* Identifier following initial #ifndef */
560   int define_seen = 0;
561
562   /* Skip initial white space (including comments). */
563   for (;; lineno++)
564     {
565       c = inf_skip_spaces (' ');
566       if (c == EOF)
567         return 0;
568       if (c != '\n')
569         break;
570     }
571   if (c != '#')
572     return 0;
573   c = inf_scan_ident (&buf, inf_skip_spaces (' '));
574   if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
575     return 0;
576
577   /* So far so good: We've seen an initial #ifndef. */
578   *ifndef_line = lineno;
579   c = inf_scan_ident (&buf, inf_skip_spaces (c));
580   if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
581     return 0;
582   protect_name = xstrdup (buf.base);
583
584   INF_UNGET (c);
585   c = inf_read_upto (&buf, '\n');
586   if (c == EOF)
587     return 0;
588   lineno++;
589
590   for (;;)
591     {
592       c = inf_skip_spaces (' ');
593       if (c == EOF)
594         return 0;
595       if (c == '\n')
596         {
597           lineno++;
598           continue;
599         }
600       if (c != '#')
601         goto skip_to_eol;
602       c = inf_scan_ident (&buf, inf_skip_spaces (' '));
603       if (SSTRING_LENGTH (&buf) == 0)
604         ;
605       else if (!strcmp (buf.base, "ifndef")
606           || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
607         {
608           if_nesting++;
609         }
610       else if (!strcmp (buf.base, "endif"))
611         {
612           if_nesting--;
613           if (if_nesting == 0)
614             break;
615         }
616       else if (!strcmp (buf.base, "else"))
617         {
618           if (if_nesting == 1)
619             return 0;
620         }
621       else if (!strcmp (buf.base, "define"))
622         {
623           if (if_nesting != 1)
624             goto skip_to_eol;
625           c = inf_skip_spaces (c);
626           c = inf_scan_ident (&buf, c);
627           if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
628             define_seen = 1;
629         }
630     skip_to_eol:
631       for (;;)
632         {
633           if (c == '\n' || c == EOF)
634             break;
635           c = INF_GET ();
636         }
637       if (c == EOF)
638         return 0;
639       lineno++;
640     }
641
642   if (!define_seen)
643      return 0;
644   *endif_line = lineno;
645   /* Skip final white space (including comments). */
646   for (;;)
647     {
648       c = inf_skip_spaces (' ');
649       if (c == EOF)
650         break;
651       if (c != '\n')
652         return 0;
653     }
654
655   return 1;
656 }
657
658 int
659 main (argc, argv)
660      int argc;
661      char **argv;
662 {
663   int inf_fd;
664   struct stat sbuf;
665   int c;
666   int i, done;
667   char *cptr, *cptr0, **pptr;
668   int ifndef_line;
669   int endif_line;
670   long to_read;
671   long int inf_size;
672
673   if (argv[0] && argv[0][0])
674     {
675       register char *p;
676
677       progname = 0;
678       for (p = argv[0]; *p; p++)
679         if (*p == '/')
680           progname = p;
681       progname = progname ? progname+1 : argv[0];
682     }
683
684   if (argc < 4)
685     {
686       fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n",
687                progname);
688       exit (-1);
689     }
690
691   inc_filename = argv[1];
692   inc_filename_length = strlen (inc_filename);
693   if (strcmp (inc_filename, "sys/stat.h") == 0)
694     special_file_handling = sys_stat_special;
695   else if (strcmp (inc_filename, "errno.h") == 0)
696     special_file_handling = errno_special, missing_errno = 1;
697
698   /* Calculate an upper bound of the number of function names in argv[4] */
699   for (i = 1, cptr = argv[4]; *cptr; cptr++)
700     if (*cptr == ' ') i++;
701   /* Find the list of prototypes required for this include file. */ 
702   required_functions = (char**)xmalloc ((i+1) * sizeof (char*));
703   for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; 
704        !done; cptr++)
705     {
706       done = *cptr == '\0';
707       if (*cptr == ' ' || done)
708         {
709           *cptr = '\0';
710           if (cptr > cptr0)
711             {
712               struct fn_decl *fn = lookup_std_proto (cptr0);
713               *pptr++ = cptr0;
714               if (fn == NULL)
715                 fprintf (stderr, "Internal error:  No prototype for %s\n",
716                          cptr0);
717               else
718                 SET_REQUIRED (fn);
719             }
720           cptr0 = cptr + 1;
721         }
722     }
723   required_unseen_count = pptr - required_functions;
724   *pptr = 0;
725
726   read_scan_file (stdin);
727
728   inf_fd = open (argv[2], O_RDONLY, 0666);
729   if (inf_fd < 0)
730     {
731       fprintf (stderr, "%s: Cannot open '%s' for reading -",
732                progname, argv[2]);
733       perror (NULL);
734       exit (-1);
735     }
736   if (fstat (inf_fd, &sbuf) < 0)
737     {
738       fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
739       perror (NULL);
740       exit (-1);
741     }
742   inf_size = sbuf.st_size;
743   inf_buffer = (char*) xmalloc (inf_size + 2);
744   inf_buffer[inf_size] = '\n';
745   inf_buffer[inf_size + 1] = '\0';
746   inf_limit = inf_buffer + inf_size;
747   inf_ptr = inf_buffer;
748
749   to_read = inf_size;
750   while (to_read > 0)
751     {
752       long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
753       if (i < 0)
754         {
755           fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
756           perror (NULL);
757           exit (-1);
758         }
759       if (i == 0)
760         {
761           inf_size -= to_read;
762           break;
763         }
764       to_read -= i;
765     }
766
767   close (inf_fd);
768
769   /* If file doesn't end with '\n', add one. */
770   if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
771     inf_limit++;
772
773   unlink (argv[3]);
774   outf = fopen (argv[3], "w");
775   if (outf == NULL)
776     {
777       fprintf (stderr, "%s: Cannot open '%s' for writing -",
778                progname, argv[3]);
779       perror (NULL);
780       exit (-1);
781     }
782
783   lineno = 1;
784
785   if (check_protection (&ifndef_line, &endif_line))
786     {
787 #if 0
788       fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n",
789                protect_name, ifndef_line, endif_line);
790 #endif
791       lbrac_line = ifndef_line+1;
792       rbrac_line = endif_line;
793     }
794   else
795     {
796       lbrac_line = 1;
797       rbrac_line = -1;
798     }
799
800   /* Reset input file. */
801   inf_ptr = inf_buffer;
802   lineno = 1;
803
804   for (;;)
805     {
806       if (lineno == lbrac_line)
807         write_lbrac ();
808       if (lineno == rbrac_line)
809         write_rbrac ();
810       for (;;)
811         {
812           struct fn_decl *fn;
813           c = INF_GET ();
814           if (c == EOF)
815             break;
816           if (isalpha (c) || c == '_')
817             {
818               c = inf_scan_ident (&buf, c);
819               INF_UNGET (c);
820               fputs (buf.base, outf);
821               fn = lookup_std_proto (buf.base);
822               /* We only want to edit the declaration matching the one
823                  seen by scan-decls, as there can be multiple
824                  declarations, selected by #ifdef __STDC__ or whatever. */
825               if (fn && fn->partial && fn->partial->line_seen == lineno)
826                 {
827                   c = inf_skip_spaces (' ');
828                   if (c == EOF)
829                     break;
830                   if (c == '(')
831                     {
832                       c = inf_skip_spaces (' ');
833                       if (c == ')')
834                         {
835                           fprintf (outf, " _PARAMS((%s))", fn->params);
836                         }
837                       else
838                         {
839                           putc ('(', outf);
840                           INF_UNGET (c);
841                         }
842                     }
843                   else
844                     fprintf (outf, " %c", c);
845                 }
846             }
847           else
848             {
849               putc (c, outf);
850               if (c == '\n')
851                 break;
852             }
853         }
854       if (c == EOF)
855         break;
856       lineno++;
857     }
858   if (rbrac_line < 0)
859     write_rbrac ();
860
861   fclose (outf);
862
863   return 0;
864 }