OSDN Git Service

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