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