OSDN Git Service

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