OSDN Git Service

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