OSDN Git Service

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