OSDN Git Service

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