OSDN Git Service

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