OSDN Git Service

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