OSDN Git Service

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