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