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