OSDN Git Service

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