OSDN Git Service

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