OSDN Git Service

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