OSDN Git Service

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