OSDN Git Service

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