OSDN Git Service

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