OSDN Git Service

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