OSDN Git Service

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