OSDN Git Service

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