OSDN Git Service

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