OSDN Git Service

(add_symbol, unexpand_if_needed, abspath):
[pf3gnuchains/gcc-fork.git] / gcc / protoize.c
1 /* Protoize program - Original version by Ron Guilmette at MCC.
2
3    Copyright (C) 1989, 1992 Free Software Foundation, Inc.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* Any reasonable C++ compiler should have all of the same features
22    as __STDC__ plus more, so make sure that __STDC__ is defined if
23    __cplusplus is defined. */
24
25 #if defined(__cplusplus) && !defined(__STDC__)
26 #define __STDC__ 1
27 #endif /* defined(__cplusplus) && !defined(__STDC__) */
28
29 #if defined(__GNUC__) || defined (__GNUG__)
30 #define VOLATILE volatile
31 #else
32 #define VOLATILE
33 #endif
34
35 #ifndef __STDC__
36 #define const
37 #define volatile
38 #endif
39
40 #include "config.h"
41
42 #if 0
43 /* Users are not supposed to use _POSIX_SOURCE to say the
44    system is a POSIX system.  That is not what _POSIX_SOURCE means! -- rms  */ 
45 /* If the user asked for POSIX via _POSIX_SOURCE, turn on POSIX code.  */
46 #if defined(_POSIX_SOURCE) && !defined(POSIX)
47 #define POSIX
48 #endif
49 #endif /* 0 */
50
51 #ifdef POSIX /* We should be able to define _POSIX_SOURCE unconditionally,
52                 but some systems respond in buggy ways to it,
53                 including SunOS 4.1.1.  Which we don't classify as POSIX.  */
54 /* In case this is a POSIX system with an ANSI C compiler,
55    ask for definition of all POSIX facilities.  */
56 #undef _POSIX_SOURCE
57 #define _POSIX_SOURCE
58 #endif
59
60 #include "gvarargs.h"
61 /* On some systems stdio.h includes stdarg.h;
62    we must bring in gvarargs.h first.  */
63 #include <stdio.h>
64 #include <ctype.h>
65 #include <errno.h>
66 #include <sys/types.h>
67 #include <sys/stat.h>
68 #ifdef POSIX
69 #include <dirent.h>
70 #else
71 #include <sys/dir.h>
72 #endif
73 #include <setjmp.h>
74
75 /* Include getopt.h for the sake of getopt_long.
76    We don't need the declaration of getopt, and it could conflict
77    with something from a system header file, so effectively nullify that.  */
78 #define getopt getopt_loser
79 #include "getopt.h"
80 #undef getopt
81
82 extern int errno;
83 extern char *sys_errlist[];
84 extern char *version_string;
85
86 /* Systems which are compatible only with POSIX 1003.1-1988 (but *not*
87    with POSIX 1003.1-1990), e.g. Ultrix 4.2, might not have
88    const qualifiers in the prototypes in the system include files.
89    Unfortunately, this can lead to GCC issuing lots of warnings for
90    calls to the following functions.  To eliminate these warnings we
91    provide the following #defines.  */
92
93 #define my_access(file,flag)    access((char *)file, flag)
94 #define my_stat(file,pkt)       stat((char *)file, pkt)
95 #define my_execvp(prog,argv)    execvp((char *)prog, (char **)argv)
96 #define my_link(file1, file2)   link((char *)file1, (char *)file2)
97 #define my_unlink(file)         unlink((char *)file)
98 #define my_open(file, mode, flag)       open((char *)file, mode, flag)
99 #define my_chmod(file, mode)    chmod((char *)file, mode)
100
101 extern char *getpwd ();
102
103 /* Aliases for pointers to void.
104    These were made to facilitate compilation with old brain-dead DEC C
105    compilers which didn't properly grok `void*' types.  */
106
107 #ifdef __STDC__
108 typedef void * pointer_type;
109 typedef const void * const_pointer_type;
110 #else
111 typedef char * pointer_type;
112 typedef char * const_pointer_type;
113 #endif
114
115 #if defined(POSIX)
116
117 #include <stdlib.h>
118 #include <unistd.h>
119 #include <signal.h>
120 #include <fcntl.h>
121
122 #else /* !defined(POSIX) */
123
124 #define R_OK    4       /* Test for Read permission */
125 #define W_OK    2       /* Test for Write permission */
126 #define X_OK    1       /* Test for eXecute permission */
127 #define F_OK    0       /* Test for existence of File */
128
129 #define O_RDONLY        0
130 #define O_WRONLY        1
131
132 /* Declaring stat or __flsbuf with a prototype
133    causes conflicts with system headers on some systems.  */
134
135 #ifndef abort
136 extern VOLATILE void abort ();
137 #endif
138 extern int kill ();
139 extern int creat ();
140 #if 0 /* These conflict with stdio.h on some systems.  */
141 extern int fprintf (FILE *, const char *, ...);
142 extern int printf (const char *, ...);
143 extern int open (const char *, int, ...);
144 #endif /* 0 */
145 extern void exit ();
146 extern pointer_type malloc ();
147 extern pointer_type realloc ();
148 extern void free ();
149 extern int read ();
150 extern int write ();
151 extern int close ();
152 extern int fflush ();
153 extern int atoi ();
154 extern int puts ();
155 extern int fputs ();
156 extern int fputc ();
157 extern int link ();
158 extern int unlink ();
159 extern int access ();
160 extern int execvp ();
161 #ifndef setjmp
162 extern int setjmp ();
163 #endif
164 #ifndef longjmp
165 extern void longjmp ();
166 #endif
167
168 #if 0 /* size_t from sys/types.h may fail to match GCC.
169          If so, we would get a warning from this.  */
170 extern size_t   strlen ()
171 #endif
172 extern char *   rindex ();
173
174 /* Fork is not declared because the declaration caused a conflict
175    on the HPPA.  */
176 #if !(defined (USG) || defined (VMS))
177 #define fork vfork
178 #endif /* (defined (USG) || defined (VMS)) */
179
180 #endif /* !defined (POSIX) */
181
182 /* Look for these where the `const' qualifier is intentionally cast aside.  */
183
184 #define NONCONST
185
186 /* Define a STRINGIFY macro that's right for ANSI or traditional C.  */
187
188 #ifdef __STDC__
189 #define STRINGIFY(STRING) #STRING
190 #else
191 #define STRINGIFY(STRING) "STRING"
192 #endif
193
194 /* Define a default place to find the SYSCALLS.X file.  */
195
196 #ifndef STD_PROTO_DIR
197 #define STD_PROTO_DIR "/usr/local/lib"
198 #endif /* !defined (STD_PROTO_DIR) */
199
200 /* Suffix of aux_info files.  */
201
202 static const char * const aux_info_suffix = ".X";
203
204 /* String to attach to filenames for saved versions of original files.  */
205
206 static const char * const save_suffix = ".save";
207
208 #ifndef UNPROTOIZE
209
210 /* File name of the file which contains descriptions of standard system
211    routines.  Note that we never actually do anything with this file per se,
212    but we do read in its corresponding aux_info file.  */
213
214 static const char syscalls_filename[] = "SYSCALLS.c";
215
216 /* Default place to find the above file.  */
217
218 static const char * const default_syscalls_dir = STD_PROTO_DIR;
219
220 /* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
221    file.  */
222
223 static char * syscalls_absolute_filename;
224
225 #endif /* !defined (UNPROTOIZE) */
226
227 /* Type of the structure that holds information about macro unexpansions. */
228
229 struct unexpansion_struct {
230   const char *expanded;
231   const char *contracted;
232 };
233 typedef struct unexpansion_struct unexpansion;
234
235 /* A table of conversions that may need to be made for some (stupid) older
236    operating systems where these types are preprocessor macros rather than
237    typedefs (as they really ought to be).
238
239    WARNING: The contracted forms must be as small (or smaller) as the
240    expanded forms, or else havoc will ensue.  */
241
242 static const unexpansion unexpansions[] = {
243   { "struct _iobuf", "FILE" },
244   { 0, 0 }
245 };
246
247 /* The number of "primary" slots in the hash tables for filenames and for
248    function names.  This can be as big or as small as you like, except that
249    it must be a power of two.  */
250
251 #define HASH_TABLE_SIZE         (1 << 9)
252
253 /* Bit mask to use when computing hash values.  */
254
255 static const int hash_mask = (HASH_TABLE_SIZE - 1);
256
257 /* Make a table of default system include directories
258    just as it is done in cccp.c.  */
259
260 #ifndef STANDARD_INCLUDE_DIR
261 #define STANDARD_INCLUDE_DIR "/usr/include"
262 #endif
263
264 #ifndef LOCAL_INCLUDE_DIR
265 #define LOCAL_INCLUDE_DIR "/usr/local/include"
266 #endif
267
268 struct default_include { const char *fname; int cplusplus; } include_defaults[]
269 #ifdef INCLUDE_DEFAULTS
270   = INCLUDE_DEFAULTS;
271 #else
272   = {
273     /* Pick up GNU C++ specific include files.  */
274     { GPLUSPLUS_INCLUDE_DIR, 1},
275     { GCC_INCLUDE_DIR, 0},
276     { TOOL_INCLUDE_DIR, 0},
277 #ifdef CROSS_COMPILE
278     /* For cross-compilation, this dir name is generated
279        automatically in Makefile.in.  */
280     { CROSS_INCLUDE_DIR, 0 },
281 #else /* not CROSS_COMPILE */
282     { LOCAL_INCLUDE_DIR, 0},
283     /* Some systems have an extra dir of include files.  */
284 #ifdef SYSTEM_INCLUDE_DIR
285     { SYSTEM_INCLUDE_DIR, 0},
286 #endif
287     { STANDARD_INCLUDE_DIR, 0},
288 #endif /* not CROSS_COMPILE */
289     { 0, 0}
290     };
291 #endif /* no INCLUDE_DEFAULTS */
292
293 /* Datatype for lists of directories or filenames.  */
294 struct string_list
295 {
296   char *name;
297   struct string_list *next;
298 };
299
300 /* List of directories in which files should be converted.  */
301
302 struct string_list *directory_list;
303
304 /* List of file names which should not be converted.
305    A file is excluded if the end of its name, following a /,
306    matches one of the names in this list.  */
307
308 struct string_list *exclude_list;
309
310 /* The name of the other style of variable-number-of-parameters functions
311    (i.e. the style that we want to leave unconverted because we don't yet
312    know how to convert them to this style.  This string is used in warning
313    messages.  */
314
315 /* Also define here the string that we can search for in the parameter lists
316    taken from the .X files which will unambiguously indicate that we have
317    found a varargs style function.  */
318
319 #ifdef UNPROTOIZE
320 static const char * const other_var_style = "stdarg";
321 #else /* !defined (UNPROTOIZE) */
322 static const char * const other_var_style = "varargs";
323 /* Note that this is a string containing the expansion of va_alist.
324    But in `main' we discard all but the first token.  */
325 static const char *varargs_style_indicator = STRINGIFY (va_alist);
326 #endif /* !defined (UNPROTOIZE) */
327
328 /* The following two types are used to create hash tables.  In this program,
329    there are two hash tables which are used to store and quickly lookup two
330    different classes of strings.  The first type of strings stored in the
331    first hash table are absolute filenames of files which protoize needs to
332    know about.  The second type of strings (stored in the second hash table)
333    are function names.  It is this second class of strings which really
334    inspired the use of the hash tables, because there may be a lot of them.  */
335
336 typedef struct hash_table_entry_struct hash_table_entry;
337
338 /* Do some typedefs so that we don't have to write "struct" so often.  */
339
340 typedef struct def_dec_info_struct def_dec_info;
341 typedef struct file_info_struct file_info;
342 typedef struct f_list_chain_item_struct f_list_chain_item;
343
344 /* In the struct below, note that the "_info" field has two different uses
345    depending on the type of hash table we are in (i.e. either the filenames
346    hash table or the function names hash table).  In the filenames hash table
347    the info fields of the entries point to the file_info struct which is
348    associated with each filename (1 per filename).  In the function names
349    hash table, the info field points to the head of a singly linked list of
350    def_dec_info entries which are all defs or decs of the function whose
351    name is pointed to by the "symbol" field.  Keeping all of the defs/decs
352    for a given function name on a special list specifically for that function
353    name makes it quick and easy to find out all of the important information
354    about a given (named) function.  */
355
356 struct hash_table_entry_struct {
357   hash_table_entry *            hash_next;      /* -> to secondary entries */
358   const char *                  symbol;         /* -> to the hashed string */
359   union {
360     const def_dec_info *        _ddip;
361     file_info *                 _fip;
362   } _info;
363 };
364 #define ddip _info._ddip
365 #define fip _info._fip
366
367 /* Define a type specifically for our two hash tables.  */
368
369 typedef hash_table_entry hash_table[HASH_TABLE_SIZE];
370
371 /* The following struct holds all of the important information about any
372    single filename (e.g. file) which we need to know about.  */
373
374 struct file_info_struct {
375   const hash_table_entry *      hash_entry; /* -> to associated hash entry */
376   const def_dec_info *          defs_decs;  /* -> to chain of defs/decs */
377   time_t                        mtime;      /* Time of last modification.  */
378 };
379
380 /* Due to the possibility that functions may return pointers to functions,
381    (which may themselves have their own parameter lists) and due to the
382    fact that returned pointers-to-functions may be of type "pointer-to-
383    function-returning-pointer-to-function" (ad nauseum) we have to keep
384    an entire chain of ANSI style formal parameter lists for each function.
385
386    Normally, for any given function, there will only be one formals list
387    on the chain, but you never know.
388
389    Note that the head of each chain of formals lists is pointed to by the
390    `f_list_chain' field of the corresponding def_dec_info record.
391
392    For any given chain, the item at the head of the chain is the *leftmost*
393    parameter list seen in the actual C language function declaration.  If
394    there are other members of the chain, then these are linked in left-to-right
395    order from the head of the chain.  */
396
397 struct f_list_chain_item_struct {
398   const f_list_chain_item *     chain_next;     /* -> to next item on chain */
399   const char *                  formals_list;   /* -> to formals list string */
400 };
401
402 /* The following struct holds all of the important information about any
403    single function definition or declaration which we need to know about.
404    Note that for unprotoize we don't need to know very much because we
405    never even create records for stuff that we don't intend to convert
406    (like for instance defs and decs which are already in old K&R format
407    and "implicit" function declarations).  */
408
409 struct def_dec_info_struct {
410   const def_dec_info *  next_in_file;   /* -> to rest of chain for file */
411   file_info *           file;           /* -> file_info for containing file */
412   int                   line;           /* source line number of def/dec */
413   const char *          ansi_decl;      /* -> left end of ansi decl */
414   hash_table_entry *    hash_entry;     /* -> hash entry for function name */
415   unsigned int          is_func_def;    /* = 0 means this is a declaration */
416   const def_dec_info *  next_for_func;  /* -> to rest of chain for func name */
417   unsigned int          f_list_count;   /* count of formals lists we expect */
418   char                  prototyped;     /* = 0 means already prototyped */
419 #ifndef UNPROTOIZE
420   const f_list_chain_item * f_list_chain;       /* -> chain of formals lists */
421   const def_dec_info *  definition;     /* -> def/dec containing related def */
422   char                  is_static;      /* = 0 means visibility is "extern"  */
423   char                  is_implicit;    /* != 0 for implicit func decl's */
424   char                  written;        /* != 0 means written for implicit */
425 #else /* !defined (UNPROTOIZE) */
426   const char *          formal_names;   /* -> to list of names of formals */
427   const char *          formal_decls;   /* -> to string of formal declarations */
428 #endif /* !defined (UNPROTOIZE) */
429 };
430
431 /* Pointer to the tail component of the filename by which this program was
432    invoked.  Used everywhere in error and warning messages.  */
433
434 static const char *pname;
435
436 /* Error counter.  Will be non-zero if we should give up at the next convenient
437    stopping point.  */
438
439 static int errors = 0;
440
441 /* Option flags.  */
442 /* ??? These comments should say what the flag mean as well as the options
443    that set them.  */
444
445 /* File name to use for running gcc.  Allows GCC 2 to be named
446    something other than gcc.  */
447 static const char *compiler_file_name = "gcc";
448
449 static int version_flag = 0;            /* Print our version number.  */
450 static int quiet_flag = 0;              /* Don't print messages normally.  */
451 static int nochange_flag = 0;           /* Don't convert, just say what files
452                                            we would have converted.  */
453 static int nosave_flag = 0;             /* Don't save the old version.  */
454 static int keep_flag = 0;               /* Don't delete the .X files.  */
455 static const char ** compile_params = 0;        /* Option string for gcc.  */
456 #ifdef UNPROTOIZE
457 static const char *indent_string = "     ";     /* Indentation for newly
458                                                    inserted parm decls.  */
459 #else /* !defined (UNPROTOIZE) */
460 static int local_flag = 0;              /* Insert new local decls (when?).  */
461 static int global_flag = 0;             /* set by -g option */
462 static int cplusplus_flag = 0;          /* Rename converted files to *.C.  */
463 static const char* nondefault_syscalls_dir = 0; /* Dir to look for
464                                                    SYSCALLS.c.X in.  */
465 #endif /* !defined (UNPROTOIZE) */
466
467 /* An index into the compile_params array where we should insert the source
468    file name when we are ready to exec the C compiler.  A zero value indicates
469    that we have not yet called munge_compile_params.  */
470
471 static int input_file_name_index = 0;
472
473 /* An index into the compile_params array where we should insert the filename
474    for the aux info file, when we run the C compiler.  */
475 static int aux_info_file_name_index = 0;
476
477 /* Count of command line arguments which were "filename" arguments.  */
478
479 static int n_base_source_files = 0;
480
481 /* Points to a malloc'ed list of pointers to all of the filenames of base
482    source files which were specified on the command line.  */
483
484 static const char **base_source_filenames;
485
486 /* Line number of the line within the current aux_info file that we
487    are currently processing.  Used for error messages in case the prototypes
488    info file is corrupted somehow.  */
489
490 static int current_aux_info_lineno;
491
492 /* Pointer to the name of the source file currently being converted.  */
493
494 static const char *convert_filename;
495
496 /* Pointer to relative root string (taken from aux_info file) which indicates
497    where directory the user was in when he did the compilation step that
498    produced the containing aux_info file. */
499
500 static const char *invocation_filename;
501
502 /* Pointer to the base of the input buffer that holds the original text for the
503    source file currently being converted.  */
504
505 static const char *orig_text_base;
506
507 /* Pointer to the byte just beyond the end of the input buffer that holds the
508    original text for the source file currently being converted.  */
509
510 static const char *orig_text_limit;
511
512 /* Pointer to the base of the input buffer that holds the cleaned text for the
513    source file currently being converted.  */
514
515 static const char *clean_text_base;
516
517 /* Pointer to the byte just beyond the end of the input buffer that holds the
518    cleaned text for the source file currently being converted.  */
519
520 static const char *clean_text_limit;
521
522 /* Pointer to the last byte in the cleaned text buffer that we have already
523    (virtually) copied to the output buffer (or decided to ignore).  */
524
525 static const char * clean_read_ptr;
526
527 /* Pointer to the base of the output buffer that holds the replacement text
528    for the source file currently being converted.  */
529
530 static char *repl_text_base;
531
532 /* Pointer to the byte just beyond the end of the output buffer that holds the
533    replacement text for the source file currently being converted.  */
534
535 static char *repl_text_limit;
536
537 /* Pointer to the last byte which has been stored into the output buffer.
538    The next byte to be stored should be stored just past where this points
539    to.  */
540
541 static char * repl_write_ptr;
542
543 /* Pointer into the cleaned text buffer for the source file we are currently
544    converting.  This points to the first character of the line that we last
545    did a "seek_to_line" to (see below).  */
546
547 static const char *last_known_line_start;
548
549 /* Number of the line (in the cleaned text buffer) that we last did a
550    "seek_to_line" to.  Will be one if we just read a new source file
551    into the cleaned text buffer.  */
552
553 static int last_known_line_number;
554
555 /* The filenames hash table.  */
556
557 static hash_table filename_primary;
558
559 /* The function names hash table.  */
560
561 static hash_table function_name_primary;
562
563 /* The place to keep the recovery address which is used only in cases where
564    we get hopelessly confused by something in the cleaned original text.  */
565
566 static jmp_buf source_confusion_recovery;
567
568 /* A pointer to the current directory filename (used by abspath).  */
569
570 static char *cwd_buffer;
571
572 /* A place to save the read pointer until we are sure that an individual
573    attempt at editing will succeed.  */
574
575 static const char * saved_clean_read_ptr;
576
577 /* A place to save the write pointer until we are sure that an individual
578    attempt at editing will succeed.  */
579
580 static char * saved_repl_write_ptr;
581
582 /* Forward declaration.  */
583
584 static const char *shortpath ();
585 \f
586 /* Allocate some space, but check that the allocation was successful.  */
587 /* alloca.c uses this, so don't make it static.  */
588
589 pointer_type
590 xmalloc (byte_count)
591      size_t byte_count;
592 {
593   pointer_type rv;
594
595   rv = malloc (byte_count);
596   if (rv == NULL)
597     {
598       fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
599       exit (1);
600       return 0;         /* avoid warnings */
601     }
602   else
603     return rv;
604 }
605
606 /* Reallocate some space, but check that the reallocation was successful.  */
607
608 pointer_type
609 xrealloc (old_space, byte_count)
610      pointer_type old_space;
611      size_t byte_count;
612 {
613   pointer_type rv;
614
615   rv = realloc (old_space, byte_count);
616   if (rv == NULL)
617     {
618       fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
619       exit (1);
620       return 0;         /* avoid warnings */
621     }
622   else
623     return rv;
624 }
625
626 /* Deallocate the area pointed to by an arbitrary pointer, but first, strip
627    the `const' qualifier from it and also make sure that the pointer value
628    is non-null.  */
629
630 void
631 xfree (p)
632      const_pointer_type p;
633 {
634   if (p)
635     free ((NONCONST pointer_type) p);
636 }
637
638 /* Make a copy of a string INPUT with size SIZE.  */
639
640 static char *
641 savestring (input, size)
642      const char *input;
643      unsigned int size;
644 {
645   char *output = (char *) xmalloc (size + 1);
646   strcpy (output, input);
647   return output;
648 }
649
650 /* Make a copy of the concatenation of INPUT1 and INPUT2.  */
651
652 static char *
653 savestring2 (input1, size1, input2, size2)
654      const char *input1;
655      unsigned int size1;
656      const char *input2;
657      unsigned int size2;
658 {
659   char *output = (char *) xmalloc (size1 + size2 + 1);
660   strcpy (output, input1);
661   strcpy (&output[size1], input2);
662   return output;
663 }
664
665 /* More 'friendly' abort that prints the line and file.
666    config.h can #define abort fancy_abort if you like that sort of thing.  */
667
668 void
669 fancy_abort ()
670 {
671   fprintf (stderr, "%s: internal abort\n", pname);
672   exit (1);
673 }
674 \f
675 /* Make a duplicate of the first N bytes of a given string in a newly
676    allocated area.  */
677
678 static char *
679 dupnstr (s, n)
680      const char *s;
681      size_t n;
682 {
683   char *ret_val = (char *) xmalloc (n + 1);
684
685   strncpy (ret_val, s, n);
686   ret_val[n] = '\0';
687   return ret_val;
688 }
689
690 /* Return a pointer to the first occurrence of s2 within s1 or NULL if s2
691    does not occur within s1.  Assume neither s1 nor s2 are null pointers.  */
692
693 static const char *
694 substr (s1, s2)
695      const char *s1;
696      const char *const s2;
697 {
698   for (; *s1 ; s1++)
699     {
700       const char *p1;
701       const char *p2;
702       int c;
703
704       for (p1 = s1, p2 = s2; c = *p2; p1++, p2++)
705         if (*p1 != c)
706           goto outer;
707       return s1;
708 outer:
709       ;
710     }
711   return 0;
712 }
713 \f
714 /* Get setup to recover in case the edit we are about to do goes awry.  */
715
716 void
717 save_pointers ()
718 {
719   saved_clean_read_ptr = clean_read_ptr;
720   saved_repl_write_ptr = repl_write_ptr;
721 }
722
723 /* Call this routine to recover our previous state whenever something looks
724    too confusing in the source code we are trying to edit.  */
725
726 void
727 restore_pointers ()
728 {
729   clean_read_ptr = saved_clean_read_ptr;
730   repl_write_ptr = saved_repl_write_ptr;
731 }
732
733 /* Return true if the given character is a legal identifier character.  */
734
735 static int
736 is_id_char (ch)
737      char ch;
738 {
739   return (isalnum (ch) || (ch == '_') || (ch == '$'));
740 }
741
742 /* Give a message indicating the proper way to invoke this program and then
743    exit with non-zero status.  */
744
745 static void
746 usage ()
747 {
748 #ifdef UNPROTOIZE
749   fprintf (stderr, "%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
750            pname, pname);
751 #else /* !defined (UNPROTOIZE) */
752   fprintf (stderr, "%s: usage '%s [ -VqfnkNlgC ] [ -B <diname> ] [ filename ... ]'\n",
753            pname, pname);
754 #endif /* !defined (UNPROTOIZE) */
755   exit (1);
756 }
757
758 /* Return true if the given filename (assumed to be an absolute filename)
759    designates a file residing anywhere beneath any one of the "system"
760    include directories.  */
761
762 static int
763 in_system_include_dir (path)
764      const char *path;
765 {
766   struct default_include *p;
767
768   if (path[0] != '/')
769     abort ();           /* Must be an absolutized filename.  */
770
771   for (p = include_defaults; p->fname; p++)
772     if (!strncmp (path, p->fname, strlen (p->fname))
773         && path[strlen (p->fname)] == '/')
774       return 1;
775   return 0;
776 }
777 \f
778 #if 0
779 /* Return true if the given filename designates a file that the user has
780    read access to and for which the user has write access to the containing
781    directory.  */
782
783 static int
784 file_could_be_converted (const char *path)
785 {
786   char *const dir_name = (char *) alloca (strlen (path) + 1);
787
788   if (my_access (path, R_OK))
789     return 0;
790
791   {
792     char *dir_last_slash;
793
794     strcpy (dir_name, path);
795     dir_last_slash = rindex (dir_name, '/');
796     if (dir_last_slash)
797       *dir_last_slash = '\0';
798     else
799       abort ();  /* Should have been an absolutized filename.  */
800   }
801
802   if (my_access (path, W_OK))
803     return 0;
804
805   return 1;
806 }
807
808 /* Return true if the given filename designates a file that we are allowed
809    to modify.  Files which we should not attempt to modify are (a) "system"
810    include files, and (b) files which the user doesn't have write access to,
811    and (c) files which reside in directories which the user doesn't have
812    write access to.  Unless requested to be quiet, give warnings about
813    files that we will not try to convert for one reason or another.  An
814    exception is made for "system" include files, which we never try to
815    convert and for which we don't issue the usual warnings.  */
816
817 static int
818 file_normally_convertible (const char *path)
819 {
820   char *const dir_name = alloca (strlen (path) + 1);
821
822   if (in_system_include_dir (path))
823     return 0;
824
825   {
826     char *dir_last_slash;
827
828     strcpy (dir_name, path);
829     dir_last_slash = rindex (dir_name, '/');
830     if (dir_last_slash)
831       *dir_last_slash = '\0';
832     else
833       abort ();  /* Should have been an absolutized filename.  */
834   }
835
836   if (my_access (path, R_OK))
837     {
838       if (!quiet_flag)
839         fprintf (stderr, "%s: warning: no read access for file `%s'\n",
840                  pname, shortpath (NULL, path));
841       return 0;
842     }
843
844   if (my_access (path, W_OK))
845     {
846       if (!quiet_flag)
847         fprintf (stderr, "%s: warning: no write access for file `%s'\n",
848                  pname, shortpath (NULL, path));
849       return 0;
850     }
851
852   if (my_access (dir_name, W_OK))
853     {
854       if (!quiet_flag)
855         fprintf (stderr, "%s: warning: no write access for dir containing `%s'\n",
856                  pname, shortpath (NULL, path));
857       return 0;
858     }
859
860   return 1;
861 }
862 #endif /* 0 */
863 \f
864 #ifndef UNPROTOIZE
865
866 /* Return true if the given file_info struct refers to the special SYSCALLS.c.X
867    file.  Return false otherwise.  */
868
869 static int
870 is_syscalls_file (fi_p)
871      const file_info *fi_p;
872 {
873   char const *f = fi_p->hash_entry->symbol;
874   size_t fl = strlen (f), sysl = sizeof (syscalls_filename) - 1;
875   return sysl <= fl  &&  strcmp (f + fl - sysl, syscalls_filename) == 0;
876 }
877
878 #endif /* !defined (UNPROTOIZE) */
879
880 /* Check to see if this file will need to have anything done to it on this
881    run.  If there is nothing in the given file which both needs conversion
882    and for which we have the necessary stuff to do the conversion, return
883    false.  Otherwise, return true.
884
885    Note that (for protoize) it is only valid to call this function *after*
886    the connections between declarations and definitions have all been made
887    by connect_defs_and_decs.  */
888
889 static int
890 needs_to_be_converted (file_p)
891      const file_info *file_p;
892 {
893   const def_dec_info *ddp;
894
895 #ifndef UNPROTOIZE
896
897   if (is_syscalls_file (file_p))
898     return 0;
899
900 #endif /* !defined (UNPROTOIZE) */
901
902   for (ddp = file_p->defs_decs; ddp; ddp = ddp->next_in_file)
903
904     if (
905
906 #ifndef UNPROTOIZE
907
908       /* ... and if we a protoizing and this function is in old style ... */
909       !ddp->prototyped
910       /* ... and if this a definition or is a decl with an associated def ... */
911       && (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
912
913 #else /* defined (UNPROTOIZE) */
914
915       /* ... and if we are unprotoizing and this function is in new style ... */
916       ddp->prototyped
917
918 #endif /* defined (UNPROTOIZE) */
919       )
920           /* ... then the containing file needs converting.  */
921           return -1;
922   return 0;
923 }
924
925 /* Return 1 if the file name NAME is in a directory
926    that should be converted.  */
927
928 static int
929 directory_specified_p (name)
930      const char *name;
931 {
932   struct string_list *p;
933
934   for (p = directory_list; p; p = p->next)
935     if (!strncmp (name, p->name, strlen (p->name))
936         && name[strlen (p->name)] == '/')
937       {
938         const char *q = name + strlen (p->name) + 1;
939
940         /* If there are more slashes, it's in a subdir, so
941            this match doesn't count.  */
942         while (*q)
943           if (*q++ == '/')
944             goto lose;
945         return 1;
946
947       lose: ;
948       }
949
950   return 0;
951 }
952
953 /* Return 1 if the file named NAME should be excluded from conversion.  */
954
955 static int
956 file_excluded_p (name)
957      const char *name;
958 {
959   struct string_list *p;
960   int len = strlen (name);
961
962   for (p = exclude_list; p; p = p->next)
963     if (!strcmp (name + len - strlen (p->name), p->name)
964         && name[len - strlen (p->name) - 1] == '/')
965       return 1;
966
967   return 0;
968 }
969
970 /* Construct a new element of a string_list.
971    STRING is the new element value, and REST holds the remaining elements.  */
972
973 static struct string_list *
974 string_list_cons (string, rest)
975      char *string;
976      struct string_list *rest;
977 {
978   struct string_list *temp
979     = (struct string_list *) xmalloc (sizeof (struct string_list));
980
981   temp->next = rest;
982   temp->name = string;
983   return temp;
984 }
985 \f
986 /* ??? The GNU convention for mentioning function args in its comments
987    is to capitalize them.  So change "hash_tab_p" to HASH_TAB_P below.
988    Likewise for all the other functions.  */
989
990 /* Given a hash table, apply some function to each node in the table. The
991    table to traverse is given as the "hash_tab_p" argument, and the
992    function to be applied to each node in the table is given as "func"
993    argument.  */
994
995 static void
996 visit_each_hash_node (hash_tab_p, func)
997      const hash_table_entry *hash_tab_p;
998      void (*func)();
999 {
1000   const hash_table_entry *primary;
1001
1002   for (primary = hash_tab_p; primary < &hash_tab_p[HASH_TABLE_SIZE]; primary++)
1003     if (primary->symbol)
1004       {
1005         hash_table_entry *second;
1006
1007         (*func)(primary);
1008         for (second = primary->hash_next; second; second = second->hash_next)
1009           (*func) (second);
1010       }
1011 }
1012
1013 /* Initialize all of the fields of a new hash table entry, pointed
1014    to by the "p" parameter.  Note that the space to hold the entry
1015    is assumed to have already been allocated before this routine is
1016    called.  */
1017
1018 static hash_table_entry *
1019 add_symbol (p, s)
1020      hash_table_entry *p;
1021      const char *s;
1022 {
1023   p->hash_next = NULL;
1024   p->symbol = savestring (s, strlen (s));
1025   p->ddip = NULL;
1026   p->fip = NULL;
1027   return p;
1028 }
1029
1030 /* Look for a particular function name or filename in the particular
1031    hash table indicated by "hash_tab_p".  If the name is not in the
1032    given hash table, add it.  Either way, return a pointer to the
1033    hash table entry for the given name.  */
1034
1035 static hash_table_entry *
1036 lookup (hash_tab_p, search_symbol)
1037      hash_table_entry *hash_tab_p;
1038      const char *search_symbol;
1039 {
1040   int hash_value = 0;
1041   const char *search_symbol_char_p = search_symbol;
1042   hash_table_entry *p;
1043
1044   while (*search_symbol_char_p)
1045     hash_value += *search_symbol_char_p++;
1046   hash_value &= hash_mask;
1047   p = &hash_tab_p[hash_value];
1048   if (! p->symbol)
1049       return add_symbol (p, search_symbol);
1050   if (!strcmp (p->symbol, search_symbol))
1051     return p;
1052   while (p->hash_next)
1053     {
1054       p = p->hash_next;
1055       if (!strcmp (p->symbol, search_symbol))
1056         return p;
1057     }
1058   p->hash_next = (hash_table_entry *) xmalloc (sizeof (hash_table_entry));
1059   p = p->hash_next;
1060   return add_symbol (p, search_symbol);
1061 }
1062 \f
1063 /* Throw a def/dec record on the junk heap.
1064
1065    Also, since we are not using this record anymore, free up all of the
1066    stuff it pointed to.  */
1067
1068 static void
1069 free_def_dec (p)
1070      def_dec_info *p;
1071 {
1072   xfree (p->ansi_decl);
1073
1074 #ifndef UNPROTOIZE
1075   {
1076     const f_list_chain_item * curr;
1077     const f_list_chain_item * next;
1078
1079     for (curr = p->f_list_chain; curr; curr = next)
1080       {
1081         next = curr->chain_next;
1082         xfree (curr);
1083       }
1084   }
1085 #endif /* !defined (UNPROTOIZE) */
1086
1087   xfree (p);
1088 }
1089
1090 /* Unexpand as many macro symbol as we can find.
1091
1092    If the given line must be unexpanded, make a copy of it in the heap and
1093    return a pointer to the unexpanded copy.  Otherwise return NULL.  */
1094
1095 static char *
1096 unexpand_if_needed (aux_info_line)
1097      const char *aux_info_line;
1098 {
1099   static char *line_buf = 0;
1100   static int line_buf_size = 0;
1101   const unexpansion* unexp_p;
1102   int got_unexpanded = 0;
1103   const char *s;
1104   char *copy_p = line_buf;
1105
1106   if (line_buf == 0)
1107     {
1108       line_buf_size = 1024;
1109       line_buf = (char *) xmalloc (line_buf_size);
1110     }
1111
1112   copy_p = line_buf;
1113
1114   /* Make a copy of the input string in line_buf, expanding as necessary.  */
1115
1116   for (s = aux_info_line; *s != '\n'; )
1117     {
1118       for (unexp_p = unexpansions; unexp_p->expanded; unexp_p++)
1119         {
1120           const char *in_p = unexp_p->expanded;
1121           size_t len = strlen (in_p);
1122
1123           if (*s == *in_p && !strncmp (s, in_p, len) && !is_id_char (s[len]))
1124             {
1125               int size = strlen (unexp_p->contracted);
1126               got_unexpanded = 1;
1127               if (copy_p + size - line_buf >= line_buf_size)
1128                 {
1129                   int offset = copy_p - line_buf;
1130                   line_buf_size *= 2;
1131                   line_buf_size += size;
1132                   line_buf = (char *) xrealloc (line_buf, line_buf_size);
1133                   copy_p = line_buf + offset;
1134                 }
1135               strcpy (copy_p, unexp_p->contracted);
1136               copy_p += size;
1137
1138               /* Assume the there will not be another replacement required
1139                  within the text just replaced.  */
1140
1141               s += len;
1142               goto continue_outer;
1143             }
1144         }
1145       if (copy_p - line_buf == line_buf_size)
1146         {
1147           int offset = copy_p - line_buf;
1148           line_buf_size *= 2;
1149           line_buf = (char *) xrealloc (line_buf, line_buf_size);
1150           copy_p = line_buf + offset;
1151         }
1152       *copy_p++ = *s++;
1153 continue_outer: ;
1154     }
1155   if (copy_p + 2 - line_buf >= line_buf_size)
1156     {
1157       int offset = copy_p - line_buf;
1158       line_buf_size *= 2;
1159       line_buf = (char *) xrealloc (line_buf, line_buf_size);
1160       copy_p = line_buf + offset;
1161     }
1162   *copy_p++ = '\n';
1163   *copy_p = '\0';
1164
1165   return (got_unexpanded ? savestring (line_buf, copy_p - line_buf) : 0);
1166 }
1167 \f
1168 /* Return the absolutized filename for the given relative
1169    filename.  Note that if that filename is already absolute, it may
1170    still be returned in a modified form because this routine also
1171    eliminates redundant slashes and single dots and eliminates double
1172    dots to get a shortest possible filename from the given input
1173    filename.  The absolutization of relative filenames is made by
1174    assuming that the given filename is to be taken as relative to
1175    the first argument (cwd) or to the current directory if cwd is
1176    NULL.  */
1177
1178 static char *
1179 abspath (cwd, rel_filename)
1180      const char *cwd;
1181      const char *rel_filename;
1182 {
1183   /* Setup the current working directory as needed.  */
1184   const char *cwd2 = (cwd) ? cwd : cwd_buffer;
1185   char *const abs_buffer
1186     = (char *) alloca (strlen (cwd2) + strlen (rel_filename) + 2);
1187   char *endp = abs_buffer;
1188   char *outp, *inp;
1189
1190   /* Copy the  filename (possibly preceded by the current working
1191      directory name) into the absolutization buffer.  */
1192
1193   {
1194     const char *src_p;
1195
1196     if (rel_filename[0] != '/')
1197       {
1198         src_p = cwd2;
1199         while (*endp++ = *src_p++)
1200           continue;
1201         *(endp-1) = '/';                        /* overwrite null */
1202       }
1203     src_p = rel_filename;
1204     while (*endp++ = *src_p++)
1205       continue;
1206   }
1207
1208   /* Now make a copy of abs_buffer into abs_buffer, shortening the
1209      filename (by taking out slashes and dots) as we go.  */
1210
1211   outp = inp = abs_buffer;
1212   *outp++ = *inp++;             /* copy first slash */
1213 #ifdef apollo
1214   if (inp[0] == '/')
1215     *outp++ = *inp++;           /* copy second slash */
1216 #endif
1217   for (;;)
1218     {
1219       if (!inp[0])
1220         break;
1221       else if (inp[0] == '/' && outp[-1] == '/')
1222         {
1223           inp++;
1224           continue;
1225         }
1226       else if (inp[0] == '.' && outp[-1] == '/')
1227         {
1228           if (!inp[1])
1229                   break;
1230           else if (inp[1] == '/')
1231             {
1232                     inp += 2;
1233                     continue;
1234             }
1235           else if ((inp[1] == '.') && (inp[2] == 0 || inp[2] == '/'))
1236             {
1237                     inp += (inp[2] == '/') ? 3 : 2;
1238                     outp -= 2;
1239                     while (outp >= abs_buffer && *outp != '/')
1240                 outp--;
1241                     if (outp < abs_buffer)
1242                 {
1243                   /* Catch cases like /.. where we try to backup to a
1244                      point above the absolute root of the logical file
1245                      system.  */
1246
1247                   fprintf (stderr, "%s: invalid file name: %s\n",
1248                            pname, rel_filename);
1249                   exit (1);
1250                 }
1251                     *++outp = '\0';
1252                     continue;
1253             }
1254         }
1255       *outp++ = *inp++;
1256     }
1257
1258   /* On exit, make sure that there is a trailing null, and make sure that
1259      the last character of the returned string is *not* a slash.  */
1260
1261   *outp = '\0';
1262   if (outp[-1] == '/')
1263     *--outp  = '\0';
1264
1265   /* Make a copy (in the heap) of the stuff left in the absolutization
1266      buffer and return a pointer to the copy.  */
1267
1268   return savestring (abs_buffer, outp - abs_buffer);
1269 }
1270 \f
1271 /* Given a filename (and possibly a directory name from which the filename
1272    is relative) return a string which is the shortest possible
1273    equivalent for the corresponding full (absolutized) filename.  The
1274    shortest possible equivalent may be constructed by converting the
1275    absolutized filename to be a relative filename (i.e. relative to
1276    the actual current working directory).  However if a relative filename
1277    is longer, then the full absolute filename is returned.
1278
1279    KNOWN BUG:
1280
1281    Note that "simple-minded" conversion of any given type of filename (either
1282    relative or absolute) may not result in a valid equivalent filename if any
1283    subpart of the original filename is actually a symbolic link.  */
1284
1285 static const char *
1286 shortpath (cwd, filename)
1287      const char *cwd;
1288      const char *filename;
1289 {
1290   char *rel_buffer;
1291   char *rel_buf_p;
1292   char *cwd_p = cwd_buffer;
1293   char *path_p;
1294   int unmatched_slash_count = 0;
1295   size_t filename_len = strlen (filename);
1296
1297   path_p = abspath (cwd, filename);
1298   rel_buf_p = rel_buffer = (char *) xmalloc (filename_len);
1299
1300   while (*cwd_p && (*cwd_p == *path_p))
1301     {
1302       cwd_p++;
1303       path_p++;
1304     }
1305   if (!*cwd_p && (!*path_p || *path_p == '/'))  /* whole pwd matched */
1306     {
1307       if (!*path_p)             /* input *is* the current path! */
1308         return ".";
1309       else
1310         return ++path_p;
1311     }
1312   else
1313     {
1314       if (*path_p)
1315         {
1316           --cwd_p;
1317           --path_p;
1318           while (*cwd_p != '/')         /* backup to last slash */
1319             {
1320               --cwd_p;
1321               --path_p;
1322             }
1323           cwd_p++;
1324           path_p++;
1325           unmatched_slash_count++;
1326         }
1327
1328       /* Find out how many directory levels in cwd were *not* matched.  */
1329       while (*cwd_p)
1330         if (*cwd_p++ == '/')
1331           unmatched_slash_count++;
1332
1333       /* Now we know how long the "short name" will be.
1334          Reject it if longer than the input.  */
1335       if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1336         return filename;
1337
1338       /* For each of them, put a `../' at the beginning of the short name.  */
1339       while (unmatched_slash_count--)
1340         {
1341           /* Give up if the result gets to be longer
1342              than the absolute path name.  */
1343           if (rel_buffer + filename_len <= rel_buf_p + 3)
1344             return filename;
1345           *rel_buf_p++ = '.';
1346           *rel_buf_p++ = '.';
1347           *rel_buf_p++ = '/';
1348         }
1349
1350       /* Then tack on the unmatched part of the desired file's name.  */
1351       do
1352         {
1353           if (rel_buffer + filename_len <= rel_buf_p)
1354             return filename;
1355         }
1356       while (*rel_buf_p++ = *path_p++);
1357
1358       --rel_buf_p;
1359       if (*(rel_buf_p-1) == '/')
1360         *--rel_buf_p = '\0';
1361       return rel_buffer;
1362     }
1363 }
1364 \f
1365 /* Lookup the given filename in the hash table for filenames.  If it is a
1366    new one, then the hash table info pointer will be null.  In this case,
1367    we create a new file_info record to go with the filename, and we initialize
1368    that record with some reasonable values.  */
1369
1370 /* FILENAME was const, but that causes a warning on AIX when calling stat.
1371    That is probably a bug in AIX, but might as well avoid the warning.  */
1372
1373 static file_info *
1374 find_file (filename, do_not_stat)
1375      char *filename;
1376      int do_not_stat;
1377 {
1378   hash_table_entry *hash_entry_p;
1379
1380   hash_entry_p = lookup (filename_primary, filename);
1381   if (hash_entry_p->fip)
1382     return hash_entry_p->fip;
1383   else
1384     {
1385       struct stat stat_buf;
1386       file_info *file_p = (file_info *) xmalloc (sizeof (file_info));
1387
1388       /* If we cannot get status on any given source file, give a warning
1389          and then just set its time of last modification to infinity.  */
1390
1391       if (do_not_stat)
1392         stat_buf.st_mtime = (time_t) 0;
1393       else
1394         {
1395           if (my_stat (filename, &stat_buf) == -1)
1396             {
1397               fprintf (stderr, "%s: %s: can't get status: %s\n",
1398                        pname, shortpath (NULL, filename), sys_errlist[errno]);
1399               stat_buf.st_mtime = (time_t) -1;
1400             }
1401         }
1402
1403       hash_entry_p->fip = file_p;
1404       file_p->hash_entry = hash_entry_p;
1405       file_p->defs_decs = NULL;
1406       file_p->mtime = stat_buf.st_mtime;
1407       return file_p;
1408     }
1409 }
1410
1411 /* Generate a fatal error because some part of the aux_info file is
1412    messed up.  */
1413
1414 static void
1415 aux_info_corrupted ()
1416 {
1417   fprintf (stderr, "\n%s: fatal error: aux info file corrupted at line %d\n",
1418            pname, current_aux_info_lineno);
1419   exit (1);
1420 }
1421
1422 /* ??? This comment is vague.  Say what the condition is for.  */
1423 /* Check to see that a condition is true.  This is kind of like an assert.  */
1424
1425 static void
1426 check_aux_info (cond)
1427      int cond;
1428 {
1429   if (! cond)
1430     aux_info_corrupted ();
1431 }
1432
1433 /* Given a pointer to the closing right parenthesis for a particular formals
1434    list (in an aux_info file) find the corresponding left parenthesis and
1435    return a pointer to it.  */
1436
1437 static const char *
1438 find_corresponding_lparen (p)
1439      const char *p;
1440 {
1441   const char *q;
1442   int paren_depth;
1443
1444   for (paren_depth = 1, q = p-1; paren_depth; q--)
1445     {
1446       switch (*q)
1447         {
1448           case ')':
1449             paren_depth++;
1450             break;
1451           case '(':
1452             paren_depth--;
1453             break;
1454         }
1455     }
1456   return ++q;
1457 }
1458 \f
1459 /* Given a line from  an aux info file, and a time at which the aux info
1460    file it came from was created, check to see if the item described in
1461    the line comes from a file which has been modified since the aux info
1462    file was created.  If so, return non-zero, else return zero.  */
1463
1464 static int
1465 referenced_file_is_newer (l, aux_info_mtime)
1466      const char *l;
1467      time_t aux_info_mtime;
1468 {
1469   const char *p;
1470   file_info *fi_p;
1471   char *filename;
1472
1473   check_aux_info (l[0] == '/');
1474   check_aux_info (l[1] == '*');
1475   check_aux_info (l[2] == ' ');
1476
1477   {
1478     const char *filename_start = p = l + 3;
1479
1480     while (*p != ':')
1481       p++;
1482     filename = (char *) alloca ((size_t) (p - filename_start) + 1);
1483     strncpy (filename, filename_start, (size_t) (p - filename_start));
1484     filename[p-filename_start] = '\0';
1485   }
1486
1487   /* Call find_file to find the file_info record associated with the file
1488      which contained this particular def or dec item.  Note that this call
1489      may cause a new file_info record to be created if this is the first time
1490      that we have ever known about this particular file.  */
1491
1492   fi_p = find_file (abspath (invocation_filename, filename), 0);
1493
1494   return (fi_p->mtime > aux_info_mtime);
1495 }
1496 \f
1497 /* Given a line of info from the aux_info file, create a new
1498    def_dec_info record to remember all of the important information about
1499    a function definition or declaration.
1500
1501    Link this record onto the list of such records for the particular file in
1502    which it occurred in proper (descending) line number order (for now).
1503
1504    If there is an identical record already on the list for the file, throw
1505    this one away.  Doing so takes care of the (useless and troublesome)
1506    duplicates which are bound to crop up due to multiple inclusions of any
1507    given individual header file.
1508
1509    Finally, link the new def_dec record onto the list of such records
1510    pertaining to this particular function name.  */
1511
1512 static void
1513 save_def_or_dec (l, is_syscalls)
1514      const char *l;
1515      int is_syscalls;
1516 {
1517   const char *p;
1518   const char *semicolon_p;
1519   def_dec_info *def_dec_p = (def_dec_info *) xmalloc (sizeof (def_dec_info));
1520
1521 #ifndef UNPROTOIZE
1522   def_dec_p->written = 0;
1523 #endif /* !defined (UNPROTOIZE) */
1524
1525   /* Start processing the line by picking off 5 pieces of information from
1526      the left hand end of the line.  These are filename, line number,
1527      new/old/implicit flag (new = ANSI prototype format), definition or
1528      declaration flag, and extern/static flag).  */
1529
1530   check_aux_info (l[0] == '/');
1531   check_aux_info (l[1] == '*');
1532   check_aux_info (l[2] == ' ');
1533
1534   {
1535     const char *filename_start = p = l + 3;
1536     char *filename;
1537
1538     while (*p != ':')
1539       p++;
1540     filename = (char *) alloca ((size_t) (p - filename_start) + 1);
1541     strncpy (filename, filename_start, (size_t) (p - filename_start));
1542     filename[p-filename_start] = '\0';
1543
1544     /* Call find_file to find the file_info record associated with the file
1545        which contained this particular def or dec item.  Note that this call
1546        may cause a new file_info record to be created if this is the first time
1547        that we have ever known about this particular file.
1548   
1549        Note that we started out by forcing all of the base source file names
1550        (i.e. the names of the aux_info files with the .X stripped off) into the
1551        filenames hash table, and we simultaneously setup file_info records for
1552        all of these base file names (even if they may be useless later).
1553        The file_info records for all of these "base" file names (properly)
1554        act as file_info records for the "original" (i.e. un-included) files
1555        which were submitted to gcc for compilation (when the -aux-info
1556        option was used).  */
1557   
1558     def_dec_p->file = find_file (abspath (invocation_filename, filename), is_syscalls);
1559   }
1560
1561   {
1562     const char *line_number_start = ++p;
1563     char line_number[10];
1564
1565     while (*p != ':')
1566       p++;
1567     strncpy (line_number, line_number_start, (size_t) (p - line_number_start));
1568     line_number[p-line_number_start] = '\0';
1569     def_dec_p->line = atoi (line_number);
1570   }
1571
1572   /* Check that this record describes a new-style, old-style, or implicit
1573      definition or declaration.  */
1574
1575   p++;  /* Skip over the `:'. */
1576   check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
1577
1578   /* Is this a new style (ANSI prototyped) definition or declaration? */
1579
1580   def_dec_p->prototyped = (*p == 'N');
1581
1582 #ifndef UNPROTOIZE
1583
1584   /* Is this an implicit declaration? */
1585
1586   def_dec_p->is_implicit = (*p == 'I');
1587
1588 #endif /* !defined (UNPROTOIZE) */
1589
1590   p++;
1591
1592   check_aux_info ((*p == 'C') || (*p == 'F'));
1593
1594   /* Is this item a function definition (F) or a declaration (C).  Note that
1595      we treat item taken from the syscalls file as though they were function
1596      definitions regardless of what the stuff in the file says.  */
1597
1598   def_dec_p->is_func_def = ((*p++ == 'F') || is_syscalls);
1599
1600 #ifndef UNPROTOIZE
1601   def_dec_p->definition = 0;    /* Fill this in later if protoizing.  */
1602 #endif /* !defined (UNPROTOIZE) */
1603
1604   check_aux_info (*p++ == ' ');
1605   check_aux_info (*p++ == '*');
1606   check_aux_info (*p++ == '/');
1607   check_aux_info (*p++ == ' ');
1608
1609 #ifdef UNPROTOIZE
1610   check_aux_info ((!strncmp (p, "static", 6)) || (!strncmp (p, "extern", 6)));
1611 #else /* !defined (UNPROTOIZE) */
1612   if (!strncmp (p, "static", 6))
1613     def_dec_p->is_static = -1;
1614   else if (!strncmp (p, "extern", 6))
1615     def_dec_p->is_static = 0;
1616   else
1617     check_aux_info (0); /* Didn't find either `extern' or `static'.  */
1618 #endif /* !defined (UNPROTOIZE) */
1619
1620   {
1621     const char *ansi_start = p;
1622
1623     p += 6;     /* Pass over the "static" or "extern".  */
1624
1625     /* We are now past the initial stuff.  Search forward from here to find
1626        the terminating semicolon that should immediately follow the entire
1627        ANSI format function declaration.  */
1628
1629     while (*++p != ';')
1630       continue;
1631
1632     semicolon_p = p;
1633
1634     /* Make a copy of the ansi declaration part of the line from the aux_info
1635        file.  */
1636
1637     def_dec_p->ansi_decl
1638       = dupnstr (ansi_start, (size_t) ((semicolon_p+1) - ansi_start));
1639   }
1640
1641   /* Backup and point at the final right paren of the final argument list.  */
1642
1643   p--;
1644
1645   /* Now isolate a whole set of formal argument lists, one-by-one.  Normally,
1646      there will only be one list to isolate, but there could be more.  */
1647
1648   def_dec_p->f_list_count = 0;
1649
1650 #ifndef UNPROTOIZE
1651   def_dec_p->f_list_chain = NULL;
1652 #endif /* !defined (UNPROTOIZE) */
1653
1654   for (;;)
1655     {
1656       const char *left_paren_p = find_corresponding_lparen (p);
1657 #ifndef UNPROTOIZE
1658       {
1659         f_list_chain_item *cip =
1660           (f_list_chain_item *) xmalloc (sizeof (f_list_chain_item));
1661
1662         cip->formals_list
1663           = dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
1664       
1665         /* Add the new chain item at the head of the current list.  */
1666
1667         cip->chain_next = def_dec_p->f_list_chain;
1668         def_dec_p->f_list_chain = cip;
1669       }
1670 #endif /* !defined (UNPROTOIZE) */
1671       def_dec_p->f_list_count++;
1672
1673       p = left_paren_p - 2;
1674
1675       /* p must now point either to another right paren, or to the last
1676          character of the name of the function that was declared/defined.
1677          If p points to another right paren, then this indicates that we
1678          are dealing with multiple formals lists.  In that case, there
1679          really should be another right paren preceding this right paren.  */
1680
1681       if (*p != ')')
1682         break;
1683       else
1684         check_aux_info (*--p == ')');
1685     }
1686
1687
1688   {
1689     const char *past_fn = p + 1;
1690
1691     check_aux_info (*past_fn == ' ');
1692
1693     /* Scan leftwards over the identifier that names the function.  */
1694
1695     while (is_id_char (*p))
1696       p--;
1697     p++;
1698
1699     /* p now points to the leftmost character of the function name.  */
1700
1701     {
1702       char *fn_string = (char *) alloca (past_fn - p + 1);
1703
1704       strncpy (fn_string, p, (size_t) (past_fn - p));
1705       fn_string[past_fn-p] = '\0';
1706       def_dec_p->hash_entry = lookup (function_name_primary, fn_string);
1707     }
1708   }
1709
1710   /* Look at all of the defs and decs for this function name that we have
1711      collected so far.  If there is already one which is at the same
1712      line number in the same file, then we can discard this new def_dec_info
1713      record.
1714
1715      As an extra assurance that any such pair of (nominally) identical
1716      function declarations are in fact identical, we also compare the
1717      ansi_decl parts of the lines from the aux_info files just to be on
1718      the safe side.
1719
1720      This comparison will fail if (for instance) the user was playing
1721      messy games with the preprocessor which ultimately causes one
1722      function declaration in one header file to look differently when
1723      that file is included by two (or more) other files.  */
1724
1725   {
1726     const def_dec_info *other;
1727
1728     for (other = def_dec_p->hash_entry->ddip; other; other = other->next_for_func)
1729       {
1730         if (def_dec_p->line == other->line && def_dec_p->file == other->file)
1731           {
1732             if (strcmp (def_dec_p->ansi_decl, other->ansi_decl))
1733               {
1734                 fprintf (stderr, "%s:%d: declaration of function `%s' takes different forms\n",
1735                          def_dec_p->file->hash_entry->symbol,
1736                          def_dec_p->line,
1737                          def_dec_p->hash_entry->symbol);
1738                 exit (1);
1739               }
1740             free_def_dec (def_dec_p);
1741             return;
1742           }
1743       }
1744   }
1745
1746 #ifdef UNPROTOIZE
1747
1748   /* If we are doing unprotoizing, we must now setup the pointers that will
1749      point to the K&R name list and to the K&R argument declarations list.
1750
1751      Note that if this is only a function declaration, then we should not
1752      expect to find any K&R style formals list following the ANSI-style
1753      formals list.  This is because GCC knows that such information is
1754      useless in the case of function declarations (function definitions
1755      are a different story however).
1756
1757      Since we are unprotoizing, we don't need any such lists anyway.
1758      All we plan to do is to delete all characters between ()'s in any
1759      case.  */
1760
1761   def_dec_p->formal_names = NULL;
1762   def_dec_p->formal_decls = NULL;
1763
1764   if (def_dec_p->is_func_def)
1765     {
1766       p = semicolon_p;
1767       check_aux_info (*++p == ' ');
1768       check_aux_info (*++p == '/');
1769       check_aux_info (*++p == '*');
1770       check_aux_info (*++p == ' ');
1771       check_aux_info (*++p == '(');
1772
1773       {
1774         const char *kr_names_start = ++p;   /* Point just inside '('. */
1775
1776         while (*p++ != ')')
1777           continue;
1778         p--;            /* point to closing right paren */
1779
1780         /* Make a copy of the K&R parameter names list.  */
1781
1782         def_dec_p->formal_names
1783           = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
1784       }
1785
1786       check_aux_info (*++p == ' ');
1787       p++;
1788
1789       /* p now points to the first character of the K&R style declarations
1790          list (if there is one) or to the star-slash combination that ends
1791          the comment in which such lists get embedded.  */
1792
1793       /* Make a copy of the K&R formal decls list and set the def_dec record
1794          to point to it.  */
1795
1796       if (*p == '*')            /* Are there no K&R declarations? */
1797         {
1798           check_aux_info (*++p == '/');
1799           def_dec_p->formal_decls = "";
1800         }
1801       else
1802         {
1803           const char *kr_decls_start = p;
1804
1805           while (p[0] != '*' || p[1] != '/')
1806             p++;
1807           p--;
1808
1809           check_aux_info (*p == ' ');
1810
1811           def_dec_p->formal_decls
1812             = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1813         }
1814
1815       /* Handle a special case.  If we have a function definition marked as
1816          being in "old" style, and if it's formal names list is empty, then
1817          it may actually have the string "void" in its real formals list
1818          in the original source code.  Just to make sure, we will get setup
1819          to convert such things anyway.
1820
1821          This kludge only needs to be here because of an insurmountable
1822          problem with generating .X files.  */
1823
1824       if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1825         def_dec_p->prototyped = 1;
1826     }
1827
1828   /* Since we are unprotoizing, if this item is already in old (K&R) style,
1829      we can just ignore it.  If that is true, throw away the itme now.  */
1830
1831   if (!def_dec_p->prototyped)
1832     {
1833       free_def_dec (def_dec_p);
1834       return;
1835     }
1836
1837 #endif /* defined (UNPROTOIZE) */
1838
1839   /* Add this record to the head of the list of records pertaining to this
1840      particular function name.  */
1841
1842   def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
1843   def_dec_p->hash_entry->ddip = def_dec_p;
1844
1845   /* Add this new def_dec_info record to the sorted list of def_dec_info
1846      records for this file.  Note that we don't have to worry about duplicates
1847      (caused by multiple inclusions of header files) here because we have
1848      already eliminated duplicates above.  */
1849
1850   if (!def_dec_p->file->defs_decs)
1851     {
1852       def_dec_p->file->defs_decs = def_dec_p;
1853       def_dec_p->next_in_file = NULL;
1854     }
1855   else
1856     {
1857       int line = def_dec_p->line;
1858       const def_dec_info *prev = NULL;
1859       const def_dec_info *curr = def_dec_p->file->defs_decs;
1860       const def_dec_info *next = curr->next_in_file;
1861
1862       while (next && (line < curr->line))
1863         {
1864           prev = curr;
1865           curr = next;
1866           next = next->next_in_file;
1867         }
1868       if (line >= curr->line)
1869         {
1870           def_dec_p->next_in_file = curr;
1871           if (prev)
1872             ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1873           else
1874             def_dec_p->file->defs_decs = def_dec_p;
1875         }
1876       else      /* assert (next == NULL); */
1877         {
1878           ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1879           /* assert (next == NULL); */
1880           def_dec_p->next_in_file = next;
1881         }
1882     }
1883 }
1884 \f
1885 /* Set up the vector COMPILE_PARAMS which is the argument list for running GCC.
1886    Also set input_file_name_index and aux_info_file_name_index
1887    to the indices of the slots where the file names should go.  */
1888
1889 /* We initialize the vector by  removing -g, -O, -S, -c, and -o options,
1890    and adding '-aux-info AUXFILE -S  -o /dev/null INFILE' at the end.  */
1891
1892 static void
1893 munge_compile_params (params_list)
1894      const char *params_list;
1895 {
1896   /* Build up the contents in a temporary vector
1897      that is so big that to has to be big enough.  */
1898   const char **temp_params
1899     = (const char **) alloca ((strlen (params_list) + 8) * sizeof (char *));
1900   int param_count = 0;
1901   const char *param;
1902
1903   temp_params[param_count++] = compiler_file_name;
1904   for (;;)
1905     {
1906       while (isspace (*params_list))
1907         params_list++;
1908       if (!*params_list)
1909         break;
1910       param = params_list;
1911       while (*params_list && !isspace (*params_list))
1912         params_list++;
1913       if (param[0] != '-')
1914         temp_params[param_count++]
1915           = dupnstr (param, (size_t) (params_list - param));
1916       else
1917         {
1918           switch (param[1])
1919             {
1920               case 'g':
1921               case 'O':
1922               case 'S':
1923               case 'c':
1924                 break;          /* Don't copy these.  */
1925               case 'o':
1926                 while (isspace (*params_list))
1927                   params_list++;
1928                 while (*params_list && !isspace (*params_list))
1929                   params_list++;
1930                 break;
1931               default:
1932                 temp_params[param_count++]
1933                   = dupnstr (param, (size_t) (params_list - param));
1934             }
1935         }
1936       if (!*params_list)
1937         break;
1938     }
1939   temp_params[param_count++] = "-aux-info";
1940
1941   /* Leave room for the aux-info file name argument.  */
1942   aux_info_file_name_index = param_count;
1943   temp_params[param_count++] = NULL;
1944
1945   temp_params[param_count++] = "-S";
1946   temp_params[param_count++] = "-o";
1947   temp_params[param_count++] = "/dev/null";
1948
1949   /* Leave room for the input file name argument.  */
1950   input_file_name_index = param_count;
1951   temp_params[param_count++] = NULL;
1952   /* Terminate the list.  */
1953   temp_params[param_count++] = NULL;
1954
1955   /* Make a copy of the compile_params in heap space.  */
1956
1957   compile_params
1958     = (const char **) xmalloc (sizeof (char *) * (param_count+1));
1959   memcpy (compile_params, temp_params, sizeof (char *) * param_count);
1960 }
1961
1962 /* Do a recompilation for the express purpose of generating a new aux_info
1963    file to go with a specific base source file.  */
1964
1965 static int
1966 gen_aux_info_file (base_filename)
1967      const char *base_filename;
1968 {
1969   int child_pid;
1970
1971   if (!input_file_name_index)
1972     munge_compile_params ("");
1973
1974   /* Store the full source file name in the argument vector.  */
1975   compile_params[input_file_name_index] = shortpath (NULL, base_filename);
1976   /* Add .X to source file name to get aux-info file name.  */
1977   compile_params[aux_info_file_name_index]
1978     = savestring2 (compile_params[input_file_name_index],
1979                    strlen (compile_params[input_file_name_index]),
1980                    ".X",
1981                    2);
1982
1983   if (!quiet_flag)
1984     fprintf (stderr, "%s: compiling `%s'\n",
1985              pname, compile_params[input_file_name_index]);
1986
1987   if (child_pid = fork ())
1988     {
1989       if (child_pid == -1)
1990         {
1991           fprintf (stderr, "%s: could not fork process: %s\n",
1992                    pname, sys_errlist[errno]);
1993           return 0;
1994         }
1995
1996 #if 0
1997       /* Print out the command line that the other process is now executing.  */
1998
1999       if (!quiet_flag)
2000         {
2001           const char **arg;
2002   
2003           fputs ("\t", stderr);
2004           for (arg = compile_params; *arg; arg++)
2005             {
2006               fputs (*arg, stderr);
2007               fputc (' ', stderr);
2008             }
2009           fputc ('\n', stderr);
2010           fflush (stderr);
2011         }
2012 #endif /* 0 */
2013
2014       {
2015         int wait_status;
2016
2017         if (wait (&wait_status) == -1)
2018           {
2019             fprintf (stderr, "%s: wait failed: %s\n",
2020                      pname, sys_errlist[errno]);
2021             return 0;
2022           }
2023         if ((wait_status & 0x7F) != 0)
2024           {
2025             fprintf (stderr, "%s: subprocess got fatal signal %d",
2026                      pname, (wait_status & 0x7F));
2027             return 0;
2028           }
2029         if (((wait_status & 0xFF00) >> 8) != 0)
2030           {
2031             fprintf (stderr, "%s: %s exited with status %d\n",
2032                      pname, base_filename, ((wait_status & 0xFF00) >> 8));
2033             return 0;
2034           }
2035         return 1;
2036       }
2037     }
2038   else
2039     {
2040       if (my_execvp (compile_params[0], (char *const *) compile_params))
2041         {
2042           int e = errno, f = fileno (stderr);
2043           write (f, pname, strlen (pname));
2044           write (f, ": ", 2);
2045           write (f, compile_params[0], strlen (compile_params[0]));
2046           write (f, ": ", 2);
2047           write (f, sys_errlist[e], strlen (sys_errlist[e]));
2048           write (f, "\n", 1);
2049           _exit (1);
2050         }
2051       return 1;         /* Never executed.  */
2052     }
2053 }
2054 \f
2055 /* Read in all of the information contained in a single aux_info file.
2056    Save all of the important stuff for later.  */
2057
2058 static void
2059 process_aux_info_file (base_source_filename, keep_it, is_syscalls)
2060      const char *base_source_filename;
2061      int keep_it;
2062      int is_syscalls;
2063 {
2064   size_t base_len = strlen (base_source_filename);
2065   char * aux_info_filename
2066     = (char *) alloca (base_len + strlen (aux_info_suffix) + 1);
2067   char *aux_info_base;
2068   char *aux_info_limit;
2069   char *aux_info_relocated_name;
2070   const char *aux_info_second_line;
2071   time_t aux_info_mtime;
2072   size_t aux_info_size;
2073   int must_create;
2074
2075   /* Construct the aux_info filename from the base source filename.  */
2076
2077   strcpy (aux_info_filename, base_source_filename);
2078   strcat (aux_info_filename, aux_info_suffix);
2079
2080   /* Check that the aux_info file exists and is readable.  If it does not
2081      exist, try to create it (once only).  */
2082
2083   /* If file doesn't exist, set must_create.
2084      Likewise if it exists and we can read it but it is obsolete.
2085      Otherwise, report an error.  */
2086   must_create = 0;
2087
2088   /* Come here with must_create set to 1 if file is out of date.  */
2089 start_over: ;
2090
2091   if (my_access (aux_info_filename, R_OK) == -1)
2092     {
2093       if (errno == ENOENT)
2094         {
2095           if (is_syscalls)
2096             {
2097               fprintf (stderr, "%s: warning: missing SYSCALLS file `%s'\n",
2098                        pname, aux_info_filename);
2099               return;
2100             }
2101           must_create = 1;
2102         }
2103       else
2104         {
2105           fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
2106                    pname, shortpath (NULL, aux_info_filename),
2107                    sys_errlist[errno]);
2108           errors++;
2109           return;
2110         }
2111     }
2112 #if 0 /* There is code farther down to take care of this.  */
2113   else
2114     {
2115       struct stat s1, s2;
2116       stat (aux_info_file_name, &s1);
2117       stat (base_source_file_name, &s2);
2118       if (s2.st_mtime > s1.st_mtime)
2119         must_create = 1;
2120     }
2121 #endif /* 0 */
2122
2123   /* If we need a .X file, create it, and verify we can read it.  */
2124   if (must_create)
2125     {
2126       if (!gen_aux_info_file (base_source_filename))
2127         {
2128           errors++;
2129           return;
2130         }
2131       if (my_access (aux_info_filename, R_OK) == -1)
2132         {
2133           fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
2134                    pname, shortpath (NULL, aux_info_filename),
2135                    sys_errlist[errno]);
2136           errors++;
2137           return;
2138         }
2139     }
2140
2141   {
2142     struct stat stat_buf;
2143
2144     /* Get some status information about this aux_info file.  */
2145   
2146     if (my_stat (aux_info_filename, &stat_buf) == -1)
2147       {
2148         fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
2149                  pname, shortpath (NULL, aux_info_filename),
2150                  sys_errlist[errno]);
2151         errors++;
2152         return;
2153       }
2154   
2155     /* Check on whether or not this aux_info file is zero length.  If it is,
2156        then just ignore it and return.  */
2157   
2158     if ((aux_info_size = stat_buf.st_size) == 0)
2159       return;
2160   
2161     /* Get the date/time of last modification for this aux_info file and
2162        remember it.  We will have to check that any source files that it
2163        contains information about are at least this old or older.  */
2164   
2165     aux_info_mtime = stat_buf.st_mtime;
2166
2167     if (!is_syscalls)
2168       {
2169         /* Compare mod time with the .c file; update .X file if obsolete.
2170            The code later on can fail to check the .c file
2171            if it did not directly define any functions.  */
2172
2173         if (my_stat (base_source_filename, &stat_buf) == -1)
2174           {
2175             fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
2176                      pname, shortpath (NULL, base_source_filename),
2177                      sys_errlist[errno]);
2178             errors++;
2179             return;
2180           }
2181         if (stat_buf.st_mtime > aux_info_mtime)
2182           {
2183             must_create = 1;
2184             goto start_over;
2185           }
2186       }
2187   }
2188
2189   {
2190     int aux_info_file;
2191
2192     /* Open the aux_info file.  */
2193   
2194     if ((aux_info_file = my_open (aux_info_filename, O_RDONLY, 0444 )) == -1)
2195       {
2196         fprintf (stderr, "%s: can't open aux info file `%s' for reading: %s\n",
2197                  pname, shortpath (NULL, aux_info_filename),
2198                  sys_errlist[errno]);
2199         return;
2200       }
2201   
2202     /* Allocate space to hold the aux_info file in memory.  */
2203   
2204     aux_info_base = xmalloc (aux_info_size + 1);
2205     aux_info_limit = aux_info_base + aux_info_size;
2206     *aux_info_limit = '\0';
2207   
2208     /* Read the aux_info file into memory.  */
2209   
2210     if (read (aux_info_file, aux_info_base, aux_info_size) != aux_info_size)
2211       {
2212         fprintf (stderr, "%s: error reading aux info file `%s': %s\n",
2213                  pname, shortpath (NULL, aux_info_filename),
2214                  sys_errlist[errno]);
2215         free (aux_info_base);
2216         close (aux_info_file);
2217         return;
2218       }
2219   
2220     /* Close the aux info file.  */
2221   
2222     if (close (aux_info_file))
2223       {
2224         fprintf (stderr, "%s: error closing aux info file `%s': %s\n",
2225                  pname, shortpath (NULL, aux_info_filename),
2226                  sys_errlist[errno]);
2227         free (aux_info_base);
2228         close (aux_info_file);
2229         return;
2230       }
2231   }
2232
2233   /* Delete the aux_info file (unless requested not to).  If the deletion
2234      fails for some reason, don't even worry about it.  */
2235
2236   if (must_create && !keep_it)
2237     if (my_unlink (aux_info_filename) == -1)
2238       fprintf (stderr, "%s: can't delete aux info file `%s': %s\n",
2239                pname, shortpath (NULL, aux_info_filename),
2240                sys_errlist[errno]);
2241
2242   /* Save a pointer into the first line of the aux_info file which
2243      contains the filename of the directory from which the compiler
2244      was invoked when the associated source file was compiled.
2245      This information is used later to help create complete
2246      filenames out of the (potentially) relative filenames in
2247      the aux_info file.  */
2248
2249   {
2250     char *p = aux_info_base;
2251
2252     while (*p != ':')
2253       p++;
2254     p++;
2255     while (*p == ' ')
2256       p++;
2257     invocation_filename = p;    /* Save a pointer to first byte of path.  */
2258     while (*p != ' ')
2259       p++;
2260     *p++ = '/';
2261     *p++ = '\0';
2262     while (*p++ != '\n')
2263       continue;
2264     aux_info_second_line = p;
2265     aux_info_relocated_name = 0;
2266     if (invocation_filename[0] != '/')
2267       {
2268         /* INVOCATION_FILENAME is relative;
2269            append it to BASE_SOURCE_FILENAME's dir.  */
2270         char *dir_end;
2271         aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
2272         strcpy (aux_info_relocated_name, base_source_filename);
2273         dir_end = rindex (aux_info_relocated_name, '/');
2274         if (dir_end)
2275           dir_end++;
2276         else
2277           dir_end = aux_info_relocated_name;
2278         strcpy (dir_end, invocation_filename);
2279         invocation_filename = aux_info_relocated_name;
2280       }
2281   }
2282
2283
2284   {
2285     const char *aux_info_p;
2286
2287     /* Do a pre-pass on the lines in the aux_info file, making sure that all
2288        of the source files referenced in there are at least as old as this
2289        aux_info file itself.  If not, go back and regenerate the aux_info
2290        file anew.  Don't do any of this for the syscalls file.  */
2291
2292     if (!is_syscalls)
2293       {
2294         current_aux_info_lineno = 2;
2295     
2296         for (aux_info_p = aux_info_second_line; *aux_info_p; )
2297           {
2298             if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2299               {
2300                 free (aux_info_base);
2301                 xfree (aux_info_relocated_name);
2302                 if (keep_it && my_unlink (aux_info_filename) == -1)
2303                   {
2304                     fprintf (stderr, "%s: can't delete file `%s': %s\n",
2305                              pname, shortpath (NULL, aux_info_filename),
2306                              sys_errlist[errno]);
2307                     return;
2308                   }
2309                 goto start_over;
2310               }
2311     
2312             /* Skip over the rest of this line to start of next line.  */
2313     
2314             while (*aux_info_p != '\n')
2315               aux_info_p++;
2316             aux_info_p++;
2317             current_aux_info_lineno++;
2318           }
2319       }
2320
2321     /* Now do the real pass on the aux_info lines.  Save their information in
2322        the in-core data base.  */
2323   
2324     current_aux_info_lineno = 2;
2325   
2326     for (aux_info_p = aux_info_second_line; *aux_info_p;)
2327       {
2328         char *unexpanded_line = unexpand_if_needed (aux_info_p);
2329   
2330         if (unexpanded_line)
2331           {
2332             save_def_or_dec (unexpanded_line, is_syscalls);
2333             free (unexpanded_line);
2334           }
2335         else
2336           save_def_or_dec (aux_info_p, is_syscalls);
2337   
2338         /* Skip over the rest of this line and get to start of next line.  */
2339   
2340         while (*aux_info_p != '\n')
2341           aux_info_p++;
2342         aux_info_p++;
2343         current_aux_info_lineno++;
2344       }
2345   }
2346
2347   free (aux_info_base);
2348   xfree (aux_info_relocated_name);
2349 }
2350 \f
2351 #ifndef UNPROTOIZE
2352
2353 /* Check an individual filename for a .c suffix.  If the filename has this
2354    suffix, rename the file such that its suffix is changed to .C.  This
2355    function implements the -C option.  */
2356
2357 static void
2358 rename_c_file (hp)
2359      const hash_table_entry *hp;
2360 {
2361   const char *filename = hp->symbol;
2362   int last_char_index = strlen (filename) - 1;
2363   char *const new_filename = (char *) alloca (strlen (filename) + 1);
2364
2365   /* Note that we don't care here if the given file was converted or not.  It
2366      is possible that the given file was *not* converted, simply because there
2367      was nothing in it which actually required conversion.  Even in this case,
2368      we want to do the renaming.  Note that we only rename files with the .c
2369      suffix.  */
2370
2371   if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.')
2372     return;
2373
2374   strcpy (new_filename, filename);
2375   new_filename[last_char_index] = 'C';
2376
2377   if (my_link (filename, new_filename) == -1)
2378     {
2379       fprintf (stderr, "%s: warning: can't link file `%s' to `%s': %s\n",
2380                pname, shortpath (NULL, filename),
2381                shortpath (NULL, new_filename), sys_errlist[errno]);
2382       errors++;
2383       return;
2384     }
2385
2386   if (my_unlink (filename) == -1)
2387     {
2388       fprintf (stderr, "%s: warning: can't delete file `%s': %s\n",
2389                pname, shortpath (NULL, filename), sys_errlist[errno]);
2390       errors++;
2391       return;
2392     }
2393 }
2394
2395 #endif /* !defined (UNPROTOIZE) */
2396 \f
2397 /* Take the list of definitions and declarations attached to a particular
2398    file_info node and reverse the order of the list.  This should get the
2399    list into an order such that the item with the lowest associated line
2400    number is nearest the head of the list.  When these lists are originally
2401    built, they are in the opposite order.  We want to traverse them in
2402    normal line number order later (i.e. lowest to highest) so reverse the
2403    order here.  */
2404
2405 static void
2406 reverse_def_dec_list (hp)
2407      const hash_table_entry *hp;
2408 {
2409   file_info *file_p = hp->fip;
2410   const def_dec_info *prev = NULL;
2411   const def_dec_info *current = file_p->defs_decs;
2412
2413   if (!( current = file_p->defs_decs))
2414     return;                     /* no list to reverse */
2415
2416   prev = current;
2417   if (! (current = current->next_in_file))
2418     return;                     /* can't reverse a single list element */
2419
2420   ((NONCONST def_dec_info *) prev)->next_in_file = NULL;
2421
2422   while (current)
2423     {
2424       const def_dec_info *next = current->next_in_file;
2425
2426       ((NONCONST def_dec_info *) current)->next_in_file = prev;
2427       prev = current;
2428       current = next;
2429     }
2430
2431   file_p->defs_decs = prev;
2432 }
2433
2434 #ifndef UNPROTOIZE
2435
2436 /* Find the (only?) extern definition for a particular function name, starting
2437    from the head of the linked list of entries for the given name.  If we
2438    cannot find an extern definition for the given function name, issue a
2439    warning and scrounge around for the next best thing, i.e. an extern
2440    function declaration with a prototype attached to it.  Note that we only
2441    allow such substitutions for extern declarations and never for static
2442    declarations.  That's because the only reason we allow them at all is
2443    to let un-prototyped function declarations for system-supplied library
2444    functions get their prototypes from our own extra SYSCALLS.c.X file which
2445    contains all of the correct prototypes for system functions.  */
2446
2447 static const def_dec_info *
2448 find_extern_def (head, user)
2449      const def_dec_info *head;
2450      const def_dec_info *user;
2451 {
2452   const def_dec_info *dd_p;
2453   const def_dec_info *extern_def_p = NULL;
2454   int conflict_noted = 0;
2455
2456   /* Don't act too stupid here.  Somebody may try to convert an entire system
2457      in one swell fwoop (rather than one program at a time, as should be done)
2458      and in that case, we may find that there are multiple extern definitions
2459      of a given function name in the entire set of source files that we are
2460      converting.  If however one of these definitions resides in exactly the
2461      same source file as the reference we are trying to satisfy then in that
2462      case it would be stupid for us to fail to realize that this one definition
2463      *must* be the precise one we are looking for.
2464
2465      To make sure that we don't miss an opportunity to make this "same file"
2466      leap of faith, we do a prescan of the list of records relating to the
2467      given function name, and we look (on this first scan) *only* for a
2468      definition of the function which is in the same file as the reference
2469      we are currently trying to satisfy.  */
2470
2471   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2472     if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
2473       return dd_p;
2474
2475   /* Now, since we have not found a definition in the same file as the
2476      reference, we scan the list again and consider all possibilities from
2477      all files.  Here we may get conflicts with the things listed in the
2478      SYSCALLS.c.X file, but if that happens it only means that the source
2479      code being converted contains its own definition of a function which
2480      could have been supplied by libc.a.  In such cases, we should avoid
2481      issuing the normal warning, and defer to the definition given in the
2482      user's own code.   */
2483
2484   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2485     if (dd_p->is_func_def && !dd_p->is_static)
2486       {
2487         if (!extern_def_p)      /* Previous definition? */
2488           extern_def_p = dd_p;  /* Remember the first definition found. */
2489         else
2490           {
2491             /* Ignore definition just found if it came from SYSCALLS.c.X.  */
2492
2493             if (is_syscalls_file (dd_p->file))
2494               continue;
2495
2496             /* Quietly replace the definition previously found with the one
2497                just found if the previous one was from SYSCALLS.c.X.  */
2498
2499             if (is_syscalls_file (extern_def_p->file))
2500               {
2501                 extern_def_p = dd_p;
2502                 continue;
2503               }
2504
2505             /* If we get here, then there is a conflict between two function
2506                declarations for the same function, both of which came from the
2507                user's own code.  */
2508
2509             if (!conflict_noted)        /* first time we noticed? */
2510               {
2511                 conflict_noted = 1;
2512                 fprintf (stderr, "%s: conflicting extern definitions of '%s'\n",
2513                          pname, head->hash_entry->symbol);
2514                 if (!quiet_flag)
2515                   {
2516                     fprintf (stderr, "%s: declarations of '%s' will not be converted\n",
2517                              pname, head->hash_entry->symbol);
2518                     fprintf (stderr, "%s: conflict list for '%s' follows:\n",
2519                              pname, head->hash_entry->symbol);
2520                     fprintf (stderr, "%s:     %s(%d): %s\n",
2521                              pname,
2522                              shortpath (NULL, extern_def_p->file->hash_entry->symbol),
2523                              extern_def_p->line, extern_def_p->ansi_decl);
2524                   }
2525               }
2526             if (!quiet_flag)
2527               fprintf (stderr, "%s:     %s(%d): %s\n",
2528                        pname,
2529                        shortpath (NULL, dd_p->file->hash_entry->symbol),
2530                        dd_p->line, dd_p->ansi_decl);
2531           }
2532       }
2533
2534   /* We want to err on the side of caution, so if we found multiple conflicting
2535      definitions for the same function, treat this as being that same as if we
2536      had found no definitions (i.e. return NULL).  */
2537
2538   if (conflict_noted)
2539     return NULL;
2540
2541   if (!extern_def_p)
2542     {
2543       /* We have no definitions for this function so do the next best thing.
2544          Search for an extern declaration already in prototype form.  */
2545
2546       for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2547         if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2548           {
2549             extern_def_p = dd_p;        /* save a pointer to the definition */
2550             if (!quiet_flag)
2551               fprintf (stderr, "%s: warning: using formals list from %s(%d) for function `%s'\n",
2552                        pname,
2553                        shortpath (NULL, dd_p->file->hash_entry->symbol),
2554                        dd_p->line, dd_p->hash_entry->symbol);
2555             break;
2556           }
2557
2558       /* Gripe about unprototyped function declarations that we found no
2559          corresponding definition (or other source of prototype information)
2560          for.
2561
2562          Gripe even if the unprototyped declaration we are worried about
2563          exists in a file in one of the "system" include directories.  We
2564          can gripe about these because we should have at least found a
2565          corresponding (pseudo) definition in the SYSCALLS.c.X file.  If we
2566          didn't, then that means that the SYSCALLS.c.X file is missing some
2567          needed prototypes for this particular system.  That is worth telling
2568          the user about!  */
2569
2570       if (!extern_def_p)
2571         {
2572           const char *file = user->file->hash_entry->symbol;
2573
2574           if (!quiet_flag)
2575             if (in_system_include_dir (file))
2576               {
2577                 /* Why copy this string into `needed' at all?
2578                    Why not just use user->ansi_decl without copying?  */
2579                 char *needed = (char *) alloca (strlen (user->ansi_decl) + 1);
2580                 char *p;
2581
2582                 strcpy (needed, user->ansi_decl);
2583                 p = (NONCONST char *) substr (needed, user->hash_entry->symbol)
2584                     + strlen (user->hash_entry->symbol) + 2;
2585                 /* Avoid having ??? in the string.  */
2586                 *p++ = '?';
2587                 *p++ = '?';
2588                 *p++ = '?';
2589                 strcpy (p, ");");
2590
2591                 fprintf (stderr, "%s: %d: `%s' used but missing from SYSCALLS\n",
2592                          shortpath (NULL, file), user->line,
2593                          needed+7);     /* Don't print "extern " */
2594               }
2595 #if 0
2596             else
2597               fprintf (stderr, "%s: %d: warning: no extern definition for `%s'\n",
2598                        shortpath (NULL, file), user->line,
2599                        user->hash_entry->symbol);
2600 #endif
2601         }
2602     }
2603   return extern_def_p;
2604 }
2605 \f
2606 /* Find the (only?) static definition for a particular function name in a
2607    given file.  Here we get the function-name and the file info indirectly
2608    from the def_dec_info record pointer which is passed in. */
2609
2610 static const def_dec_info *
2611 find_static_definition (user)
2612      const def_dec_info *user;
2613 {
2614   const def_dec_info *head = user->hash_entry->ddip;
2615   const def_dec_info *dd_p;
2616   int num_static_defs = 0;
2617   const def_dec_info *static_def_p = NULL;
2618
2619   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2620     if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
2621       {
2622         static_def_p = dd_p;    /* save a pointer to the definition */
2623         num_static_defs++;
2624       }
2625   if (num_static_defs == 0)
2626     {
2627       if (!quiet_flag)
2628         fprintf (stderr, "%s: warning: no static definition for `%s' in file `%s'\n",
2629                  pname, head->hash_entry->symbol,
2630                  shortpath (NULL, user->file->hash_entry->symbol));
2631     }
2632   else if (num_static_defs > 1)
2633     {
2634       fprintf (stderr, "%s: multiple static defs of `%s' in file `%s'\n",
2635                pname, head->hash_entry->symbol,
2636                shortpath (NULL, user->file->hash_entry->symbol));
2637       return NULL;
2638     }
2639   return static_def_p;
2640 }
2641
2642 /* Find good prototype style formal argument lists for all of the function
2643    declarations which didn't have them before now.
2644
2645    To do this we consider each function name one at a time.  For each function
2646    name, we look at the items on the linked list of def_dec_info records for
2647    that particular name.
2648
2649    Somewhere on this list we should find one (and only one) def_dec_info
2650    record which represents the actual function definition, and this record
2651    should have a nice formal argument list already associated with it.
2652
2653    Thus, all we have to do is to connect up all of the other def_dec_info
2654    records for this particular function name to the special one which has
2655    the full-blown formals list.
2656
2657    Of course it is a little more complicated than just that.  See below for
2658    more details.  */
2659
2660 static void
2661 connect_defs_and_decs (hp)
2662      const hash_table_entry *hp;
2663 {
2664   const def_dec_info *dd_p;
2665   const def_dec_info *extern_def_p = NULL;
2666   int first_extern_reference = 1;
2667
2668   /* Traverse the list of definitions and declarations for this particular
2669      function name.  For each item on the list, if it is a function
2670      definition (either old style or new style) then GCC has already been
2671      kind enough to produce a prototype for us, and it is associated with
2672      the item already, so declare the item as its own associated "definition".
2673
2674      Also, for each item which is only a function declaration, but which
2675      nonetheless has its own prototype already (obviously supplied by the user)
2676      declare the item as it's own definition.
2677
2678      Note that when/if there are multiple user-supplied prototypes already
2679      present for multiple declarations of any given function, these multiple
2680      prototypes *should* all match exactly with one another and with the
2681      prototype for the actual function definition.  We don't check for this
2682      here however, since we assume that the compiler must have already done
2683      this consistency checking when it was creating the .X files.  */
2684
2685   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2686     if (dd_p->prototyped)
2687       ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
2688
2689   /* Traverse the list of definitions and declarations for this particular
2690      function name.  For each item on the list, if it is an extern function
2691      declaration and if it has no associated definition yet, go try to find
2692      the matching extern definition for the declaration.
2693
2694      When looking for the matching function definition, warn the user if we
2695      fail to find one.
2696
2697      If we find more that one function definition also issue a warning.
2698
2699      Do the search for the matching definition only once per unique function
2700      name (and only when absolutely needed) so that we can avoid putting out
2701      redundant warning messages, and so that we will only put out warning
2702      messages when there is actually a reference (i.e. a declaration) for
2703      which we need to find a matching definition.  */
2704
2705   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2706     if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
2707       {
2708         if (first_extern_reference)
2709           {
2710             extern_def_p = find_extern_def (hp->ddip, dd_p);
2711             first_extern_reference = 0;
2712           }
2713         ((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
2714       }
2715
2716   /* Traverse the list of definitions and declarations for this particular
2717      function name.  For each item on the list, if it is a static function
2718      declaration and if it has no associated definition yet, go try to find
2719      the matching static definition for the declaration within the same file.
2720
2721      When looking for the matching function definition, warn the user if we
2722      fail to find one in the same file with the declaration, and refuse to
2723      convert this kind of cross-file static function declaration.  After all,
2724      this is stupid practice and should be discouraged.
2725
2726      We don't have to worry about the possibility that there is more than one
2727      matching function definition in the given file because that would have
2728      been flagged as an error by the compiler.
2729
2730      Do the search for the matching definition only once per unique
2731      function-name/source-file pair (and only when absolutely needed) so that
2732      we can avoid putting out redundant warning messages, and so that we will
2733      only put out warning messages when there is actually a reference (i.e. a
2734      declaration) for which we actually need to find a matching definition.  */
2735
2736   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2737     if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
2738       {
2739         const def_dec_info *dd_p2;
2740         const def_dec_info *static_def;
2741
2742         /* We have now found a single static declaration for which we need to
2743            find a matching definition.  We want to minimize the work (and the
2744            number of warnings), so we will find an appropriate (matching)
2745            static definition for this declaration, and then distribute it
2746            (as the definition for) any and all other static declarations
2747            for this function name which occur within the same file, and which
2748            do not already have definitions.
2749
2750            Note that a trick is used here to prevent subsequent attempts to
2751            call find_static_definition for a given function-name & file
2752            if the first such call returns NULL.  Essentially, we convert
2753            these NULL return values to -1, and put the -1 into the definition
2754            field for each other static declaration from the same file which
2755            does not already have an associated definition.
2756            This makes these other static declarations look like they are
2757            actually defined already when the outer loop here revisits them
2758            later on.  Thus, the outer loop will skip over them.  Later, we
2759            turn the -1's back to NULL's.  */
2760
2761       ((NONCONST def_dec_info *) dd_p)->definition =
2762         (static_def = find_static_definition (dd_p))
2763           ? static_def
2764           : (const def_dec_info *) -1;
2765
2766       for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2767         if (!dd_p2->is_func_def && dd_p2->is_static
2768          && !dd_p2->definition && (dd_p2->file == dd_p->file))
2769           ((NONCONST def_dec_info *)dd_p2)->definition = dd_p->definition;
2770       }
2771
2772   /* Convert any dummy (-1) definitions we created in the step above back to
2773      NULL's (as they should be).  */
2774
2775   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2776     if (dd_p->definition == (def_dec_info *) -1)
2777       ((NONCONST def_dec_info *) dd_p)->definition = NULL;
2778 }
2779
2780 #endif /* !defined (UNPROTOIZE) */
2781
2782 /* Give a pointer into the clean text buffer, return a number which is the
2783    original source line number that the given pointer points into.  */
2784
2785 static int
2786 identify_lineno (clean_p)
2787      const char *clean_p;
2788 {
2789   int line_num = 1;
2790   const char *scan_p;
2791
2792   for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
2793     if (*scan_p == '\n')
2794       line_num++;
2795   return line_num;
2796 }
2797
2798 /* Issue an error message and give up on doing this particular edit.  */
2799
2800 static void
2801 declare_source_confusing (clean_p)
2802      const char *clean_p;
2803 {
2804   if (!quiet_flag)
2805     {
2806       if (clean_p == 0)
2807         fprintf (stderr, "%s: %d: warning: source too confusing\n",
2808                  shortpath (NULL, convert_filename), last_known_line_number);
2809       else
2810         fprintf (stderr, "%s: %d: warning: source too confusing\n",
2811                  shortpath (NULL, convert_filename),
2812                  identify_lineno (clean_p));
2813     }
2814   longjmp (source_confusion_recovery, 1);
2815 }
2816
2817 /* Check that a condition which is expected to be true in the original source
2818    code is in fact true.  If not, issue an error message and give up on
2819    converting this particular source file.  */
2820
2821 static void
2822 check_source (cond, clean_p)
2823      int cond;
2824      const char *clean_p;
2825 {
2826   if (!cond)
2827     declare_source_confusing (clean_p);
2828 }
2829
2830 /* If we think of the in-core cleaned text buffer as a memory mapped
2831    file (with the variable last_known_line_start acting as sort of a
2832    file pointer) then we can imagine doing "seeks" on the buffer.  The
2833    following routine implements a kind of "seek" operation for the in-core
2834    (cleaned) copy of the source file.  When finished, it returns a pointer to
2835    the start of a given (numbered) line in the cleaned text buffer.
2836
2837    Note that protoize only has to "seek" in the forward direction on the
2838    in-core cleaned text file buffers, and it never needs to back up.
2839
2840    This routine is made a little bit faster by remembering the line number
2841    (and pointer value) supplied (and returned) from the previous "seek".
2842    This prevents us from always having to start all over back at the top
2843    of the in-core cleaned buffer again.  */
2844
2845 static const char *
2846 seek_to_line (n)
2847      int n;
2848 {
2849   if (n < last_known_line_number)
2850     abort ();
2851
2852   while (n > last_known_line_number)
2853     {
2854       while (*last_known_line_start != '\n')
2855         check_source (++last_known_line_start < clean_text_limit, 0);
2856       last_known_line_start++;
2857       last_known_line_number++;
2858     }
2859   return last_known_line_start;
2860 }
2861
2862 /* Given a pointer to a character in the cleaned text buffer, return a pointer
2863    to the next non-whitepace character which follows it.  */
2864
2865 static const char *
2866 forward_to_next_token_char (ptr)
2867      const char *ptr;
2868 {
2869   for (++ptr; isspace (*ptr); check_source (++ptr < clean_text_limit, 0))
2870     continue;
2871   return ptr;
2872 }
2873
2874 /* Copy a chunk of text of length `len' and starting at `str' to the current
2875    output buffer.  Note that all attempts to add stuff to the current output
2876    buffer ultimately go through here.  */
2877
2878 static void
2879 output_bytes (str, len)
2880      const char *str;
2881      size_t len;
2882 {
2883   if ((repl_write_ptr + 1) + len >= repl_text_limit)
2884     {
2885       size_t new_size = (repl_text_limit - repl_text_base) << 1;
2886       char *new_buf = (char *) xrealloc (repl_text_base, new_size);
2887
2888       repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
2889       repl_text_base = new_buf;
2890       repl_text_limit = new_buf + new_size;
2891     }
2892   memcpy (repl_write_ptr + 1, str, len);
2893   repl_write_ptr += len;
2894 }
2895
2896 /* Copy all bytes (except the trailing null) of a null terminated string to
2897    the current output buffer.  */
2898
2899 static void
2900 output_string (str)
2901      const char *str;
2902 {
2903   output_bytes (str, strlen (str));
2904 }
2905
2906 /* Copy some characters from the original text buffer to the current output
2907    buffer.
2908
2909    This routine takes a pointer argument `p' which is assumed to be a pointer
2910    into the cleaned text buffer.  The bytes which are copied are the `original'
2911    equivalents for the set of bytes between the last value of `clean_read_ptr'
2912    and the argument value `p'.
2913
2914    The set of bytes copied however, comes *not* from the cleaned text buffer,
2915    but rather from the direct counterparts of these bytes within the original
2916    text buffer.
2917
2918    Thus, when this function is called, some bytes from the original text
2919    buffer (which may include original comments and preprocessing directives)
2920    will be copied into the  output buffer.
2921
2922    Note that the request implide when this routine is called includes the
2923    byte pointed to by the argument pointer `p'.  */
2924
2925 static void
2926 output_up_to (p)
2927      const char *p;
2928 {
2929   size_t copy_length = (size_t) (p - clean_read_ptr);
2930   const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
2931
2932   if (copy_length == 0)
2933     return;
2934
2935   output_bytes (copy_start, copy_length);
2936   clean_read_ptr = p;
2937 }
2938
2939 /* Given a pointer to a def_dec_info record which represents some form of
2940    definition of a function (perhaps a real definition, or in lieu of that
2941    perhaps just a declaration with a full prototype) return true if this
2942    function is one which we should avoid converting.  Return false
2943    otherwise.  */
2944
2945 static int
2946 other_variable_style_function (ansi_header)
2947      const char *ansi_header;
2948 {
2949 #ifdef UNPROTOIZE
2950
2951   /* See if we have a stdarg function, or a function which has stdarg style
2952      parameters or a stdarg style return type.  */
2953
2954   return substr (ansi_header, "...") != 0;
2955
2956 #else /* !defined (UNPROTOIZE) */
2957
2958   /* See if we have a varargs function, or a function which has varargs style
2959      parameters or a varargs style return type.  */
2960
2961   const char *p;
2962   int len = strlen (varargs_style_indicator);
2963
2964   for (p = ansi_header; p; )
2965     {
2966       const char *candidate;
2967
2968       if ((candidate = substr (p, varargs_style_indicator)) == 0)
2969         return 0;
2970       else
2971         if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
2972           return 1;
2973         else
2974           p = candidate + 1;
2975     }
2976   return 0;
2977 #endif /* !defined (UNPROTOIZE) */
2978 }
2979
2980 /* Do the editing operation specifically for a function "declaration".  Note
2981    that editing for function "definitions" are handled in a separate routine
2982    below.  */
2983
2984 static void
2985 edit_fn_declaration (def_dec_p, clean_text_p)
2986      const def_dec_info *def_dec_p;
2987      const char *volatile clean_text_p;
2988 {
2989   const char *start_formals;
2990   const char *end_formals;
2991   const char *function_to_edit = def_dec_p->hash_entry->symbol;
2992   size_t func_name_len = strlen (function_to_edit);
2993   const char *end_of_fn_name;
2994
2995 #ifndef UNPROTOIZE
2996
2997   const f_list_chain_item *this_f_list_chain_item;
2998   const def_dec_info *definition = def_dec_p->definition;
2999
3000   /* If we are protoizing, and if we found no corresponding definition for
3001      this particular function declaration, then just leave this declaration
3002      exactly as it is.  */
3003
3004   if (!definition)
3005     return;
3006
3007   /* If we are protoizing, and if the corresponding definition that we found
3008      for this particular function declaration defined an old style varargs
3009      function, then we want to issue a warning and just leave this function
3010      declaration unconverted.  */
3011
3012   if (other_variable_style_function (definition->ansi_decl))
3013     {
3014       if (!quiet_flag)
3015         fprintf (stderr, "%s: %d: warning: varargs function declaration not converted\n",
3016                  shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3017                  def_dec_p->line);
3018       return;
3019     }
3020
3021 #endif /* !defined (UNPROTOIZE) */
3022
3023   /* Setup here to recover from confusing source code detected during this
3024      particular "edit".  */
3025
3026   save_pointers ();
3027   if (setjmp (source_confusion_recovery))
3028     {
3029       restore_pointers ();
3030       fprintf (stderr, "%s: declaration of function `%s' not converted\n",
3031                pname, function_to_edit);
3032       return;
3033     }
3034
3035   /* We are editing a function declaration.  The line number we did a seek to
3036      contains the comma or semicolon which follows the declaration.  Our job
3037      now is to scan backwards looking for the function name.  This name *must*
3038      be followed by open paren (ignoring whitespace, of course).  We need to
3039      replace everything between that open paren and the corresponding closing
3040      paren.  If we are protoizing, we need to insert the prototype-style
3041      formals lists.  If we are unprotoizing, we need to just delete everything
3042      between the pairs of opening and closing parens.  */
3043
3044   /* First move up to the end of the line.  */
3045
3046   while (*clean_text_p != '\n')
3047     check_source (++clean_text_p < clean_text_limit, 0);
3048   clean_text_p--;  /* Point to just before the newline character.  */
3049
3050   /* Now we can scan backwards for the function name.  */
3051
3052   do
3053     {
3054       for (;;)
3055         {
3056           /* Scan leftwards until we find some character which can be
3057              part of an identifier.  */
3058
3059           while (!is_id_char (*clean_text_p))
3060             check_source (--clean_text_p > clean_read_ptr, 0);
3061
3062           /* Scan backwards until we find a char that cannot be part of an
3063              identifier.  */
3064
3065           while (is_id_char (*clean_text_p))
3066             check_source (--clean_text_p > clean_read_ptr, 0);
3067
3068           /* Having found an "id break", see if the following id is the one
3069              that we are looking for.  If so, then exit from this loop.  */
3070
3071           if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
3072             {
3073               char ch = *(clean_text_p + 1 + func_name_len);
3074
3075               /* Must also check to see that the name in the source text
3076                  ends where it should (in order to prevent bogus matches
3077                  on similar but longer identifiers.  */
3078
3079               if (! is_id_char (ch))
3080                 break;                  /* exit from loop */
3081             }
3082         }
3083     
3084       /* We have now found the first perfect match for the function name in
3085          our backward search.  This may or may not be the actual function
3086          name at the start of the actual function declaration (i.e. we could
3087          have easily been mislead).  We will try to avoid getting fooled too
3088          often by looking forward for the open paren which should follow the
3089          identifier we just found.  We ignore whitespace while hunting.  If
3090          the next non-whitespace byte we see is *not* an open left paren,
3091          then we must assume that we have been fooled and we start over
3092          again accordingly.  Note that there is no guarantee, that even if
3093          we do see the open paren, that we are in the right place.
3094          Programmers do the strangest things sometimes!  */
3095     
3096       end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
3097       start_formals = forward_to_next_token_char (end_of_fn_name);
3098     }
3099   while (*start_formals != '(');
3100
3101   /* start_of_formals now points to the opening left paren which immediately
3102      follows the name of the function.  */
3103
3104   /* Note that there may be several formals lists which need to be modified
3105      due to the possibility that the return type of this function is a
3106      pointer-to-function type.  If there are several formals lists, we
3107      convert them in left-to-right order here.  */
3108
3109 #ifndef UNPROTOIZE
3110   this_f_list_chain_item = definition->f_list_chain;
3111 #endif /* !defined (UNPROTOIZE) */
3112
3113   for (;;)
3114     {
3115       {
3116         int depth;
3117
3118         end_formals = start_formals + 1;
3119         depth = 1;
3120         for (; depth; check_source (++end_formals < clean_text_limit, 0))
3121           {
3122             switch (*end_formals)
3123               {
3124                 case '(':
3125                   depth++;
3126                   break;
3127                 case ')':
3128                   depth--;
3129                   break;
3130               }
3131           }
3132         end_formals--;
3133       }
3134
3135       /* end_formals now points to the closing right paren of the formals
3136          list whose left paren is pointed to by start_formals.  */
3137     
3138       /* Now, if we are protoizing, we insert the new ANSI-style formals list
3139          attached to the associated definition of this function.  If however
3140          we are unprotoizing, then we simply delete any formals list which
3141          may be present.  */
3142     
3143       output_up_to (start_formals);
3144 #ifndef UNPROTOIZE
3145       if (this_f_list_chain_item)
3146         {
3147           output_string (this_f_list_chain_item->formals_list);
3148           this_f_list_chain_item = this_f_list_chain_item->chain_next;
3149         }
3150       else
3151         {
3152           if (!quiet_flag)
3153             fprintf (stderr, "%s: warning: too many parameter lists in declaration of `%s'\n",
3154                      pname, def_dec_p->hash_entry->symbol);
3155           check_source (0, end_formals);  /* leave the declaration intact */
3156         }
3157 #endif /* !defined (UNPROTOIZE) */
3158       clean_read_ptr = end_formals - 1;
3159
3160       /* Now see if it looks like there may be another formals list associated
3161          with the function declaration that we are converting (following the
3162          formals list that we just converted.  */
3163
3164       {
3165         const char *another_r_paren = forward_to_next_token_char (end_formals);
3166
3167         if ((*another_r_paren != ')')
3168             || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3169           {
3170 #ifndef UNPROTOIZE
3171             if (this_f_list_chain_item)
3172               {
3173                 if (!quiet_flag)
3174                   fprintf (stderr, "\n%s: warning: too few parameter lists in declaration of `%s'\n",
3175                            pname, def_dec_p->hash_entry->symbol);
3176                 check_source (0, start_formals); /* leave the decl intact */
3177               }
3178 #endif /* !defined (UNPROTOIZE) */
3179             break;
3180   
3181           }
3182       }
3183
3184       /* There does appear to be yet another formals list, so loop around
3185          again, and convert it also.  */
3186     }
3187 }
3188
3189 /* Edit a whole group of formals lists, starting with the rightmost one
3190    from some set of formals lists.  This routine is called once (from the
3191    outside) for each function declaration which is converted.  It is
3192    recursive however, and it calls itself once for each remaining formal
3193    list that lies to the left of the one it was originally called to work
3194    on.  Thus, a whole set gets done in right-to-left order.
3195
3196    This routine returns non-zero if it thinks that it should not be trying
3197    to convert this particular function definition (because the name of the
3198    function doesn't match the one expected).  */
3199
3200 static int
3201 edit_formals_lists (end_formals, f_list_count, def_dec_p)
3202      const char *end_formals;
3203      unsigned int f_list_count;
3204      const def_dec_info *def_dec_p;
3205 {
3206   const char *start_formals;
3207   int depth;
3208
3209   start_formals = end_formals - 1;
3210   depth = 1;
3211   for (; depth; check_source (--start_formals > clean_read_ptr, 0))
3212     {
3213       switch (*start_formals)
3214         {
3215           case '(':
3216             depth--;
3217             break;
3218           case ')':
3219             depth++;
3220             break;
3221         }
3222     }
3223   start_formals++;
3224
3225   /* start_formals now points to the opening left paren of the formals list.  */
3226
3227   f_list_count--;
3228
3229   if (f_list_count)
3230     {
3231       const char *next_end;
3232
3233       /* There should be more formal lists to the left of here.  */
3234
3235       next_end = start_formals - 1;
3236       check_source (next_end > clean_read_ptr, 0);
3237       while (isspace (*next_end))
3238         check_source (--next_end > clean_read_ptr, 0);
3239       check_source (*next_end == ')', next_end);
3240       check_source (--next_end > clean_read_ptr, 0);
3241       check_source (*next_end == ')', next_end);
3242       if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3243         return 1;
3244     }
3245
3246   /* Check that the function name in the header we are working on is the same
3247      as the one we would expect to find.  If not, issue a warning and return
3248      non-zero.  */
3249
3250   if (f_list_count == 0)
3251     {
3252       const char *expected = def_dec_p->hash_entry->symbol;
3253       const char *func_name_start;
3254       const char *func_name_limit;
3255       size_t func_name_len;
3256
3257       for (func_name_limit = start_formals-1; isspace (*func_name_limit); )
3258         check_source (--func_name_limit > clean_read_ptr, 0);
3259
3260       for (func_name_start = func_name_limit++;
3261            is_id_char (*func_name_start);
3262            func_name_start--)
3263         check_source (func_name_start > clean_read_ptr, 0);
3264       func_name_start++;
3265       func_name_len = func_name_limit - func_name_start;
3266       if (func_name_len == 0)
3267         check_source (0, func_name_start);
3268       if (func_name_len != strlen (expected)
3269           || strncmp (func_name_start, expected, func_name_len))
3270         {
3271           fprintf (stderr, "%s: %d: warning: found `%s' but expected `%s'\n",
3272                    shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3273                    identify_lineno (func_name_start),
3274                    dupnstr (func_name_start, func_name_len),
3275                    expected);
3276           return 1;
3277         }
3278     }
3279
3280   output_up_to (start_formals);
3281
3282 #ifdef UNPROTOIZE
3283   if (f_list_count == 0)
3284     output_string (def_dec_p->formal_names);
3285 #else /* !defined (UNPROTOIZE) */
3286   {
3287     unsigned f_list_depth;
3288     const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
3289
3290     /* At this point, the current value of f_list count says how many
3291        links we have to follow through the f_list_chain to get to the
3292        particular formals list that we need to output next.  */
3293
3294     for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
3295       flci_p = flci_p->chain_next;
3296     output_string (flci_p->formals_list);
3297   }
3298 #endif /* !defined (UNPROTOIZE) */
3299
3300   clean_read_ptr = end_formals - 1;
3301   return 0;
3302 }
3303
3304 /* Given a pointer to a byte in the clean text buffer which points to the
3305    beginning of a line that contains a "follower" token for a function
3306    definition header, do whatever is necessary to find the right closing
3307    paren for the rightmost formals list of the function definition header.
3308 */
3309
3310 static const char *
3311 find_rightmost_formals_list (clean_text_p)
3312      const char *clean_text_p;
3313 {
3314   const char *end_formals;
3315
3316   /* We are editing a function definition.  The line number we did a seek
3317      to contains the first token which immediately follows the entire set of
3318      formals lists which are part of this particular function definition
3319      header.
3320
3321      Our job now is to scan leftwards in the clean text looking for the
3322      right-paren which is at the end of the function header's rightmost
3323      formals list.
3324
3325      If we ignore whitespace, this right paren should be the first one we
3326      see which is (ignoring whitespace) immediately followed either by the
3327      open curly-brace beginning the function body or by an alphabetic
3328      character (in the case where the function definition is in old (K&R)
3329      style and there are some declarations of formal parameters).  */
3330
3331    /* It is possible that the right paren we are looking for is on the
3332       current line (together with its following token).  Just in case that
3333       might be true, we start out here by skipping down to the right end of
3334       the current line before starting our scan.  */
3335
3336   for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
3337     continue;
3338   end_formals--;
3339
3340 #ifdef UNPROTOIZE
3341
3342   /* Now scan backwards while looking for the right end of the rightmost
3343      formals list associated with this function definition.  */
3344
3345   {
3346     char ch;
3347     const char *l_brace_p;
3348
3349     /* Look leftward and try to find a right-paren.  */
3350
3351     while (*end_formals != ')')
3352       {
3353         if (isspace (*end_formals))
3354           while (isspace (*end_formals))
3355             check_source (--end_formals > clean_read_ptr, 0);
3356         else
3357           check_source (--end_formals > clean_read_ptr, 0);
3358       }
3359
3360     ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3361     /* Since we are unprotoizing an ANSI-style (prototyped) function
3362        definition, there had better not be anything (except whitespace)
3363        between the end of the ANSI formals list and the beginning of the
3364        function body (i.e. the '{').  */
3365
3366     check_source (ch == '{', l_brace_p);
3367   }
3368
3369 #else /* !defined (UNPROTOIZE) */
3370
3371   /* Now scan backwards while looking for the right end of the rightmost
3372      formals list associated with this function definition.  */
3373
3374   while (1)
3375     {
3376       char ch;
3377       const char *l_brace_p;
3378
3379       /* Look leftward and try to find a right-paren.  */
3380
3381       while (*end_formals != ')')
3382         {
3383           if (isspace (*end_formals))
3384             while (isspace (*end_formals))
3385               check_source (--end_formals > clean_read_ptr, 0);
3386           else
3387             check_source (--end_formals > clean_read_ptr, 0);
3388         }
3389
3390       ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3391
3392       /* Since it is possible that we found a right paren before the starting
3393          '{' of the body which IS NOT the one at the end of the real K&R
3394          formals list (say for instance, we found one embedded inside one of
3395          the old K&R formal parameter declarations) we have to check to be
3396          sure that this is in fact the right paren that we were looking for.
3397
3398          The one we were looking for *must* be followed by either a '{' or
3399          by an alphabetic character, while others *cannot* legally be followed
3400          by such characters.  */
3401
3402       if ((ch == '{') || isalpha (ch))
3403         break;
3404
3405       /* At this point, we have found a right paren, but we know that it is
3406          not the one we were looking for, so backup one character and keep
3407          looking.  */
3408
3409       check_source (--end_formals > clean_read_ptr, 0);
3410     }
3411
3412 #endif /* !defined (UNPROTOIZE) */
3413
3414   return end_formals;
3415 }
3416
3417 #ifndef UNPROTOIZE
3418
3419 /* Insert into the output file a totally new declaration for a function
3420    which (up until now) was being called from within the current block
3421    without having been declared at any point such that the declaration
3422    was visible (i.e. in scope) at the point of the call.
3423
3424    We need to add in explicit declarations for all such function calls
3425    in order to get the full benefit of prototype-based function call
3426    parameter type checking.  */
3427
3428 static void
3429 add_local_decl (def_dec_p, clean_text_p)
3430      const def_dec_info *def_dec_p;
3431      const char *clean_text_p;
3432 {
3433   const char *start_of_block;
3434   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3435
3436   /* Don't insert new local explicit declarations unless explicitly requested
3437      to do so.  */
3438
3439   if (!local_flag)
3440     return;
3441
3442   /* Setup here to recover from confusing source code detected during this
3443      particular "edit".  */
3444
3445   save_pointers ();
3446   if (setjmp (source_confusion_recovery))
3447     {
3448       restore_pointers ();
3449       fprintf (stderr, "%s: local declaration for function `%s' not inserted\n",
3450                pname, function_to_edit);
3451       return;
3452     }
3453
3454   /* We have already done a seek to the start of the line which should
3455      contain *the* open curly brace which begins the block in which we need
3456      to insert an explicit function declaration (to replace the implicit one).
3457
3458      Now we scan that line, starting from the left, until we find the
3459      open curly brace we are looking for.  Note that there may actually be
3460      multiple open curly braces on the given line, but we will be happy
3461      with the leftmost one no matter what.  */
3462
3463   start_of_block = clean_text_p;
3464   while (*start_of_block != '{' && *start_of_block != '\n')
3465     check_source (++start_of_block < clean_text_limit, 0);
3466
3467   /* Note that the line from the original source could possibly
3468      contain *no* open curly braces!  This happens if the line contains
3469      a macro call which expands into a chunk of text which includes a
3470      block (and that block's associated open and close curly braces).
3471      In cases like this, we give up, issue a warning, and do nothing.  */
3472
3473   if (*start_of_block != '{')
3474     {
3475       if (!quiet_flag)
3476         fprintf (stderr,
3477           "\n%s: %d: warning: can't add declaration of `%s' into macro call\n",
3478           def_dec_p->file->hash_entry->symbol, def_dec_p->line, 
3479           def_dec_p->hash_entry->symbol);
3480       return;
3481     }
3482
3483   /* Figure out what a nice (pretty) indentation would be for the new
3484      declaration we are adding.  In order to do this, we must scan forward
3485      from the '{' until we find the first line which starts with some
3486      non-whitespace characters (i.e. real "token" material).  */
3487
3488   {
3489     const char *ep = forward_to_next_token_char (start_of_block) - 1;
3490     const char *sp;
3491
3492     /* Now we have ep pointing at the rightmost byte of some existing indent
3493        stuff.  At least that is the hope.
3494
3495        We can now just scan backwards and find the left end of the existing
3496        indentation string, and then copy it to the output buffer.  */
3497
3498     for (sp = ep; isspace (*sp) && *sp != '\n'; sp--)
3499       continue;
3500
3501     /* Now write out the open { which began this block, and any following
3502        trash up to and including the last byte of the existing indent that
3503        we just found.  */
3504
3505     output_up_to (ep);
3506   
3507     /* Now we go ahead and insert the new declaration at this point.
3508
3509        If the definition of the given function is in the same file that we
3510        are currently editing, and if its full ANSI declaration normally
3511        would start with the keyword `extern', suppress the `extern'.  */
3512   
3513     {
3514       const char *decl = def_dec_p->definition->ansi_decl;
3515   
3516       if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3517         decl += 7;
3518       output_string (decl);
3519     }
3520
3521     /* Finally, write out a new indent string, just like the preceding one
3522        that we found.  This will typically include a newline as the first
3523        character of the indent string.  */
3524
3525     output_bytes (sp, (size_t) (ep - sp) + 1);
3526   }
3527 }
3528
3529 /* Given a pointer to a file_info record, and a pointer to the beginning
3530    of a line (in the clean text buffer) which is assumed to contain the
3531    first "follower" token for the first function definition header in the
3532    given file, find a good place to insert some new global function
3533    declarations (which will replace scattered and imprecise implicit ones)
3534    and then insert the new explicit declaration at that point in the file.  */
3535
3536 static void
3537 add_global_decls (file_p, clean_text_p)
3538      const file_info *file_p;
3539      const char *clean_text_p;
3540 {
3541   const def_dec_info *dd_p;
3542   const char *scan_p;
3543
3544   /* Setup here to recover from confusing source code detected during this
3545      particular "edit".  */
3546
3547   save_pointers ();
3548   if (setjmp (source_confusion_recovery))
3549     {
3550       restore_pointers ();
3551       fprintf (stderr, "%s: global declarations for file `%s' not inserted\n",
3552                pname, shortpath (NULL, file_p->hash_entry->symbol));
3553       return;
3554     }
3555
3556   /* Start by finding a good location for adding the new explicit function
3557      declarations.  To do this, we scan backwards, ignoring whitespace
3558      and comments and other junk until we find either a semicolon, or until
3559      we hit the beginning of the file.  */
3560
3561   scan_p = find_rightmost_formals_list (clean_text_p);
3562   for (;; --scan_p)
3563     {
3564       if (scan_p < clean_text_base)
3565         break;
3566       check_source (scan_p > clean_read_ptr, 0);
3567       if (*scan_p == ';')
3568         break;
3569     }
3570
3571   /* scan_p now points either to a semicolon, or to just before the start
3572      of the whole file.  */
3573
3574   /* Now scan forward for the first non-whitespace character.  In theory,
3575      this should be the first character of the following function definition
3576      header.  We will put in the added declarations just prior to that. */
3577
3578   scan_p++;
3579   while (isspace (*scan_p))
3580     scan_p++;
3581   scan_p--;
3582
3583   output_up_to (scan_p);
3584
3585   /* Now write out full prototypes for all of the things that had been
3586      implicitly declared in this file (but only those for which we were
3587      actually able to find unique matching definitions).  Avoid duplicates
3588      by marking things that we write out as we go.   */
3589
3590   {
3591     int some_decls_added = 0;
3592   
3593     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3594       if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3595         {
3596           const char *decl = dd_p->definition->ansi_decl;
3597   
3598           /* If the function for which we are inserting a declaration is
3599              actually defined later in the same file, then suppress the
3600              leading `extern' keyword (if there is one).  */
3601   
3602           if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3603             decl += 7;
3604   
3605           output_string ("\n");
3606           output_string (decl);
3607           some_decls_added = 1;
3608           ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3609         }
3610     if (some_decls_added)
3611       output_string ("\n\n");
3612   }
3613
3614   /* Unmark all of the definitions that we just marked.  */
3615
3616   for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3617     if (dd_p->definition)
3618       ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
3619 }
3620
3621 #endif /* !defined (UNPROTOIZE) */
3622
3623 /* Do the editing operation specifically for a function "definition".  Note
3624    that editing operations for function "declarations" are handled by a
3625    separate routine above.  */
3626
3627 static void
3628 edit_fn_definition (def_dec_p, clean_text_p)
3629      const def_dec_info *def_dec_p;
3630      const char *clean_text_p;
3631 {
3632   const char *end_formals;
3633   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3634
3635   /* Setup here to recover from confusing source code detected during this
3636      particular "edit".  */
3637
3638   save_pointers ();
3639   if (setjmp (source_confusion_recovery))
3640     {
3641       restore_pointers ();
3642       fprintf (stderr, "%s: definition of function `%s' not converted\n",
3643                pname, function_to_edit);
3644       return;
3645     }
3646
3647   end_formals = find_rightmost_formals_list (clean_text_p);
3648
3649   /* end_of_formals now points to the closing right paren of the rightmost
3650      formals list which is actually part of the `header' of the function
3651      definition that we are converting.  */
3652
3653   /* If the header of this function definition looks like it declares a
3654      function with a variable number of arguments, and if the way it does
3655      that is different from that way we would like it (i.e. varargs vs.
3656      stdarg) then issue a warning and leave the header unconverted.  */
3657      
3658   if (other_variable_style_function (def_dec_p->ansi_decl))
3659     {
3660       if (!quiet_flag)
3661         fprintf (stderr, "%s: %d: warning: definition of %s not converted\n",
3662                  shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3663                  identify_lineno (end_formals), 
3664                  other_var_style);
3665       output_up_to (end_formals);
3666       return;
3667     }
3668
3669   if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
3670     {
3671       restore_pointers ();
3672       fprintf (stderr, "%s: definition of function `%s' not converted\n",
3673                pname, function_to_edit);
3674       return;
3675     }
3676
3677   /* Have to output the last right paren because this never gets flushed by
3678      edit_formals_list.  */
3679
3680   output_up_to (end_formals);
3681
3682 #ifdef UNPROTOIZE
3683   {
3684     const char *decl_p;
3685     const char *semicolon_p;
3686     const char *limit_p;
3687     const char *scan_p;
3688     int had_newlines = 0;
3689
3690     /* Now write out the K&R style formal declarations, one per line.  */
3691
3692     decl_p = def_dec_p->formal_decls;
3693     limit_p = decl_p + strlen (decl_p);
3694     for (;decl_p < limit_p; decl_p = semicolon_p + 2)
3695       {
3696         for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3697           continue;
3698         output_string ("\n");
3699         output_string (indent_string);
3700         output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
3701       }
3702
3703     /* If there are no newlines between the end of the formals list and the
3704        start of the body, we should insert one now.  */
3705
3706     for (scan_p = end_formals+1; *scan_p != '{'; )
3707       {
3708         if (*scan_p == '\n')
3709           {
3710             had_newlines = 1;
3711             break;
3712           }
3713         check_source (++scan_p < clean_text_limit, 0);
3714       }
3715     if (!had_newlines)
3716       output_string ("\n");
3717   }
3718 #else /* !defined (UNPROTOIZE) */
3719   /* If we are protoizing, there may be some flotsum & jetsum (like comments
3720      and preprocessing directives) after the old formals list but before
3721      the following { and we would like to preserve that stuff while effectively
3722      deleting the existing K&R formal parameter declarations.  We do so here
3723      in a rather tricky way.  Basically, we white out any stuff *except*
3724      the comments/pp-directives in the original text buffer, then, if there
3725      is anything in this area *other* than whitespace, we output it.  */
3726   {
3727     const char *end_formals_orig;
3728     const char *start_body;
3729     const char *start_body_orig;
3730     const char *scan;
3731     const char *scan_orig;
3732     int have_flotsum = 0;
3733     int have_newlines = 0;
3734
3735     for (start_body = end_formals + 1; *start_body != '{';)
3736       check_source (++start_body < clean_text_limit, 0);
3737
3738     end_formals_orig = orig_text_base + (end_formals - clean_text_base);
3739     start_body_orig = orig_text_base + (start_body - clean_text_base);
3740     scan = end_formals + 1;
3741     scan_orig = end_formals_orig + 1;
3742     for (; scan < start_body; scan++, scan_orig++)
3743       {
3744         if (*scan == *scan_orig)
3745           {
3746             have_newlines |= (*scan_orig == '\n');
3747             /* Leave identical whitespace alone.  */
3748             if (!isspace (*scan_orig))
3749               *((NONCONST char *)scan_orig) = ' '; /* identical - so whiteout */
3750           }
3751         else
3752           have_flotsum = 1;
3753       }
3754     if (have_flotsum)
3755       output_bytes (end_formals_orig + 1,
3756                     (size_t) (start_body_orig - end_formals_orig) - 1);
3757     else
3758       if (have_newlines)
3759         output_string ("\n");
3760       else
3761         output_string (" ");
3762     clean_read_ptr = start_body - 1;
3763   }
3764 #endif /* !defined (UNPROTOIZE) */
3765 }
3766
3767 /* Clean up the clean text buffer.  Do this by converting comments and
3768    preprocessor directives into spaces.   Also convert line continuations
3769    into whitespace.  Also, whiteout string and character literals.  */
3770
3771 static void
3772 do_cleaning (new_clean_text_base, new_clean_text_limit)
3773      char *new_clean_text_base;
3774      char *new_clean_text_limit;
3775 {
3776   char *scan_p;
3777   int non_whitespace_since_newline = 0;
3778
3779   for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
3780     {
3781       switch (*scan_p)
3782         {
3783           case '/':                     /* Handle comments.  */
3784             if (scan_p[1] != '*')
3785               goto regular;
3786             non_whitespace_since_newline = 1;
3787             scan_p[0] = ' ';
3788             scan_p[1] = ' ';
3789             scan_p += 2;
3790             while (scan_p[1] != '/' || scan_p[0] != '*')
3791               {
3792                 if (!isspace (*scan_p))
3793                   *scan_p = ' ';
3794                 if (++scan_p >= new_clean_text_limit)
3795                   abort ();
3796               }
3797             *scan_p++ = ' ';
3798             *scan_p = ' ';
3799             break;
3800
3801           case '#':                     /* Handle pp directives.  */
3802             if (non_whitespace_since_newline)
3803               goto regular;
3804             *scan_p = ' ';
3805             while (scan_p[1] != '\n' || scan_p[0] == '\\')
3806               {
3807                 if (!isspace (*scan_p))
3808                   *scan_p = ' ';
3809                 if (++scan_p >= new_clean_text_limit)
3810                   abort ();
3811               }
3812             *scan_p++ = ' ';
3813             break;
3814
3815           case '\'':                    /* Handle character literals.  */
3816             non_whitespace_since_newline = 1;
3817             while (scan_p[1] != '\'' || scan_p[0] == '\\')
3818               {
3819                 if (scan_p[0] == '\\' && !isspace (scan_p[1]))
3820                   scan_p[1] = ' ';
3821                 if (!isspace (*scan_p))
3822                   *scan_p = ' ';
3823                 if (++scan_p >= new_clean_text_limit)
3824                   abort ();
3825               }
3826             *scan_p++ = ' ';
3827             break;
3828
3829           case '"':                     /* Handle string literals.  */
3830             non_whitespace_since_newline = 1;
3831             while (scan_p[1] != '"' || scan_p[0] == '\\')
3832               {
3833                 if (scan_p[0] == '\\' && !isspace (scan_p[1]))
3834                   scan_p[1] = ' ';
3835                 if (!isspace (*scan_p))
3836                   *scan_p = ' ';
3837                 if (++scan_p >= new_clean_text_limit)
3838                   abort ();
3839               }
3840             *scan_p++ = ' ';
3841             break;
3842
3843           case '\\':                    /* Handle line continuations.  */
3844             if (scan_p[1] != '\n')
3845               goto regular;
3846             *scan_p = ' ';
3847             break;
3848
3849           case '\n':
3850             non_whitespace_since_newline = 0;   /* Reset.  */
3851             break;
3852
3853           case ' ':
3854           case '\v':
3855           case '\t':
3856           case '\r':
3857           case '\f':
3858           case '\b':
3859             break;              /* Whitespace characters.  */
3860
3861           default:
3862 regular:
3863             non_whitespace_since_newline = 1;
3864             break;
3865         }
3866     }
3867 }
3868
3869 /* Given a pointer to the closing right parenthesis for a particular formals
3870    list (in the clean text buffer) find the corresponding left parenthesis
3871    and return a pointer to it.  */
3872
3873 static const char *
3874 careful_find_l_paren (p)
3875      const char *p;
3876 {
3877   const char *q;
3878   int paren_depth;
3879
3880   for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
3881     {
3882       switch (*q)
3883         {
3884           case ')':
3885             paren_depth++;
3886             break;
3887           case '(':
3888             paren_depth--;
3889             break;
3890         }
3891     }
3892   return ++q;
3893 }
3894
3895 /* Scan the clean text buffer for cases of function definitions that we
3896    don't really know about because they were preprocessed out when the
3897    aux info files were created.
3898
3899    In this version of protoize/unprotoize we just give a warning for each
3900    one found.  A later version may be able to at least unprotoize such
3901    missed items.
3902
3903    Note that we may easily find all function definitions simply by
3904    looking for places where there is a left paren which is (ignoring
3905    whitespace) immediately followed by either a left-brace or by an
3906    upper or lower case letter.  Whenever we find this combination, we
3907    have also found a function definition header.
3908
3909    Finding function *declarations* using syntactic clues is much harder.
3910    I will probably try to do this in a later version though.  */
3911
3912 static void
3913 scan_for_missed_items (file_p)
3914      const file_info *file_p;
3915 {
3916   static const char *scan_p;
3917   const char *limit = clean_text_limit - 3;
3918   static const char *backup_limit;
3919
3920   backup_limit = clean_text_base - 1;
3921
3922   for (scan_p = clean_text_base; scan_p < limit; scan_p++)
3923     {
3924       if (*scan_p == ')')
3925         {
3926           static const char *last_r_paren;
3927           const char *ahead_p;
3928
3929           last_r_paren = scan_p;
3930
3931           for (ahead_p = scan_p + 1; isspace (*ahead_p); )
3932             check_source (++ahead_p < limit, limit);
3933
3934           scan_p = ahead_p - 1;
3935
3936           if (isalpha (*ahead_p) || *ahead_p == '{')
3937             {
3938               const char *last_l_paren;
3939               const int lineno = identify_lineno (ahead_p);
3940
3941               if (setjmp (source_confusion_recovery))
3942                 continue;
3943
3944               /* We know we have a function definition header.  Now skip
3945                  leftwards over all of its associated formals lists.  */
3946
3947               do
3948                 {
3949                   last_l_paren = careful_find_l_paren (last_r_paren);
3950                   for (last_r_paren = last_l_paren-1; isspace (*last_r_paren); )
3951                     check_source (--last_r_paren >= backup_limit, backup_limit);
3952                 }
3953               while (*last_r_paren == ')');
3954
3955               if (is_id_char (*last_r_paren))
3956                 {
3957                   const char *id_limit = last_r_paren + 1;
3958                   const char *id_start;
3959                   size_t id_length;
3960                   const def_dec_info *dd_p;
3961
3962                   for (id_start = id_limit-1; is_id_char (*id_start); )
3963                     check_source (--id_start >= backup_limit, backup_limit);
3964                   id_start++;
3965                   backup_limit = id_start;
3966                   if ((id_length = (size_t) (id_limit - id_start)) == 0)
3967                     goto not_missed;
3968
3969                   {
3970                     char *func_name = (char *) alloca (id_length + 1);
3971                     static const char * const stmt_keywords[]
3972                       = { "if", "else", "do", "while", "for", "switch", "case", "return", 0 };
3973                     const char * const *stmt_keyword;
3974
3975                     strncpy (func_name, id_start, id_length);
3976                     func_name[id_length] = '\0';
3977
3978                     /* We must check here to see if we are actually looking at
3979                        a statement rather than an actual function call.  */
3980
3981                     for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
3982                       if (!strcmp (func_name, *stmt_keyword))
3983                         goto not_missed;
3984
3985 #if 0
3986                     fprintf (stderr, "%s: found definition of `%s' at %s(%d)\n",
3987                              pname,
3988                              func_name,
3989                              shortpath (NULL, file_p->hash_entry->symbol),
3990                              identify_lineno (id_start));
3991 #endif                          /* 0 */
3992                     /* We really should check for a match of the function name
3993                        here also, but why bother.  */
3994
3995                     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3996                       if (dd_p->is_func_def && dd_p->line == lineno)
3997                         goto not_missed;
3998
3999                     /* If we make it here, then we did not know about this
4000                        function definition.  */
4001
4002                     fprintf (stderr, "%s: %d: warning: `%s' excluded by preprocessing\n",
4003                              shortpath (NULL, file_p->hash_entry->symbol),
4004                              identify_lineno (id_start), func_name);
4005                     fprintf (stderr, "%s: function definition not converted\n",
4006                              pname);
4007                   }
4008                 not_missed: ;
4009                 }
4010             }
4011         }
4012     }
4013 }
4014
4015 /* Do all editing operations for a single source file (either a "base" file
4016    or an "include" file).  To do this we read the file into memory, keep a
4017    virgin copy there, make another cleaned in-core copy of the original file
4018    (i.e. one in which all of the comments and preprocessor directives have
4019    been replaced with whitespace), then use these two in-core copies of the
4020    file to make a new edited in-core copy of the file.  Finally, rename the
4021    original file (as a way of saving it), and then write the edited version
4022    of the file from core to a disk file of the same name as the original.
4023
4024    Note that the trick of making a copy of the original sans comments &
4025    preprocessor directives make the editing a whole lot easier.  */
4026    
4027 static void
4028 edit_file (hp)
4029      const hash_table_entry *hp;
4030 {
4031   struct stat stat_buf;
4032   const file_info *file_p = hp->fip;
4033   char *new_orig_text_base;
4034   char *new_orig_text_limit;
4035   char *new_clean_text_base;
4036   char *new_clean_text_limit;
4037   size_t orig_size;
4038   size_t repl_size;
4039   int first_definition_in_file;
4040
4041   /* If we are not supposed to be converting this file, or if there is
4042      nothing in there which needs converting, just skip this file.  */
4043
4044   if (!needs_to_be_converted (file_p))
4045     return;
4046
4047   convert_filename = file_p->hash_entry->symbol;
4048
4049   /* Convert a file if it is in a directory where we want conversion
4050      and the file is not excluded.  */
4051
4052   if (!directory_specified_p (convert_filename)
4053       || file_excluded_p (convert_filename))
4054     {
4055       if (!quiet_flag
4056 #ifdef UNPROTOIZE
4057           /* Don't even mention "system" include files unless we are
4058              protoizing.  If we are protoizing, we mention these as a
4059              gentle way of prodding the user to convert his "system"
4060              include files to prototype format.  */
4061           && !in_system_include_dir (convert_filename)
4062 #endif /* defined (UNPROTOIZE) */
4063           )
4064         fprintf (stderr, "%s: `%s' not converted\n",
4065                  pname, shortpath (NULL, convert_filename));
4066       return;
4067     }
4068
4069   /* Let the user know what we are up to.  */
4070
4071   if (nochange_flag)
4072     fprintf (stderr, "%s: would convert file `%s'\n",
4073              pname, shortpath (NULL, convert_filename));
4074   else
4075     fprintf (stderr, "%s: converting file `%s'\n",
4076              pname, shortpath (NULL, convert_filename));
4077   fflush (stderr);
4078
4079   /* Find out the size (in bytes) of the original file.  */
4080
4081   /* The cast avoids an erroneous warning on AIX.  */
4082   if (my_stat ((char *)convert_filename, &stat_buf) == -1)
4083     {
4084       fprintf (stderr, "%s: can't get status for file `%s': %s\n",
4085                pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
4086       return;
4087     }
4088   orig_size = stat_buf.st_size;
4089
4090   /* Allocate a buffer to hold the original text.  */
4091
4092   orig_text_base = new_orig_text_base = (char *) xmalloc (orig_size + 2);
4093   orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
4094
4095   /* Allocate a buffer to hold the cleaned-up version of the original text.  */
4096
4097   clean_text_base = new_clean_text_base = (char *) xmalloc (orig_size + 2);
4098   clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
4099   clean_read_ptr = clean_text_base - 1;
4100
4101   /* Allocate a buffer that will hopefully be large enough to hold the entire
4102      converted output text.  As an initial guess for the maximum size of the
4103      output buffer, use 125% of the size of the original + some extra.  This
4104      buffer can be expanded later as needed.  */
4105
4106   repl_size = orig_size + (orig_size >> 2) + 4096;
4107   repl_text_base = (char *) xmalloc (repl_size + 2);
4108   repl_text_limit = repl_text_base + repl_size - 1;
4109   repl_write_ptr = repl_text_base - 1;
4110
4111   {
4112     int input_file;
4113
4114     /* Open the file to be converted in READ ONLY mode.  */
4115
4116     if ((input_file = my_open (convert_filename, O_RDONLY, 0444)) == -1)
4117       {
4118         fprintf (stderr, "%s: can't open file `%s' for reading: %s\n",
4119                  pname, shortpath (NULL, convert_filename),
4120                  sys_errlist[errno]);
4121         return;
4122       }
4123
4124     /* Read the entire original source text file into the original text buffer
4125        in one swell fwoop.  Then figure out where the end of the text is and
4126        make sure that it ends with a newline followed by a null.  */
4127
4128     if (read (input_file, new_orig_text_base, orig_size) != orig_size)
4129       {
4130         close (input_file);
4131         fprintf (stderr, "\n%s: error reading input file `%s': %s\n",
4132                  pname, shortpath (NULL, convert_filename),
4133                  sys_errlist[errno]);
4134         return;
4135       }
4136
4137     close (input_file);
4138   }
4139
4140   if (orig_size == 0 || orig_text_limit[-1] != '\n')
4141     {
4142       *new_orig_text_limit++ = '\n';
4143       orig_text_limit++;
4144     }
4145
4146   /* Create the cleaned up copy of the original text.  */
4147
4148   memcpy (new_clean_text_base, orig_text_base,
4149           (size_t) (orig_text_limit - orig_text_base));
4150   do_cleaning (new_clean_text_base, new_clean_text_limit);
4151
4152 #if 0
4153   {
4154     int clean_file;
4155     size_t clean_size = orig_text_limit - orig_text_base;
4156     char *const clean_filename = (char *) alloca (strlen (convert_filename) + 6 + 1);
4157
4158     /* Open (and create) the clean file.  */
4159   
4160     strcpy (clean_filename, convert_filename);
4161     strcat (clean_filename, ".clean");
4162     if ((clean_file = creat (clean_filename, 0666)) == -1)
4163       {
4164         fprintf (stderr, "%s: can't create/open clean file `%s': %s\n",
4165                  pname, shortpath (NULL, clean_filename),
4166                  sys_errlist[errno]);
4167         return;
4168       }
4169   
4170     /* Write the clean file.  */
4171   
4172     if (write (clean_file, new_clean_text_base, clean_size) != clean_size)
4173       fprintf (stderr, "%s: error writing file `%s': %s\n",
4174                pname, shortpath (NULL, clean_filename), sys_errlist[errno]);
4175   
4176     close (clean_file);
4177   }
4178 #endif /* 0 */
4179
4180   /* Do a simplified scan of the input looking for things that were not
4181      mentioned in the aux info files because of the fact that they were
4182      in a region of the source which was preprocessed-out (via #if or
4183      via #ifdef).  */
4184
4185   scan_for_missed_items (file_p);
4186
4187   /* Setup to do line-oriented forward seeking in the clean text buffer.  */
4188
4189   last_known_line_number = 1;
4190   last_known_line_start = clean_text_base;
4191
4192   /* Now get down to business and make all of the necessary edits.  */
4193
4194   {
4195     const def_dec_info *def_dec_p;
4196
4197     first_definition_in_file = 1;
4198     def_dec_p = file_p->defs_decs;
4199     for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
4200       {
4201         const char *clean_text_p = seek_to_line (def_dec_p->line);
4202   
4203         /* clean_text_p now points to the first character of the line which
4204            contains the `terminator' for the declaration or definition that
4205            we are about to process.  */
4206   
4207 #ifndef UNPROTOIZE
4208   
4209         if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4210           {
4211             add_global_decls (def_dec_p->file, clean_text_p);
4212             first_definition_in_file = 0;
4213           }
4214
4215         /* Don't edit this item if it is already in prototype format or if it
4216            is a function declaration and we have found no corresponding
4217            definition.  */
4218
4219         if (def_dec_p->prototyped
4220          || (!def_dec_p->is_func_def && !def_dec_p->definition))
4221           continue;
4222
4223 #endif /* !defined (UNPROTOIZE) */
4224
4225         if (def_dec_p->is_func_def)
4226           edit_fn_definition (def_dec_p, clean_text_p);
4227         else
4228 #ifndef UNPROTOIZE
4229         if (def_dec_p->is_implicit)
4230           add_local_decl (def_dec_p, clean_text_p);
4231         else
4232 #endif /* !defined (UNPROTOIZE) */
4233             edit_fn_declaration (def_dec_p, clean_text_p);
4234       }
4235   }
4236
4237   /* Finalize things.  Output the last trailing part of the original text.  */
4238
4239   output_up_to (clean_text_limit - 1);
4240
4241   /* If this is just a test run, stop now and just deallocate the buffers.  */
4242
4243   if (nochange_flag)
4244     {
4245       free (new_orig_text_base);
4246       free (new_clean_text_base);
4247       free (repl_text_base);
4248       return;
4249     }
4250
4251   /* Change the name of the original input file.  This is just a quick way of
4252      saving the original file.  */
4253
4254   if (!nosave_flag)
4255     {
4256       char *new_filename =
4257           (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
4258   
4259       strcpy (new_filename, convert_filename);
4260       strcat (new_filename, save_suffix);
4261       if (my_link (convert_filename, new_filename) == -1)
4262         {
4263           if (errno == EEXIST)
4264             {
4265               if (!quiet_flag)
4266                 fprintf (stderr, "%s: warning: file `%s' already saved in `%s'\n",
4267                          pname,
4268                          shortpath (NULL, convert_filename),
4269                          shortpath (NULL, new_filename));
4270             }
4271           else
4272             {
4273               fprintf (stderr, "%s: can't link file `%s' to `%s': %s\n",
4274                        pname,
4275                        shortpath (NULL, convert_filename),
4276                        shortpath (NULL, new_filename),
4277                        sys_errlist[errno]);
4278               return;
4279             }
4280         }
4281     }
4282
4283   if (my_unlink (convert_filename) == -1)
4284     {
4285       fprintf (stderr, "%s: can't delete file `%s': %s\n",
4286                pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
4287       return;
4288     }
4289
4290   {
4291     int output_file;
4292
4293     /* Open (and create) the output file.  */
4294   
4295     if ((output_file = creat (convert_filename, 0666)) == -1)
4296       {
4297         fprintf (stderr, "%s: can't create/open output file `%s': %s\n",
4298                  pname, shortpath (NULL, convert_filename),
4299                  sys_errlist[errno]);
4300         return;
4301       }
4302   
4303     /* Write the output file.  */
4304   
4305     {
4306       unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4307   
4308       if (write (output_file, repl_text_base, out_size) != out_size)
4309         fprintf (stderr, "%s: error writing file `%s': %s\n",
4310                  pname, shortpath (NULL, convert_filename),
4311                  sys_errlist[errno]);
4312     }
4313   
4314     close (output_file);
4315   }
4316
4317   /* Deallocate the conversion buffers.  */
4318
4319   free (new_orig_text_base);
4320   free (new_clean_text_base);
4321   free (repl_text_base);
4322
4323   /* Change the mode of the output file to match the original file.  */
4324
4325   /* The cast avoids an erroneous warning on AIX.  */
4326   if (my_chmod ((char *)convert_filename, stat_buf.st_mode) == -1)
4327     fprintf (stderr, "%s: can't change mode of file `%s': %s\n",
4328              pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
4329
4330   /* Note:  We would try to change the owner and group of the output file
4331      to match those of the input file here, except that may not be a good
4332      thing to do because it might be misleading.  Also, it might not even
4333      be possible to do that (on BSD systems with quotas for instance).  */
4334 }
4335
4336 /* Do all of the individual steps needed to do the protoization (or
4337    unprotoization) of the files referenced in the aux_info files given
4338    in the command line.  */
4339
4340 static void
4341 do_processing ()
4342 {
4343   const char * const *base_pp;
4344   const char * const * const end_pps
4345     = &base_source_filenames[n_base_source_files];
4346
4347 #ifndef UNPROTOIZE
4348   int syscalls_len;
4349 #endif /* !defined (UNPROTOIZE) */
4350
4351   /* One-by-one, check (and create if necessary), open, and read all of the
4352      stuff in each aux_info file.  After reading each aux_info file, the
4353      aux_info_file just read will be automatically deleted unless the
4354      keep_flag is set.  */
4355
4356   for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
4357     process_aux_info_file (*base_pp, keep_flag, 0);
4358
4359 #ifndef UNPROTOIZE
4360
4361   /* Also open and read the special SYSCALLS.c aux_info file which gives us
4362      the prototypes for all of the standard system-supplied functions.  */
4363
4364   if (nondefault_syscalls_dir)
4365     {
4366       syscalls_absolute_filename
4367         = (char *) xmalloc (strlen (nondefault_syscalls_dir)
4368                             + sizeof (syscalls_filename) + 1);
4369       strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
4370     }
4371   else
4372     {
4373       syscalls_absolute_filename
4374         = (char *) xmalloc (strlen (default_syscalls_dir)
4375                             + sizeof (syscalls_filename) + 1);
4376       strcpy (syscalls_absolute_filename, default_syscalls_dir);
4377     }
4378
4379   syscalls_len = strlen (syscalls_absolute_filename);
4380   if (*(syscalls_absolute_filename + syscalls_len - 1) != '/')
4381     {
4382       *(syscalls_absolute_filename + syscalls_len++) = '/';
4383       *(syscalls_absolute_filename + syscalls_len) = '\0';
4384     }
4385   strcat (syscalls_absolute_filename, syscalls_filename);
4386   
4387   /* Call process_aux_info_file in such a way that it does not try to
4388      delete the SYSCALLS aux_info file.  */
4389
4390   process_aux_info_file (syscalls_absolute_filename, 1, 1);
4391
4392 #endif /* !defined (UNPROTOIZE) */
4393
4394   /* When we first read in all of the information from the aux_info files
4395      we saved in it descending line number order, because that was likely to
4396      be faster.  Now however, we want the chains of def & dec records to
4397      appear in ascending line number order as we get further away from the
4398      file_info record that they hang from.  The following line causes all of
4399      these lists to be rearranged into ascending line number order.  */
4400
4401   visit_each_hash_node (filename_primary, reverse_def_dec_list);
4402
4403 #ifndef UNPROTOIZE
4404
4405   /* Now do the "real" work.  The following line causes each declaration record
4406      to be "visited".  For each of these nodes, an attempt is made to match
4407      up the function declaration with a corresponding function definition,
4408      which should have a full prototype-format formals list with it.  Once
4409      these match-ups are made, the conversion of the function declarations
4410      to prototype format can be made.  */
4411
4412   visit_each_hash_node (function_name_primary, connect_defs_and_decs);
4413
4414 #endif /* !defined (UNPROTOIZE) */
4415
4416   /* Now convert each file that can be converted (and needs to be).  */
4417
4418   visit_each_hash_node (filename_primary, edit_file);
4419
4420 #ifndef UNPROTOIZE
4421
4422   /* If we are working in cplusplus mode, try to rename all .c files to .C
4423      files.  Don't panic if some of the renames don't work.  */
4424
4425   if (cplusplus_flag && !nochange_flag)
4426     visit_each_hash_node (filename_primary, rename_c_file);
4427
4428 #endif /* !defined (UNPROTOIZE) */
4429 }
4430 \f
4431 static struct option longopts[] =
4432 {
4433   {"version", 0, 0, 'V'},
4434   {"file_name", 0, 0, 'p'},
4435   {"quiet", 0, 0, 'q'},
4436   {"silent", 0, 0, 'q'},
4437   {"force", 0, 0, 'f'},
4438   {"keep", 0, 0, 'k'},
4439   {"nosave", 0, 0, 'N'},
4440   {"nochange", 0, 0, 'n'},
4441   {"compiler-options", 1, 0, 'c'},
4442   {"exclude", 1, 0, 'x'},
4443   {"directory", 1, 0, 'd'},
4444 #ifdef UNPROTOIZE
4445   {"indent", 1, 0, 'i'},
4446 #else
4447   {"local", 0, 0, 'l'},
4448   {"global", 0, 0, 'g'},
4449   {"c++", 0, 0, 'C'},
4450   {"syscalls-dir", 1, 0, 'B'},
4451 #endif
4452   {0, 0, 0, 0}
4453 };
4454
4455 int
4456 main (argc, argv)
4457      int argc;
4458      char **const argv;
4459 {
4460   int longind;
4461   int c;
4462   const char *params = "";
4463
4464   pname = rindex (argv[0], '/');
4465   pname = pname ? pname+1 : argv[0];
4466
4467   cwd_buffer = getpwd ();
4468   if (!cwd_buffer)
4469     {
4470       fprintf (stderr, "%s: cannot get working directory: %s\n",
4471                pname, sys_errlist[errno]);
4472       exit (1);
4473     }
4474
4475   /* By default, convert the files in the current directory.  */
4476   directory_list = string_list_cons (cwd_buffer, NULL);
4477
4478   while ((c = getopt_long (argc, argv,
4479 #ifdef UNPROTOIZE
4480                            "c:d:i:knNp:qvVx:",
4481 #else
4482                            "B:c:Cd:gklnNp:qvVx:",
4483 #endif
4484                            longopts, &longind)) != EOF)
4485     {
4486       if (c == 0)               /* Long option. */
4487         c = longopts[longind].val;
4488       switch (c)
4489         {
4490         case 'p':
4491           compiler_file_name = optarg;
4492           break;
4493         case 'd':
4494           directory_list
4495             = string_list_cons (abspath (NULL, optarg), directory_list);
4496           break;
4497         case 'x':
4498           exclude_list = string_list_cons (optarg, exclude_list);
4499           break;
4500             
4501         case 'v':
4502         case 'V':
4503           version_flag = 1;
4504           break;
4505         case 'q':
4506           quiet_flag = 1;
4507           break;
4508 #if 0
4509         case 'f':
4510           force_flag = 1;
4511           break;
4512 #endif
4513         case 'n':
4514           nochange_flag = 1;
4515           keep_flag = 1;
4516           break;
4517         case 'N':
4518           nosave_flag = 1;
4519           break;
4520         case 'k':
4521           keep_flag = 1;
4522           break;
4523         case 'c':
4524           params = optarg;
4525           break;
4526 #ifdef UNPROTOIZE
4527         case 'i':
4528           indent_string = optarg;
4529           break;
4530 #else                           /* !defined (UNPROTOIZE) */
4531         case 'l':
4532           local_flag = 1;
4533           break;
4534         case 'g':
4535           global_flag = 1;
4536           break;
4537         case 'C':
4538           cplusplus_flag = 1;
4539           break;
4540         case 'B':
4541           nondefault_syscalls_dir = optarg;
4542           break;
4543 #endif                          /* !defined (UNPROTOIZE) */
4544         default:
4545           usage ();
4546         }
4547     }
4548  
4549   /* Set up compile_params based on -p and -c options.  */
4550   munge_compile_params (params);
4551
4552   n_base_source_files = argc - optind;
4553
4554   /* Now actually make a list of the base source filenames.  */
4555
4556   base_source_filenames =
4557     (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
4558   n_base_source_files = 0;
4559   for (; optind < argc; optind++)
4560     {
4561       const char *path = abspath (NULL, argv[optind]);
4562       int len = strlen (path);
4563
4564       if (path[len-1] == 'c' && path[len-2] == '.')
4565         base_source_filenames[n_base_source_files++] = path;
4566       else
4567         {
4568           fprintf (stderr, "%s: input file names must have .c suffixes: %s\n",
4569                    pname, shortpath (NULL, path));
4570           errors++;
4571         }
4572     }
4573
4574 #ifndef UNPROTOIZE
4575   /* We are only interested in the very first identifier token in the
4576      definition of `va_list', so if there is more junk after that first
4577      identifier token, delete it from the `varargs_style_indicator'.  */
4578   {
4579     const char *cp;
4580
4581     for (cp = varargs_style_indicator; isalnum (*cp) || *cp == '_'; cp++)
4582       continue;
4583     if (*cp != 0)
4584       varargs_style_indicator = savestring (varargs_style_indicator,
4585                                             cp - varargs_style_indicator);
4586   }
4587 #endif /* !defined (UNPROTOIZE) */
4588
4589   if (errors)
4590     usage ();
4591   else
4592     {
4593       if (version_flag)
4594         fprintf (stderr, "%s: %s\n", pname, version_string);
4595       do_processing ();
4596     }
4597   if (errors)
4598     exit (1);
4599   else
4600     exit (0);
4601   return 1;
4602 }