OSDN Git Service

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