OSDN Git Service

* protoize.c (gen_aux_info_file): Let pexecute call choose_temp_base if
[pf3gnuchains/gcc-fork.git] / gcc / protoize.c
1 /* Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
2    Copyright (C) 1989, 92-98, 1999 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 "intl.h"
62 #undef abort
63
64 #if ! defined (_WIN32) || defined (__CYGWIN__) || defined (_UWIN)
65 #if defined(POSIX) || defined(CONCURRENT)
66 #include <dirent.h>
67 #else
68 #include <sys/dir.h>
69 #endif
70 #endif
71 #include <setjmp.h>
72
73 /* Some systems like Linux don't declare rindex if _POSIX_SOURCE is declared,
74    but it normally does declare it.  This means that configure thinks we don't
75    need to declare it.  Favor using strrchr if it is available.  */
76
77 #ifndef strrchr
78 #ifndef HAVE_STRRCHR
79 #ifdef  HAVE_RINDEX
80 #define strrchr rindex
81 #endif
82 #endif
83 #endif
84
85 /* Include getopt.h for the sake of getopt_long.
86    We don't need the declaration of getopt, and it could conflict
87    with something from a system header file, so effectively nullify that.  */
88 #define getopt getopt_loser
89 #include "getopt.h"
90 #undef getopt
91
92 extern char *version_string;
93
94 /* Systems which are compatible only with POSIX 1003.1-1988 (but *not*
95    with POSIX 1003.1-1990), e.g. Ultrix 4.2, might not have
96    const qualifiers in the prototypes in the system include files.
97    Unfortunately, this can lead to GCC issuing lots of warnings for
98    calls to the following functions.  To eliminate these warnings we
99    provide the following #defines.  */
100
101 #define my_access(file,flag)    access((char *)file, flag)
102 #define my_stat(file,pkt)       stat((char *)file, pkt)
103 #ifdef __MINGW32__
104 #define my_link(file1, file2)   -1
105 #else
106 #define my_link(file1, file2)   link((char *)file1, (char *)file2)
107 #endif
108 #define my_unlink(file)         unlink((char *)file)
109 #define my_open(file, mode, flag)       open((char *)file, mode, flag)
110 #define my_chmod(file, mode)    chmod((char *)file, mode)
111
112 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
113 static void aux_info_corrupted PARAMS ((void)) ATTRIBUTE_NORETURN;
114 static void declare_source_confusing PARAMS ((const char *)) ATTRIBUTE_NORETURN;
115
116 /* Aliases for pointers to void.
117    These were made to facilitate compilation with old brain-dead DEC C
118    compilers which didn't properly grok `void*' types.  */
119
120 typedef PTR pointer_type;
121 typedef const PTR const_pointer_type;
122
123 #if defined(POSIX)
124
125 #include <signal.h>
126
127 #else /* !defined(POSIX) */
128
129 /* Declaring stat or __flsbuf with a prototype
130    causes conflicts with system headers on some systems.  */
131
132 #if 0 /* These conflict with stdio.h on some systems.  */
133 extern int creat ();
134 extern int fprintf (FILE *, const char *, ...);
135 extern int printf (const char *, ...);
136 extern int open (const char *, int, ...);
137 extern int read ();
138 extern int write ();
139 #endif /* 0 */
140 extern int close ();
141 extern int fflush ();
142 extern int atoi ();
143 extern int puts ();
144 #ifndef fputs   /* This may have been #defined by "system.h".  */
145 extern int fputs ();
146 #endif
147 #ifndef fputc   /* some systems define this as a macro. */
148 extern int fputc ();
149 #endif
150 extern int unlink ();
151 extern int access ();
152
153 #if 0 /* size_t from sys/types.h may fail to match GCC.
154          If so, we would get a warning from this.  */
155 extern size_t   strlen ()
156 #endif
157
158 #endif /* !defined (POSIX) */
159
160 /* Look for these where the `const' qualifier is intentionally cast aside.  */
161
162 #define NONCONST
163
164 /* Define a default place to find the SYSCALLS.X file.  */
165
166 #ifndef UNPROTOIZE
167
168 #ifndef STANDARD_EXEC_PREFIX
169 #define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-lib/"
170 #endif /* !defined STANDARD_EXEC_PREFIX */
171
172 static char *standard_exec_prefix = STANDARD_EXEC_PREFIX;
173 static char *target_machine = DEFAULT_TARGET_MACHINE;
174 static char *target_version = DEFAULT_TARGET_VERSION;
175
176 #ifndef GET_ENV_PATH_LIST
177 #define GET_ENV_PATH_LIST(VAR,NAME)     do { (VAR) = getenv (NAME); } while (0)
178 #endif
179
180 #endif /* !defined (UNPROTOIZE) */
181
182 /* Suffix of aux_info files.  */
183
184 static const char * const aux_info_suffix = ".X";
185
186 /* String to attach to filenames for saved versions of original files.  */
187
188 static const char * const save_suffix = ".save";
189
190 #ifndef UNPROTOIZE
191
192 /* File name of the file which contains descriptions of standard system
193    routines.  Note that we never actually do anything with this file per se,
194    but we do read in its corresponding aux_info file.  */
195
196 static const char syscalls_filename[] = "SYSCALLS.c";
197
198 /* Default place to find the above file.  */
199
200 static char * default_syscalls_dir;
201
202 /* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
203    file.  */
204
205 static char * syscalls_absolute_filename;
206
207 #endif /* !defined (UNPROTOIZE) */
208
209 /* Type of the structure that holds information about macro unexpansions.  */
210
211 struct unexpansion_struct {
212   const char *expanded;
213   const char *contracted;
214 };
215 typedef struct unexpansion_struct unexpansion;
216
217 /* A table of conversions that may need to be made for some (stupid) older
218    operating systems where these types are preprocessor macros rather than
219    typedefs (as they really ought to be).
220
221    WARNING: The contracted forms must be as small (or smaller) as the
222    expanded forms, or else havoc will ensue.  */
223
224 static const unexpansion unexpansions[] = {
225   { "struct _iobuf", "FILE" },
226   { 0, 0 }
227 };
228
229 /* The number of "primary" slots in the hash tables for filenames and for
230    function names.  This can be as big or as small as you like, except that
231    it must be a power of two.  */
232
233 #define HASH_TABLE_SIZE         (1 << 9)
234
235 /* Bit mask to use when computing hash values.  */
236
237 static const int hash_mask = (HASH_TABLE_SIZE - 1);
238
239 /* Make a table of default system include directories
240    just as it is done in cccp.c.  */
241
242 #ifndef STANDARD_INCLUDE_DIR
243 #define STANDARD_INCLUDE_DIR "/usr/include"
244 #endif
245
246 #ifndef LOCAL_INCLUDE_DIR
247 #define LOCAL_INCLUDE_DIR "/usr/local/include"
248 #endif
249
250 struct default_include { const char *fname; 
251                          const char *component;
252                          int x1, x2; } include_defaults[]
253 #ifdef INCLUDE_DEFAULTS
254   = INCLUDE_DEFAULTS;
255 #else
256   = {
257     /* Pick up GNU C++ specific include files.  */
258     { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
259 #ifdef CROSS_COMPILE
260     /* This is the dir for fixincludes.  Put it just before
261        the files that we fix.  */
262     { GCC_INCLUDE_DIR, "GCC", 0, 0 },
263     /* For cross-compilation, this dir name is generated
264        automatically in Makefile.in.  */
265     { CROSS_INCLUDE_DIR, 0, 0, 0 },
266     /* This is another place that the target system's headers might be.  */
267     { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
268 #else /* not CROSS_COMPILE */
269     /* This should be /use/local/include and should come before
270        the fixincludes-fixed header files.  */
271     { LOCAL_INCLUDE_DIR, 0, 0, 1 },
272     /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
273        Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h.  */
274     { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
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     /* Some systems have an extra dir of include files.  */
279 #ifdef SYSTEM_INCLUDE_DIR
280     { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
281 #endif
282     { STANDARD_INCLUDE_DIR, 0, 0, 0},
283 #endif /* not CROSS_COMPILE */
284     { 0, 0, 0, 0}
285     };
286 #endif /* no INCLUDE_DEFAULTS */
287
288 /* Datatype for lists of directories or filenames.  */
289 struct string_list
290 {
291   char *name;
292   struct string_list *next;
293 };
294
295 /* List of directories in which files should be converted.  */
296
297 struct string_list *directory_list;
298
299 /* List of file names which should not be converted.
300    A file is excluded if the end of its name, following a /,
301    matches one of the names in this list.  */
302
303 struct string_list *exclude_list;
304
305 /* The name of the other style of variable-number-of-parameters functions
306    (i.e. the style that we want to leave unconverted because we don't yet
307    know how to convert them to this style.  This string is used in warning
308    messages.  */
309
310 /* Also define here the string that we can search for in the parameter lists
311    taken from the .X files which will unambiguously indicate that we have
312    found a varargs style function.  */
313
314 #ifdef UNPROTOIZE
315 static const char * const other_var_style = "stdarg";
316 #else /* !defined (UNPROTOIZE) */
317 static const char * const other_var_style = "varargs";
318 /* Note that this is a string containing the expansion of va_alist.
319    But in `main' we discard all but the first token.  */
320 static const char *varargs_style_indicator = STRINGIFY (va_alist);
321 #endif /* !defined (UNPROTOIZE) */
322
323 /* The following two types are used to create hash tables.  In this program,
324    there are two hash tables which are used to store and quickly lookup two
325    different classes of strings.  The first type of strings stored in the
326    first hash table are absolute filenames of files which protoize needs to
327    know about.  The second type of strings (stored in the second hash table)
328    are function names.  It is this second class of strings which really
329    inspired the use of the hash tables, because there may be a lot of them.  */
330
331 typedef struct hash_table_entry_struct hash_table_entry;
332
333 /* Do some typedefs so that we don't have to write "struct" so often.  */
334
335 typedef struct def_dec_info_struct def_dec_info;
336 typedef struct file_info_struct file_info;
337 typedef struct f_list_chain_item_struct f_list_chain_item;
338
339 /* In the struct below, note that the "_info" field has two different uses
340    depending on the type of hash table we are in (i.e. either the filenames
341    hash table or the function names hash table).  In the filenames hash table
342    the info fields of the entries point to the file_info struct which is
343    associated with each filename (1 per filename).  In the function names
344    hash table, the info field points to the head of a singly linked list of
345    def_dec_info entries which are all defs or decs of the function whose
346    name is pointed to by the "symbol" field.  Keeping all of the defs/decs
347    for a given function name on a special list specifically for that function
348    name makes it quick and easy to find out all of the important information
349    about a given (named) function.  */
350
351 struct hash_table_entry_struct {
352   hash_table_entry *            hash_next;      /* -> to secondary entries */
353   const char *                  symbol;         /* -> to the hashed string */
354   union {
355     const def_dec_info *        _ddip;
356     file_info *                 _fip;
357   } _info;
358 };
359 #define ddip _info._ddip
360 #define fip _info._fip
361
362 /* Define a type specifically for our two hash tables.  */
363
364 typedef hash_table_entry hash_table[HASH_TABLE_SIZE];
365
366 /* The following struct holds all of the important information about any
367    single filename (e.g. file) which we need to know about.  */
368
369 struct file_info_struct {
370   const hash_table_entry *      hash_entry; /* -> to associated hash entry */
371   const def_dec_info *          defs_decs;  /* -> to chain of defs/decs */
372   time_t                        mtime;      /* Time of last modification.  */
373 };
374
375 /* Due to the possibility that functions may return pointers to functions,
376    (which may themselves have their own parameter lists) and due to the
377    fact that returned pointers-to-functions may be of type "pointer-to-
378    function-returning-pointer-to-function" (ad nauseum) we have to keep
379    an entire chain of ANSI style formal parameter lists for each function.
380
381    Normally, for any given function, there will only be one formals list
382    on the chain, but you never know.
383
384    Note that the head of each chain of formals lists is pointed to by the
385    `f_list_chain' field of the corresponding def_dec_info record.
386
387    For any given chain, the item at the head of the chain is the *leftmost*
388    parameter list seen in the actual C language function declaration.  If
389    there are other members of the chain, then these are linked in left-to-right
390    order from the head of the chain.  */
391
392 struct f_list_chain_item_struct {
393   const f_list_chain_item *     chain_next;     /* -> to next item on chain */
394   const char *                  formals_list;   /* -> to formals list string */
395 };
396
397 /* The following struct holds all of the important information about any
398    single function definition or declaration which we need to know about.
399    Note that for unprotoize we don't need to know very much because we
400    never even create records for stuff that we don't intend to convert
401    (like for instance defs and decs which are already in old K&R format
402    and "implicit" function declarations).  */
403
404 struct def_dec_info_struct {
405   const def_dec_info *  next_in_file;   /* -> to rest of chain for file */
406   file_info *           file;           /* -> file_info for containing file */
407   int                   line;           /* source line number of def/dec */
408   const char *          ansi_decl;      /* -> left end of ansi decl */
409   hash_table_entry *    hash_entry;     /* -> hash entry for function name */
410   unsigned int          is_func_def;    /* = 0 means this is a declaration */
411   const def_dec_info *  next_for_func;  /* -> to rest of chain for func name */
412   unsigned int          f_list_count;   /* count of formals lists we expect */
413   char                  prototyped;     /* = 0 means already prototyped */
414 #ifndef UNPROTOIZE
415   const f_list_chain_item * f_list_chain;       /* -> chain of formals lists */
416   const def_dec_info *  definition;     /* -> def/dec containing related def */
417   char                  is_static;      /* = 0 means visibility is "extern"  */
418   char                  is_implicit;    /* != 0 for implicit func decl's */
419   char                  written;        /* != 0 means written for implicit */
420 #else /* !defined (UNPROTOIZE) */
421   const char *          formal_names;   /* -> to list of names of formals */
422   const char *          formal_decls;   /* -> to string of formal declarations */
423 #endif /* !defined (UNPROTOIZE) */
424 };
425
426 /* Pointer to the tail component of the filename by which this program was
427    invoked.  Used everywhere in error and warning messages.  */
428
429 static const char *pname;
430
431 /* Error counter.  Will be non-zero if we should give up at the next convenient
432    stopping point.  */
433
434 static int errors = 0;
435
436 /* Option flags.  */
437 /* ??? These comments should say what the flag mean as well as the options
438    that set them.  */
439
440 /* File name to use for running gcc.  Allows GCC 2 to be named
441    something other than gcc.  */
442 static const char *compiler_file_name = "gcc";
443
444 static int version_flag = 0;            /* Print our version number.  */
445 static int quiet_flag = 0;              /* Don't print messages normally.  */
446 static int nochange_flag = 0;           /* Don't convert, just say what files
447                                            we would have converted.  */
448 static int nosave_flag = 0;             /* Don't save the old version.  */
449 static int keep_flag = 0;               /* Don't delete the .X files.  */
450 static const char ** compile_params = 0;        /* Option string for gcc.  */
451 #ifdef UNPROTOIZE
452 static const char *indent_string = "     ";     /* Indentation for newly
453                                                    inserted parm decls.  */
454 #else /* !defined (UNPROTOIZE) */
455 static int local_flag = 0;              /* Insert new local decls (when?).  */
456 static int global_flag = 0;             /* set by -g option */
457 static int cplusplus_flag = 0;          /* Rename converted files to *.C.  */
458 static const char *nondefault_syscalls_dir = 0; /* Dir to look for
459                                                    SYSCALLS.c.X in.  */
460 #endif /* !defined (UNPROTOIZE) */
461
462 /* An index into the compile_params array where we should insert the source
463    file name when we are ready to exec the C compiler.  A zero value indicates
464    that we have not yet called munge_compile_params.  */
465
466 static int input_file_name_index = 0;
467
468 /* An index into the compile_params array where we should insert the filename
469    for the aux info file, when we run the C compiler.  */
470 static int aux_info_file_name_index = 0;
471
472 /* Count of command line arguments which were "filename" arguments.  */
473
474 static int n_base_source_files = 0;
475
476 /* Points to a malloc'ed list of pointers to all of the filenames of base
477    source files which were specified on the command line.  */
478
479 static const char **base_source_filenames;
480
481 /* Line number of the line within the current aux_info file that we
482    are currently processing.  Used for error messages in case the prototypes
483    info file is corrupted somehow.  */
484
485 static int current_aux_info_lineno;
486
487 /* Pointer to the name of the source file currently being converted.  */
488
489 static const char *convert_filename;
490
491 /* Pointer to relative root string (taken from aux_info file) which indicates
492    where directory the user was in when he did the compilation step that
493    produced the containing aux_info file.  */
494
495 static const char *invocation_filename;
496
497 /* Pointer to the base of the input buffer that holds the original text for the
498    source file currently being converted.  */
499
500 static const char *orig_text_base;
501
502 /* Pointer to the byte just beyond the end of the input buffer that holds the
503    original text for the source file currently being converted.  */
504
505 static const char *orig_text_limit;
506
507 /* Pointer to the base of the input buffer that holds the cleaned text for the
508    source file currently being converted.  */
509
510 static const char *clean_text_base;
511
512 /* Pointer to the byte just beyond the end of the input buffer that holds the
513    cleaned text for the source file currently being converted.  */
514
515 static const char *clean_text_limit;
516
517 /* Pointer to the last byte in the cleaned text buffer that we have already
518    (virtually) copied to the output buffer (or decided to ignore).  */
519
520 static const char * clean_read_ptr;
521
522 /* Pointer to the base of the output buffer that holds the replacement text
523    for the source file currently being converted.  */
524
525 static char *repl_text_base;
526
527 /* Pointer to the byte just beyond the end of the output buffer that holds the
528    replacement text for the source file currently being converted.  */
529
530 static char *repl_text_limit;
531
532 /* Pointer to the last byte which has been stored into the output buffer.
533    The next byte to be stored should be stored just past where this points
534    to.  */
535
536 static char * repl_write_ptr;
537
538 /* Pointer into the cleaned text buffer for the source file we are currently
539    converting.  This points to the first character of the line that we last
540    did a "seek_to_line" to (see below).  */
541
542 static const char *last_known_line_start;
543
544 /* Number of the line (in the cleaned text buffer) that we last did a
545    "seek_to_line" to.  Will be one if we just read a new source file
546    into the cleaned text buffer.  */
547
548 static int last_known_line_number;
549
550 /* The filenames hash table.  */
551
552 static hash_table filename_primary;
553
554 /* The function names hash table.  */
555
556 static hash_table function_name_primary;
557
558 /* The place to keep the recovery address which is used only in cases where
559    we get hopelessly confused by something in the cleaned original text.  */
560
561 static jmp_buf source_confusion_recovery;
562
563 /* A pointer to the current directory filename (used by abspath).  */
564
565 static char *cwd_buffer;
566
567 /* A place to save the read pointer until we are sure that an individual
568    attempt at editing will succeed.  */
569
570 static const char * saved_clean_read_ptr;
571
572 /* A place to save the write pointer until we are sure that an individual
573    attempt at editing will succeed.  */
574
575 static char * saved_repl_write_ptr;
576
577 /* Forward declaration.  */
578
579 static const char *shortpath ();
580 \f
581 /* Translate and output an error message.  */
582 static void notice                      PARAMS ((const char *, ...))
583   ATTRIBUTE_PRINTF_1;
584 static void
585 notice VPARAMS ((const char *msgid, ...))
586 {
587 #ifndef ANSI_PROTOTYPES
588   const char *msgid;
589 #endif
590   va_list ap;
591
592   VA_START (ap, msgid);
593
594 #ifndef ANSI_PROTOTYPES
595   msgid = va_arg (ap, const char *);
596 #endif
597
598   vfprintf (stderr, _(msgid), ap);
599   va_end (ap);
600 }
601
602 \f
603 char *
604 xstrerror(e)
605      int e;
606 {
607
608 #ifdef HAVE_STRERROR
609   return strerror(e);
610
611 #else
612   if (!e)
613     return "";
614
615   if (e > 0 && e < sys_nerr)
616     return sys_errlist[e];
617
618   return "errno = ?";
619 #endif
620 }
621 \f
622 /* Allocate some space, but check that the allocation was successful.  */
623 /* alloca.c uses this, so don't make it static.  */
624
625 pointer_type
626 xmalloc (byte_count)
627      size_t byte_count;
628 {
629   register pointer_type rv = (pointer_type) malloc (byte_count);
630   if (rv == NULL)
631     {
632       notice ("\n%s: virtual memory exceeded\n", pname);
633       exit (FATAL_EXIT_CODE);
634     }
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   register pointer_type rv;
646   if (old_space)
647     rv = (pointer_type) realloc (old_space, byte_count);
648   else
649     rv = (pointer_type) malloc (byte_count);
650   if (rv == NULL)
651     {
652       notice ("\n%s: virtual memory exceeded\n", pname);
653       exit (FATAL_EXIT_CODE);
654     }
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   notice ("%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         notice ("%s: error writing file `%s': %s\n",
794                 pname, shortpath (NULL, out_fname), xstrerror (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   notice ("%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
838           pname, pname);
839 #else /* !defined (UNPROTOIZE) */
840   notice ("%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         notice ("%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         notice ("%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         notice ("%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 #if defined (apollo) || defined (_WIN32) || defined (__INTERIX)
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                         notice ("%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               notice ("%s: %s: can't get status: %s\n",
1487                       pname, shortpath (NULL, filename),
1488                       xstrerror (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   notice ("\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                 notice ("%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     notice ("%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
2089     pid = pexecute (compile_params[0], (char * const *) compile_params,
2090                     pname, NULL, &errmsg_fmt, &errmsg_arg,
2091                     PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH);
2092
2093     if (pid == -1)
2094       {
2095         int errno_val = errno;
2096         fprintf (stderr, "%s: ", pname);
2097         fprintf (stderr, errmsg_fmt, errmsg_arg);
2098         fprintf (stderr, ": %s\n", xstrerror (errno_val));
2099         return 0;
2100       }
2101
2102     pid = pwait (pid, &wait_status, 0);
2103     if (pid == -1)
2104       {
2105         notice ("%s: wait: %s\n", pname, xstrerror (errno));
2106         return 0;
2107       }
2108     if (WIFSIGNALED (wait_status))
2109       {
2110         notice ("%s: subprocess got fatal signal %d\n",
2111                 pname, WTERMSIG (wait_status));
2112         return 0;
2113       }
2114     if (WIFEXITED (wait_status))
2115       {
2116         if (WEXITSTATUS (wait_status) != 0)
2117           {
2118             notice ("%s: %s exited with status %d\n",
2119                     pname, compile_params[0], WEXITSTATUS (wait_status));
2120             return 0;
2121           }
2122         return 1;
2123       }
2124     abort ();
2125   }
2126 }
2127 \f
2128 /* Read in all of the information contained in a single aux_info file.
2129    Save all of the important stuff for later.  */
2130
2131 static void
2132 process_aux_info_file (base_source_filename, keep_it, is_syscalls)
2133      const char *base_source_filename;
2134      int keep_it;
2135      int is_syscalls;
2136 {
2137   size_t base_len = strlen (base_source_filename);
2138   char * aux_info_filename
2139     = (char *) alloca (base_len + strlen (aux_info_suffix) + 1);
2140   char *aux_info_base;
2141   char *aux_info_limit;
2142   char *aux_info_relocated_name;
2143   const char *aux_info_second_line;
2144   time_t aux_info_mtime;
2145   size_t aux_info_size;
2146   int must_create;
2147
2148   /* Construct the aux_info filename from the base source filename.  */
2149
2150   strcpy (aux_info_filename, base_source_filename);
2151   strcat (aux_info_filename, aux_info_suffix);
2152
2153   /* Check that the aux_info file exists and is readable.  If it does not
2154      exist, try to create it (once only).  */
2155
2156   /* If file doesn't exist, set must_create.
2157      Likewise if it exists and we can read it but it is obsolete.
2158      Otherwise, report an error.  */
2159   must_create = 0;
2160
2161   /* Come here with must_create set to 1 if file is out of date.  */
2162 start_over: ;
2163
2164   if (my_access (aux_info_filename, R_OK) == -1)
2165     {
2166       if (errno == ENOENT)
2167         {
2168           if (is_syscalls)
2169             {
2170               notice ("%s: warning: missing SYSCALLS file `%s'\n",
2171                       pname, aux_info_filename);
2172               return;
2173             }
2174           must_create = 1;
2175         }
2176       else
2177         {
2178           int errno_val = errno;
2179           notice ("%s: can't read aux info file `%s': %s\n",
2180                   pname, shortpath (NULL, aux_info_filename),
2181                   xstrerror (errno_val));
2182           errors++;
2183           return;
2184         }
2185     }
2186 #if 0 /* There is code farther down to take care of this.  */
2187   else
2188     {
2189       struct stat s1, s2;
2190       stat (aux_info_file_name, &s1);
2191       stat (base_source_file_name, &s2);
2192       if (s2.st_mtime > s1.st_mtime)
2193         must_create = 1;
2194     }
2195 #endif /* 0 */
2196
2197   /* If we need a .X file, create it, and verify we can read it.  */
2198   if (must_create)
2199     {
2200       if (!gen_aux_info_file (base_source_filename))
2201         {
2202           errors++;
2203           return;
2204         }
2205       if (my_access (aux_info_filename, R_OK) == -1)
2206         {
2207           int errno_val = errno;
2208           notice ("%s: can't read aux info file `%s': %s\n",
2209                   pname, shortpath (NULL, aux_info_filename),
2210                   xstrerror (errno_val));
2211           errors++;
2212           return;
2213         }
2214     }
2215
2216   {
2217     struct stat stat_buf;
2218
2219     /* Get some status information about this aux_info file.  */
2220   
2221     if (my_stat (aux_info_filename, &stat_buf) == -1)
2222       {
2223         int errno_val = errno;
2224         notice ("%s: can't get status of aux info file `%s': %s\n",
2225                 pname, shortpath (NULL, aux_info_filename),
2226                 xstrerror (errno_val));
2227         errors++;
2228         return;
2229       }
2230   
2231     /* Check on whether or not this aux_info file is zero length.  If it is,
2232        then just ignore it and return.  */
2233   
2234     if ((aux_info_size = stat_buf.st_size) == 0)
2235       return;
2236   
2237     /* Get the date/time of last modification for this aux_info file and
2238        remember it.  We will have to check that any source files that it
2239        contains information about are at least this old or older.  */
2240   
2241     aux_info_mtime = stat_buf.st_mtime;
2242
2243     if (!is_syscalls)
2244       {
2245         /* Compare mod time with the .c file; update .X file if obsolete.
2246            The code later on can fail to check the .c file
2247            if it did not directly define any functions.  */
2248
2249         if (my_stat (base_source_filename, &stat_buf) == -1)
2250           {
2251             int errno_val = errno;
2252             notice ("%s: can't get status of aux info file `%s': %s\n",
2253                     pname, shortpath (NULL, base_source_filename),
2254                     xstrerror (errno_val));
2255             errors++;
2256             return;
2257           }
2258         if (stat_buf.st_mtime > aux_info_mtime)
2259           {
2260             must_create = 1;
2261             goto start_over;
2262           }
2263       }
2264   }
2265
2266   {
2267     int aux_info_file;
2268
2269     /* Open the aux_info file.  */
2270   
2271     if ((aux_info_file = my_open (aux_info_filename, O_RDONLY, 0444 )) == -1)
2272       {
2273         int errno_val = errno;
2274         notice ("%s: can't open aux info file `%s' for reading: %s\n",
2275                 pname, shortpath (NULL, aux_info_filename),
2276                 xstrerror (errno_val));
2277         return;
2278       }
2279   
2280     /* Allocate space to hold the aux_info file in memory.  */
2281   
2282     aux_info_base = xmalloc (aux_info_size + 1);
2283     aux_info_limit = aux_info_base + aux_info_size;
2284     *aux_info_limit = '\0';
2285   
2286     /* Read the aux_info file into memory.  */
2287   
2288     if (safe_read (aux_info_file, aux_info_base, aux_info_size) !=
2289         (int) aux_info_size)
2290       {
2291         int errno_val = errno;
2292         notice ("%s: error reading aux info file `%s': %s\n",
2293                 pname, shortpath (NULL, aux_info_filename),
2294                 xstrerror (errno_val));
2295         free (aux_info_base);
2296         close (aux_info_file);
2297         return;
2298       }
2299   
2300     /* Close the aux info file.  */
2301   
2302     if (close (aux_info_file))
2303       {
2304         int errno_val = errno;
2305         notice ("%s: error closing aux info file `%s': %s\n",
2306                 pname, shortpath (NULL, aux_info_filename),
2307                 xstrerror (errno_val));
2308         free (aux_info_base);
2309         close (aux_info_file);
2310         return;
2311       }
2312   }
2313
2314   /* Delete the aux_info file (unless requested not to).  If the deletion
2315      fails for some reason, don't even worry about it.  */
2316
2317   if (must_create && !keep_it)
2318     if (my_unlink (aux_info_filename) == -1)
2319       {
2320         int errno_val = errno;
2321         notice ("%s: can't delete aux info file `%s': %s\n",
2322                 pname, shortpath (NULL, aux_info_filename),
2323                 xstrerror (errno_val));
2324       }
2325
2326   /* Save a pointer into the first line of the aux_info file which
2327      contains the filename of the directory from which the compiler
2328      was invoked when the associated source file was compiled.
2329      This information is used later to help create complete
2330      filenames out of the (potentially) relative filenames in
2331      the aux_info file.  */
2332
2333   {
2334     char *p = aux_info_base;
2335
2336     while (*p != ':')
2337       p++;
2338     p++;
2339     while (*p == ' ')
2340       p++;
2341     invocation_filename = p;    /* Save a pointer to first byte of path.  */
2342     while (*p != ' ')
2343       p++;
2344     *p++ = '/';
2345     *p++ = '\0';
2346     while (*p++ != '\n')
2347       continue;
2348     aux_info_second_line = p;
2349     aux_info_relocated_name = 0;
2350     if (invocation_filename[0] != '/')
2351       {
2352         /* INVOCATION_FILENAME is relative;
2353            append it to BASE_SOURCE_FILENAME's dir.  */
2354         char *dir_end;
2355         aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
2356         strcpy (aux_info_relocated_name, base_source_filename);
2357         dir_end = strrchr (aux_info_relocated_name, '/');
2358         if (dir_end)
2359           dir_end++;
2360         else
2361           dir_end = aux_info_relocated_name;
2362         strcpy (dir_end, invocation_filename);
2363         invocation_filename = aux_info_relocated_name;
2364       }
2365   }
2366
2367
2368   {
2369     const char *aux_info_p;
2370
2371     /* Do a pre-pass on the lines in the aux_info file, making sure that all
2372        of the source files referenced in there are at least as old as this
2373        aux_info file itself.  If not, go back and regenerate the aux_info
2374        file anew.  Don't do any of this for the syscalls file.  */
2375
2376     if (!is_syscalls)
2377       {
2378         current_aux_info_lineno = 2;
2379     
2380         for (aux_info_p = aux_info_second_line; *aux_info_p; )
2381           {
2382             if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2383               {
2384                 free (aux_info_base);
2385                 xfree (aux_info_relocated_name);
2386                 if (keep_it && my_unlink (aux_info_filename) == -1)
2387                   {
2388                     int errno_val = errno;
2389                     notice ("%s: can't delete file `%s': %s\n",
2390                             pname, shortpath (NULL, aux_info_filename),
2391                             xstrerror (errno_val));
2392                     return;
2393                   }
2394                 must_create = 1;
2395                 goto start_over;
2396               }
2397     
2398             /* Skip over the rest of this line to start of next line.  */
2399     
2400             while (*aux_info_p != '\n')
2401               aux_info_p++;
2402             aux_info_p++;
2403             current_aux_info_lineno++;
2404           }
2405       }
2406
2407     /* Now do the real pass on the aux_info lines.  Save their information in
2408        the in-core data base.  */
2409   
2410     current_aux_info_lineno = 2;
2411   
2412     for (aux_info_p = aux_info_second_line; *aux_info_p;)
2413       {
2414         char *unexpanded_line = unexpand_if_needed (aux_info_p);
2415   
2416         if (unexpanded_line)
2417           {
2418             save_def_or_dec (unexpanded_line, is_syscalls);
2419             free (unexpanded_line);
2420           }
2421         else
2422           save_def_or_dec (aux_info_p, is_syscalls);
2423   
2424         /* Skip over the rest of this line and get to start of next line.  */
2425   
2426         while (*aux_info_p != '\n')
2427           aux_info_p++;
2428         aux_info_p++;
2429         current_aux_info_lineno++;
2430       }
2431   }
2432
2433   free (aux_info_base);
2434   xfree (aux_info_relocated_name);
2435 }
2436 \f
2437 #ifndef UNPROTOIZE
2438
2439 /* Check an individual filename for a .c suffix.  If the filename has this
2440    suffix, rename the file such that its suffix is changed to .C.  This
2441    function implements the -C option.  */
2442
2443 static void
2444 rename_c_file (hp)
2445      const hash_table_entry *hp;
2446 {
2447   const char *filename = hp->symbol;
2448   int last_char_index = strlen (filename) - 1;
2449   char *const new_filename = (char *) alloca (strlen (filename) + 1);
2450
2451   /* Note that we don't care here if the given file was converted or not.  It
2452      is possible that the given file was *not* converted, simply because there
2453      was nothing in it which actually required conversion.  Even in this case,
2454      we want to do the renaming.  Note that we only rename files with the .c
2455      suffix.  */
2456
2457   if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.')
2458     return;
2459
2460   strcpy (new_filename, filename);
2461   new_filename[last_char_index] = 'C';
2462
2463   if (my_link (filename, new_filename) == -1)
2464     {
2465       int errno_val = errno;
2466       notice ("%s: warning: can't link file `%s' to `%s': %s\n",
2467               pname, shortpath (NULL, filename),
2468               shortpath (NULL, new_filename), xstrerror (errno_val));
2469       errors++;
2470       return;
2471     }
2472
2473   if (my_unlink (filename) == -1)
2474     {
2475       int errno_val = errno;
2476       notice ("%s: warning: can't delete file `%s': %s\n",
2477               pname, shortpath (NULL, filename), xstrerror (errno_val));
2478       errors++;
2479       return;
2480     }
2481 }
2482
2483 #endif /* !defined (UNPROTOIZE) */
2484 \f
2485 /* Take the list of definitions and declarations attached to a particular
2486    file_info node and reverse the order of the list.  This should get the
2487    list into an order such that the item with the lowest associated line
2488    number is nearest the head of the list.  When these lists are originally
2489    built, they are in the opposite order.  We want to traverse them in
2490    normal line number order later (i.e. lowest to highest) so reverse the
2491    order here.  */
2492
2493 static void
2494 reverse_def_dec_list (hp)
2495      const hash_table_entry *hp;
2496 {
2497   file_info *file_p = hp->fip;
2498   def_dec_info *prev = NULL;
2499   def_dec_info *current = (def_dec_info *)file_p->defs_decs;
2500
2501   if (!current)
2502     return;                     /* no list to reverse */
2503
2504   prev = current;
2505   if (! (current = (def_dec_info *)current->next_in_file))
2506     return;                     /* can't reverse a single list element */
2507
2508   prev->next_in_file = NULL;
2509
2510   while (current)
2511     {
2512       def_dec_info *next = (def_dec_info *)current->next_in_file;
2513
2514       current->next_in_file = prev;
2515       prev = current;
2516       current = next;
2517     }
2518
2519   file_p->defs_decs = prev;
2520 }
2521
2522 #ifndef UNPROTOIZE
2523
2524 /* Find the (only?) extern definition for a particular function name, starting
2525    from the head of the linked list of entries for the given name.  If we
2526    cannot find an extern definition for the given function name, issue a
2527    warning and scrounge around for the next best thing, i.e. an extern
2528    function declaration with a prototype attached to it.  Note that we only
2529    allow such substitutions for extern declarations and never for static
2530    declarations.  That's because the only reason we allow them at all is
2531    to let un-prototyped function declarations for system-supplied library
2532    functions get their prototypes from our own extra SYSCALLS.c.X file which
2533    contains all of the correct prototypes for system functions.  */
2534
2535 static const def_dec_info *
2536 find_extern_def (head, user)
2537      const def_dec_info *head;
2538      const def_dec_info *user;
2539 {
2540   const def_dec_info *dd_p;
2541   const def_dec_info *extern_def_p = NULL;
2542   int conflict_noted = 0;
2543
2544   /* Don't act too stupid here.  Somebody may try to convert an entire system
2545      in one swell fwoop (rather than one program at a time, as should be done)
2546      and in that case, we may find that there are multiple extern definitions
2547      of a given function name in the entire set of source files that we are
2548      converting.  If however one of these definitions resides in exactly the
2549      same source file as the reference we are trying to satisfy then in that
2550      case it would be stupid for us to fail to realize that this one definition
2551      *must* be the precise one we are looking for.
2552
2553      To make sure that we don't miss an opportunity to make this "same file"
2554      leap of faith, we do a prescan of the list of records relating to the
2555      given function name, and we look (on this first scan) *only* for a
2556      definition of the function which is in the same file as the reference
2557      we are currently trying to satisfy.  */
2558
2559   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2560     if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
2561       return dd_p;
2562
2563   /* Now, since we have not found a definition in the same file as the
2564      reference, we scan the list again and consider all possibilities from
2565      all files.  Here we may get conflicts with the things listed in the
2566      SYSCALLS.c.X file, but if that happens it only means that the source
2567      code being converted contains its own definition of a function which
2568      could have been supplied by libc.a.  In such cases, we should avoid
2569      issuing the normal warning, and defer to the definition given in the
2570      user's own code.   */
2571
2572   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2573     if (dd_p->is_func_def && !dd_p->is_static)
2574       {
2575         if (!extern_def_p)      /* Previous definition? */
2576           extern_def_p = dd_p;  /* Remember the first definition found.  */
2577         else
2578           {
2579             /* Ignore definition just found if it came from SYSCALLS.c.X.  */
2580
2581             if (is_syscalls_file (dd_p->file))
2582               continue;
2583
2584             /* Quietly replace the definition previously found with the one
2585                just found if the previous one was from SYSCALLS.c.X.  */
2586
2587             if (is_syscalls_file (extern_def_p->file))
2588               {
2589                 extern_def_p = dd_p;
2590                 continue;
2591               }
2592
2593             /* If we get here, then there is a conflict between two function
2594                declarations for the same function, both of which came from the
2595                user's own code.  */
2596
2597             if (!conflict_noted)        /* first time we noticed? */
2598               {
2599                 conflict_noted = 1;
2600                 notice ("%s: conflicting extern definitions of '%s'\n",
2601                         pname, head->hash_entry->symbol);
2602                 if (!quiet_flag)
2603                   {
2604                     notice ("%s: declarations of '%s' will not be converted\n",
2605                             pname, head->hash_entry->symbol);
2606                     notice ("%s: conflict list for '%s' follows:\n",
2607                             pname, head->hash_entry->symbol);
2608                     fprintf (stderr, "%s:     %s(%d): %s\n",
2609                              pname,
2610                              shortpath (NULL, extern_def_p->file->hash_entry->symbol),
2611                              extern_def_p->line, extern_def_p->ansi_decl);
2612                   }
2613               }
2614             if (!quiet_flag)
2615               fprintf (stderr, "%s:     %s(%d): %s\n",
2616                        pname,
2617                        shortpath (NULL, dd_p->file->hash_entry->symbol),
2618                        dd_p->line, dd_p->ansi_decl);
2619           }
2620       }
2621
2622   /* We want to err on the side of caution, so if we found multiple conflicting
2623      definitions for the same function, treat this as being that same as if we
2624      had found no definitions (i.e. return NULL).  */
2625
2626   if (conflict_noted)
2627     return NULL;
2628
2629   if (!extern_def_p)
2630     {
2631       /* We have no definitions for this function so do the next best thing.
2632          Search for an extern declaration already in prototype form.  */
2633
2634       for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2635         if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2636           {
2637             extern_def_p = dd_p;        /* save a pointer to the definition */
2638             if (!quiet_flag)
2639               notice ("%s: warning: using formals list from %s(%d) for function `%s'\n",
2640                       pname,
2641                       shortpath (NULL, dd_p->file->hash_entry->symbol),
2642                       dd_p->line, dd_p->hash_entry->symbol);
2643             break;
2644           }
2645
2646       /* Gripe about unprototyped function declarations that we found no
2647          corresponding definition (or other source of prototype information)
2648          for.
2649
2650          Gripe even if the unprototyped declaration we are worried about
2651          exists in a file in one of the "system" include directories.  We
2652          can gripe about these because we should have at least found a
2653          corresponding (pseudo) definition in the SYSCALLS.c.X file.  If we
2654          didn't, then that means that the SYSCALLS.c.X file is missing some
2655          needed prototypes for this particular system.  That is worth telling
2656          the user about!  */
2657
2658       if (!extern_def_p)
2659         {
2660           const char *file = user->file->hash_entry->symbol;
2661
2662           if (!quiet_flag)
2663             if (in_system_include_dir (file))
2664               {
2665                 /* Why copy this string into `needed' at all?
2666                    Why not just use user->ansi_decl without copying?  */
2667                 char *needed = (char *) alloca (strlen (user->ansi_decl) + 1);
2668                 char *p;
2669
2670                 strcpy (needed, user->ansi_decl);
2671                 p = (NONCONST char *) substr (needed, user->hash_entry->symbol)
2672                     + strlen (user->hash_entry->symbol) + 2;
2673                 /* Avoid having ??? in the string.  */
2674                 *p++ = '?';
2675                 *p++ = '?';
2676                 *p++ = '?';
2677                 strcpy (p, ");");
2678
2679                 notice ("%s: %d: `%s' used but missing from SYSCALLS\n",
2680                         shortpath (NULL, file), user->line,
2681                         needed+7);      /* Don't print "extern " */
2682               }
2683 #if 0
2684             else
2685               notice ("%s: %d: warning: no extern definition for `%s'\n",
2686                       shortpath (NULL, file), user->line,
2687                       user->hash_entry->symbol);
2688 #endif
2689         }
2690     }
2691   return extern_def_p;
2692 }
2693 \f
2694 /* Find the (only?) static definition for a particular function name in a
2695    given file.  Here we get the function-name and the file info indirectly
2696    from the def_dec_info record pointer which is passed in.  */
2697
2698 static const def_dec_info *
2699 find_static_definition (user)
2700      const def_dec_info *user;
2701 {
2702   const def_dec_info *head = user->hash_entry->ddip;
2703   const def_dec_info *dd_p;
2704   int num_static_defs = 0;
2705   const def_dec_info *static_def_p = NULL;
2706
2707   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2708     if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
2709       {
2710         static_def_p = dd_p;    /* save a pointer to the definition */
2711         num_static_defs++;
2712       }
2713   if (num_static_defs == 0)
2714     {
2715       if (!quiet_flag)
2716         notice ("%s: warning: no static definition for `%s' in file `%s'\n",
2717                 pname, head->hash_entry->symbol,
2718                 shortpath (NULL, user->file->hash_entry->symbol));
2719     }
2720   else if (num_static_defs > 1)
2721     {
2722       notice ("%s: multiple static defs of `%s' in file `%s'\n",
2723               pname, head->hash_entry->symbol,
2724               shortpath (NULL, user->file->hash_entry->symbol));
2725       return NULL;
2726     }
2727   return static_def_p;
2728 }
2729
2730 /* Find good prototype style formal argument lists for all of the function
2731    declarations which didn't have them before now.
2732
2733    To do this we consider each function name one at a time.  For each function
2734    name, we look at the items on the linked list of def_dec_info records for
2735    that particular name.
2736
2737    Somewhere on this list we should find one (and only one) def_dec_info
2738    record which represents the actual function definition, and this record
2739    should have a nice formal argument list already associated with it.
2740
2741    Thus, all we have to do is to connect up all of the other def_dec_info
2742    records for this particular function name to the special one which has
2743    the full-blown formals list.
2744
2745    Of course it is a little more complicated than just that.  See below for
2746    more details.  */
2747
2748 static void
2749 connect_defs_and_decs (hp)
2750      const hash_table_entry *hp;
2751 {
2752   const def_dec_info *dd_p;
2753   const def_dec_info *extern_def_p = NULL;
2754   int first_extern_reference = 1;
2755
2756   /* Traverse the list of definitions and declarations for this particular
2757      function name.  For each item on the list, if it is a function
2758      definition (either old style or new style) then GCC has already been
2759      kind enough to produce a prototype for us, and it is associated with
2760      the item already, so declare the item as its own associated "definition".
2761
2762      Also, for each item which is only a function declaration, but which
2763      nonetheless has its own prototype already (obviously supplied by the user)
2764      declare the item as its own definition.
2765
2766      Note that when/if there are multiple user-supplied prototypes already
2767      present for multiple declarations of any given function, these multiple
2768      prototypes *should* all match exactly with one another and with the
2769      prototype for the actual function definition.  We don't check for this
2770      here however, since we assume that the compiler must have already done
2771      this consistency checking when it was creating the .X files.  */
2772
2773   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2774     if (dd_p->prototyped)
2775       ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
2776
2777   /* Traverse the list of definitions and declarations for this particular
2778      function name.  For each item on the list, if it is an extern function
2779      declaration and if it has no associated definition yet, go try to find
2780      the matching extern definition for the declaration.
2781
2782      When looking for the matching function definition, warn the user if we
2783      fail to find one.
2784
2785      If we find more that one function definition also issue a warning.
2786
2787      Do the search for the matching definition only once per unique function
2788      name (and only when absolutely needed) so that we can avoid putting out
2789      redundant warning messages, and so that we will only put out warning
2790      messages when there is actually a reference (i.e. a declaration) for
2791      which we need to find a matching definition.  */
2792
2793   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2794     if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
2795       {
2796         if (first_extern_reference)
2797           {
2798             extern_def_p = find_extern_def (hp->ddip, dd_p);
2799             first_extern_reference = 0;
2800           }
2801         ((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
2802       }
2803
2804   /* Traverse the list of definitions and declarations for this particular
2805      function name.  For each item on the list, if it is a static function
2806      declaration and if it has no associated definition yet, go try to find
2807      the matching static definition for the declaration within the same file.
2808
2809      When looking for the matching function definition, warn the user if we
2810      fail to find one in the same file with the declaration, and refuse to
2811      convert this kind of cross-file static function declaration.  After all,
2812      this is stupid practice and should be discouraged.
2813
2814      We don't have to worry about the possibility that there is more than one
2815      matching function definition in the given file because that would have
2816      been flagged as an error by the compiler.
2817
2818      Do the search for the matching definition only once per unique
2819      function-name/source-file pair (and only when absolutely needed) so that
2820      we can avoid putting out redundant warning messages, and so that we will
2821      only put out warning messages when there is actually a reference (i.e. a
2822      declaration) for which we actually need to find a matching definition.  */
2823
2824   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2825     if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
2826       {
2827         const def_dec_info *dd_p2;
2828         const def_dec_info *static_def;
2829
2830         /* We have now found a single static declaration for which we need to
2831            find a matching definition.  We want to minimize the work (and the
2832            number of warnings), so we will find an appropriate (matching)
2833            static definition for this declaration, and then distribute it
2834            (as the definition for) any and all other static declarations
2835            for this function name which occur within the same file, and which
2836            do not already have definitions.
2837
2838            Note that a trick is used here to prevent subsequent attempts to
2839            call find_static_definition for a given function-name & file
2840            if the first such call returns NULL.  Essentially, we convert
2841            these NULL return values to -1, and put the -1 into the definition
2842            field for each other static declaration from the same file which
2843            does not already have an associated definition.
2844            This makes these other static declarations look like they are
2845            actually defined already when the outer loop here revisits them
2846            later on.  Thus, the outer loop will skip over them.  Later, we
2847            turn the -1's back to NULL's.  */
2848
2849       ((NONCONST def_dec_info *) dd_p)->definition =
2850         (static_def = find_static_definition (dd_p))
2851           ? static_def
2852           : (const def_dec_info *) -1;
2853
2854       for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2855         if (!dd_p2->is_func_def && dd_p2->is_static
2856          && !dd_p2->definition && (dd_p2->file == dd_p->file))
2857           ((NONCONST def_dec_info *)dd_p2)->definition = dd_p->definition;
2858       }
2859
2860   /* Convert any dummy (-1) definitions we created in the step above back to
2861      NULL's (as they should be).  */
2862
2863   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2864     if (dd_p->definition == (def_dec_info *) -1)
2865       ((NONCONST def_dec_info *) dd_p)->definition = NULL;
2866 }
2867
2868 #endif /* !defined (UNPROTOIZE) */
2869
2870 /* Give a pointer into the clean text buffer, return a number which is the
2871    original source line number that the given pointer points into.  */
2872
2873 static int
2874 identify_lineno (clean_p)
2875      const char *clean_p;
2876 {
2877   int line_num = 1;
2878   const char *scan_p;
2879
2880   for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
2881     if (*scan_p == '\n')
2882       line_num++;
2883   return line_num;
2884 }
2885
2886 /* Issue an error message and give up on doing this particular edit.  */
2887
2888 static void
2889 declare_source_confusing (clean_p)
2890      const char *clean_p;
2891 {
2892   if (!quiet_flag)
2893     {
2894       if (clean_p == 0)
2895         notice ("%s: %d: warning: source too confusing\n",
2896                 shortpath (NULL, convert_filename), last_known_line_number);
2897       else
2898         notice ("%s: %d: warning: source too confusing\n",
2899                 shortpath (NULL, convert_filename),
2900                 identify_lineno (clean_p));
2901     }
2902   longjmp (source_confusion_recovery, 1);
2903 }
2904
2905 /* Check that a condition which is expected to be true in the original source
2906    code is in fact true.  If not, issue an error message and give up on
2907    converting this particular source file.  */
2908
2909 static void
2910 check_source (cond, clean_p)
2911      int cond;
2912      const char *clean_p;
2913 {
2914   if (!cond)
2915     declare_source_confusing (clean_p);
2916 }
2917
2918 /* If we think of the in-core cleaned text buffer as a memory mapped
2919    file (with the variable last_known_line_start acting as sort of a
2920    file pointer) then we can imagine doing "seeks" on the buffer.  The
2921    following routine implements a kind of "seek" operation for the in-core
2922    (cleaned) copy of the source file.  When finished, it returns a pointer to
2923    the start of a given (numbered) line in the cleaned text buffer.
2924
2925    Note that protoize only has to "seek" in the forward direction on the
2926    in-core cleaned text file buffers, and it never needs to back up.
2927
2928    This routine is made a little bit faster by remembering the line number
2929    (and pointer value) supplied (and returned) from the previous "seek".
2930    This prevents us from always having to start all over back at the top
2931    of the in-core cleaned buffer again.  */
2932
2933 static const char *
2934 seek_to_line (n)
2935      int n;
2936 {
2937   if (n < last_known_line_number)
2938     abort ();
2939
2940   while (n > last_known_line_number)
2941     {
2942       while (*last_known_line_start != '\n')
2943         check_source (++last_known_line_start < clean_text_limit, 0);
2944       last_known_line_start++;
2945       last_known_line_number++;
2946     }
2947   return last_known_line_start;
2948 }
2949
2950 /* Given a pointer to a character in the cleaned text buffer, return a pointer
2951    to the next non-whitespace character which follows it.  */
2952
2953 static const char *
2954 forward_to_next_token_char (ptr)
2955      const char *ptr;
2956 {
2957   for (++ptr; ISSPACE ((const unsigned char)*ptr);
2958        check_source (++ptr < clean_text_limit, 0))
2959     continue;
2960   return ptr;
2961 }
2962
2963 /* Copy a chunk of text of length `len' and starting at `str' to the current
2964    output buffer.  Note that all attempts to add stuff to the current output
2965    buffer ultimately go through here.  */
2966
2967 static void
2968 output_bytes (str, len)
2969      const char *str;
2970      size_t len;
2971 {
2972   if ((repl_write_ptr + 1) + len >= repl_text_limit)
2973     {
2974       size_t new_size = (repl_text_limit - repl_text_base) << 1;
2975       char *new_buf = (char *) xrealloc (repl_text_base, new_size);
2976
2977       repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
2978       repl_text_base = new_buf;
2979       repl_text_limit = new_buf + new_size;
2980     }
2981   memcpy (repl_write_ptr + 1, str, len);
2982   repl_write_ptr += len;
2983 }
2984
2985 /* Copy all bytes (except the trailing null) of a null terminated string to
2986    the current output buffer.  */
2987
2988 static void
2989 output_string (str)
2990      const char *str;
2991 {
2992   output_bytes (str, strlen (str));
2993 }
2994
2995 /* Copy some characters from the original text buffer to the current output
2996    buffer.
2997
2998    This routine takes a pointer argument `p' which is assumed to be a pointer
2999    into the cleaned text buffer.  The bytes which are copied are the `original'
3000    equivalents for the set of bytes between the last value of `clean_read_ptr'
3001    and the argument value `p'.
3002
3003    The set of bytes copied however, comes *not* from the cleaned text buffer,
3004    but rather from the direct counterparts of these bytes within the original
3005    text buffer.
3006
3007    Thus, when this function is called, some bytes from the original text
3008    buffer (which may include original comments and preprocessing directives)
3009    will be copied into the  output buffer.
3010
3011    Note that the request implied when this routine is called includes the
3012    byte pointed to by the argument pointer `p'.  */
3013
3014 static void
3015 output_up_to (p)
3016      const char *p;
3017 {
3018   size_t copy_length = (size_t) (p - clean_read_ptr);
3019   const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
3020
3021   if (copy_length == 0)
3022     return;
3023
3024   output_bytes (copy_start, copy_length);
3025   clean_read_ptr = p;
3026 }
3027
3028 /* Given a pointer to a def_dec_info record which represents some form of
3029    definition of a function (perhaps a real definition, or in lieu of that
3030    perhaps just a declaration with a full prototype) return true if this
3031    function is one which we should avoid converting.  Return false
3032    otherwise.  */
3033
3034 static int
3035 other_variable_style_function (ansi_header)
3036      const char *ansi_header;
3037 {
3038 #ifdef UNPROTOIZE
3039
3040   /* See if we have a stdarg function, or a function which has stdarg style
3041      parameters or a stdarg style return type.  */
3042
3043   return substr (ansi_header, "...") != 0;
3044
3045 #else /* !defined (UNPROTOIZE) */
3046
3047   /* See if we have a varargs function, or a function which has varargs style
3048      parameters or a varargs style return type.  */
3049
3050   const char *p;
3051   int len = strlen (varargs_style_indicator);
3052
3053   for (p = ansi_header; p; )
3054     {
3055       const char *candidate;
3056
3057       if ((candidate = substr (p, varargs_style_indicator)) == 0)
3058         return 0;
3059       else
3060         if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
3061           return 1;
3062         else
3063           p = candidate + 1;
3064     }
3065   return 0;
3066 #endif /* !defined (UNPROTOIZE) */
3067 }
3068
3069 /* Do the editing operation specifically for a function "declaration".  Note
3070    that editing for function "definitions" are handled in a separate routine
3071    below.  */
3072
3073 static void
3074 edit_fn_declaration (def_dec_p, clean_text_p)
3075      const def_dec_info *def_dec_p;
3076      const char *volatile clean_text_p;
3077 {
3078   const char *start_formals;
3079   const char *end_formals;
3080   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3081   size_t func_name_len = strlen (function_to_edit);
3082   const char *end_of_fn_name;
3083
3084 #ifndef UNPROTOIZE
3085
3086   const f_list_chain_item *this_f_list_chain_item;
3087   const def_dec_info *definition = def_dec_p->definition;
3088
3089   /* If we are protoizing, and if we found no corresponding definition for
3090      this particular function declaration, then just leave this declaration
3091      exactly as it is.  */
3092
3093   if (!definition)
3094     return;
3095
3096   /* If we are protoizing, and if the corresponding definition that we found
3097      for this particular function declaration defined an old style varargs
3098      function, then we want to issue a warning and just leave this function
3099      declaration unconverted.  */
3100
3101   if (other_variable_style_function (definition->ansi_decl))
3102     {
3103       if (!quiet_flag)
3104         notice ("%s: %d: warning: varargs function declaration not converted\n",
3105                 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3106                 def_dec_p->line);
3107       return;
3108     }
3109
3110 #endif /* !defined (UNPROTOIZE) */
3111
3112   /* Setup here to recover from confusing source code detected during this
3113      particular "edit".  */
3114
3115   save_pointers ();
3116   if (setjmp (source_confusion_recovery))
3117     {
3118       restore_pointers ();
3119       notice ("%s: declaration of function `%s' not converted\n",
3120               pname, function_to_edit);
3121       return;
3122     }
3123
3124   /* We are editing a function declaration.  The line number we did a seek to
3125      contains the comma or semicolon which follows the declaration.  Our job
3126      now is to scan backwards looking for the function name.  This name *must*
3127      be followed by open paren (ignoring whitespace, of course).  We need to
3128      replace everything between that open paren and the corresponding closing
3129      paren.  If we are protoizing, we need to insert the prototype-style
3130      formals lists.  If we are unprotoizing, we need to just delete everything
3131      between the pairs of opening and closing parens.  */
3132
3133   /* First move up to the end of the line.  */
3134
3135   while (*clean_text_p != '\n')
3136     check_source (++clean_text_p < clean_text_limit, 0);
3137   clean_text_p--;  /* Point to just before the newline character.  */
3138
3139   /* Now we can scan backwards for the function name.  */
3140
3141   do
3142     {
3143       for (;;)
3144         {
3145           /* Scan leftwards until we find some character which can be
3146              part of an identifier.  */
3147
3148           while (!is_id_char (*clean_text_p))
3149             check_source (--clean_text_p > clean_read_ptr, 0);
3150
3151           /* Scan backwards until we find a char that cannot be part of an
3152              identifier.  */
3153
3154           while (is_id_char (*clean_text_p))
3155             check_source (--clean_text_p > clean_read_ptr, 0);
3156
3157           /* Having found an "id break", see if the following id is the one
3158              that we are looking for.  If so, then exit from this loop.  */
3159
3160           if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
3161             {
3162               char ch = *(clean_text_p + 1 + func_name_len);
3163
3164               /* Must also check to see that the name in the source text
3165                  ends where it should (in order to prevent bogus matches
3166                  on similar but longer identifiers.  */
3167
3168               if (! is_id_char (ch))
3169                 break;                  /* exit from loop */
3170             }
3171         }
3172     
3173       /* We have now found the first perfect match for the function name in
3174          our backward search.  This may or may not be the actual function
3175          name at the start of the actual function declaration (i.e. we could
3176          have easily been mislead).  We will try to avoid getting fooled too
3177          often by looking forward for the open paren which should follow the
3178          identifier we just found.  We ignore whitespace while hunting.  If
3179          the next non-whitespace byte we see is *not* an open left paren,
3180          then we must assume that we have been fooled and we start over
3181          again accordingly.  Note that there is no guarantee, that even if
3182          we do see the open paren, that we are in the right place.
3183          Programmers do the strangest things sometimes!  */
3184     
3185       end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
3186       start_formals = forward_to_next_token_char (end_of_fn_name);
3187     }
3188   while (*start_formals != '(');
3189
3190   /* start_of_formals now points to the opening left paren which immediately
3191      follows the name of the function.  */
3192
3193   /* Note that there may be several formals lists which need to be modified
3194      due to the possibility that the return type of this function is a
3195      pointer-to-function type.  If there are several formals lists, we
3196      convert them in left-to-right order here.  */
3197
3198 #ifndef UNPROTOIZE
3199   this_f_list_chain_item = definition->f_list_chain;
3200 #endif /* !defined (UNPROTOIZE) */
3201
3202   for (;;)
3203     {
3204       {
3205         int depth;
3206
3207         end_formals = start_formals + 1;
3208         depth = 1;
3209         for (; depth; check_source (++end_formals < clean_text_limit, 0))
3210           {
3211             switch (*end_formals)
3212               {
3213                 case '(':
3214                   depth++;
3215                   break;
3216                 case ')':
3217                   depth--;
3218                   break;
3219               }
3220           }
3221         end_formals--;
3222       }
3223
3224       /* end_formals now points to the closing right paren of the formals
3225          list whose left paren is pointed to by start_formals.  */
3226     
3227       /* Now, if we are protoizing, we insert the new ANSI-style formals list
3228          attached to the associated definition of this function.  If however
3229          we are unprotoizing, then we simply delete any formals list which
3230          may be present.  */
3231     
3232       output_up_to (start_formals);
3233 #ifndef UNPROTOIZE
3234       if (this_f_list_chain_item)
3235         {
3236           output_string (this_f_list_chain_item->formals_list);
3237           this_f_list_chain_item = this_f_list_chain_item->chain_next;
3238         }
3239       else
3240         {
3241           if (!quiet_flag)
3242             notice ("%s: warning: too many parameter lists in declaration of `%s'\n",
3243                     pname, def_dec_p->hash_entry->symbol);
3244           check_source (0, end_formals);  /* leave the declaration intact */
3245         }
3246 #endif /* !defined (UNPROTOIZE) */
3247       clean_read_ptr = end_formals - 1;
3248
3249       /* Now see if it looks like there may be another formals list associated
3250          with the function declaration that we are converting (following the
3251          formals list that we just converted.  */
3252
3253       {
3254         const char *another_r_paren = forward_to_next_token_char (end_formals);
3255
3256         if ((*another_r_paren != ')')
3257             || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3258           {
3259 #ifndef UNPROTOIZE
3260             if (this_f_list_chain_item)
3261               {
3262                 if (!quiet_flag)
3263                   notice ("\n%s: warning: too few parameter lists in declaration of `%s'\n",
3264                           pname, def_dec_p->hash_entry->symbol);
3265                 check_source (0, start_formals); /* leave the decl intact */
3266               }
3267 #endif /* !defined (UNPROTOIZE) */
3268             break;
3269   
3270           }
3271       }
3272
3273       /* There does appear to be yet another formals list, so loop around
3274          again, and convert it also.  */
3275     }
3276 }
3277
3278 /* Edit a whole group of formals lists, starting with the rightmost one
3279    from some set of formals lists.  This routine is called once (from the
3280    outside) for each function declaration which is converted.  It is
3281    recursive however, and it calls itself once for each remaining formal
3282    list that lies to the left of the one it was originally called to work
3283    on.  Thus, a whole set gets done in right-to-left order.
3284
3285    This routine returns non-zero if it thinks that it should not be trying
3286    to convert this particular function definition (because the name of the
3287    function doesn't match the one expected).  */
3288
3289 static int
3290 edit_formals_lists (end_formals, f_list_count, def_dec_p)
3291      const char *end_formals;
3292      unsigned int f_list_count;
3293      const def_dec_info *def_dec_p;
3294 {
3295   const char *start_formals;
3296   int depth;
3297
3298   start_formals = end_formals - 1;
3299   depth = 1;
3300   for (; depth; check_source (--start_formals > clean_read_ptr, 0))
3301     {
3302       switch (*start_formals)
3303         {
3304           case '(':
3305             depth--;
3306             break;
3307           case ')':
3308             depth++;
3309             break;
3310         }
3311     }
3312   start_formals++;
3313
3314   /* start_formals now points to the opening left paren of the formals list.  */
3315
3316   f_list_count--;
3317
3318   if (f_list_count)
3319     {
3320       const char *next_end;
3321
3322       /* There should be more formal lists to the left of here.  */
3323
3324       next_end = start_formals - 1;
3325       check_source (next_end > clean_read_ptr, 0);
3326       while (ISSPACE ((const unsigned char)*next_end))
3327         check_source (--next_end > clean_read_ptr, 0);
3328       check_source (*next_end == ')', next_end);
3329       check_source (--next_end > clean_read_ptr, 0);
3330       check_source (*next_end == ')', next_end);
3331       if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3332         return 1;
3333     }
3334
3335   /* Check that the function name in the header we are working on is the same
3336      as the one we would expect to find.  If not, issue a warning and return
3337      non-zero.  */
3338
3339   if (f_list_count == 0)
3340     {
3341       const char *expected = def_dec_p->hash_entry->symbol;
3342       const char *func_name_start;
3343       const char *func_name_limit;
3344       size_t func_name_len;
3345
3346       for (func_name_limit = start_formals-1;
3347            ISSPACE ((const unsigned char)*func_name_limit); )
3348         check_source (--func_name_limit > clean_read_ptr, 0);
3349
3350       for (func_name_start = func_name_limit++;
3351            is_id_char (*func_name_start);
3352            func_name_start--)
3353         check_source (func_name_start > clean_read_ptr, 0);
3354       func_name_start++;
3355       func_name_len = func_name_limit - func_name_start;
3356       if (func_name_len == 0)
3357         check_source (0, func_name_start);
3358       if (func_name_len != strlen (expected)
3359           || strncmp (func_name_start, expected, func_name_len))
3360         {
3361           notice ("%s: %d: warning: found `%s' but expected `%s'\n",
3362                   shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3363                   identify_lineno (func_name_start),
3364                   dupnstr (func_name_start, func_name_len),
3365                   expected);
3366           return 1;
3367         }
3368     }
3369
3370   output_up_to (start_formals);
3371
3372 #ifdef UNPROTOIZE
3373   if (f_list_count == 0)
3374     output_string (def_dec_p->formal_names);
3375 #else /* !defined (UNPROTOIZE) */
3376   {
3377     unsigned f_list_depth;
3378     const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
3379
3380     /* At this point, the current value of f_list count says how many
3381        links we have to follow through the f_list_chain to get to the
3382        particular formals list that we need to output next.  */
3383
3384     for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
3385       flci_p = flci_p->chain_next;
3386     output_string (flci_p->formals_list);
3387   }
3388 #endif /* !defined (UNPROTOIZE) */
3389
3390   clean_read_ptr = end_formals - 1;
3391   return 0;
3392 }
3393
3394 /* Given a pointer to a byte in the clean text buffer which points to
3395    the beginning of a line that contains a "follower" token for a
3396    function definition header, do whatever is necessary to find the
3397    right closing paren for the rightmost formals list of the function
3398    definition header.  */
3399
3400 static const char *
3401 find_rightmost_formals_list (clean_text_p)
3402      const char *clean_text_p;
3403 {
3404   const char *end_formals;
3405
3406   /* We are editing a function definition.  The line number we did a seek
3407      to contains the first token which immediately follows the entire set of
3408      formals lists which are part of this particular function definition
3409      header.
3410
3411      Our job now is to scan leftwards in the clean text looking for the
3412      right-paren which is at the end of the function header's rightmost
3413      formals list.
3414
3415      If we ignore whitespace, this right paren should be the first one we
3416      see which is (ignoring whitespace) immediately followed either by the
3417      open curly-brace beginning the function body or by an alphabetic
3418      character (in the case where the function definition is in old (K&R)
3419      style and there are some declarations of formal parameters).  */
3420
3421    /* It is possible that the right paren we are looking for is on the
3422       current line (together with its following token).  Just in case that
3423       might be true, we start out here by skipping down to the right end of
3424       the current line before starting our scan.  */
3425
3426   for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
3427     continue;
3428   end_formals--;
3429
3430 #ifdef UNPROTOIZE
3431
3432   /* Now scan backwards while looking for the right end of the rightmost
3433      formals list associated with this function definition.  */
3434
3435   {
3436     char ch;
3437     const char *l_brace_p;
3438
3439     /* Look leftward and try to find a right-paren.  */
3440
3441     while (*end_formals != ')')
3442       {
3443         if (ISSPACE ((unsigned char)*end_formals))
3444           while (ISSPACE ((unsigned char)*end_formals))
3445             check_source (--end_formals > clean_read_ptr, 0);
3446         else
3447           check_source (--end_formals > clean_read_ptr, 0);
3448       }
3449
3450     ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3451     /* Since we are unprotoizing an ANSI-style (prototyped) function
3452        definition, there had better not be anything (except whitespace)
3453        between the end of the ANSI formals list and the beginning of the
3454        function body (i.e. the '{').  */
3455
3456     check_source (ch == '{', l_brace_p);
3457   }
3458
3459 #else /* !defined (UNPROTOIZE) */
3460
3461   /* Now scan backwards while looking for the right end of the rightmost
3462      formals list associated with this function definition.  */
3463
3464   while (1)
3465     {
3466       char ch;
3467       const char *l_brace_p;
3468
3469       /* Look leftward and try to find a right-paren.  */
3470
3471       while (*end_formals != ')')
3472         {
3473           if (ISSPACE ((const unsigned char)*end_formals))
3474             while (ISSPACE ((const unsigned char)*end_formals))
3475               check_source (--end_formals > clean_read_ptr, 0);
3476           else
3477             check_source (--end_formals > clean_read_ptr, 0);
3478         }
3479
3480       ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3481
3482       /* Since it is possible that we found a right paren before the starting
3483          '{' of the body which IS NOT the one at the end of the real K&R
3484          formals list (say for instance, we found one embedded inside one of
3485          the old K&R formal parameter declarations) we have to check to be
3486          sure that this is in fact the right paren that we were looking for.
3487
3488          The one we were looking for *must* be followed by either a '{' or
3489          by an alphabetic character, while others *cannot* validly be followed
3490          by such characters.  */
3491
3492       if ((ch == '{') || ISALPHA ((unsigned char)ch))
3493         break;
3494
3495       /* At this point, we have found a right paren, but we know that it is
3496          not the one we were looking for, so backup one character and keep
3497          looking.  */
3498
3499       check_source (--end_formals > clean_read_ptr, 0);
3500     }
3501
3502 #endif /* !defined (UNPROTOIZE) */
3503
3504   return end_formals;
3505 }
3506
3507 #ifndef UNPROTOIZE
3508
3509 /* Insert into the output file a totally new declaration for a function
3510    which (up until now) was being called from within the current block
3511    without having been declared at any point such that the declaration
3512    was visible (i.e. in scope) at the point of the call.
3513
3514    We need to add in explicit declarations for all such function calls
3515    in order to get the full benefit of prototype-based function call
3516    parameter type checking.  */
3517
3518 static void
3519 add_local_decl (def_dec_p, clean_text_p)
3520      const def_dec_info *def_dec_p;
3521      const char *clean_text_p;
3522 {
3523   const char *start_of_block;
3524   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3525
3526   /* Don't insert new local explicit declarations unless explicitly requested
3527      to do so.  */
3528
3529   if (!local_flag)
3530     return;
3531
3532   /* Setup here to recover from confusing source code detected during this
3533      particular "edit".  */
3534
3535   save_pointers ();
3536   if (setjmp (source_confusion_recovery))
3537     {
3538       restore_pointers ();
3539       notice ("%s: local declaration for function `%s' not inserted\n",
3540               pname, function_to_edit);
3541       return;
3542     }
3543
3544   /* We have already done a seek to the start of the line which should
3545      contain *the* open curly brace which begins the block in which we need
3546      to insert an explicit function declaration (to replace the implicit one).
3547
3548      Now we scan that line, starting from the left, until we find the
3549      open curly brace we are looking for.  Note that there may actually be
3550      multiple open curly braces on the given line, but we will be happy
3551      with the leftmost one no matter what.  */
3552
3553   start_of_block = clean_text_p;
3554   while (*start_of_block != '{' && *start_of_block != '\n')
3555     check_source (++start_of_block < clean_text_limit, 0);
3556
3557   /* Note that the line from the original source could possibly
3558      contain *no* open curly braces!  This happens if the line contains
3559      a macro call which expands into a chunk of text which includes a
3560      block (and that block's associated open and close curly braces).
3561      In cases like this, we give up, issue a warning, and do nothing.  */
3562
3563   if (*start_of_block != '{')
3564     {
3565       if (!quiet_flag)
3566         notice ("\n%s: %d: warning: can't add declaration of `%s' into macro call\n",
3567           def_dec_p->file->hash_entry->symbol, def_dec_p->line, 
3568           def_dec_p->hash_entry->symbol);
3569       return;
3570     }
3571
3572   /* Figure out what a nice (pretty) indentation would be for the new
3573      declaration we are adding.  In order to do this, we must scan forward
3574      from the '{' until we find the first line which starts with some
3575      non-whitespace characters (i.e. real "token" material).  */
3576
3577   {
3578     const char *ep = forward_to_next_token_char (start_of_block) - 1;
3579     const char *sp;
3580
3581     /* Now we have ep pointing at the rightmost byte of some existing indent
3582        stuff.  At least that is the hope.
3583
3584        We can now just scan backwards and find the left end of the existing
3585        indentation string, and then copy it to the output buffer.  */
3586
3587     for (sp = ep; ISSPACE ((const unsigned char)*sp) && *sp != '\n'; sp--)
3588       continue;
3589
3590     /* Now write out the open { which began this block, and any following
3591        trash up to and including the last byte of the existing indent that
3592        we just found.  */
3593
3594     output_up_to (ep);
3595   
3596     /* Now we go ahead and insert the new declaration at this point.
3597
3598        If the definition of the given function is in the same file that we
3599        are currently editing, and if its full ANSI declaration normally
3600        would start with the keyword `extern', suppress the `extern'.  */
3601   
3602     {
3603       const char *decl = def_dec_p->definition->ansi_decl;
3604   
3605       if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3606         decl += 7;
3607       output_string (decl);
3608     }
3609
3610     /* Finally, write out a new indent string, just like the preceding one
3611        that we found.  This will typically include a newline as the first
3612        character of the indent string.  */
3613
3614     output_bytes (sp, (size_t) (ep - sp) + 1);
3615   }
3616 }
3617
3618 /* Given a pointer to a file_info record, and a pointer to the beginning
3619    of a line (in the clean text buffer) which is assumed to contain the
3620    first "follower" token for the first function definition header in the
3621    given file, find a good place to insert some new global function
3622    declarations (which will replace scattered and imprecise implicit ones)
3623    and then insert the new explicit declaration at that point in the file.  */
3624
3625 static void
3626 add_global_decls (file_p, clean_text_p)
3627      const file_info *file_p;
3628      const char *clean_text_p;
3629 {
3630   const def_dec_info *dd_p;
3631   const char *scan_p;
3632
3633   /* Setup here to recover from confusing source code detected during this
3634      particular "edit".  */
3635
3636   save_pointers ();
3637   if (setjmp (source_confusion_recovery))
3638     {
3639       restore_pointers ();
3640       notice ("%s: global declarations for file `%s' not inserted\n",
3641               pname, shortpath (NULL, file_p->hash_entry->symbol));
3642       return;
3643     }
3644
3645   /* Start by finding a good location for adding the new explicit function
3646      declarations.  To do this, we scan backwards, ignoring whitespace
3647      and comments and other junk until we find either a semicolon, or until
3648      we hit the beginning of the file.  */
3649
3650   scan_p = find_rightmost_formals_list (clean_text_p);
3651   for (;; --scan_p)
3652     {
3653       if (scan_p < clean_text_base)
3654         break;
3655       check_source (scan_p > clean_read_ptr, 0);
3656       if (*scan_p == ';')
3657         break;
3658     }
3659
3660   /* scan_p now points either to a semicolon, or to just before the start
3661      of the whole file.  */
3662
3663   /* Now scan forward for the first non-whitespace character.  In theory,
3664      this should be the first character of the following function definition
3665      header.  We will put in the added declarations just prior to that.  */
3666
3667   scan_p++;
3668   while (ISSPACE ((const unsigned char)*scan_p))
3669     scan_p++;
3670   scan_p--;
3671
3672   output_up_to (scan_p);
3673
3674   /* Now write out full prototypes for all of the things that had been
3675      implicitly declared in this file (but only those for which we were
3676      actually able to find unique matching definitions).  Avoid duplicates
3677      by marking things that we write out as we go.   */
3678
3679   {
3680     int some_decls_added = 0;
3681   
3682     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3683       if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3684         {
3685           const char *decl = dd_p->definition->ansi_decl;
3686   
3687           /* If the function for which we are inserting a declaration is
3688              actually defined later in the same file, then suppress the
3689              leading `extern' keyword (if there is one).  */
3690   
3691           if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3692             decl += 7;
3693   
3694           output_string ("\n");
3695           output_string (decl);
3696           some_decls_added = 1;
3697           ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3698         }
3699     if (some_decls_added)
3700       output_string ("\n\n");
3701   }
3702
3703   /* Unmark all of the definitions that we just marked.  */
3704
3705   for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3706     if (dd_p->definition)
3707       ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
3708 }
3709
3710 #endif /* !defined (UNPROTOIZE) */
3711
3712 /* Do the editing operation specifically for a function "definition".  Note
3713    that editing operations for function "declarations" are handled by a
3714    separate routine above.  */
3715
3716 static void
3717 edit_fn_definition (def_dec_p, clean_text_p)
3718      const def_dec_info *def_dec_p;
3719      const char *clean_text_p;
3720 {
3721   const char *end_formals;
3722   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3723
3724   /* Setup here to recover from confusing source code detected during this
3725      particular "edit".  */
3726
3727   save_pointers ();
3728   if (setjmp (source_confusion_recovery))
3729     {
3730       restore_pointers ();
3731       notice ("%s: definition of function `%s' not converted\n",
3732               pname, function_to_edit);
3733       return;
3734     }
3735
3736   end_formals = find_rightmost_formals_list (clean_text_p);
3737
3738   /* end_of_formals now points to the closing right paren of the rightmost
3739      formals list which is actually part of the `header' of the function
3740      definition that we are converting.  */
3741
3742   /* If the header of this function definition looks like it declares a
3743      function with a variable number of arguments, and if the way it does
3744      that is different from that way we would like it (i.e. varargs vs.
3745      stdarg) then issue a warning and leave the header unconverted.  */
3746      
3747   if (other_variable_style_function (def_dec_p->ansi_decl))
3748     {
3749       if (!quiet_flag)
3750         notice ("%s: %d: warning: definition of %s not converted\n",
3751                 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3752                 identify_lineno (end_formals), 
3753                 other_var_style);
3754       output_up_to (end_formals);
3755       return;
3756     }
3757
3758   if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
3759     {
3760       restore_pointers ();
3761       notice ("%s: definition of function `%s' not converted\n",
3762               pname, function_to_edit);
3763       return;
3764     }
3765
3766   /* Have to output the last right paren because this never gets flushed by
3767      edit_formals_list.  */
3768
3769   output_up_to (end_formals);
3770
3771 #ifdef UNPROTOIZE
3772   {
3773     const char *decl_p;
3774     const char *semicolon_p;
3775     const char *limit_p;
3776     const char *scan_p;
3777     int had_newlines = 0;
3778
3779     /* Now write out the K&R style formal declarations, one per line.  */
3780
3781     decl_p = def_dec_p->formal_decls;
3782     limit_p = decl_p + strlen (decl_p);
3783     for (;decl_p < limit_p; decl_p = semicolon_p + 2)
3784       {
3785         for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3786           continue;
3787         output_string ("\n");
3788         output_string (indent_string);
3789         output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
3790       }
3791
3792     /* If there are no newlines between the end of the formals list and the
3793        start of the body, we should insert one now.  */
3794
3795     for (scan_p = end_formals+1; *scan_p != '{'; )
3796       {
3797         if (*scan_p == '\n')
3798           {
3799             had_newlines = 1;
3800             break;
3801           }
3802         check_source (++scan_p < clean_text_limit, 0);
3803       }
3804     if (!had_newlines)
3805       output_string ("\n");
3806   }
3807 #else /* !defined (UNPROTOIZE) */
3808   /* If we are protoizing, there may be some flotsam & jetsam (like comments
3809      and preprocessing directives) after the old formals list but before
3810      the following { and we would like to preserve that stuff while effectively
3811      deleting the existing K&R formal parameter declarations.  We do so here
3812      in a rather tricky way.  Basically, we white out any stuff *except*
3813      the comments/pp-directives in the original text buffer, then, if there
3814      is anything in this area *other* than whitespace, we output it.  */
3815   {
3816     const char *end_formals_orig;
3817     const char *start_body;
3818     const char *start_body_orig;
3819     const char *scan;
3820     const char *scan_orig;
3821     int have_flotsam = 0;
3822     int have_newlines = 0;
3823
3824     for (start_body = end_formals + 1; *start_body != '{';)
3825       check_source (++start_body < clean_text_limit, 0);
3826
3827     end_formals_orig = orig_text_base + (end_formals - clean_text_base);
3828     start_body_orig = orig_text_base + (start_body - clean_text_base);
3829     scan = end_formals + 1;
3830     scan_orig = end_formals_orig + 1;
3831     for (; scan < start_body; scan++, scan_orig++)
3832       {
3833         if (*scan == *scan_orig)
3834           {
3835             have_newlines |= (*scan_orig == '\n');
3836             /* Leave identical whitespace alone.  */
3837             if (!ISSPACE ((const unsigned char)*scan_orig))
3838               *((NONCONST char *)scan_orig) = ' '; /* identical - so whiteout */
3839           }
3840         else
3841           have_flotsam = 1;
3842       }
3843     if (have_flotsam)
3844       output_bytes (end_formals_orig + 1,
3845                     (size_t) (start_body_orig - end_formals_orig) - 1);
3846     else
3847       if (have_newlines)
3848         output_string ("\n");
3849       else
3850         output_string (" ");
3851     clean_read_ptr = start_body - 1;
3852   }
3853 #endif /* !defined (UNPROTOIZE) */
3854 }
3855
3856 /* Clean up the clean text buffer.  Do this by converting comments and
3857    preprocessing directives into spaces.   Also convert line continuations
3858    into whitespace.  Also, whiteout string and character literals.  */
3859
3860 static void
3861 do_cleaning (new_clean_text_base, new_clean_text_limit)
3862      char *new_clean_text_base;
3863      char *new_clean_text_limit;
3864 {
3865   char *scan_p;
3866   int non_whitespace_since_newline = 0;
3867
3868   for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
3869     {
3870       switch (*scan_p)
3871         {
3872           case '/':                     /* Handle comments.  */
3873             if (scan_p[1] != '*')
3874               goto regular;
3875             non_whitespace_since_newline = 1;
3876             scan_p[0] = ' ';
3877             scan_p[1] = ' ';
3878             scan_p += 2;
3879             while (scan_p[1] != '/' || scan_p[0] != '*')
3880               {
3881                 if (!ISSPACE ((const unsigned char)*scan_p))
3882                   *scan_p = ' ';
3883                 if (++scan_p >= new_clean_text_limit)
3884                   abort ();
3885               }
3886             *scan_p++ = ' ';
3887             *scan_p = ' ';
3888             break;
3889
3890           case '#':                     /* Handle pp directives.  */
3891             if (non_whitespace_since_newline)
3892               goto regular;
3893             *scan_p = ' ';
3894             while (scan_p[1] != '\n' || scan_p[0] == '\\')
3895               {
3896                 if (!ISSPACE ((const unsigned char)*scan_p))
3897                   *scan_p = ' ';
3898                 if (++scan_p >= new_clean_text_limit)
3899                   abort ();
3900               }
3901             *scan_p++ = ' ';
3902             break;
3903
3904           case '\'':                    /* Handle character literals.  */
3905             non_whitespace_since_newline = 1;
3906             while (scan_p[1] != '\'' || scan_p[0] == '\\')
3907               {
3908                 if (scan_p[0] == '\\'
3909                     && !ISSPACE ((const unsigned char)scan_p[1]))
3910                   scan_p[1] = ' ';
3911                 if (!ISSPACE ((const unsigned char)*scan_p))
3912                   *scan_p = ' ';
3913                 if (++scan_p >= new_clean_text_limit)
3914                   abort ();
3915               }
3916             *scan_p++ = ' ';
3917             break;
3918
3919           case '"':                     /* Handle string literals.  */
3920             non_whitespace_since_newline = 1;
3921             while (scan_p[1] != '"' || scan_p[0] == '\\')
3922               {
3923                 if (scan_p[0] == '\\'
3924                     && !ISSPACE ((const unsigned char)scan_p[1]))
3925                   scan_p[1] = ' ';
3926                 if (!ISSPACE ((const unsigned char)*scan_p))
3927                   *scan_p = ' ';
3928                 if (++scan_p >= new_clean_text_limit)
3929                   abort ();
3930               }
3931             if (!ISSPACE ((const unsigned char)*scan_p))
3932               *scan_p = ' ';
3933             scan_p++;
3934             break;
3935
3936           case '\\':                    /* Handle line continuations.  */
3937             if (scan_p[1] != '\n')
3938               goto regular;
3939             *scan_p = ' ';
3940             break;
3941
3942           case '\n':
3943             non_whitespace_since_newline = 0;   /* Reset.  */
3944             break;
3945
3946           case ' ':
3947           case '\v':
3948           case '\t':
3949           case '\r':
3950           case '\f':
3951           case '\b':
3952             break;              /* Whitespace characters.  */
3953
3954           default:
3955 regular:
3956             non_whitespace_since_newline = 1;
3957             break;
3958         }
3959     }
3960 }
3961
3962 /* Given a pointer to the closing right parenthesis for a particular formals
3963    list (in the clean text buffer) find the corresponding left parenthesis
3964    and return a pointer to it.  */
3965
3966 static const char *
3967 careful_find_l_paren (p)
3968      const char *p;
3969 {
3970   const char *q;
3971   int paren_depth;
3972
3973   for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
3974     {
3975       switch (*q)
3976         {
3977           case ')':
3978             paren_depth++;
3979             break;
3980           case '(':
3981             paren_depth--;
3982             break;
3983         }
3984     }
3985   return ++q;
3986 }
3987
3988 /* Scan the clean text buffer for cases of function definitions that we
3989    don't really know about because they were preprocessed out when the
3990    aux info files were created.
3991
3992    In this version of protoize/unprotoize we just give a warning for each
3993    one found.  A later version may be able to at least unprotoize such
3994    missed items.
3995
3996    Note that we may easily find all function definitions simply by
3997    looking for places where there is a left paren which is (ignoring
3998    whitespace) immediately followed by either a left-brace or by an
3999    upper or lower case letter.  Whenever we find this combination, we
4000    have also found a function definition header.
4001
4002    Finding function *declarations* using syntactic clues is much harder.
4003    I will probably try to do this in a later version though.  */
4004
4005 static void
4006 scan_for_missed_items (file_p)
4007      const file_info *file_p;
4008 {
4009   static const char *scan_p;
4010   const char *limit = clean_text_limit - 3;
4011   static const char *backup_limit;
4012
4013   backup_limit = clean_text_base - 1;
4014
4015   for (scan_p = clean_text_base; scan_p < limit; scan_p++)
4016     {
4017       if (*scan_p == ')')
4018         {
4019           static const char *last_r_paren;
4020           const char *ahead_p;
4021
4022           last_r_paren = scan_p;
4023
4024           for (ahead_p = scan_p + 1; ISSPACE ((const unsigned char)*ahead_p); )
4025             check_source (++ahead_p < limit, limit);
4026
4027           scan_p = ahead_p - 1;
4028
4029           if (ISALPHA ((const unsigned char)*ahead_p) || *ahead_p == '{')
4030             {
4031               const char *last_l_paren;
4032               const int lineno = identify_lineno (ahead_p);
4033
4034               if (setjmp (source_confusion_recovery))
4035                 continue;
4036
4037               /* We know we have a function definition header.  Now skip
4038                  leftwards over all of its associated formals lists.  */
4039
4040               do
4041                 {
4042                   last_l_paren = careful_find_l_paren (last_r_paren);
4043                   for (last_r_paren = last_l_paren-1;
4044                        ISSPACE ((const unsigned char)*last_r_paren); )
4045                     check_source (--last_r_paren >= backup_limit, backup_limit);
4046                 }
4047               while (*last_r_paren == ')');
4048
4049               if (is_id_char (*last_r_paren))
4050                 {
4051                   const char *id_limit = last_r_paren + 1;
4052                   const char *id_start;
4053                   size_t id_length;
4054                   const def_dec_info *dd_p;
4055
4056                   for (id_start = id_limit-1; is_id_char (*id_start); )
4057                     check_source (--id_start >= backup_limit, backup_limit);
4058                   id_start++;
4059                   backup_limit = id_start;
4060                   if ((id_length = (size_t) (id_limit - id_start)) == 0)
4061                     goto not_missed;
4062
4063                   {
4064                     char *func_name = (char *) alloca (id_length + 1);
4065                     static const char * const stmt_keywords[]
4066                       = { "if", "else", "do", "while", "for", "switch", "case", "return", 0 };
4067                     const char * const *stmt_keyword;
4068
4069                     strncpy (func_name, id_start, id_length);
4070                     func_name[id_length] = '\0';
4071
4072                     /* We must check here to see if we are actually looking at
4073                        a statement rather than an actual function call.  */
4074
4075                     for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
4076                       if (!strcmp (func_name, *stmt_keyword))
4077                         goto not_missed;
4078
4079 #if 0
4080                     notice ("%s: found definition of `%s' at %s(%d)\n",
4081                             pname,
4082                             func_name,
4083                             shortpath (NULL, file_p->hash_entry->symbol),
4084                             identify_lineno (id_start));
4085 #endif                          /* 0 */
4086                     /* We really should check for a match of the function name
4087                        here also, but why bother.  */
4088
4089                     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
4090                       if (dd_p->is_func_def && dd_p->line == lineno)
4091                         goto not_missed;
4092
4093                     /* If we make it here, then we did not know about this
4094                        function definition.  */
4095
4096                     notice ("%s: %d: warning: `%s' excluded by preprocessing\n",
4097                             shortpath (NULL, file_p->hash_entry->symbol),
4098                             identify_lineno (id_start), func_name);
4099                     notice ("%s: function definition not converted\n",
4100                             pname);
4101                   }
4102                 not_missed: ;
4103                 }
4104             }
4105         }
4106     }
4107 }
4108
4109 /* Do all editing operations for a single source file (either a "base" file
4110    or an "include" file).  To do this we read the file into memory, keep a
4111    virgin copy there, make another cleaned in-core copy of the original file
4112    (i.e. one in which all of the comments and preprocessing directives have
4113    been replaced with whitespace), then use these two in-core copies of the
4114    file to make a new edited in-core copy of the file.  Finally, rename the
4115    original file (as a way of saving it), and then write the edited version
4116    of the file from core to a disk file of the same name as the original.
4117
4118    Note that the trick of making a copy of the original sans comments &
4119    preprocessing directives make the editing a whole lot easier.  */
4120    
4121 static void
4122 edit_file (hp)
4123      const hash_table_entry *hp;
4124 {
4125   struct stat stat_buf;
4126   const file_info *file_p = hp->fip;
4127   char *new_orig_text_base;
4128   char *new_orig_text_limit;
4129   char *new_clean_text_base;
4130   char *new_clean_text_limit;
4131   size_t orig_size;
4132   size_t repl_size;
4133   int first_definition_in_file;
4134
4135   /* If we are not supposed to be converting this file, or if there is
4136      nothing in there which needs converting, just skip this file.  */
4137
4138   if (!needs_to_be_converted (file_p))
4139     return;
4140
4141   convert_filename = file_p->hash_entry->symbol;
4142
4143   /* Convert a file if it is in a directory where we want conversion
4144      and the file is not excluded.  */
4145
4146   if (!directory_specified_p (convert_filename)
4147       || file_excluded_p (convert_filename))
4148     {
4149       if (!quiet_flag
4150 #ifdef UNPROTOIZE
4151           /* Don't even mention "system" include files unless we are
4152              protoizing.  If we are protoizing, we mention these as a
4153              gentle way of prodding the user to convert his "system"
4154              include files to prototype format.  */
4155           && !in_system_include_dir (convert_filename)
4156 #endif /* defined (UNPROTOIZE) */
4157           )
4158         notice ("%s: `%s' not converted\n",
4159                 pname, shortpath (NULL, convert_filename));
4160       return;
4161     }
4162
4163   /* Let the user know what we are up to.  */
4164
4165   if (nochange_flag)
4166     notice ("%s: would convert file `%s'\n",
4167             pname, shortpath (NULL, convert_filename));
4168   else
4169     notice ("%s: converting file `%s'\n",
4170             pname, shortpath (NULL, convert_filename));
4171   fflush (stderr);
4172
4173   /* Find out the size (in bytes) of the original file.  */
4174
4175   /* The cast avoids an erroneous warning on AIX.  */
4176   if (my_stat ((char *)convert_filename, &stat_buf) == -1)
4177     {
4178       int errno_val = errno;
4179       notice ("%s: can't get status for file `%s': %s\n",
4180               pname, shortpath (NULL, convert_filename),
4181               xstrerror (errno_val));
4182       return;
4183     }
4184   orig_size = stat_buf.st_size;
4185
4186   /* Allocate a buffer to hold the original text.  */
4187
4188   orig_text_base = new_orig_text_base = (char *) xmalloc (orig_size + 2);
4189   orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
4190
4191   /* Allocate a buffer to hold the cleaned-up version of the original text.  */
4192
4193   clean_text_base = new_clean_text_base = (char *) xmalloc (orig_size + 2);
4194   clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
4195   clean_read_ptr = clean_text_base - 1;
4196
4197   /* Allocate a buffer that will hopefully be large enough to hold the entire
4198      converted output text.  As an initial guess for the maximum size of the
4199      output buffer, use 125% of the size of the original + some extra.  This
4200      buffer can be expanded later as needed.  */
4201
4202   repl_size = orig_size + (orig_size >> 2) + 4096;
4203   repl_text_base = (char *) xmalloc (repl_size + 2);
4204   repl_text_limit = repl_text_base + repl_size - 1;
4205   repl_write_ptr = repl_text_base - 1;
4206
4207   {
4208     int input_file;
4209
4210     /* Open the file to be converted in READ ONLY mode.  */
4211
4212     if ((input_file = my_open (convert_filename, O_RDONLY, 0444)) == -1)
4213       {
4214         int errno_val = errno;
4215         notice ("%s: can't open file `%s' for reading: %s\n",
4216                 pname, shortpath (NULL, convert_filename),
4217                 xstrerror (errno_val));
4218         return;
4219       }
4220
4221     /* Read the entire original source text file into the original text buffer
4222        in one swell fwoop.  Then figure out where the end of the text is and
4223        make sure that it ends with a newline followed by a null.  */
4224
4225     if (safe_read (input_file, new_orig_text_base, orig_size) !=
4226         (int) orig_size)
4227       {
4228         int errno_val = errno;
4229         close (input_file);
4230         notice ("\n%s: error reading input file `%s': %s\n",
4231                 pname, shortpath (NULL, convert_filename),
4232                 xstrerror (errno_val));
4233         return;
4234       }
4235
4236     close (input_file);
4237   }
4238
4239   if (orig_size == 0 || orig_text_limit[-1] != '\n')
4240     {
4241       *new_orig_text_limit++ = '\n';
4242       orig_text_limit++;
4243     }
4244
4245   /* Create the cleaned up copy of the original text.  */
4246
4247   memcpy (new_clean_text_base, orig_text_base,
4248           (size_t) (orig_text_limit - orig_text_base));
4249   do_cleaning (new_clean_text_base, new_clean_text_limit);
4250
4251 #if 0
4252   {
4253     int clean_file;
4254     size_t clean_size = orig_text_limit - orig_text_base;
4255     char *const clean_filename = (char *) alloca (strlen (convert_filename) + 6 + 1);
4256
4257     /* Open (and create) the clean file.  */
4258   
4259     strcpy (clean_filename, convert_filename);
4260     strcat (clean_filename, ".clean");
4261     if ((clean_file = creat (clean_filename, 0666)) == -1)
4262       {
4263         int errno_val = errno;
4264         notice ("%s: can't create/open clean file `%s': %s\n",
4265                 pname, shortpath (NULL, clean_filename),
4266                 xstrerror (errno_val));
4267         return;
4268       }
4269   
4270     /* Write the clean file.  */
4271   
4272     safe_write (clean_file, new_clean_text_base, clean_size, clean_filename);
4273   
4274     close (clean_file);
4275   }
4276 #endif /* 0 */
4277
4278   /* Do a simplified scan of the input looking for things that were not
4279      mentioned in the aux info files because of the fact that they were
4280      in a region of the source which was preprocessed-out (via #if or
4281      via #ifdef).  */
4282
4283   scan_for_missed_items (file_p);
4284
4285   /* Setup to do line-oriented forward seeking in the clean text buffer.  */
4286
4287   last_known_line_number = 1;
4288   last_known_line_start = clean_text_base;
4289
4290   /* Now get down to business and make all of the necessary edits.  */
4291
4292   {
4293     const def_dec_info *def_dec_p;
4294
4295     first_definition_in_file = 1;
4296     def_dec_p = file_p->defs_decs;
4297     for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
4298       {
4299         const char *clean_text_p = seek_to_line (def_dec_p->line);
4300   
4301         /* clean_text_p now points to the first character of the line which
4302            contains the `terminator' for the declaration or definition that
4303            we are about to process.  */
4304   
4305 #ifndef UNPROTOIZE
4306   
4307         if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4308           {
4309             add_global_decls (def_dec_p->file, clean_text_p);
4310             first_definition_in_file = 0;
4311           }
4312
4313         /* Don't edit this item if it is already in prototype format or if it
4314            is a function declaration and we have found no corresponding
4315            definition.  */
4316
4317         if (def_dec_p->prototyped
4318          || (!def_dec_p->is_func_def && !def_dec_p->definition))
4319           continue;
4320
4321 #endif /* !defined (UNPROTOIZE) */
4322
4323         if (def_dec_p->is_func_def)
4324           edit_fn_definition (def_dec_p, clean_text_p);
4325         else
4326 #ifndef UNPROTOIZE
4327         if (def_dec_p->is_implicit)
4328           add_local_decl (def_dec_p, clean_text_p);
4329         else
4330 #endif /* !defined (UNPROTOIZE) */
4331             edit_fn_declaration (def_dec_p, clean_text_p);
4332       }
4333   }
4334
4335   /* Finalize things.  Output the last trailing part of the original text.  */
4336
4337   output_up_to (clean_text_limit - 1);
4338
4339   /* If this is just a test run, stop now and just deallocate the buffers.  */
4340
4341   if (nochange_flag)
4342     {
4343       free (new_orig_text_base);
4344       free (new_clean_text_base);
4345       free (repl_text_base);
4346       return;
4347     }
4348
4349   /* Change the name of the original input file.  This is just a quick way of
4350      saving the original file.  */
4351
4352   if (!nosave_flag)
4353     {
4354       char *new_filename
4355         = (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
4356   
4357       strcpy (new_filename, convert_filename);
4358       strcat (new_filename, save_suffix);
4359       if (my_link (convert_filename, new_filename) == -1)
4360         {
4361           int errno_val = errno;
4362           if (errno_val == EEXIST)
4363             {
4364               if (!quiet_flag)
4365                 notice ("%s: warning: file `%s' already saved in `%s'\n",
4366                         pname,
4367                         shortpath (NULL, convert_filename),
4368                         shortpath (NULL, new_filename));
4369             }
4370           else
4371             {
4372               notice ("%s: can't link file `%s' to `%s': %s\n",
4373                       pname,
4374                       shortpath (NULL, convert_filename),
4375                       shortpath (NULL, new_filename),
4376                       xstrerror (errno_val));
4377               return;
4378             }
4379         }
4380     }
4381
4382   if (my_unlink (convert_filename) == -1)
4383     {
4384       int errno_val = errno;
4385       notice ("%s: can't delete file `%s': %s\n",
4386               pname, shortpath (NULL, convert_filename),
4387               xstrerror (errno_val));
4388       return;
4389     }
4390
4391   {
4392     int output_file;
4393
4394     /* Open (and create) the output file.  */
4395   
4396     if ((output_file = creat (convert_filename, 0666)) == -1)
4397       {
4398         int errno_val = errno;
4399         notice ("%s: can't create/open output file `%s': %s\n",
4400                 pname, shortpath (NULL, convert_filename),
4401                 xstrerror (errno_val));
4402         return;
4403       }
4404   
4405     /* Write the output file.  */
4406   
4407     {
4408       unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4409   
4410       safe_write (output_file, repl_text_base, out_size, convert_filename);
4411     }
4412   
4413     close (output_file);
4414   }
4415
4416   /* Deallocate the conversion buffers.  */
4417
4418   free (new_orig_text_base);
4419   free (new_clean_text_base);
4420   free (repl_text_base);
4421
4422   /* Change the mode of the output file to match the original file.  */
4423
4424   /* The cast avoids an erroneous warning on AIX.  */
4425   if (my_chmod ((char *)convert_filename, stat_buf.st_mode) == -1)
4426     {
4427       int errno_val = errno;
4428       notice ("%s: can't change mode of file `%s': %s\n",
4429               pname, shortpath (NULL, convert_filename),
4430               xstrerror (errno_val));
4431     }
4432
4433   /* Note:  We would try to change the owner and group of the output file
4434      to match those of the input file here, except that may not be a good
4435      thing to do because it might be misleading.  Also, it might not even
4436      be possible to do that (on BSD systems with quotas for instance).  */
4437 }
4438
4439 /* Do all of the individual steps needed to do the protoization (or
4440    unprotoization) of the files referenced in the aux_info files given
4441    in the command line.  */
4442
4443 static void
4444 do_processing ()
4445 {
4446   const char * const *base_pp;
4447   const char * const * const end_pps
4448     = &base_source_filenames[n_base_source_files];
4449
4450 #ifndef UNPROTOIZE
4451   int syscalls_len;
4452 #endif /* !defined (UNPROTOIZE) */
4453
4454   /* One-by-one, check (and create if necessary), open, and read all of the
4455      stuff in each aux_info file.  After reading each aux_info file, the
4456      aux_info_file just read will be automatically deleted unless the
4457      keep_flag is set.  */
4458
4459   for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
4460     process_aux_info_file (*base_pp, keep_flag, 0);
4461
4462 #ifndef UNPROTOIZE
4463
4464   /* Also open and read the special SYSCALLS.c aux_info file which gives us
4465      the prototypes for all of the standard system-supplied functions.  */
4466
4467   if (nondefault_syscalls_dir)
4468     {
4469       syscalls_absolute_filename
4470         = (char *) xmalloc (strlen (nondefault_syscalls_dir) + 1
4471                             + sizeof (syscalls_filename));
4472       strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
4473     }
4474   else
4475     {
4476       GET_ENV_PATH_LIST (default_syscalls_dir, "GCC_EXEC_PREFIX");
4477       if (!default_syscalls_dir)
4478         {
4479           default_syscalls_dir = standard_exec_prefix;
4480         }
4481       syscalls_absolute_filename
4482         = (char *) xmalloc (strlen (default_syscalls_dir) + 0
4483                             + strlen (target_machine) + 1
4484                             + strlen (target_version) + 1
4485                             + sizeof (syscalls_filename));
4486       strcpy (syscalls_absolute_filename, default_syscalls_dir);
4487       strcat (syscalls_absolute_filename, target_machine);
4488       strcat (syscalls_absolute_filename, "/");
4489       strcat (syscalls_absolute_filename, target_version);
4490       strcat (syscalls_absolute_filename, "/");
4491     }
4492
4493   syscalls_len = strlen (syscalls_absolute_filename);
4494   if (*(syscalls_absolute_filename + syscalls_len - 1) != '/')
4495     {
4496       *(syscalls_absolute_filename + syscalls_len++) = '/';
4497       *(syscalls_absolute_filename + syscalls_len) = '\0';
4498     }
4499   strcat (syscalls_absolute_filename, syscalls_filename);
4500   
4501   /* Call process_aux_info_file in such a way that it does not try to
4502      delete the SYSCALLS aux_info file.  */
4503
4504   process_aux_info_file (syscalls_absolute_filename, 1, 1);
4505
4506 #endif /* !defined (UNPROTOIZE) */
4507
4508   /* When we first read in all of the information from the aux_info files
4509      we saved in it descending line number order, because that was likely to
4510      be faster.  Now however, we want the chains of def & dec records to
4511      appear in ascending line number order as we get further away from the
4512      file_info record that they hang from.  The following line causes all of
4513      these lists to be rearranged into ascending line number order.  */
4514
4515   visit_each_hash_node (filename_primary, reverse_def_dec_list);
4516
4517 #ifndef UNPROTOIZE
4518
4519   /* Now do the "real" work.  The following line causes each declaration record
4520      to be "visited".  For each of these nodes, an attempt is made to match
4521      up the function declaration with a corresponding function definition,
4522      which should have a full prototype-format formals list with it.  Once
4523      these match-ups are made, the conversion of the function declarations
4524      to prototype format can be made.  */
4525
4526   visit_each_hash_node (function_name_primary, connect_defs_and_decs);
4527
4528 #endif /* !defined (UNPROTOIZE) */
4529
4530   /* Now convert each file that can be converted (and needs to be).  */
4531
4532   visit_each_hash_node (filename_primary, edit_file);
4533
4534 #ifndef UNPROTOIZE
4535
4536   /* If we are working in cplusplus mode, try to rename all .c files to .C
4537      files.  Don't panic if some of the renames don't work.  */
4538
4539   if (cplusplus_flag && !nochange_flag)
4540     visit_each_hash_node (filename_primary, rename_c_file);
4541
4542 #endif /* !defined (UNPROTOIZE) */
4543 }
4544 \f
4545 static struct option longopts[] =
4546 {
4547   {"version", 0, 0, 'V'},
4548   {"file_name", 0, 0, 'p'},
4549   {"quiet", 0, 0, 'q'},
4550   {"silent", 0, 0, 'q'},
4551   {"force", 0, 0, 'f'},
4552   {"keep", 0, 0, 'k'},
4553   {"nosave", 0, 0, 'N'},
4554   {"nochange", 0, 0, 'n'},
4555   {"compiler-options", 1, 0, 'c'},
4556   {"exclude", 1, 0, 'x'},
4557   {"directory", 1, 0, 'd'},
4558 #ifdef UNPROTOIZE
4559   {"indent", 1, 0, 'i'},
4560 #else
4561   {"local", 0, 0, 'l'},
4562   {"global", 0, 0, 'g'},
4563   {"c++", 0, 0, 'C'},
4564   {"syscalls-dir", 1, 0, 'B'},
4565 #endif
4566   {0, 0, 0, 0}
4567 };
4568
4569 int
4570 main (argc, argv)
4571      int argc;
4572      char **const argv;
4573 {
4574   int longind;
4575   int c;
4576   const char *params = "";
4577
4578   pname = strrchr (argv[0], '/');
4579   pname = pname ? pname+1 : argv[0];
4580
4581 #ifdef HAVE_LC_MESSAGES
4582   setlocale (LC_MESSAGES, "");
4583 #endif
4584   (void) bindtextdomain (PACKAGE, localedir);
4585   (void) textdomain (PACKAGE);
4586
4587   cwd_buffer = getpwd ();
4588   if (!cwd_buffer)
4589     {
4590       notice ("%s: cannot get working directory: %s\n",
4591               pname, xstrerror(errno));
4592       exit (FATAL_EXIT_CODE);
4593     }
4594
4595   /* By default, convert the files in the current directory.  */
4596   directory_list = string_list_cons (cwd_buffer, NULL);
4597
4598   while ((c = getopt_long (argc, argv,
4599 #ifdef UNPROTOIZE
4600                            "c:d:i:knNp:qvVx:",
4601 #else
4602                            "B:c:Cd:gklnNp:qvVx:",
4603 #endif
4604                            longopts, &longind)) != EOF)
4605     {
4606       if (c == 0)               /* Long option.  */
4607         c = longopts[longind].val;
4608       switch (c)
4609         {
4610         case 'p':
4611           compiler_file_name = optarg;
4612           break;
4613         case 'd':
4614           directory_list
4615             = string_list_cons (abspath (NULL, optarg), directory_list);
4616           break;
4617         case 'x':
4618           exclude_list = string_list_cons (optarg, exclude_list);
4619           break;
4620             
4621         case 'v':
4622         case 'V':
4623           version_flag = 1;
4624           break;
4625         case 'q':
4626           quiet_flag = 1;
4627           break;
4628 #if 0
4629         case 'f':
4630           force_flag = 1;
4631           break;
4632 #endif
4633         case 'n':
4634           nochange_flag = 1;
4635           keep_flag = 1;
4636           break;
4637         case 'N':
4638           nosave_flag = 1;
4639           break;
4640         case 'k':
4641           keep_flag = 1;
4642           break;
4643         case 'c':
4644           params = optarg;
4645           break;
4646 #ifdef UNPROTOIZE
4647         case 'i':
4648           indent_string = optarg;
4649           break;
4650 #else                           /* !defined (UNPROTOIZE) */
4651         case 'l':
4652           local_flag = 1;
4653           break;
4654         case 'g':
4655           global_flag = 1;
4656           break;
4657         case 'C':
4658           cplusplus_flag = 1;
4659           break;
4660         case 'B':
4661           nondefault_syscalls_dir = optarg;
4662           break;
4663 #endif                          /* !defined (UNPROTOIZE) */
4664         default:
4665           usage ();
4666         }
4667     }
4668  
4669   /* Set up compile_params based on -p and -c options.  */
4670   munge_compile_params (params);
4671
4672   n_base_source_files = argc - optind;
4673
4674   /* Now actually make a list of the base source filenames.  */
4675
4676   base_source_filenames
4677     = (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
4678   n_base_source_files = 0;
4679   for (; optind < argc; optind++)
4680     {
4681       const char *path = abspath (NULL, argv[optind]);
4682       int len = strlen (path);
4683
4684       if (path[len-1] == 'c' && path[len-2] == '.')
4685         base_source_filenames[n_base_source_files++] = path;
4686       else
4687         {
4688           notice ("%s: input file names must have .c suffixes: %s\n",
4689                   pname, shortpath (NULL, path));
4690           errors++;
4691         }
4692     }
4693
4694 #ifndef UNPROTOIZE
4695   /* We are only interested in the very first identifier token in the
4696      definition of `va_list', so if there is more junk after that first
4697      identifier token, delete it from the `varargs_style_indicator'.  */
4698   {
4699     const char *cp;
4700
4701     for (cp = varargs_style_indicator;
4702          ISALNUM ((const unsigned char)*cp) || *cp == '_'; cp++)
4703       continue;
4704     if (*cp != 0)
4705       varargs_style_indicator = savestring (varargs_style_indicator,
4706                                             cp - varargs_style_indicator);
4707   }
4708 #endif /* !defined (UNPROTOIZE) */
4709
4710   if (errors)
4711     usage ();
4712   else
4713     {
4714       if (version_flag)
4715         fprintf (stderr, "%s: %s\n", pname, version_string);
4716       do_processing ();
4717     }
4718
4719   exit (errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
4720
4721   return 1;
4722 }