OSDN Git Service

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