118334Speter/* Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
290075Sobrien   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
418334Speter
590075SobrienThis file is part of GCC.
618334Speter
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1118334Speter
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
2118334Speter
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
24132718Skan#include "coretypes.h"
25132718Skan#include "tm.h"
2690075Sobrien#include "intl.h"
2796263Sobrien#include "cppdefault.h"
2818334Speter
2990075Sobrien#include <setjmp.h>
3090075Sobrien#include <signal.h>
3190075Sobrien#if ! defined( SIGCHLD ) && defined( SIGCLD )
3290075Sobrien#  define SIGCHLD SIGCLD
3318334Speter#endif
3490075Sobrien#ifdef HAVE_UNISTD_H
3590075Sobrien#include <unistd.h>
3618334Speter#endif
3790075Sobrien#include "version.h"
3818334Speter
3990075Sobrien/* Include getopt.h for the sake of getopt_long.  */
4090075Sobrien#include "getopt.h"
4118334Speter
4290075Sobrien/* Macro to see if the path elements match.  */
4390075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
4490075Sobrien#define IS_SAME_PATH_CHAR(a,b) (TOUPPER (a) == TOUPPER (b))
4590075Sobrien#else
4690075Sobrien#define IS_SAME_PATH_CHAR(a,b) ((a) == (b))
4718334Speter#endif
4818334Speter
4990075Sobrien/* Macro to see if the paths match.  */
50132718Skan#define IS_SAME_PATH(a,b) (FILENAME_CMP (a, b) == 0)
5118334Speter
5290075Sobrien/* Suffix for aux-info files.  */
5390075Sobrien#ifdef __MSDOS__
5490075Sobrien#define AUX_INFO_SUFFIX "X"
5518334Speter#else
5690075Sobrien#define AUX_INFO_SUFFIX ".X"
5718334Speter#endif
5818334Speter
5990075Sobrien/* Suffix for saved files.  */
6090075Sobrien#ifdef __MSDOS__
6190075Sobrien#define SAVE_SUFFIX "sav"
6290075Sobrien#else
6390075Sobrien#define SAVE_SUFFIX ".save"
6450397Sobrien#endif
6550397Sobrien
6690075Sobrien/* Suffix for renamed C++ files.  */
6790075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
6890075Sobrien#define CPLUS_FILE_SUFFIX "cc"
6950397Sobrien#else
7090075Sobrien#define CPLUS_FILE_SUFFIX "C"
7150397Sobrien#endif
7218334Speter
73132718Skanstatic void usage (void) ATTRIBUTE_NORETURN;
74132718Skanstatic void aux_info_corrupted (void) ATTRIBUTE_NORETURN;
75132718Skanstatic void declare_source_confusing (const char *) ATTRIBUTE_NORETURN;
76132718Skanstatic const char *shortpath (const char *, const char *);
77132718Skanstatic void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
78132718Skanstatic char *savestring (const char *, unsigned int);
79132718Skanstatic char *dupnstr (const char *, size_t);
80132718Skanstatic int safe_read (int, void *, int);
81132718Skanstatic void safe_write (int, void *, int, const char *);
82132718Skanstatic void save_pointers (void);
83132718Skanstatic void restore_pointers (void);
84132718Skanstatic int is_id_char (int);
85132718Skanstatic int in_system_include_dir (const char *);
86132718Skanstatic int directory_specified_p (const char *);
87132718Skanstatic int file_excluded_p (const char *);
88132718Skanstatic char *unexpand_if_needed (const char *);
89132718Skanstatic char *abspath (const char *, const char *);
90132718Skanstatic void check_aux_info (int);
91132718Skanstatic const char *find_corresponding_lparen (const char *);
92132718Skanstatic int referenced_file_is_newer (const char *, time_t);
93132718Skanstatic void save_def_or_dec (const char *, int);
94132718Skanstatic void munge_compile_params (const char *);
95132718Skanstatic int gen_aux_info_file (const char *);
96132718Skanstatic void process_aux_info_file (const char *, int, int);
97132718Skanstatic int identify_lineno (const char *);
98132718Skanstatic void check_source (int, const char *);
99132718Skanstatic const char *seek_to_line (int);
100132718Skanstatic const char *forward_to_next_token_char (const char *);
101132718Skanstatic void output_bytes (const char *, size_t);
102132718Skanstatic void output_string (const char *);
103132718Skanstatic void output_up_to (const char *);
104132718Skanstatic int other_variable_style_function (const char *);
105132718Skanstatic const char *find_rightmost_formals_list (const char *);
106132718Skanstatic void do_cleaning (char *, const char *);
107132718Skanstatic const char *careful_find_l_paren (const char *);
108132718Skanstatic void do_processing (void);
10918334Speter
11090075Sobrien/* Look for these where the `const' qualifier is intentionally cast aside.  */
11190075Sobrien#define NONCONST
11250397Sobrien
11390075Sobrien/* Define a default place to find the SYSCALLS.X file.  */
11418334Speter
11590075Sobrien#ifndef UNPROTOIZE
11618334Speter
11790075Sobrien#ifndef STANDARD_EXEC_PREFIX
11890075Sobrien#define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-lib/"
11990075Sobrien#endif /* !defined STANDARD_EXEC_PREFIX */
12018334Speter
12190075Sobrienstatic const char * const standard_exec_prefix = STANDARD_EXEC_PREFIX;
12290075Sobrienstatic const char * const target_machine = DEFAULT_TARGET_MACHINE;
12390075Sobrienstatic const char * const target_version = DEFAULT_TARGET_VERSION;
12418334Speter
12590075Sobrien#endif /* !defined (UNPROTOIZE) */
12618334Speter
12790075Sobrien/* Suffix of aux_info files.  */
12818334Speter
12990075Sobrienstatic const char * const aux_info_suffix = AUX_INFO_SUFFIX;
13018334Speter
13190075Sobrien/* String to attach to filenames for saved versions of original files.  */
13218334Speter
13390075Sobrienstatic const char * const save_suffix = SAVE_SUFFIX;
13418334Speter
135132718Skan#ifndef UNPROTOIZE
136132718Skan
13790075Sobrien/* String to attach to C filenames renamed to C++.  */
13818334Speter
13990075Sobrienstatic const char * const cplus_suffix = CPLUS_FILE_SUFFIX;
14018334Speter
14118334Speter/* File name of the file which contains descriptions of standard system
14218334Speter   routines.  Note that we never actually do anything with this file per se,
14318334Speter   but we do read in its corresponding aux_info file.  */
14418334Speter
14518334Speterstatic const char syscalls_filename[] = "SYSCALLS.c";
14618334Speter
14718334Speter/* Default place to find the above file.  */
14818334Speter
14990075Sobrienstatic const char * default_syscalls_dir;
15018334Speter
15118334Speter/* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
15218334Speter   file.  */
15318334Speter
15418334Speterstatic char * syscalls_absolute_filename;
15518334Speter
15618334Speter#endif /* !defined (UNPROTOIZE) */
15718334Speter
15850397Sobrien/* Type of the structure that holds information about macro unexpansions.  */
15918334Speter
16018334Speterstruct unexpansion_struct {
16190075Sobrien  const char *const expanded;
16290075Sobrien  const char *const contracted;
16318334Speter};
16418334Spetertypedef struct unexpansion_struct unexpansion;
16518334Speter
16618334Speter/* A table of conversions that may need to be made for some (stupid) older
16718334Speter   operating systems where these types are preprocessor macros rather than
16818334Speter   typedefs (as they really ought to be).
16918334Speter
17018334Speter   WARNING: The contracted forms must be as small (or smaller) as the
17118334Speter   expanded forms, or else havoc will ensue.  */
17218334Speter
17318334Speterstatic const unexpansion unexpansions[] = {
17418334Speter  { "struct _iobuf", "FILE" },
17518334Speter  { 0, 0 }
17618334Speter};
17718334Speter
17818334Speter/* The number of "primary" slots in the hash tables for filenames and for
17918334Speter   function names.  This can be as big or as small as you like, except that
18018334Speter   it must be a power of two.  */
18118334Speter
18218334Speter#define HASH_TABLE_SIZE		(1 << 9)
18318334Speter
18418334Speter/* Bit mask to use when computing hash values.  */
18518334Speter
18618334Speterstatic const int hash_mask = (HASH_TABLE_SIZE - 1);
18718334Speter
18818334Speter
18918334Speter/* Datatype for lists of directories or filenames.  */
19018334Speterstruct string_list
19118334Speter{
19290075Sobrien  const char *name;
19318334Speter  struct string_list *next;
19418334Speter};
19518334Speter
196132718Skanstatic struct string_list *string_list_cons (const char *,
197132718Skan					     struct string_list *);
19890075Sobrien
19918334Speter/* List of directories in which files should be converted.  */
20018334Speter
20118334Speterstruct string_list *directory_list;
20218334Speter
20318334Speter/* List of file names which should not be converted.
20418334Speter   A file is excluded if the end of its name, following a /,
20518334Speter   matches one of the names in this list.  */
20618334Speter
20718334Speterstruct string_list *exclude_list;
20818334Speter
20918334Speter/* The name of the other style of variable-number-of-parameters functions
21018334Speter   (i.e. the style that we want to leave unconverted because we don't yet
21118334Speter   know how to convert them to this style.  This string is used in warning
21218334Speter   messages.  */
21318334Speter
21418334Speter/* Also define here the string that we can search for in the parameter lists
21518334Speter   taken from the .X files which will unambiguously indicate that we have
21618334Speter   found a varargs style function.  */
21718334Speter
21818334Speter#ifdef UNPROTOIZE
21918334Speterstatic const char * const other_var_style = "stdarg";
22018334Speter#else /* !defined (UNPROTOIZE) */
22118334Speterstatic const char * const other_var_style = "varargs";
222132718Skanstatic const char *varargs_style_indicator = "va_alist";
22318334Speter#endif /* !defined (UNPROTOIZE) */
22418334Speter
22518334Speter/* The following two types are used to create hash tables.  In this program,
22618334Speter   there are two hash tables which are used to store and quickly lookup two
22718334Speter   different classes of strings.  The first type of strings stored in the
22818334Speter   first hash table are absolute filenames of files which protoize needs to
22918334Speter   know about.  The second type of strings (stored in the second hash table)
23018334Speter   are function names.  It is this second class of strings which really
23118334Speter   inspired the use of the hash tables, because there may be a lot of them.  */
23218334Speter
23318334Spetertypedef struct hash_table_entry_struct hash_table_entry;
23418334Speter
23518334Speter/* Do some typedefs so that we don't have to write "struct" so often.  */
23618334Speter
23718334Spetertypedef struct def_dec_info_struct def_dec_info;
23818334Spetertypedef struct file_info_struct file_info;
23918334Spetertypedef struct f_list_chain_item_struct f_list_chain_item;
24018334Speter
24190075Sobrien#ifndef UNPROTOIZE
242132718Skanstatic int is_syscalls_file (const file_info *);
243132718Skanstatic void rename_c_file (const hash_table_entry *);
244132718Skanstatic const def_dec_info *find_extern_def (const def_dec_info *,
245132718Skan					    const def_dec_info *);
246132718Skanstatic const def_dec_info *find_static_definition (const def_dec_info *);
247132718Skanstatic void connect_defs_and_decs (const hash_table_entry *);
248132718Skanstatic void add_local_decl (const def_dec_info *, const char *);
249132718Skanstatic void add_global_decls (const file_info *, const char *);
25090075Sobrien#endif /* ! UNPROTOIZE */
251132718Skanstatic int needs_to_be_converted (const file_info *);
252132718Skanstatic void visit_each_hash_node (const hash_table_entry *,
253132718Skan				  void (*)(const hash_table_entry *));
254132718Skanstatic hash_table_entry *add_symbol (hash_table_entry *, const char *);
255132718Skanstatic hash_table_entry *lookup (hash_table_entry *, const char *);
256132718Skanstatic void free_def_dec (def_dec_info *);
257132718Skanstatic file_info *find_file (const char *, int);
258132718Skanstatic void reverse_def_dec_list (const hash_table_entry *);
259132718Skanstatic void edit_fn_declaration (const def_dec_info *, const char *);
260132718Skanstatic int edit_formals_lists (const char *, unsigned int,
261132718Skan			       const def_dec_info *);
262132718Skanstatic void edit_fn_definition (const def_dec_info *, const char *);
263132718Skanstatic void scan_for_missed_items (const file_info *);
264132718Skanstatic void edit_file (const hash_table_entry *);
26590075Sobrien
26618334Speter/* In the struct below, note that the "_info" field has two different uses
26718334Speter   depending on the type of hash table we are in (i.e. either the filenames
26818334Speter   hash table or the function names hash table).  In the filenames hash table
26918334Speter   the info fields of the entries point to the file_info struct which is
27018334Speter   associated with each filename (1 per filename).  In the function names
27118334Speter   hash table, the info field points to the head of a singly linked list of
27218334Speter   def_dec_info entries which are all defs or decs of the function whose
27318334Speter   name is pointed to by the "symbol" field.  Keeping all of the defs/decs
27418334Speter   for a given function name on a special list specifically for that function
27518334Speter   name makes it quick and easy to find out all of the important information
27618334Speter   about a given (named) function.  */
27718334Speter
27818334Speterstruct hash_table_entry_struct {
27918334Speter  hash_table_entry *		hash_next;	/* -> to secondary entries */
28018334Speter  const char *			symbol;		/* -> to the hashed string */
28118334Speter  union {
28218334Speter    const def_dec_info *	_ddip;
28318334Speter    file_info *			_fip;
28418334Speter  } _info;
28518334Speter};
28618334Speter#define ddip _info._ddip
28718334Speter#define fip _info._fip
28818334Speter
28918334Speter/* Define a type specifically for our two hash tables.  */
29018334Speter
29118334Spetertypedef hash_table_entry hash_table[HASH_TABLE_SIZE];
29218334Speter
29318334Speter/* The following struct holds all of the important information about any
29418334Speter   single filename (e.g. file) which we need to know about.  */
29518334Speter
29618334Speterstruct file_info_struct {
29718334Speter  const hash_table_entry *	hash_entry; /* -> to associated hash entry */
29818334Speter  const def_dec_info *		defs_decs;  /* -> to chain of defs/decs */
29918334Speter  time_t			mtime;      /* Time of last modification.  */
30018334Speter};
30118334Speter
30218334Speter/* Due to the possibility that functions may return pointers to functions,
30318334Speter   (which may themselves have their own parameter lists) and due to the
30418334Speter   fact that returned pointers-to-functions may be of type "pointer-to-
30518334Speter   function-returning-pointer-to-function" (ad nauseum) we have to keep
30618334Speter   an entire chain of ANSI style formal parameter lists for each function.
30718334Speter
30818334Speter   Normally, for any given function, there will only be one formals list
30918334Speter   on the chain, but you never know.
31018334Speter
31118334Speter   Note that the head of each chain of formals lists is pointed to by the
31218334Speter   `f_list_chain' field of the corresponding def_dec_info record.
31318334Speter
31418334Speter   For any given chain, the item at the head of the chain is the *leftmost*
31518334Speter   parameter list seen in the actual C language function declaration.  If
31618334Speter   there are other members of the chain, then these are linked in left-to-right
31718334Speter   order from the head of the chain.  */
31818334Speter
31918334Speterstruct f_list_chain_item_struct {
32018334Speter  const f_list_chain_item *	chain_next;	/* -> to next item on chain */
32118334Speter  const char *			formals_list;	/* -> to formals list string */
32218334Speter};
32318334Speter
32418334Speter/* The following struct holds all of the important information about any
32518334Speter   single function definition or declaration which we need to know about.
32618334Speter   Note that for unprotoize we don't need to know very much because we
32718334Speter   never even create records for stuff that we don't intend to convert
32818334Speter   (like for instance defs and decs which are already in old K&R format
32918334Speter   and "implicit" function declarations).  */
33018334Speter
33118334Speterstruct def_dec_info_struct {
33218334Speter  const def_dec_info *	next_in_file;	/* -> to rest of chain for file */
33318334Speter  file_info *        	file;		/* -> file_info for containing file */
33418334Speter  int        		line;		/* source line number of def/dec */
33518334Speter  const char *		ansi_decl;	/* -> left end of ansi decl */
33618334Speter  hash_table_entry *	hash_entry;	/* -> hash entry for function name */
33718334Speter  unsigned int        	is_func_def;	/* = 0 means this is a declaration */
33818334Speter  const def_dec_info *	next_for_func;	/* -> to rest of chain for func name */
33918334Speter  unsigned int		f_list_count;	/* count of formals lists we expect */
34018334Speter  char			prototyped;	/* = 0 means already prototyped */
34118334Speter#ifndef UNPROTOIZE
34218334Speter  const f_list_chain_item * f_list_chain;	/* -> chain of formals lists */
34318334Speter  const def_dec_info *	definition;	/* -> def/dec containing related def */
34418334Speter  char	        	is_static;	/* = 0 means visibility is "extern"  */
34518334Speter  char			is_implicit;	/* != 0 for implicit func decl's */
34618334Speter  char			written;	/* != 0 means written for implicit */
34718334Speter#else /* !defined (UNPROTOIZE) */
34818334Speter  const char *		formal_names;	/* -> to list of names of formals */
34918334Speter  const char *		formal_decls;	/* -> to string of formal declarations */
35018334Speter#endif /* !defined (UNPROTOIZE) */
35118334Speter};
35218334Speter
35318334Speter/* Pointer to the tail component of the filename by which this program was
35418334Speter   invoked.  Used everywhere in error and warning messages.  */
35518334Speter
35618334Speterstatic const char *pname;
35718334Speter
358117395Skan/* Error counter.  Will be nonzero if we should give up at the next convenient
35918334Speter   stopping point.  */
36018334Speter
36118334Speterstatic int errors = 0;
36218334Speter
36318334Speter/* Option flags.  */
364169689Skan/* ??? The variables are not marked static because some of them have
365169689Skan   the same names as gcc variables declared in options.h.  */
36618334Speter/* ??? These comments should say what the flag mean as well as the options
36718334Speter   that set them.  */
36818334Speter
36918334Speter/* File name to use for running gcc.  Allows GCC 2 to be named
37018334Speter   something other than gcc.  */
37118334Speterstatic const char *compiler_file_name = "gcc";
37218334Speter
373169689Skanint version_flag = 0;		/* Print our version number.  */
374169689Skanint quiet_flag = 0;		/* Don't print messages normally.  */
375169689Skanint nochange_flag = 0;		/* Don't convert, just say what files
376169689Skan				   we would have converted.  */
377169689Skanint nosave_flag = 0;		/* Don't save the old version.  */
378169689Skanint keep_flag = 0;		/* Don't delete the .X files.  */
37918334Speterstatic const char ** compile_params = 0;	/* Option string for gcc.  */
38018334Speter#ifdef UNPROTOIZE
38118334Speterstatic const char *indent_string = "     ";	/* Indentation for newly
38218334Speter						   inserted parm decls.  */
38318334Speter#else /* !defined (UNPROTOIZE) */
384169689Skanint local_flag = 0;		/* Insert new local decls (when?).  */
385169689Skanint global_flag = 0;		/* set by -g option */
386169689Skanint cplusplus_flag = 0;		/* Rename converted files to *.C.  */
38750397Sobrienstatic const char *nondefault_syscalls_dir = 0; /* Dir to look for
38818334Speter						   SYSCALLS.c.X in.  */
38918334Speter#endif /* !defined (UNPROTOIZE) */
39018334Speter
39118334Speter/* An index into the compile_params array where we should insert the source
39218334Speter   file name when we are ready to exec the C compiler.  A zero value indicates
39318334Speter   that we have not yet called munge_compile_params.  */
39418334Speter
39518334Speterstatic int input_file_name_index = 0;
39618334Speter
39718334Speter/* An index into the compile_params array where we should insert the filename
39818334Speter   for the aux info file, when we run the C compiler.  */
39918334Speterstatic int aux_info_file_name_index = 0;
40018334Speter
40118334Speter/* Count of command line arguments which were "filename" arguments.  */
40218334Speter
40318334Speterstatic int n_base_source_files = 0;
40418334Speter
40518334Speter/* Points to a malloc'ed list of pointers to all of the filenames of base
40618334Speter   source files which were specified on the command line.  */
40718334Speter
40818334Speterstatic const char **base_source_filenames;
40918334Speter
41018334Speter/* Line number of the line within the current aux_info file that we
41118334Speter   are currently processing.  Used for error messages in case the prototypes
41218334Speter   info file is corrupted somehow.  */
41318334Speter
41418334Speterstatic int current_aux_info_lineno;
41518334Speter
41618334Speter/* Pointer to the name of the source file currently being converted.  */
41718334Speter
41818334Speterstatic const char *convert_filename;
41918334Speter
42018334Speter/* Pointer to relative root string (taken from aux_info file) which indicates
42118334Speter   where directory the user was in when he did the compilation step that
42250397Sobrien   produced the containing aux_info file.  */
42318334Speter
42418334Speterstatic const char *invocation_filename;
42518334Speter
42618334Speter/* Pointer to the base of the input buffer that holds the original text for the
42718334Speter   source file currently being converted.  */
42818334Speter
42918334Speterstatic const char *orig_text_base;
43018334Speter
43118334Speter/* Pointer to the byte just beyond the end of the input buffer that holds the
43218334Speter   original text for the source file currently being converted.  */
43318334Speter
43418334Speterstatic const char *orig_text_limit;
43518334Speter
43618334Speter/* Pointer to the base of the input buffer that holds the cleaned text for the
43718334Speter   source file currently being converted.  */
43818334Speter
43918334Speterstatic const char *clean_text_base;
44018334Speter
44118334Speter/* Pointer to the byte just beyond the end of the input buffer that holds the
44218334Speter   cleaned text for the source file currently being converted.  */
44318334Speter
44418334Speterstatic const char *clean_text_limit;
44518334Speter
44618334Speter/* Pointer to the last byte in the cleaned text buffer that we have already
44718334Speter   (virtually) copied to the output buffer (or decided to ignore).  */
44818334Speter
44918334Speterstatic const char * clean_read_ptr;
45018334Speter
45118334Speter/* Pointer to the base of the output buffer that holds the replacement text
45218334Speter   for the source file currently being converted.  */
45318334Speter
45418334Speterstatic char *repl_text_base;
45518334Speter
45618334Speter/* Pointer to the byte just beyond the end of the output buffer that holds the
45718334Speter   replacement text for the source file currently being converted.  */
45818334Speter
45918334Speterstatic char *repl_text_limit;
46018334Speter
46118334Speter/* Pointer to the last byte which has been stored into the output buffer.
46218334Speter   The next byte to be stored should be stored just past where this points
46318334Speter   to.  */
46418334Speter
46518334Speterstatic char * repl_write_ptr;
46618334Speter
46718334Speter/* Pointer into the cleaned text buffer for the source file we are currently
46818334Speter   converting.  This points to the first character of the line that we last
46918334Speter   did a "seek_to_line" to (see below).  */
47018334Speter
47118334Speterstatic const char *last_known_line_start;
47218334Speter
47318334Speter/* Number of the line (in the cleaned text buffer) that we last did a
47418334Speter   "seek_to_line" to.  Will be one if we just read a new source file
47518334Speter   into the cleaned text buffer.  */
47618334Speter
47718334Speterstatic int last_known_line_number;
47818334Speter
47918334Speter/* The filenames hash table.  */
48018334Speter
48118334Speterstatic hash_table filename_primary;
48218334Speter
48318334Speter/* The function names hash table.  */
48418334Speter
48518334Speterstatic hash_table function_name_primary;
48618334Speter
48718334Speter/* The place to keep the recovery address which is used only in cases where
48818334Speter   we get hopelessly confused by something in the cleaned original text.  */
48918334Speter
49018334Speterstatic jmp_buf source_confusion_recovery;
49118334Speter
49218334Speter/* A pointer to the current directory filename (used by abspath).  */
49318334Speter
49418334Speterstatic char *cwd_buffer;
49518334Speter
49618334Speter/* A place to save the read pointer until we are sure that an individual
49718334Speter   attempt at editing will succeed.  */
49818334Speter
49918334Speterstatic const char * saved_clean_read_ptr;
50018334Speter
50118334Speter/* A place to save the write pointer until we are sure that an individual
50218334Speter   attempt at editing will succeed.  */
50318334Speter
50418334Speterstatic char * saved_repl_write_ptr;
50518334Speter
50652284Sobrien/* Translate and output an error message.  */
50752284Sobrienstatic void
508169689Skannotice (const char *cmsgid, ...)
50952284Sobrien{
510132718Skan  va_list ap;
511132718Skan
512169689Skan  va_start (ap, cmsgid);
513169689Skan  vfprintf (stderr, _(cmsgid), ap);
514132718Skan  va_end (ap);
51552284Sobrien}
51652284Sobrien
51752284Sobrien
51818334Speter/* Make a copy of a string INPUT with size SIZE.  */
51918334Speter
52018334Speterstatic char *
521132718Skansavestring (const char *input, unsigned int size)
52218334Speter{
523132718Skan  char *output = xmalloc (size + 1);
52418334Speter  strcpy (output, input);
52518334Speter  return output;
52618334Speter}
52718334Speter
52818334Speter
52918334Speter/* Make a duplicate of the first N bytes of a given string in a newly
53018334Speter   allocated area.  */
53118334Speter
53218334Speterstatic char *
533132718Skandupnstr (const char *s, size_t n)
53418334Speter{
535132718Skan  char *ret_val = xmalloc (n + 1);
53618334Speter
53718334Speter  strncpy (ret_val, s, n);
53818334Speter  ret_val[n] = '\0';
53918334Speter  return ret_val;
54018334Speter}
54118334Speter
54218334Speter/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
54318334Speter   retrying if necessary.  Return the actual number of bytes read.  */
54418334Speter
54518334Speterstatic int
546132718Skansafe_read (int desc, void *ptr, int len)
54718334Speter{
54818334Speter  int left = len;
54918334Speter  while (left > 0) {
55018334Speter    int nchars = read (desc, ptr, left);
55118334Speter    if (nchars < 0)
55218334Speter      {
55318334Speter#ifdef EINTR
55418334Speter	if (errno == EINTR)
55518334Speter	  continue;
55618334Speter#endif
55718334Speter	return nchars;
55818334Speter      }
55918334Speter    if (nchars == 0)
56018334Speter      break;
56190075Sobrien    /* Arithmetic on void pointers is a gcc extension.  */
56290075Sobrien    ptr = (char *) ptr + nchars;
56318334Speter    left -= nchars;
56418334Speter  }
56518334Speter  return len - left;
56618334Speter}
56718334Speter
56818334Speter/* Write LEN bytes at PTR to descriptor DESC,
56918334Speter   retrying if necessary, and treating any real error as fatal.  */
57018334Speter
57118334Speterstatic void
572132718Skansafe_write (int desc, void *ptr, int len, const char *out_fname)
57318334Speter{
57418334Speter  while (len > 0) {
57518334Speter    int written = write (desc, ptr, len);
57618334Speter    if (written < 0)
57718334Speter      {
57850397Sobrien	int errno_val = errno;
57918334Speter#ifdef EINTR
58050397Sobrien	if (errno_val == EINTR)
58118334Speter	  continue;
58218334Speter#endif
583169689Skan	notice ("%s: error writing file '%s': %s\n",
58452284Sobrien		pname, shortpath (NULL, out_fname), xstrerror (errno_val));
58518334Speter	return;
58618334Speter      }
58790075Sobrien    /* Arithmetic on void pointers is a gcc extension.  */
58890075Sobrien    ptr = (char *) ptr + written;
58918334Speter    len -= written;
59018334Speter  }
59118334Speter}
59218334Speter
59318334Speter/* Get setup to recover in case the edit we are about to do goes awry.  */
59418334Speter
59590075Sobrienstatic void
596132718Skansave_pointers (void)
59718334Speter{
59818334Speter  saved_clean_read_ptr = clean_read_ptr;
59918334Speter  saved_repl_write_ptr = repl_write_ptr;
60018334Speter}
60118334Speter
60218334Speter/* Call this routine to recover our previous state whenever something looks
60318334Speter   too confusing in the source code we are trying to edit.  */
60418334Speter
60590075Sobrienstatic void
606132718Skanrestore_pointers (void)
60718334Speter{
60818334Speter  clean_read_ptr = saved_clean_read_ptr;
60918334Speter  repl_write_ptr = saved_repl_write_ptr;
61018334Speter}
61118334Speter
61218334Speter/* Return true if the given character is a valid identifier character.  */
61318334Speter
61418334Speterstatic int
615132718Skanis_id_char (int ch)
61618334Speter{
61790075Sobrien  return (ISIDNUM (ch) || (ch == '$'));
61818334Speter}
61918334Speter
62018334Speter/* Give a message indicating the proper way to invoke this program and then
621117395Skan   exit with nonzero status.  */
62218334Speter
62318334Speterstatic void
624132718Skanusage (void)
62518334Speter{
62618334Speter#ifdef UNPROTOIZE
62752284Sobrien  notice ("%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
62852284Sobrien	  pname, pname);
62918334Speter#else /* !defined (UNPROTOIZE) */
63052284Sobrien  notice ("%s: usage '%s [ -VqfnkNlgC ] [ -B <dirname> ] [ filename ... ]'\n",
63152284Sobrien	  pname, pname);
63218334Speter#endif /* !defined (UNPROTOIZE) */
63350397Sobrien  exit (FATAL_EXIT_CODE);
63418334Speter}
63518334Speter
63618334Speter/* Return true if the given filename (assumed to be an absolute filename)
63718334Speter   designates a file residing anywhere beneath any one of the "system"
63818334Speter   include directories.  */
63918334Speter
64018334Speterstatic int
641132718Skanin_system_include_dir (const char *path)
64218334Speter{
64390075Sobrien  const struct default_include *p;
64418334Speter
645169689Skan  gcc_assert (IS_ABSOLUTE_PATH (path));
64618334Speter
64796263Sobrien  for (p = cpp_include_defaults; p->fname; p++)
64818334Speter    if (!strncmp (path, p->fname, strlen (p->fname))
64990075Sobrien	&& IS_DIR_SEPARATOR (path[strlen (p->fname)]))
65018334Speter      return 1;
65118334Speter  return 0;
65218334Speter}
65318334Speter
65418334Speter#if 0
65518334Speter/* Return true if the given filename designates a file that the user has
65618334Speter   read access to and for which the user has write access to the containing
65718334Speter   directory.  */
65818334Speter
65918334Speterstatic int
66018334Speterfile_could_be_converted (const char *path)
66118334Speter{
662132718Skan  char *const dir_name = alloca (strlen (path) + 1);
66318334Speter
66490075Sobrien  if (access (path, R_OK))
66518334Speter    return 0;
66618334Speter
66718334Speter  {
66818334Speter    char *dir_last_slash;
66918334Speter
67018334Speter    strcpy (dir_name, path);
67190075Sobrien    dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
67290075Sobrien#ifdef DIR_SEPARATOR_2
67390075Sobrien    {
67490075Sobrien      char *slash;
67590075Sobrien
676117395Skan      slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
677117395Skan		       DIR_SEPARATOR_2);
67890075Sobrien      if (slash)
67990075Sobrien	dir_last_slash = slash;
68090075Sobrien    }
68190075Sobrien#endif
682169689Skan    gcc_assert (dir_last_slash);
683169689Skan    *dir_last_slash = '\0';
68418334Speter  }
68518334Speter
68690075Sobrien  if (access (path, W_OK))
68718334Speter    return 0;
68818334Speter
68918334Speter  return 1;
69018334Speter}
69118334Speter
69218334Speter/* Return true if the given filename designates a file that we are allowed
69318334Speter   to modify.  Files which we should not attempt to modify are (a) "system"
69418334Speter   include files, and (b) files which the user doesn't have write access to,
69518334Speter   and (c) files which reside in directories which the user doesn't have
69618334Speter   write access to.  Unless requested to be quiet, give warnings about
69718334Speter   files that we will not try to convert for one reason or another.  An
69818334Speter   exception is made for "system" include files, which we never try to
69918334Speter   convert and for which we don't issue the usual warnings.  */
70018334Speter
70118334Speterstatic int
70218334Speterfile_normally_convertible (const char *path)
70318334Speter{
70418334Speter  char *const dir_name = alloca (strlen (path) + 1);
70518334Speter
70618334Speter  if (in_system_include_dir (path))
70718334Speter    return 0;
70818334Speter
70918334Speter  {
71018334Speter    char *dir_last_slash;
71118334Speter
71218334Speter    strcpy (dir_name, path);
71390075Sobrien    dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
71490075Sobrien#ifdef DIR_SEPARATOR_2
71590075Sobrien    {
71690075Sobrien      char *slash;
71790075Sobrien
718117395Skan      slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
719117395Skan		       DIR_SEPARATOR_2);
72090075Sobrien      if (slash)
72190075Sobrien	dir_last_slash = slash;
72290075Sobrien    }
72390075Sobrien#endif
724169689Skan    gcc_assert (dir_last_slash);
725169689Skan    *dir_last_slash = '\0';
72618334Speter  }
72718334Speter
72890075Sobrien  if (access (path, R_OK))
72918334Speter    {
73018334Speter      if (!quiet_flag)
731169689Skan	notice ("%s: warning: no read access for file '%s'\n",
73252284Sobrien		pname, shortpath (NULL, path));
73318334Speter      return 0;
73418334Speter    }
73518334Speter
73690075Sobrien  if (access (path, W_OK))
73718334Speter    {
73818334Speter      if (!quiet_flag)
739169689Skan	notice ("%s: warning: no write access for file '%s'\n",
74052284Sobrien		pname, shortpath (NULL, path));
74118334Speter      return 0;
74218334Speter    }
74318334Speter
74490075Sobrien  if (access (dir_name, W_OK))
74518334Speter    {
74618334Speter      if (!quiet_flag)
747169689Skan	notice ("%s: warning: no write access for dir containing '%s'\n",
74852284Sobrien		pname, shortpath (NULL, path));
74918334Speter      return 0;
75018334Speter    }
75118334Speter
75218334Speter  return 1;
75318334Speter}
75418334Speter#endif /* 0 */
75518334Speter
75618334Speter#ifndef UNPROTOIZE
75718334Speter
75818334Speter/* Return true if the given file_info struct refers to the special SYSCALLS.c.X
75918334Speter   file.  Return false otherwise.  */
76018334Speter
76118334Speterstatic int
762132718Skanis_syscalls_file (const file_info *fi_p)
76318334Speter{
76418334Speter  char const *f = fi_p->hash_entry->symbol;
76518334Speter  size_t fl = strlen (f), sysl = sizeof (syscalls_filename) - 1;
76618334Speter  return sysl <= fl  &&  strcmp (f + fl - sysl, syscalls_filename) == 0;
76718334Speter}
76818334Speter
76918334Speter#endif /* !defined (UNPROTOIZE) */
77018334Speter
77118334Speter/* Check to see if this file will need to have anything done to it on this
77218334Speter   run.  If there is nothing in the given file which both needs conversion
77318334Speter   and for which we have the necessary stuff to do the conversion, return
77418334Speter   false.  Otherwise, return true.
77518334Speter
77618334Speter   Note that (for protoize) it is only valid to call this function *after*
77718334Speter   the connections between declarations and definitions have all been made
77818334Speter   by connect_defs_and_decs.  */
77918334Speter
78018334Speterstatic int
781132718Skanneeds_to_be_converted (const file_info *file_p)
78218334Speter{
78318334Speter  const def_dec_info *ddp;
78418334Speter
78518334Speter#ifndef UNPROTOIZE
78618334Speter
78718334Speter  if (is_syscalls_file (file_p))
78818334Speter    return 0;
78918334Speter
79018334Speter#endif /* !defined (UNPROTOIZE) */
79118334Speter
79218334Speter  for (ddp = file_p->defs_decs; ddp; ddp = ddp->next_in_file)
79318334Speter
79418334Speter    if (
79518334Speter
79618334Speter#ifndef UNPROTOIZE
79718334Speter
79850397Sobrien      /* ... and if we a protoizing and this function is in old style ...  */
79918334Speter      !ddp->prototyped
80050397Sobrien      /* ... and if this a definition or is a decl with an associated def ...  */
80118334Speter      && (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
80218334Speter
80318334Speter#else /* defined (UNPROTOIZE) */
80418334Speter
80550397Sobrien      /* ... and if we are unprotoizing and this function is in new style ...  */
80618334Speter      ddp->prototyped
80718334Speter
80818334Speter#endif /* defined (UNPROTOIZE) */
80918334Speter      )
810117395Skan	  /* ... then the containing file needs converting.  */
811117395Skan	  return -1;
81218334Speter  return 0;
81318334Speter}
81418334Speter
81518334Speter/* Return 1 if the file name NAME is in a directory
81618334Speter   that should be converted.  */
81718334Speter
81818334Speterstatic int
819132718Skandirectory_specified_p (const char *name)
82018334Speter{
82118334Speter  struct string_list *p;
82218334Speter
82318334Speter  for (p = directory_list; p; p = p->next)
82418334Speter    if (!strncmp (name, p->name, strlen (p->name))
82590075Sobrien	&& IS_DIR_SEPARATOR (name[strlen (p->name)]))
82618334Speter      {
82718334Speter	const char *q = name + strlen (p->name) + 1;
82818334Speter
82918334Speter	/* If there are more slashes, it's in a subdir, so
83018334Speter	   this match doesn't count.  */
83190075Sobrien	while (*q++)
83290075Sobrien	  if (IS_DIR_SEPARATOR (*(q-1)))
83318334Speter	    goto lose;
83418334Speter	return 1;
83518334Speter
83618334Speter      lose: ;
83718334Speter      }
83818334Speter
83918334Speter  return 0;
84018334Speter}
84118334Speter
84218334Speter/* Return 1 if the file named NAME should be excluded from conversion.  */
84318334Speter
84418334Speterstatic int
845132718Skanfile_excluded_p (const char *name)
84618334Speter{
84718334Speter  struct string_list *p;
84818334Speter  int len = strlen (name);
84918334Speter
85018334Speter  for (p = exclude_list; p; p = p->next)
85118334Speter    if (!strcmp (name + len - strlen (p->name), p->name)
85290075Sobrien	&& IS_DIR_SEPARATOR (name[len - strlen (p->name) - 1]))
85318334Speter      return 1;
85418334Speter
85518334Speter  return 0;
85618334Speter}
85718334Speter
85818334Speter/* Construct a new element of a string_list.
85918334Speter   STRING is the new element value, and REST holds the remaining elements.  */
86018334Speter
86118334Speterstatic struct string_list *
862132718Skanstring_list_cons (const char *string, struct string_list *rest)
86318334Speter{
864132718Skan  struct string_list *temp = xmalloc (sizeof (struct string_list));
86518334Speter
86618334Speter  temp->next = rest;
86718334Speter  temp->name = string;
86818334Speter  return temp;
86918334Speter}
87018334Speter
87118334Speter/* ??? The GNU convention for mentioning function args in its comments
87218334Speter   is to capitalize them.  So change "hash_tab_p" to HASH_TAB_P below.
87318334Speter   Likewise for all the other functions.  */
87418334Speter
87518334Speter/* Given a hash table, apply some function to each node in the table. The
87618334Speter   table to traverse is given as the "hash_tab_p" argument, and the
87718334Speter   function to be applied to each node in the table is given as "func"
87818334Speter   argument.  */
87918334Speter
88018334Speterstatic void
881132718Skanvisit_each_hash_node (const hash_table_entry *hash_tab_p,
882132718Skan		      void (*func) (const hash_table_entry *))
88318334Speter{
88418334Speter  const hash_table_entry *primary;
88518334Speter
88618334Speter  for (primary = hash_tab_p; primary < &hash_tab_p[HASH_TABLE_SIZE]; primary++)
88718334Speter    if (primary->symbol)
88818334Speter      {
889117395Skan	hash_table_entry *second;
89018334Speter
891117395Skan	(*func)(primary);
892117395Skan	for (second = primary->hash_next; second; second = second->hash_next)
893117395Skan	  (*func) (second);
89418334Speter      }
89518334Speter}
89618334Speter
89718334Speter/* Initialize all of the fields of a new hash table entry, pointed
89818334Speter   to by the "p" parameter.  Note that the space to hold the entry
89918334Speter   is assumed to have already been allocated before this routine is
90018334Speter   called.  */
90118334Speter
90218334Speterstatic hash_table_entry *
903132718Skanadd_symbol (hash_table_entry *p, const char *s)
90418334Speter{
90518334Speter  p->hash_next = NULL;
90690075Sobrien  p->symbol = xstrdup (s);
90718334Speter  p->ddip = NULL;
90818334Speter  p->fip = NULL;
90918334Speter  return p;
91018334Speter}
91118334Speter
91218334Speter/* Look for a particular function name or filename in the particular
91318334Speter   hash table indicated by "hash_tab_p".  If the name is not in the
91418334Speter   given hash table, add it.  Either way, return a pointer to the
91518334Speter   hash table entry for the given name.  */
91618334Speter
91718334Speterstatic hash_table_entry *
918132718Skanlookup (hash_table_entry *hash_tab_p, const char *search_symbol)
91918334Speter{
92018334Speter  int hash_value = 0;
92118334Speter  const char *search_symbol_char_p = search_symbol;
92218334Speter  hash_table_entry *p;
92318334Speter
92418334Speter  while (*search_symbol_char_p)
92518334Speter    hash_value += *search_symbol_char_p++;
92618334Speter  hash_value &= hash_mask;
92718334Speter  p = &hash_tab_p[hash_value];
92818334Speter  if (! p->symbol)
92918334Speter      return add_symbol (p, search_symbol);
93018334Speter  if (!strcmp (p->symbol, search_symbol))
93118334Speter    return p;
93218334Speter  while (p->hash_next)
93318334Speter    {
93418334Speter      p = p->hash_next;
93518334Speter      if (!strcmp (p->symbol, search_symbol))
936117395Skan	return p;
93718334Speter    }
938132718Skan  p->hash_next = xmalloc (sizeof (hash_table_entry));
93918334Speter  p = p->hash_next;
94018334Speter  return add_symbol (p, search_symbol);
94118334Speter}
94218334Speter
94318334Speter/* Throw a def/dec record on the junk heap.
94418334Speter
94518334Speter   Also, since we are not using this record anymore, free up all of the
94618334Speter   stuff it pointed to.  */
94718334Speter
94818334Speterstatic void
949132718Skanfree_def_dec (def_dec_info *p)
95018334Speter{
951132718Skan  free ((NONCONST void *) p->ansi_decl);
95218334Speter
95318334Speter#ifndef UNPROTOIZE
95418334Speter  {
95518334Speter    const f_list_chain_item * curr;
95618334Speter    const f_list_chain_item * next;
95718334Speter
95818334Speter    for (curr = p->f_list_chain; curr; curr = next)
95918334Speter      {
960117395Skan	next = curr->chain_next;
961132718Skan	free ((NONCONST void *) curr);
96218334Speter      }
96318334Speter  }
96418334Speter#endif /* !defined (UNPROTOIZE) */
96518334Speter
96690075Sobrien  free (p);
96718334Speter}
96818334Speter
969169689Skan/* Unexpand as many macro symbols as we can find.
97018334Speter
97118334Speter   If the given line must be unexpanded, make a copy of it in the heap and
97218334Speter   return a pointer to the unexpanded copy.  Otherwise return NULL.  */
97318334Speter
97418334Speterstatic char *
975132718Skanunexpand_if_needed (const char *aux_info_line)
97618334Speter{
97718334Speter  static char *line_buf = 0;
97818334Speter  static int line_buf_size = 0;
97950397Sobrien  const unexpansion *unexp_p;
98018334Speter  int got_unexpanded = 0;
98118334Speter  const char *s;
98218334Speter  char *copy_p = line_buf;
98318334Speter
98418334Speter  if (line_buf == 0)
98518334Speter    {
98618334Speter      line_buf_size = 1024;
987132718Skan      line_buf = xmalloc (line_buf_size);
98818334Speter    }
98918334Speter
99018334Speter  copy_p = line_buf;
99118334Speter
99218334Speter  /* Make a copy of the input string in line_buf, expanding as necessary.  */
99318334Speter
99418334Speter  for (s = aux_info_line; *s != '\n'; )
99518334Speter    {
99618334Speter      for (unexp_p = unexpansions; unexp_p->expanded; unexp_p++)
997117395Skan	{
998117395Skan	  const char *in_p = unexp_p->expanded;
999117395Skan	  size_t len = strlen (in_p);
100018334Speter
1001117395Skan	  if (*s == *in_p && !strncmp (s, in_p, len) && !is_id_char (s[len]))
1002117395Skan	    {
100318334Speter	      int size = strlen (unexp_p->contracted);
1004117395Skan	      got_unexpanded = 1;
100518334Speter	      if (copy_p + size - line_buf >= line_buf_size)
100618334Speter		{
100718334Speter		  int offset = copy_p - line_buf;
100818334Speter		  line_buf_size *= 2;
100918334Speter		  line_buf_size += size;
1010132718Skan		  line_buf = xrealloc (line_buf, line_buf_size);
101118334Speter		  copy_p = line_buf + offset;
101218334Speter		}
1013117395Skan	      strcpy (copy_p, unexp_p->contracted);
1014117395Skan	      copy_p += size;
101518334Speter
1016117395Skan	      /* Assume that there will not be another replacement required
1017117395Skan	         within the text just replaced.  */
101818334Speter
1019117395Skan	      s += len;
1020117395Skan	      goto continue_outer;
1021117395Skan	    }
1022117395Skan	}
102318334Speter      if (copy_p - line_buf == line_buf_size)
102418334Speter	{
102518334Speter	  int offset = copy_p - line_buf;
102618334Speter	  line_buf_size *= 2;
1027132718Skan	  line_buf = xrealloc (line_buf, line_buf_size);
102818334Speter	  copy_p = line_buf + offset;
102918334Speter	}
103018334Speter      *copy_p++ = *s++;
103118334Spetercontinue_outer: ;
103218334Speter    }
103318334Speter  if (copy_p + 2 - line_buf >= line_buf_size)
103418334Speter    {
103518334Speter      int offset = copy_p - line_buf;
103618334Speter      line_buf_size *= 2;
1037132718Skan      line_buf = xrealloc (line_buf, line_buf_size);
103818334Speter      copy_p = line_buf + offset;
103918334Speter    }
104018334Speter  *copy_p++ = '\n';
104118334Speter  *copy_p = '\0';
104218334Speter
104318334Speter  return (got_unexpanded ? savestring (line_buf, copy_p - line_buf) : 0);
104418334Speter}
104518334Speter
104618334Speter/* Return the absolutized filename for the given relative
104718334Speter   filename.  Note that if that filename is already absolute, it may
104818334Speter   still be returned in a modified form because this routine also
104918334Speter   eliminates redundant slashes and single dots and eliminates double
105018334Speter   dots to get a shortest possible filename from the given input
105118334Speter   filename.  The absolutization of relative filenames is made by
105218334Speter   assuming that the given filename is to be taken as relative to
105318334Speter   the first argument (cwd) or to the current directory if cwd is
105418334Speter   NULL.  */
105518334Speter
105618334Speterstatic char *
1057132718Skanabspath (const char *cwd, const char *rel_filename)
105818334Speter{
105918334Speter  /* Setup the current working directory as needed.  */
106090075Sobrien  const char *const cwd2 = (cwd) ? cwd : cwd_buffer;
1061132718Skan  char *const abs_buffer = alloca (strlen (cwd2) + strlen (rel_filename) + 2);
106218334Speter  char *endp = abs_buffer;
106318334Speter  char *outp, *inp;
106418334Speter
106518334Speter  /* Copy the  filename (possibly preceded by the current working
106618334Speter     directory name) into the absolutization buffer.  */
106718334Speter
106818334Speter  {
106918334Speter    const char *src_p;
107018334Speter
1071132718Skan    if (! IS_ABSOLUTE_PATH (rel_filename))
107218334Speter      {
1073117395Skan	src_p = cwd2;
1074117395Skan	while ((*endp++ = *src_p++))
1075117395Skan	  continue;
1076117395Skan	*(endp-1) = DIR_SEPARATOR;     		/* overwrite null */
107718334Speter      }
107890075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
107990075Sobrien    else if (IS_DIR_SEPARATOR (rel_filename[0]))
108090075Sobrien      {
1081117395Skan	/* A path starting with a directory separator is considered absolute
1082117395Skan	   for dos based filesystems, but it's really not -- it's just the
108390075Sobrien	   convention used throughout GCC and it works. However, in this
108490075Sobrien	   case, we still need to prepend the drive spec from cwd_buffer.  */
108590075Sobrien	*endp++ = cwd2[0];
108690075Sobrien	*endp++ = cwd2[1];
108790075Sobrien      }
108890075Sobrien#endif
108918334Speter    src_p = rel_filename;
109050397Sobrien    while ((*endp++ = *src_p++))
109118334Speter      continue;
109218334Speter  }
109318334Speter
109418334Speter  /* Now make a copy of abs_buffer into abs_buffer, shortening the
109518334Speter     filename (by taking out slashes and dots) as we go.  */
109618334Speter
109718334Speter  outp = inp = abs_buffer;
109818334Speter  *outp++ = *inp++;        	/* copy first slash */
109952284Sobrien#if defined (apollo) || defined (_WIN32) || defined (__INTERIX)
110090075Sobrien  if (IS_DIR_SEPARATOR (inp[0]))
110118334Speter    *outp++ = *inp++;        	/* copy second slash */
110218334Speter#endif
110318334Speter  for (;;)
110418334Speter    {
110518334Speter      if (!inp[0])
1106117395Skan	break;
110790075Sobrien      else if (IS_DIR_SEPARATOR (inp[0]) && IS_DIR_SEPARATOR (outp[-1]))
1108117395Skan	{
1109117395Skan	  inp++;
1110117395Skan	  continue;
1111117395Skan	}
111290075Sobrien      else if (inp[0] == '.' && IS_DIR_SEPARATOR (outp[-1]))
1113117395Skan	{
1114117395Skan	  if (!inp[1])
1115117395Skan	    break;
1116117395Skan	  else if (IS_DIR_SEPARATOR (inp[1]))
1117117395Skan	    {
1118117395Skan	      inp += 2;
1119117395Skan	      continue;
1120117395Skan	    }
1121117395Skan	  else if ((inp[1] == '.') && (inp[2] == 0
112290075Sobrien	                               || IS_DIR_SEPARATOR (inp[2])))
1123117395Skan	    {
1124117395Skan	      inp += (IS_DIR_SEPARATOR (inp[2])) ? 3 : 2;
1125117395Skan	      outp -= 2;
1126117395Skan	      while (outp >= abs_buffer && ! IS_DIR_SEPARATOR (*outp))
1127117395Skan	      	outp--;
1128117395Skan	      if (outp < abs_buffer)
1129117395Skan		{
1130117395Skan		  /* Catch cases like /.. where we try to backup to a
1131117395Skan		     point above the absolute root of the logical file
1132117395Skan		     system.  */
113318334Speter
1134117395Skan		  notice ("%s: invalid file name: %s\n",
1135117395Skan			  pname, rel_filename);
1136117395Skan		  exit (FATAL_EXIT_CODE);
1137117395Skan		}
1138117395Skan	      *++outp = '\0';
1139117395Skan	      continue;
1140117395Skan	    }
1141117395Skan	}
114218334Speter      *outp++ = *inp++;
114318334Speter    }
114418334Speter
114518334Speter  /* On exit, make sure that there is a trailing null, and make sure that
114618334Speter     the last character of the returned string is *not* a slash.  */
114718334Speter
114818334Speter  *outp = '\0';
114990075Sobrien  if (IS_DIR_SEPARATOR (outp[-1]))
115018334Speter    *--outp  = '\0';
115118334Speter
115218334Speter  /* Make a copy (in the heap) of the stuff left in the absolutization
115318334Speter     buffer and return a pointer to the copy.  */
115418334Speter
115518334Speter  return savestring (abs_buffer, outp - abs_buffer);
115618334Speter}
115718334Speter
115818334Speter/* Given a filename (and possibly a directory name from which the filename
115918334Speter   is relative) return a string which is the shortest possible
116018334Speter   equivalent for the corresponding full (absolutized) filename.  The
116118334Speter   shortest possible equivalent may be constructed by converting the
116218334Speter   absolutized filename to be a relative filename (i.e. relative to
116318334Speter   the actual current working directory).  However if a relative filename
116418334Speter   is longer, then the full absolute filename is returned.
116518334Speter
116618334Speter   KNOWN BUG:
116718334Speter
116818334Speter   Note that "simple-minded" conversion of any given type of filename (either
116918334Speter   relative or absolute) may not result in a valid equivalent filename if any
117018334Speter   subpart of the original filename is actually a symbolic link.  */
117118334Speter
117218334Speterstatic const char *
1173132718Skanshortpath (const char *cwd, const char *filename)
117418334Speter{
117518334Speter  char *rel_buffer;
117618334Speter  char *rel_buf_p;
117718334Speter  char *cwd_p = cwd_buffer;
117818334Speter  char *path_p;
117918334Speter  int unmatched_slash_count = 0;
118018334Speter  size_t filename_len = strlen (filename);
118118334Speter
118218334Speter  path_p = abspath (cwd, filename);
1183132718Skan  rel_buf_p = rel_buffer = xmalloc (filename_len);
118418334Speter
118590075Sobrien  while (*cwd_p && IS_SAME_PATH_CHAR (*cwd_p, *path_p))
118618334Speter    {
118718334Speter      cwd_p++;
118818334Speter      path_p++;
118918334Speter    }
119090075Sobrien  if (!*cwd_p && (!*path_p || IS_DIR_SEPARATOR (*path_p)))
119118334Speter    {
119290075Sobrien      /* whole pwd matched */
119318334Speter      if (!*path_p)        	/* input *is* the current path! */
1194117395Skan	return ".";
119518334Speter      else
1196117395Skan	return ++path_p;
119718334Speter    }
119818334Speter  else
119918334Speter    {
120018334Speter      if (*path_p)
1201117395Skan	{
1202117395Skan	  --cwd_p;
1203117395Skan	  --path_p;
1204117395Skan	  while (! IS_DIR_SEPARATOR (*cwd_p))     /* backup to last slash */
1205117395Skan	    {
1206117395Skan	      --cwd_p;
1207117395Skan	      --path_p;
1208117395Skan	    }
1209117395Skan	  cwd_p++;
1210117395Skan	  path_p++;
1211117395Skan	  unmatched_slash_count++;
1212117395Skan	}
121318334Speter
121418334Speter      /* Find out how many directory levels in cwd were *not* matched.  */
121590075Sobrien      while (*cwd_p++)
1216117395Skan	if (IS_DIR_SEPARATOR (*(cwd_p-1)))
121718334Speter	  unmatched_slash_count++;
121818334Speter
121918334Speter      /* Now we know how long the "short name" will be.
122018334Speter	 Reject it if longer than the input.  */
122118334Speter      if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
122218334Speter	return filename;
122318334Speter
122418334Speter      /* For each of them, put a `../' at the beginning of the short name.  */
122518334Speter      while (unmatched_slash_count--)
1226117395Skan	{
122718334Speter	  /* Give up if the result gets to be longer
122818334Speter	     than the absolute path name.  */
122918334Speter	  if (rel_buffer + filename_len <= rel_buf_p + 3)
123018334Speter	    return filename;
1231117395Skan	  *rel_buf_p++ = '.';
1232117395Skan	  *rel_buf_p++ = '.';
1233117395Skan	  *rel_buf_p++ = DIR_SEPARATOR;
1234117395Skan	}
123518334Speter
123618334Speter      /* Then tack on the unmatched part of the desired file's name.  */
123718334Speter      do
123818334Speter	{
123918334Speter	  if (rel_buffer + filename_len <= rel_buf_p)
124018334Speter	    return filename;
124118334Speter	}
124250397Sobrien      while ((*rel_buf_p++ = *path_p++));
124318334Speter
124418334Speter      --rel_buf_p;
124590075Sobrien      if (IS_DIR_SEPARATOR (*(rel_buf_p-1)))
1246117395Skan	*--rel_buf_p = '\0';
124718334Speter      return rel_buffer;
124818334Speter    }
124918334Speter}
125018334Speter
125118334Speter/* Lookup the given filename in the hash table for filenames.  If it is a
125218334Speter   new one, then the hash table info pointer will be null.  In this case,
125318334Speter   we create a new file_info record to go with the filename, and we initialize
125418334Speter   that record with some reasonable values.  */
125518334Speter
125618334Speter/* FILENAME was const, but that causes a warning on AIX when calling stat.
125718334Speter   That is probably a bug in AIX, but might as well avoid the warning.  */
125818334Speter
125918334Speterstatic file_info *
1260132718Skanfind_file (const char *filename, int do_not_stat)
126118334Speter{
126218334Speter  hash_table_entry *hash_entry_p;
126318334Speter
126418334Speter  hash_entry_p = lookup (filename_primary, filename);
126518334Speter  if (hash_entry_p->fip)
126618334Speter    return hash_entry_p->fip;
126718334Speter  else
126818334Speter    {
126918334Speter      struct stat stat_buf;
1270132718Skan      file_info *file_p = xmalloc (sizeof (file_info));
127118334Speter
127218334Speter      /* If we cannot get status on any given source file, give a warning
1273117395Skan	 and then just set its time of last modification to infinity.  */
127418334Speter
127518334Speter      if (do_not_stat)
1276117395Skan	stat_buf.st_mtime = (time_t) 0;
127718334Speter      else
1278117395Skan	{
1279117395Skan	  if (stat (filename, &stat_buf) == -1)
1280117395Skan	    {
128150397Sobrien	      int errno_val = errno;
1282117395Skan	      notice ("%s: %s: can't get status: %s\n",
128352284Sobrien		      pname, shortpath (NULL, filename),
128452284Sobrien		      xstrerror (errno_val));
1285117395Skan	      stat_buf.st_mtime = (time_t) -1;
1286117395Skan	    }
1287117395Skan	}
128818334Speter
128918334Speter      hash_entry_p->fip = file_p;
129018334Speter      file_p->hash_entry = hash_entry_p;
129118334Speter      file_p->defs_decs = NULL;
129218334Speter      file_p->mtime = stat_buf.st_mtime;
129318334Speter      return file_p;
129418334Speter    }
129518334Speter}
129618334Speter
129718334Speter/* Generate a fatal error because some part of the aux_info file is
129818334Speter   messed up.  */
129918334Speter
130018334Speterstatic void
1301132718Skanaux_info_corrupted (void)
130218334Speter{
130352284Sobrien  notice ("\n%s: fatal error: aux info file corrupted at line %d\n",
130452284Sobrien	  pname, current_aux_info_lineno);
130550397Sobrien  exit (FATAL_EXIT_CODE);
130618334Speter}
130718334Speter
130818334Speter/* ??? This comment is vague.  Say what the condition is for.  */
130918334Speter/* Check to see that a condition is true.  This is kind of like an assert.  */
131018334Speter
131118334Speterstatic void
1312132718Skancheck_aux_info (int cond)
131318334Speter{
131418334Speter  if (! cond)
131518334Speter    aux_info_corrupted ();
131618334Speter}
131718334Speter
131818334Speter/* Given a pointer to the closing right parenthesis for a particular formals
131918334Speter   list (in an aux_info file) find the corresponding left parenthesis and
132018334Speter   return a pointer to it.  */
132118334Speter
132218334Speterstatic const char *
1323132718Skanfind_corresponding_lparen (const char *p)
132418334Speter{
132518334Speter  const char *q;
132618334Speter  int paren_depth;
132718334Speter
132818334Speter  for (paren_depth = 1, q = p-1; paren_depth; q--)
132918334Speter    {
133018334Speter      switch (*q)
1331117395Skan	{
1332117395Skan	case ')':
1333117395Skan	  paren_depth++;
1334117395Skan	  break;
1335117395Skan	case '(':
1336117395Skan	  paren_depth--;
1337117395Skan	  break;
1338117395Skan	}
133918334Speter    }
134018334Speter  return ++q;
134118334Speter}
134218334Speter
134318334Speter/* Given a line from  an aux info file, and a time at which the aux info
134418334Speter   file it came from was created, check to see if the item described in
134518334Speter   the line comes from a file which has been modified since the aux info
1346117395Skan   file was created.  If so, return nonzero, else return zero.  */
134718334Speter
134818334Speterstatic int
1349132718Skanreferenced_file_is_newer (const char *l, time_t aux_info_mtime)
135018334Speter{
135118334Speter  const char *p;
135218334Speter  file_info *fi_p;
135318334Speter  char *filename;
135418334Speter
135518334Speter  check_aux_info (l[0] == '/');
135618334Speter  check_aux_info (l[1] == '*');
135718334Speter  check_aux_info (l[2] == ' ');
135818334Speter
135918334Speter  {
136018334Speter    const char *filename_start = p = l + 3;
136118334Speter
136290075Sobrien    while (*p != ':'
136390075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1364117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
136590075Sobrien#endif
1366117395Skan	   )
136718334Speter      p++;
1368132718Skan    filename = alloca ((size_t) (p - filename_start) + 1);
136918334Speter    strncpy (filename, filename_start, (size_t) (p - filename_start));
137018334Speter    filename[p-filename_start] = '\0';
137118334Speter  }
137218334Speter
137318334Speter  /* Call find_file to find the file_info record associated with the file
137418334Speter     which contained this particular def or dec item.  Note that this call
137518334Speter     may cause a new file_info record to be created if this is the first time
137618334Speter     that we have ever known about this particular file.  */
137718334Speter
137818334Speter  fi_p = find_file (abspath (invocation_filename, filename), 0);
137918334Speter
138018334Speter  return (fi_p->mtime > aux_info_mtime);
138118334Speter}
138218334Speter
138318334Speter/* Given a line of info from the aux_info file, create a new
138418334Speter   def_dec_info record to remember all of the important information about
138518334Speter   a function definition or declaration.
138618334Speter
138718334Speter   Link this record onto the list of such records for the particular file in
138818334Speter   which it occurred in proper (descending) line number order (for now).
138918334Speter
139018334Speter   If there is an identical record already on the list for the file, throw
139118334Speter   this one away.  Doing so takes care of the (useless and troublesome)
139218334Speter   duplicates which are bound to crop up due to multiple inclusions of any
139318334Speter   given individual header file.
139418334Speter
139518334Speter   Finally, link the new def_dec record onto the list of such records
139618334Speter   pertaining to this particular function name.  */
139718334Speter
139818334Speterstatic void
1399132718Skansave_def_or_dec (const char *l, int is_syscalls)
140018334Speter{
140118334Speter  const char *p;
140218334Speter  const char *semicolon_p;
1403132718Skan  def_dec_info *def_dec_p = xmalloc (sizeof (def_dec_info));
140418334Speter
140518334Speter#ifndef UNPROTOIZE
140618334Speter  def_dec_p->written = 0;
140718334Speter#endif /* !defined (UNPROTOIZE) */
140818334Speter
140918334Speter  /* Start processing the line by picking off 5 pieces of information from
141018334Speter     the left hand end of the line.  These are filename, line number,
141118334Speter     new/old/implicit flag (new = ANSI prototype format), definition or
141218334Speter     declaration flag, and extern/static flag).  */
141318334Speter
141418334Speter  check_aux_info (l[0] == '/');
141518334Speter  check_aux_info (l[1] == '*');
141618334Speter  check_aux_info (l[2] == ' ');
141718334Speter
141818334Speter  {
141918334Speter    const char *filename_start = p = l + 3;
142018334Speter    char *filename;
142118334Speter
142290075Sobrien    while (*p != ':'
142390075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1424117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
142590075Sobrien#endif
1426117395Skan	   )
142718334Speter      p++;
1428132718Skan    filename = alloca ((size_t) (p - filename_start) + 1);
142918334Speter    strncpy (filename, filename_start, (size_t) (p - filename_start));
143018334Speter    filename[p-filename_start] = '\0';
143118334Speter
143218334Speter    /* Call find_file to find the file_info record associated with the file
143318334Speter       which contained this particular def or dec item.  Note that this call
143418334Speter       may cause a new file_info record to be created if this is the first time
143518334Speter       that we have ever known about this particular file.
1436117395Skan
143718334Speter       Note that we started out by forcing all of the base source file names
143818334Speter       (i.e. the names of the aux_info files with the .X stripped off) into the
143918334Speter       filenames hash table, and we simultaneously setup file_info records for
144018334Speter       all of these base file names (even if they may be useless later).
144118334Speter       The file_info records for all of these "base" file names (properly)
144218334Speter       act as file_info records for the "original" (i.e. un-included) files
144318334Speter       which were submitted to gcc for compilation (when the -aux-info
144418334Speter       option was used).  */
1445117395Skan
144618334Speter    def_dec_p->file = find_file (abspath (invocation_filename, filename), is_syscalls);
144718334Speter  }
144818334Speter
144918334Speter  {
145018334Speter    const char *line_number_start = ++p;
145118334Speter    char line_number[10];
145218334Speter
145390075Sobrien    while (*p != ':'
145490075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1455117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
145690075Sobrien#endif
1457117395Skan	   )
145818334Speter      p++;
145918334Speter    strncpy (line_number, line_number_start, (size_t) (p - line_number_start));
146018334Speter    line_number[p-line_number_start] = '\0';
146118334Speter    def_dec_p->line = atoi (line_number);
146218334Speter  }
146318334Speter
146418334Speter  /* Check that this record describes a new-style, old-style, or implicit
146518334Speter     definition or declaration.  */
146618334Speter
146750397Sobrien  p++;	/* Skip over the `:'.  */
146818334Speter  check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
146918334Speter
147018334Speter  /* Is this a new style (ANSI prototyped) definition or declaration? */
147118334Speter
147218334Speter  def_dec_p->prototyped = (*p == 'N');
147318334Speter
147418334Speter#ifndef UNPROTOIZE
147518334Speter
147618334Speter  /* Is this an implicit declaration? */
147718334Speter
147818334Speter  def_dec_p->is_implicit = (*p == 'I');
147918334Speter
148018334Speter#endif /* !defined (UNPROTOIZE) */
148118334Speter
148218334Speter  p++;
148318334Speter
148418334Speter  check_aux_info ((*p == 'C') || (*p == 'F'));
148518334Speter
148618334Speter  /* Is this item a function definition (F) or a declaration (C).  Note that
148718334Speter     we treat item taken from the syscalls file as though they were function
148818334Speter     definitions regardless of what the stuff in the file says.  */
148918334Speter
149018334Speter  def_dec_p->is_func_def = ((*p++ == 'F') || is_syscalls);
149118334Speter
149218334Speter#ifndef UNPROTOIZE
149318334Speter  def_dec_p->definition = 0;	/* Fill this in later if protoizing.  */
149418334Speter#endif /* !defined (UNPROTOIZE) */
149518334Speter
149618334Speter  check_aux_info (*p++ == ' ');
149718334Speter  check_aux_info (*p++ == '*');
149818334Speter  check_aux_info (*p++ == '/');
149918334Speter  check_aux_info (*p++ == ' ');
150018334Speter
150118334Speter#ifdef UNPROTOIZE
150218334Speter  check_aux_info ((!strncmp (p, "static", 6)) || (!strncmp (p, "extern", 6)));
150318334Speter#else /* !defined (UNPROTOIZE) */
150418334Speter  if (!strncmp (p, "static", 6))
150518334Speter    def_dec_p->is_static = -1;
150618334Speter  else if (!strncmp (p, "extern", 6))
150718334Speter    def_dec_p->is_static = 0;
150818334Speter  else
150918334Speter    check_aux_info (0);	/* Didn't find either `extern' or `static'.  */
151018334Speter#endif /* !defined (UNPROTOIZE) */
151118334Speter
151218334Speter  {
151318334Speter    const char *ansi_start = p;
151418334Speter
151518334Speter    p += 6;	/* Pass over the "static" or "extern".  */
151618334Speter
151718334Speter    /* We are now past the initial stuff.  Search forward from here to find
151818334Speter       the terminating semicolon that should immediately follow the entire
151918334Speter       ANSI format function declaration.  */
152018334Speter
152118334Speter    while (*++p != ';')
152218334Speter      continue;
152318334Speter
152418334Speter    semicolon_p = p;
152518334Speter
152618334Speter    /* Make a copy of the ansi declaration part of the line from the aux_info
152718334Speter       file.  */
152818334Speter
152918334Speter    def_dec_p->ansi_decl
153018334Speter      = dupnstr (ansi_start, (size_t) ((semicolon_p+1) - ansi_start));
153118334Speter
153218334Speter    /* Backup and point at the final right paren of the final argument list.  */
153318334Speter
153418334Speter    p--;
153518334Speter
153618334Speter#ifndef UNPROTOIZE
153718334Speter    def_dec_p->f_list_chain = NULL;
153818334Speter#endif /* !defined (UNPROTOIZE) */
153918334Speter
154018334Speter    while (p != ansi_start && (p[-1] == ' ' || p[-1] == '\t')) p--;
154118334Speter    if (*p != ')')
154218334Speter      {
154318334Speter	free_def_dec (def_dec_p);
154418334Speter	return;
154518334Speter      }
154618334Speter  }
154718334Speter
154818334Speter  /* Now isolate a whole set of formal argument lists, one-by-one.  Normally,
154918334Speter     there will only be one list to isolate, but there could be more.  */
155018334Speter
155118334Speter  def_dec_p->f_list_count = 0;
155218334Speter
155318334Speter  for (;;)
155418334Speter    {
155518334Speter      const char *left_paren_p = find_corresponding_lparen (p);
155618334Speter#ifndef UNPROTOIZE
155718334Speter      {
1558132718Skan	f_list_chain_item *cip = xmalloc (sizeof (f_list_chain_item));
155918334Speter
1560117395Skan	cip->formals_list
156118334Speter	  = dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
156218334Speter
1563117395Skan	/* Add the new chain item at the head of the current list.  */
1564117395Skan
1565117395Skan	cip->chain_next = def_dec_p->f_list_chain;
1566117395Skan	def_dec_p->f_list_chain = cip;
156718334Speter      }
156818334Speter#endif /* !defined (UNPROTOIZE) */
156918334Speter      def_dec_p->f_list_count++;
157018334Speter
157118334Speter      p = left_paren_p - 2;
157218334Speter
157318334Speter      /* p must now point either to another right paren, or to the last
1574117395Skan	 character of the name of the function that was declared/defined.
1575117395Skan	 If p points to another right paren, then this indicates that we
1576117395Skan	 are dealing with multiple formals lists.  In that case, there
1577117395Skan	 really should be another right paren preceding this right paren.  */
157818334Speter
157918334Speter      if (*p != ')')
1580117395Skan	break;
158118334Speter      else
1582117395Skan	check_aux_info (*--p == ')');
158318334Speter    }
158418334Speter
158518334Speter
158618334Speter  {
158718334Speter    const char *past_fn = p + 1;
158818334Speter
158918334Speter    check_aux_info (*past_fn == ' ');
159018334Speter
159118334Speter    /* Scan leftwards over the identifier that names the function.  */
159218334Speter
159318334Speter    while (is_id_char (*p))
159418334Speter      p--;
159518334Speter    p++;
159618334Speter
159718334Speter    /* p now points to the leftmost character of the function name.  */
159818334Speter
159918334Speter    {
1600132718Skan      char *fn_string = alloca (past_fn - p + 1);
160118334Speter
160218334Speter      strncpy (fn_string, p, (size_t) (past_fn - p));
160318334Speter      fn_string[past_fn-p] = '\0';
160418334Speter      def_dec_p->hash_entry = lookup (function_name_primary, fn_string);
160518334Speter    }
160618334Speter  }
160718334Speter
160818334Speter  /* Look at all of the defs and decs for this function name that we have
160918334Speter     collected so far.  If there is already one which is at the same
161018334Speter     line number in the same file, then we can discard this new def_dec_info
161118334Speter     record.
161218334Speter
161318334Speter     As an extra assurance that any such pair of (nominally) identical
161418334Speter     function declarations are in fact identical, we also compare the
161518334Speter     ansi_decl parts of the lines from the aux_info files just to be on
161618334Speter     the safe side.
161718334Speter
161818334Speter     This comparison will fail if (for instance) the user was playing
161918334Speter     messy games with the preprocessor which ultimately causes one
162018334Speter     function declaration in one header file to look differently when
162118334Speter     that file is included by two (or more) other files.  */
162218334Speter
162318334Speter  {
162418334Speter    const def_dec_info *other;
162518334Speter
162618334Speter    for (other = def_dec_p->hash_entry->ddip; other; other = other->next_for_func)
162718334Speter      {
1628117395Skan	if (def_dec_p->line == other->line && def_dec_p->file == other->file)
1629117395Skan	  {
1630117395Skan	    if (strcmp (def_dec_p->ansi_decl, other->ansi_decl))
1631117395Skan	      {
1632169689Skan	        notice ("%s:%d: declaration of function '%s' takes different forms\n",
163352284Sobrien			def_dec_p->file->hash_entry->symbol,
163452284Sobrien			def_dec_p->line,
163552284Sobrien			def_dec_p->hash_entry->symbol);
1636117395Skan	        exit (FATAL_EXIT_CODE);
1637117395Skan	      }
1638117395Skan	    free_def_dec (def_dec_p);
1639117395Skan	    return;
1640117395Skan	  }
164118334Speter      }
164218334Speter  }
164318334Speter
164418334Speter#ifdef UNPROTOIZE
164518334Speter
164618334Speter  /* If we are doing unprotoizing, we must now setup the pointers that will
164718334Speter     point to the K&R name list and to the K&R argument declarations list.
164818334Speter
164918334Speter     Note that if this is only a function declaration, then we should not
165018334Speter     expect to find any K&R style formals list following the ANSI-style
165118334Speter     formals list.  This is because GCC knows that such information is
165218334Speter     useless in the case of function declarations (function definitions
165318334Speter     are a different story however).
165418334Speter
165518334Speter     Since we are unprotoizing, we don't need any such lists anyway.
165618334Speter     All we plan to do is to delete all characters between ()'s in any
165718334Speter     case.  */
165818334Speter
165918334Speter  def_dec_p->formal_names = NULL;
166018334Speter  def_dec_p->formal_decls = NULL;
166118334Speter
166218334Speter  if (def_dec_p->is_func_def)
166318334Speter    {
166418334Speter      p = semicolon_p;
166518334Speter      check_aux_info (*++p == ' ');
166618334Speter      check_aux_info (*++p == '/');
166718334Speter      check_aux_info (*++p == '*');
166818334Speter      check_aux_info (*++p == ' ');
166918334Speter      check_aux_info (*++p == '(');
167018334Speter
167118334Speter      {
1672117395Skan	const char *kr_names_start = ++p;   /* Point just inside '('.  */
167318334Speter
1674117395Skan	while (*p++ != ')')
1675117395Skan	  continue;
1676117395Skan	p--;		/* point to closing right paren */
167718334Speter
1678117395Skan	/* Make a copy of the K&R parameter names list.  */
167918334Speter
1680117395Skan	def_dec_p->formal_names
168118334Speter	  = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
168218334Speter      }
168318334Speter
168418334Speter      check_aux_info (*++p == ' ');
168518334Speter      p++;
168618334Speter
168718334Speter      /* p now points to the first character of the K&R style declarations
1688117395Skan	 list (if there is one) or to the star-slash combination that ends
1689117395Skan	 the comment in which such lists get embedded.  */
169018334Speter
169118334Speter      /* Make a copy of the K&R formal decls list and set the def_dec record
1692117395Skan	 to point to it.  */
169318334Speter
169418334Speter      if (*p == '*')		/* Are there no K&R declarations? */
1695117395Skan	{
1696117395Skan	  check_aux_info (*++p == '/');
1697117395Skan	  def_dec_p->formal_decls = "";
1698117395Skan	}
169918334Speter      else
1700117395Skan	{
1701117395Skan	  const char *kr_decls_start = p;
170218334Speter
1703117395Skan	  while (p[0] != '*' || p[1] != '/')
1704117395Skan	    p++;
1705117395Skan	  p--;
170618334Speter
1707117395Skan	  check_aux_info (*p == ' ');
170818334Speter
1709117395Skan	  def_dec_p->formal_decls
171018334Speter	    = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1711117395Skan	}
171218334Speter
171318334Speter      /* Handle a special case.  If we have a function definition marked as
1714117395Skan	 being in "old" style, and if its formal names list is empty, then
1715117395Skan	 it may actually have the string "void" in its real formals list
1716117395Skan	 in the original source code.  Just to make sure, we will get setup
1717117395Skan	 to convert such things anyway.
171818334Speter
1719117395Skan	 This kludge only needs to be here because of an insurmountable
1720117395Skan	 problem with generating .X files.  */
172118334Speter
172218334Speter      if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1723117395Skan	def_dec_p->prototyped = 1;
172418334Speter    }
172518334Speter
172618334Speter  /* Since we are unprotoizing, if this item is already in old (K&R) style,
172718334Speter     we can just ignore it.  If that is true, throw away the itme now.  */
172818334Speter
172918334Speter  if (!def_dec_p->prototyped)
173018334Speter    {
173118334Speter      free_def_dec (def_dec_p);
173218334Speter      return;
173318334Speter    }
173418334Speter
173518334Speter#endif /* defined (UNPROTOIZE) */
173618334Speter
173718334Speter  /* Add this record to the head of the list of records pertaining to this
173818334Speter     particular function name.  */
173918334Speter
174018334Speter  def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
174118334Speter  def_dec_p->hash_entry->ddip = def_dec_p;
174218334Speter
174318334Speter  /* Add this new def_dec_info record to the sorted list of def_dec_info
174418334Speter     records for this file.  Note that we don't have to worry about duplicates
174518334Speter     (caused by multiple inclusions of header files) here because we have
174618334Speter     already eliminated duplicates above.  */
174718334Speter
174818334Speter  if (!def_dec_p->file->defs_decs)
174918334Speter    {
175018334Speter      def_dec_p->file->defs_decs = def_dec_p;
175118334Speter      def_dec_p->next_in_file = NULL;
175218334Speter    }
175318334Speter  else
175418334Speter    {
175518334Speter      int line = def_dec_p->line;
175618334Speter      const def_dec_info *prev = NULL;
175718334Speter      const def_dec_info *curr = def_dec_p->file->defs_decs;
175818334Speter      const def_dec_info *next = curr->next_in_file;
175918334Speter
176018334Speter      while (next && (line < curr->line))
1761117395Skan	{
1762117395Skan	  prev = curr;
1763117395Skan	  curr = next;
1764117395Skan	  next = next->next_in_file;
1765117395Skan	}
176618334Speter      if (line >= curr->line)
1767117395Skan	{
1768117395Skan	  def_dec_p->next_in_file = curr;
1769117395Skan	  if (prev)
1770117395Skan	    ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1771117395Skan	  else
1772117395Skan	    def_dec_p->file->defs_decs = def_dec_p;
1773117395Skan	}
177418334Speter      else	/* assert (next == NULL); */
1775117395Skan	{
1776117395Skan	  ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1777117395Skan	  /* assert (next == NULL); */
1778117395Skan	  def_dec_p->next_in_file = next;
1779117395Skan	}
178018334Speter    }
178118334Speter}
178218334Speter
178318334Speter/* Set up the vector COMPILE_PARAMS which is the argument list for running GCC.
178418334Speter   Also set input_file_name_index and aux_info_file_name_index
178518334Speter   to the indices of the slots where the file names should go.  */
178618334Speter
178718334Speter/* We initialize the vector by  removing -g, -O, -S, -c, and -o options,
178818334Speter   and adding '-aux-info AUXFILE -S  -o /dev/null INFILE' at the end.  */
178918334Speter
179018334Speterstatic void
1791132718Skanmunge_compile_params (const char *params_list)
179218334Speter{
179318334Speter  /* Build up the contents in a temporary vector
179418334Speter     that is so big that to has to be big enough.  */
179518334Speter  const char **temp_params
1796132718Skan    = alloca ((strlen (params_list) + 8) * sizeof (char *));
179718334Speter  int param_count = 0;
179818334Speter  const char *param;
179990075Sobrien  struct stat st;
180018334Speter
180118334Speter  temp_params[param_count++] = compiler_file_name;
180218334Speter  for (;;)
180318334Speter    {
180452284Sobrien      while (ISSPACE ((const unsigned char)*params_list))
1805117395Skan	params_list++;
180618334Speter      if (!*params_list)
1807117395Skan	break;
180818334Speter      param = params_list;
180952284Sobrien      while (*params_list && !ISSPACE ((const unsigned char)*params_list))
1810117395Skan	params_list++;
181118334Speter      if (param[0] != '-')
1812117395Skan	temp_params[param_count++]
181318334Speter	  = dupnstr (param, (size_t) (params_list - param));
181418334Speter      else
1815117395Skan	{
1816117395Skan	  switch (param[1])
1817117395Skan	    {
1818117395Skan	    case 'g':
1819117395Skan	    case 'O':
1820117395Skan	    case 'S':
1821117395Skan	    case 'c':
1822117395Skan	      break;		/* Don't copy these.  */
1823117395Skan	    case 'o':
1824117395Skan	      while (ISSPACE ((const unsigned char)*params_list))
1825117395Skan		params_list++;
1826117395Skan	      while (*params_list
1827117395Skan		     && !ISSPACE ((const unsigned char)*params_list))
1828117395Skan		params_list++;
1829117395Skan	      break;
1830117395Skan	    default:
1831117395Skan	      temp_params[param_count++]
1832117395Skan		= dupnstr (param, (size_t) (params_list - param));
1833117395Skan	    }
1834117395Skan	}
183518334Speter      if (!*params_list)
1836117395Skan	break;
183718334Speter    }
183818334Speter  temp_params[param_count++] = "-aux-info";
183918334Speter
184018334Speter  /* Leave room for the aux-info file name argument.  */
184118334Speter  aux_info_file_name_index = param_count;
184218334Speter  temp_params[param_count++] = NULL;
184318334Speter
184418334Speter  temp_params[param_count++] = "-S";
184518334Speter  temp_params[param_count++] = "-o";
1846117395Skan
184790075Sobrien  if ((stat (HOST_BIT_BUCKET, &st) == 0)
184890075Sobrien      && (!S_ISDIR (st.st_mode))
184990075Sobrien      && (access (HOST_BIT_BUCKET, W_OK) == 0))
185090075Sobrien    temp_params[param_count++] = HOST_BIT_BUCKET;
185190075Sobrien  else
185290075Sobrien    /* FIXME: This is hardly likely to be right, if HOST_BIT_BUCKET is not
185390075Sobrien       writable.  But until this is rejigged to use make_temp_file(), this
185490075Sobrien       is the best we can do.  */
185590075Sobrien    temp_params[param_count++] = "/dev/null";
185618334Speter
185718334Speter  /* Leave room for the input file name argument.  */
185818334Speter  input_file_name_index = param_count;
185918334Speter  temp_params[param_count++] = NULL;
186018334Speter  /* Terminate the list.  */
186118334Speter  temp_params[param_count++] = NULL;
186218334Speter
186318334Speter  /* Make a copy of the compile_params in heap space.  */
186418334Speter
1865132718Skan  compile_params = xmalloc (sizeof (char *) * (param_count+1));
186618334Speter  memcpy (compile_params, temp_params, sizeof (char *) * param_count);
186718334Speter}
186818334Speter
186918334Speter/* Do a recompilation for the express purpose of generating a new aux_info
187050397Sobrien   file to go with a specific base source file.
187118334Speter
187250397Sobrien   The result is a boolean indicating success.  */
187350397Sobrien
187418334Speterstatic int
1875132718Skangen_aux_info_file (const char *base_filename)
187618334Speter{
187718334Speter  if (!input_file_name_index)
187818334Speter    munge_compile_params ("");
187918334Speter
188018334Speter  /* Store the full source file name in the argument vector.  */
188118334Speter  compile_params[input_file_name_index] = shortpath (NULL, base_filename);
188218334Speter  /* Add .X to source file name to get aux-info file name.  */
188390075Sobrien  compile_params[aux_info_file_name_index] =
188490075Sobrien    concat (compile_params[input_file_name_index], aux_info_suffix, NULL);
1885117395Skan
188618334Speter  if (!quiet_flag)
1887169689Skan    notice ("%s: compiling '%s'\n",
188852284Sobrien	    pname, compile_params[input_file_name_index]);
188918334Speter
189050397Sobrien  {
189150397Sobrien    char *errmsg_fmt, *errmsg_arg;
189250397Sobrien    int wait_status, pid;
189318334Speter
189450397Sobrien    pid = pexecute (compile_params[0], (char * const *) compile_params,
189590075Sobrien		    pname, NULL, &errmsg_fmt, &errmsg_arg,
189650397Sobrien		    PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH);
189718334Speter
189850397Sobrien    if (pid == -1)
189950397Sobrien      {
190050397Sobrien	int errno_val = errno;
190150397Sobrien	fprintf (stderr, "%s: ", pname);
190250397Sobrien	fprintf (stderr, errmsg_fmt, errmsg_arg);
190352284Sobrien	fprintf (stderr, ": %s\n", xstrerror (errno_val));
190450397Sobrien	return 0;
190550397Sobrien      }
190618334Speter
190750397Sobrien    pid = pwait (pid, &wait_status, 0);
190850397Sobrien    if (pid == -1)
190918334Speter      {
191052284Sobrien	notice ("%s: wait: %s\n", pname, xstrerror (errno));
191150397Sobrien	return 0;
191250397Sobrien      }
191350397Sobrien    if (WIFSIGNALED (wait_status))
191450397Sobrien      {
191552284Sobrien	notice ("%s: subprocess got fatal signal %d\n",
191652284Sobrien		pname, WTERMSIG (wait_status));
191750397Sobrien	return 0;
191850397Sobrien      }
191950397Sobrien    if (WIFEXITED (wait_status))
192050397Sobrien      {
192150397Sobrien	if (WEXITSTATUS (wait_status) != 0)
192218334Speter	  {
192352284Sobrien	    notice ("%s: %s exited with status %d\n",
192452284Sobrien		    pname, compile_params[0], WEXITSTATUS (wait_status));
192518334Speter	    return 0;
192618334Speter	  }
192718334Speter	return 1;
192818334Speter      }
1929169689Skan    gcc_unreachable ();
193050397Sobrien  }
193118334Speter}
193218334Speter
193318334Speter/* Read in all of the information contained in a single aux_info file.
193418334Speter   Save all of the important stuff for later.  */
193518334Speter
193618334Speterstatic void
1937132718Skanprocess_aux_info_file (const char *base_source_filename, int keep_it,
1938132718Skan		       int is_syscalls)
193918334Speter{
194018334Speter  size_t base_len = strlen (base_source_filename);
1941132718Skan  char * aux_info_filename = alloca (base_len + strlen (aux_info_suffix) + 1);
194218334Speter  char *aux_info_base;
194318334Speter  char *aux_info_limit;
194418334Speter  char *aux_info_relocated_name;
194518334Speter  const char *aux_info_second_line;
194618334Speter  time_t aux_info_mtime;
194718334Speter  size_t aux_info_size;
194818334Speter  int must_create;
194918334Speter
195018334Speter  /* Construct the aux_info filename from the base source filename.  */
195118334Speter
195218334Speter  strcpy (aux_info_filename, base_source_filename);
195318334Speter  strcat (aux_info_filename, aux_info_suffix);
195418334Speter
195518334Speter  /* Check that the aux_info file exists and is readable.  If it does not
195618334Speter     exist, try to create it (once only).  */
195718334Speter
195818334Speter  /* If file doesn't exist, set must_create.
195918334Speter     Likewise if it exists and we can read it but it is obsolete.
196018334Speter     Otherwise, report an error.  */
196118334Speter  must_create = 0;
196218334Speter
196318334Speter  /* Come here with must_create set to 1 if file is out of date.  */
196418334Speterstart_over: ;
196518334Speter
196690075Sobrien  if (access (aux_info_filename, R_OK) == -1)
196718334Speter    {
196818334Speter      if (errno == ENOENT)
196918334Speter	{
197018334Speter	  if (is_syscalls)
197118334Speter	    {
1972169689Skan	      notice ("%s: warning: missing SYSCALLS file '%s'\n",
197352284Sobrien		      pname, aux_info_filename);
197418334Speter	      return;
197518334Speter	    }
197618334Speter	  must_create = 1;
197718334Speter	}
197818334Speter      else
197918334Speter	{
198050397Sobrien	  int errno_val = errno;
1981169689Skan	  notice ("%s: can't read aux info file '%s': %s\n",
198252284Sobrien		  pname, shortpath (NULL, aux_info_filename),
198352284Sobrien		  xstrerror (errno_val));
198418334Speter	  errors++;
198518334Speter	  return;
198618334Speter	}
198718334Speter    }
198818334Speter#if 0 /* There is code farther down to take care of this.  */
198918334Speter  else
199018334Speter    {
199118334Speter      struct stat s1, s2;
199218334Speter      stat (aux_info_file_name, &s1);
199318334Speter      stat (base_source_file_name, &s2);
199418334Speter      if (s2.st_mtime > s1.st_mtime)
199518334Speter	must_create = 1;
199618334Speter    }
199718334Speter#endif /* 0 */
199818334Speter
199918334Speter  /* If we need a .X file, create it, and verify we can read it.  */
200018334Speter  if (must_create)
200118334Speter    {
200218334Speter      if (!gen_aux_info_file (base_source_filename))
200318334Speter	{
200418334Speter	  errors++;
200518334Speter	  return;
200618334Speter	}
200790075Sobrien      if (access (aux_info_filename, R_OK) == -1)
200818334Speter	{
200950397Sobrien	  int errno_val = errno;
2010169689Skan	  notice ("%s: can't read aux info file '%s': %s\n",
201152284Sobrien		  pname, shortpath (NULL, aux_info_filename),
201252284Sobrien		  xstrerror (errno_val));
201318334Speter	  errors++;
201418334Speter	  return;
201518334Speter	}
201618334Speter    }
201718334Speter
201818334Speter  {
201918334Speter    struct stat stat_buf;
202018334Speter
202118334Speter    /* Get some status information about this aux_info file.  */
2022117395Skan
202390075Sobrien    if (stat (aux_info_filename, &stat_buf) == -1)
202418334Speter      {
202550397Sobrien	int errno_val = errno;
2026169689Skan	notice ("%s: can't get status of aux info file '%s': %s\n",
202752284Sobrien		pname, shortpath (NULL, aux_info_filename),
202852284Sobrien		xstrerror (errno_val));
2029117395Skan	errors++;
2030117395Skan	return;
203118334Speter      }
2032117395Skan
203318334Speter    /* Check on whether or not this aux_info file is zero length.  If it is,
203418334Speter       then just ignore it and return.  */
2035117395Skan
203618334Speter    if ((aux_info_size = stat_buf.st_size) == 0)
203718334Speter      return;
2038117395Skan
203918334Speter    /* Get the date/time of last modification for this aux_info file and
204018334Speter       remember it.  We will have to check that any source files that it
204118334Speter       contains information about are at least this old or older.  */
2042117395Skan
204318334Speter    aux_info_mtime = stat_buf.st_mtime;
204418334Speter
204518334Speter    if (!is_syscalls)
204618334Speter      {
204718334Speter	/* Compare mod time with the .c file; update .X file if obsolete.
204818334Speter	   The code later on can fail to check the .c file
204918334Speter	   if it did not directly define any functions.  */
205018334Speter
205190075Sobrien	if (stat (base_source_filename, &stat_buf) == -1)
205218334Speter	  {
205350397Sobrien	    int errno_val = errno;
2054169689Skan	    notice ("%s: can't get status of aux info file '%s': %s\n",
205552284Sobrien		    pname, shortpath (NULL, base_source_filename),
205652284Sobrien		    xstrerror (errno_val));
205718334Speter	    errors++;
205818334Speter	    return;
205918334Speter	  }
206018334Speter	if (stat_buf.st_mtime > aux_info_mtime)
206118334Speter	  {
206218334Speter	    must_create = 1;
206318334Speter	    goto start_over;
206418334Speter	  }
206518334Speter      }
206618334Speter  }
206718334Speter
206818334Speter  {
206918334Speter    int aux_info_file;
207090075Sobrien    int fd_flags;
207118334Speter
207218334Speter    /* Open the aux_info file.  */
2073117395Skan
207490075Sobrien    fd_flags = O_RDONLY;
207590075Sobrien#ifdef O_BINARY
207690075Sobrien    /* Use binary mode to avoid having to deal with different EOL characters.  */
207790075Sobrien    fd_flags |= O_BINARY;
207890075Sobrien#endif
207990075Sobrien    if ((aux_info_file = open (aux_info_filename, fd_flags, 0444 )) == -1)
208018334Speter      {
208150397Sobrien	int errno_val = errno;
2082169689Skan	notice ("%s: can't open aux info file '%s' for reading: %s\n",
208352284Sobrien		pname, shortpath (NULL, aux_info_filename),
208452284Sobrien		xstrerror (errno_val));
2085117395Skan	return;
208618334Speter      }
2087117395Skan
208818334Speter    /* Allocate space to hold the aux_info file in memory.  */
2089117395Skan
209018334Speter    aux_info_base = xmalloc (aux_info_size + 1);
209118334Speter    aux_info_limit = aux_info_base + aux_info_size;
209218334Speter    *aux_info_limit = '\0';
2093117395Skan
209418334Speter    /* Read the aux_info file into memory.  */
2095117395Skan
209652284Sobrien    if (safe_read (aux_info_file, aux_info_base, aux_info_size) !=
209752284Sobrien	(int) aux_info_size)
209818334Speter      {
209950397Sobrien	int errno_val = errno;
2100169689Skan	notice ("%s: error reading aux info file '%s': %s\n",
210152284Sobrien		pname, shortpath (NULL, aux_info_filename),
210252284Sobrien		xstrerror (errno_val));
2103117395Skan	free (aux_info_base);
2104117395Skan	close (aux_info_file);
2105117395Skan	return;
210618334Speter      }
2107117395Skan
210818334Speter    /* Close the aux info file.  */
2109117395Skan
211018334Speter    if (close (aux_info_file))
211118334Speter      {
211250397Sobrien	int errno_val = errno;
2113169689Skan	notice ("%s: error closing aux info file '%s': %s\n",
211452284Sobrien		pname, shortpath (NULL, aux_info_filename),
211552284Sobrien		xstrerror (errno_val));
2116117395Skan	free (aux_info_base);
2117117395Skan	close (aux_info_file);
2118117395Skan	return;
211918334Speter      }
212018334Speter  }
212118334Speter
212218334Speter  /* Delete the aux_info file (unless requested not to).  If the deletion
212318334Speter     fails for some reason, don't even worry about it.  */
212418334Speter
212518334Speter  if (must_create && !keep_it)
212690075Sobrien    if (unlink (aux_info_filename) == -1)
212750397Sobrien      {
212850397Sobrien	int errno_val = errno;
2129169689Skan	notice ("%s: can't delete aux info file '%s': %s\n",
213052284Sobrien		pname, shortpath (NULL, aux_info_filename),
213152284Sobrien		xstrerror (errno_val));
213250397Sobrien      }
213318334Speter
213418334Speter  /* Save a pointer into the first line of the aux_info file which
213518334Speter     contains the filename of the directory from which the compiler
213618334Speter     was invoked when the associated source file was compiled.
213718334Speter     This information is used later to help create complete
213818334Speter     filenames out of the (potentially) relative filenames in
213918334Speter     the aux_info file.  */
214018334Speter
214118334Speter  {
214218334Speter    char *p = aux_info_base;
214318334Speter
214490075Sobrien    while (*p != ':'
214590075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
2146117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
214790075Sobrien#endif
2148117395Skan	   )
214918334Speter      p++;
215018334Speter    p++;
215118334Speter    while (*p == ' ')
215218334Speter      p++;
215318334Speter    invocation_filename = p;	/* Save a pointer to first byte of path.  */
215418334Speter    while (*p != ' ')
215518334Speter      p++;
215690075Sobrien    *p++ = DIR_SEPARATOR;
215718334Speter    *p++ = '\0';
215818334Speter    while (*p++ != '\n')
215918334Speter      continue;
216018334Speter    aux_info_second_line = p;
216118334Speter    aux_info_relocated_name = 0;
2162132718Skan    if (! IS_ABSOLUTE_PATH (invocation_filename))
216318334Speter      {
216418334Speter	/* INVOCATION_FILENAME is relative;
216518334Speter	   append it to BASE_SOURCE_FILENAME's dir.  */
216618334Speter	char *dir_end;
216718334Speter	aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
216818334Speter	strcpy (aux_info_relocated_name, base_source_filename);
216990075Sobrien	dir_end = strrchr (aux_info_relocated_name, DIR_SEPARATOR);
217090075Sobrien#ifdef DIR_SEPARATOR_2
217190075Sobrien	{
217290075Sobrien	  char *slash;
217390075Sobrien
2174117395Skan	  slash = strrchr (dir_end ? dir_end : aux_info_relocated_name,
2175117395Skan			   DIR_SEPARATOR_2);
217690075Sobrien	  if (slash)
217790075Sobrien	    dir_end = slash;
217890075Sobrien	}
217990075Sobrien#endif
218018334Speter	if (dir_end)
218118334Speter	  dir_end++;
218218334Speter	else
218318334Speter	  dir_end = aux_info_relocated_name;
218418334Speter	strcpy (dir_end, invocation_filename);
218518334Speter	invocation_filename = aux_info_relocated_name;
218618334Speter      }
218718334Speter  }
218818334Speter
218918334Speter
219018334Speter  {
219118334Speter    const char *aux_info_p;
219218334Speter
219318334Speter    /* Do a pre-pass on the lines in the aux_info file, making sure that all
219418334Speter       of the source files referenced in there are at least as old as this
219518334Speter       aux_info file itself.  If not, go back and regenerate the aux_info
219618334Speter       file anew.  Don't do any of this for the syscalls file.  */
219718334Speter
219818334Speter    if (!is_syscalls)
219918334Speter      {
2200117395Skan	current_aux_info_lineno = 2;
2201117395Skan
2202117395Skan	for (aux_info_p = aux_info_second_line; *aux_info_p; )
2203117395Skan	  {
2204117395Skan	    if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2205117395Skan	      {
2206117395Skan		free (aux_info_base);
220790075Sobrien		free (aux_info_relocated_name);
2208117395Skan		if (keep_it && unlink (aux_info_filename) == -1)
2209117395Skan		  {
221050397Sobrien		    int errno_val = errno;
2211169689Skan	            notice ("%s: can't delete file '%s': %s\n",
221252284Sobrien			    pname, shortpath (NULL, aux_info_filename),
221352284Sobrien			    xstrerror (errno_val));
2214117395Skan	            return;
2215117395Skan	          }
221618334Speter		must_create = 1;
2217117395Skan	        goto start_over;
2218117395Skan	      }
2219117395Skan
2220117395Skan	    /* Skip over the rest of this line to start of next line.  */
2221117395Skan
2222117395Skan	    while (*aux_info_p != '\n')
2223117395Skan	      aux_info_p++;
2224117395Skan	    aux_info_p++;
2225117395Skan	    current_aux_info_lineno++;
2226117395Skan	  }
222718334Speter      }
222818334Speter
222918334Speter    /* Now do the real pass on the aux_info lines.  Save their information in
223018334Speter       the in-core data base.  */
2231117395Skan
223218334Speter    current_aux_info_lineno = 2;
2233117395Skan
223418334Speter    for (aux_info_p = aux_info_second_line; *aux_info_p;)
223518334Speter      {
2236117395Skan	char *unexpanded_line = unexpand_if_needed (aux_info_p);
2237117395Skan
2238117395Skan	if (unexpanded_line)
2239117395Skan	  {
2240117395Skan	    save_def_or_dec (unexpanded_line, is_syscalls);
2241117395Skan	    free (unexpanded_line);
2242117395Skan	  }
2243117395Skan	else
2244117395Skan	  save_def_or_dec (aux_info_p, is_syscalls);
2245117395Skan
2246117395Skan	/* Skip over the rest of this line and get to start of next line.  */
2247117395Skan
2248117395Skan	while (*aux_info_p != '\n')
2249117395Skan	  aux_info_p++;
2250117395Skan	aux_info_p++;
2251117395Skan	current_aux_info_lineno++;
225218334Speter      }
225318334Speter  }
225418334Speter
225518334Speter  free (aux_info_base);
225690075Sobrien  free (aux_info_relocated_name);
225718334Speter}
225818334Speter
225918334Speter#ifndef UNPROTOIZE
226018334Speter
226118334Speter/* Check an individual filename for a .c suffix.  If the filename has this
226218334Speter   suffix, rename the file such that its suffix is changed to .C.  This
226318334Speter   function implements the -C option.  */
226418334Speter
226518334Speterstatic void
2266132718Skanrename_c_file (const hash_table_entry *hp)
226718334Speter{
226818334Speter  const char *filename = hp->symbol;
226918334Speter  int last_char_index = strlen (filename) - 1;
2270132718Skan  char *const new_filename = alloca (strlen (filename)
2271132718Skan				     + strlen (cplus_suffix) + 1);
227218334Speter
227318334Speter  /* Note that we don't care here if the given file was converted or not.  It
227418334Speter     is possible that the given file was *not* converted, simply because there
227518334Speter     was nothing in it which actually required conversion.  Even in this case,
227618334Speter     we want to do the renaming.  Note that we only rename files with the .c
227790075Sobrien     suffix (except for the syscalls file, which is left alone).  */
227818334Speter
227990075Sobrien  if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.'
228090075Sobrien      || IS_SAME_PATH (syscalls_absolute_filename, filename))
228118334Speter    return;
228218334Speter
228318334Speter  strcpy (new_filename, filename);
228490075Sobrien  strcpy (&new_filename[last_char_index], cplus_suffix);
228518334Speter
228690075Sobrien  if (rename (filename, new_filename) == -1)
228718334Speter    {
228850397Sobrien      int errno_val = errno;
2289169689Skan      notice ("%s: warning: can't rename file '%s' to '%s': %s\n",
229052284Sobrien	      pname, shortpath (NULL, filename),
229152284Sobrien	      shortpath (NULL, new_filename), xstrerror (errno_val));
229218334Speter      errors++;
229318334Speter      return;
229418334Speter    }
229518334Speter}
229618334Speter
229718334Speter#endif /* !defined (UNPROTOIZE) */
229818334Speter
229918334Speter/* Take the list of definitions and declarations attached to a particular
230018334Speter   file_info node and reverse the order of the list.  This should get the
230118334Speter   list into an order such that the item with the lowest associated line
230218334Speter   number is nearest the head of the list.  When these lists are originally
230318334Speter   built, they are in the opposite order.  We want to traverse them in
230418334Speter   normal line number order later (i.e. lowest to highest) so reverse the
230518334Speter   order here.  */
230618334Speter
230718334Speterstatic void
2308132718Skanreverse_def_dec_list (const hash_table_entry *hp)
230918334Speter{
231018334Speter  file_info *file_p = hp->fip;
231118334Speter  def_dec_info *prev = NULL;
231290075Sobrien  def_dec_info *current = (def_dec_info *) file_p->defs_decs;
231318334Speter
231418334Speter  if (!current)
231518334Speter    return;        		/* no list to reverse */
231618334Speter
231718334Speter  prev = current;
231890075Sobrien  if (! (current = (def_dec_info *) current->next_in_file))
231918334Speter    return;        		/* can't reverse a single list element */
232018334Speter
232118334Speter  prev->next_in_file = NULL;
232218334Speter
232318334Speter  while (current)
232418334Speter    {
232590075Sobrien      def_dec_info *next = (def_dec_info *) current->next_in_file;
232618334Speter
232718334Speter      current->next_in_file = prev;
232818334Speter      prev = current;
232918334Speter      current = next;
233018334Speter    }
233118334Speter
233218334Speter  file_p->defs_decs = prev;
233318334Speter}
233418334Speter
233518334Speter#ifndef UNPROTOIZE
233618334Speter
233718334Speter/* Find the (only?) extern definition for a particular function name, starting
233818334Speter   from the head of the linked list of entries for the given name.  If we
233918334Speter   cannot find an extern definition for the given function name, issue a
234018334Speter   warning and scrounge around for the next best thing, i.e. an extern
234118334Speter   function declaration with a prototype attached to it.  Note that we only
234218334Speter   allow such substitutions for extern declarations and never for static
234318334Speter   declarations.  That's because the only reason we allow them at all is
234418334Speter   to let un-prototyped function declarations for system-supplied library
234518334Speter   functions get their prototypes from our own extra SYSCALLS.c.X file which
234618334Speter   contains all of the correct prototypes for system functions.  */
234718334Speter
234818334Speterstatic const def_dec_info *
2349132718Skanfind_extern_def (const def_dec_info *head, const def_dec_info *user)
235018334Speter{
235118334Speter  const def_dec_info *dd_p;
235218334Speter  const def_dec_info *extern_def_p = NULL;
235318334Speter  int conflict_noted = 0;
235418334Speter
235518334Speter  /* Don't act too stupid here.  Somebody may try to convert an entire system
235618334Speter     in one swell fwoop (rather than one program at a time, as should be done)
235718334Speter     and in that case, we may find that there are multiple extern definitions
235818334Speter     of a given function name in the entire set of source files that we are
235918334Speter     converting.  If however one of these definitions resides in exactly the
236018334Speter     same source file as the reference we are trying to satisfy then in that
236118334Speter     case it would be stupid for us to fail to realize that this one definition
236218334Speter     *must* be the precise one we are looking for.
236318334Speter
236418334Speter     To make sure that we don't miss an opportunity to make this "same file"
236518334Speter     leap of faith, we do a prescan of the list of records relating to the
236618334Speter     given function name, and we look (on this first scan) *only* for a
236718334Speter     definition of the function which is in the same file as the reference
236818334Speter     we are currently trying to satisfy.  */
236918334Speter
237018334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
237118334Speter    if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
237218334Speter      return dd_p;
237318334Speter
237418334Speter  /* Now, since we have not found a definition in the same file as the
237518334Speter     reference, we scan the list again and consider all possibilities from
237618334Speter     all files.  Here we may get conflicts with the things listed in the
237718334Speter     SYSCALLS.c.X file, but if that happens it only means that the source
237818334Speter     code being converted contains its own definition of a function which
237918334Speter     could have been supplied by libc.a.  In such cases, we should avoid
238018334Speter     issuing the normal warning, and defer to the definition given in the
238190075Sobrien     user's own code.  */
238218334Speter
238318334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
238418334Speter    if (dd_p->is_func_def && !dd_p->is_static)
238518334Speter      {
2386117395Skan	if (!extern_def_p)	/* Previous definition? */
2387117395Skan	  extern_def_p = dd_p;	/* Remember the first definition found.  */
2388117395Skan	else
2389117395Skan	  {
2390117395Skan	    /* Ignore definition just found if it came from SYSCALLS.c.X.  */
239118334Speter
2392117395Skan	    if (is_syscalls_file (dd_p->file))
2393117395Skan	      continue;
239418334Speter
2395117395Skan	    /* Quietly replace the definition previously found with the one
2396117395Skan	       just found if the previous one was from SYSCALLS.c.X.  */
239718334Speter
2398117395Skan	    if (is_syscalls_file (extern_def_p->file))
2399117395Skan	      {
2400117395Skan	        extern_def_p = dd_p;
2401117395Skan	        continue;
2402117395Skan	      }
240318334Speter
2404117395Skan	    /* If we get here, then there is a conflict between two function
2405117395Skan	       declarations for the same function, both of which came from the
2406117395Skan	       user's own code.  */
240718334Speter
2408117395Skan	    if (!conflict_noted)	/* first time we noticed? */
2409117395Skan	      {
2410117395Skan		conflict_noted = 1;
2411117395Skan		notice ("%s: conflicting extern definitions of '%s'\n",
241252284Sobrien			pname, head->hash_entry->symbol);
2413117395Skan		if (!quiet_flag)
2414117395Skan		  {
2415117395Skan		    notice ("%s: declarations of '%s' will not be converted\n",
241652284Sobrien			    pname, head->hash_entry->symbol);
2417117395Skan		    notice ("%s: conflict list for '%s' follows:\n",
241852284Sobrien			    pname, head->hash_entry->symbol);
2419117395Skan		    fprintf (stderr, "%s:     %s(%d): %s\n",
242018334Speter			     pname,
242118334Speter			     shortpath (NULL, extern_def_p->file->hash_entry->symbol),
242218334Speter			     extern_def_p->line, extern_def_p->ansi_decl);
2423117395Skan		  }
2424117395Skan	      }
2425117395Skan	    if (!quiet_flag)
2426117395Skan	      fprintf (stderr, "%s:     %s(%d): %s\n",
242718334Speter		       pname,
242818334Speter		       shortpath (NULL, dd_p->file->hash_entry->symbol),
242918334Speter		       dd_p->line, dd_p->ansi_decl);
2430117395Skan	  }
243118334Speter      }
243218334Speter
243318334Speter  /* We want to err on the side of caution, so if we found multiple conflicting
243418334Speter     definitions for the same function, treat this as being that same as if we
243518334Speter     had found no definitions (i.e. return NULL).  */
243618334Speter
243718334Speter  if (conflict_noted)
243818334Speter    return NULL;
243918334Speter
244018334Speter  if (!extern_def_p)
244118334Speter    {
244218334Speter      /* We have no definitions for this function so do the next best thing.
2443117395Skan	 Search for an extern declaration already in prototype form.  */
244418334Speter
244518334Speter      for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2446117395Skan	if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2447117395Skan	  {
2448117395Skan	    extern_def_p = dd_p;	/* save a pointer to the definition */
2449117395Skan	    if (!quiet_flag)
2450169689Skan	      notice ("%s: warning: using formals list from %s(%d) for function '%s'\n",
245152284Sobrien		      pname,
245252284Sobrien		      shortpath (NULL, dd_p->file->hash_entry->symbol),
245352284Sobrien		      dd_p->line, dd_p->hash_entry->symbol);
2454117395Skan	    break;
2455117395Skan	  }
245618334Speter
245718334Speter      /* Gripe about unprototyped function declarations that we found no
2458117395Skan	 corresponding definition (or other source of prototype information)
2459117395Skan	 for.
246018334Speter
2461117395Skan	 Gripe even if the unprototyped declaration we are worried about
2462117395Skan	 exists in a file in one of the "system" include directories.  We
2463117395Skan	 can gripe about these because we should have at least found a
2464117395Skan	 corresponding (pseudo) definition in the SYSCALLS.c.X file.  If we
246518334Speter	 didn't, then that means that the SYSCALLS.c.X file is missing some
2466117395Skan	 needed prototypes for this particular system.  That is worth telling
2467117395Skan	 the user about!  */
246818334Speter
246918334Speter      if (!extern_def_p)
2470117395Skan	{
2471117395Skan	  const char *file = user->file->hash_entry->symbol;
247218334Speter
2473117395Skan	  if (!quiet_flag)
2474117395Skan	    if (in_system_include_dir (file))
2475117395Skan	      {
247618334Speter		/* Why copy this string into `needed' at all?
247718334Speter		   Why not just use user->ansi_decl without copying?  */
2478132718Skan		char *needed = alloca (strlen (user->ansi_decl) + 1);
2479117395Skan	        char *p;
248018334Speter
2481117395Skan	        strcpy (needed, user->ansi_decl);
2482132718Skan	        p = strstr (needed, user->hash_entry->symbol)
2483117395Skan	            + strlen (user->hash_entry->symbol) + 2;
248418334Speter		/* Avoid having ??? in the string.  */
248518334Speter		*p++ = '?';
248618334Speter		*p++ = '?';
248718334Speter		*p++ = '?';
2488117395Skan	        strcpy (p, ");");
248918334Speter
2490169689Skan	        notice ("%s: %d: '%s' used but missing from SYSCALLS\n",
249152284Sobrien			shortpath (NULL, file), user->line,
249252284Sobrien			needed+7);	/* Don't print "extern " */
2493117395Skan	      }
249418334Speter#if 0
2495117395Skan	    else
2496169689Skan	      notice ("%s: %d: warning: no extern definition for '%s'\n",
249752284Sobrien		      shortpath (NULL, file), user->line,
249852284Sobrien		      user->hash_entry->symbol);
249918334Speter#endif
2500117395Skan	}
250118334Speter    }
250218334Speter  return extern_def_p;
250318334Speter}
250418334Speter
250518334Speter/* Find the (only?) static definition for a particular function name in a
250618334Speter   given file.  Here we get the function-name and the file info indirectly
250750397Sobrien   from the def_dec_info record pointer which is passed in.  */
250818334Speter
250918334Speterstatic const def_dec_info *
2510132718Skanfind_static_definition (const def_dec_info *user)
251118334Speter{
251218334Speter  const def_dec_info *head = user->hash_entry->ddip;
251318334Speter  const def_dec_info *dd_p;
251418334Speter  int num_static_defs = 0;
251518334Speter  const def_dec_info *static_def_p = NULL;
251618334Speter
251718334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
251818334Speter    if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
251918334Speter      {
2520117395Skan	static_def_p = dd_p;	/* save a pointer to the definition */
2521117395Skan	num_static_defs++;
252218334Speter      }
252318334Speter  if (num_static_defs == 0)
252418334Speter    {
252518334Speter      if (!quiet_flag)
2526169689Skan	notice ("%s: warning: no static definition for '%s' in file '%s'\n",
252752284Sobrien		pname, head->hash_entry->symbol,
252852284Sobrien		shortpath (NULL, user->file->hash_entry->symbol));
252918334Speter    }
253018334Speter  else if (num_static_defs > 1)
253118334Speter    {
2532169689Skan      notice ("%s: multiple static defs of '%s' in file '%s'\n",
253352284Sobrien	      pname, head->hash_entry->symbol,
253452284Sobrien	      shortpath (NULL, user->file->hash_entry->symbol));
253518334Speter      return NULL;
253618334Speter    }
253718334Speter  return static_def_p;
253818334Speter}
253918334Speter
254018334Speter/* Find good prototype style formal argument lists for all of the function
254118334Speter   declarations which didn't have them before now.
254218334Speter
254318334Speter   To do this we consider each function name one at a time.  For each function
254418334Speter   name, we look at the items on the linked list of def_dec_info records for
254518334Speter   that particular name.
254618334Speter
254718334Speter   Somewhere on this list we should find one (and only one) def_dec_info
254818334Speter   record which represents the actual function definition, and this record
254918334Speter   should have a nice formal argument list already associated with it.
255018334Speter
255118334Speter   Thus, all we have to do is to connect up all of the other def_dec_info
255218334Speter   records for this particular function name to the special one which has
255318334Speter   the full-blown formals list.
255418334Speter
255518334Speter   Of course it is a little more complicated than just that.  See below for
255618334Speter   more details.  */
255718334Speter
255818334Speterstatic void
2559132718Skanconnect_defs_and_decs (const hash_table_entry *hp)
256018334Speter{
256118334Speter  const def_dec_info *dd_p;
256218334Speter  const def_dec_info *extern_def_p = NULL;
256318334Speter  int first_extern_reference = 1;
256418334Speter
256518334Speter  /* Traverse the list of definitions and declarations for this particular
256618334Speter     function name.  For each item on the list, if it is a function
256718334Speter     definition (either old style or new style) then GCC has already been
256818334Speter     kind enough to produce a prototype for us, and it is associated with
256918334Speter     the item already, so declare the item as its own associated "definition".
257018334Speter
257118334Speter     Also, for each item which is only a function declaration, but which
257218334Speter     nonetheless has its own prototype already (obviously supplied by the user)
257350397Sobrien     declare the item as its own definition.
257418334Speter
257518334Speter     Note that when/if there are multiple user-supplied prototypes already
257618334Speter     present for multiple declarations of any given function, these multiple
257718334Speter     prototypes *should* all match exactly with one another and with the
257818334Speter     prototype for the actual function definition.  We don't check for this
257918334Speter     here however, since we assume that the compiler must have already done
258018334Speter     this consistency checking when it was creating the .X files.  */
258118334Speter
258218334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
258318334Speter    if (dd_p->prototyped)
258418334Speter      ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
258518334Speter
258618334Speter  /* Traverse the list of definitions and declarations for this particular
258718334Speter     function name.  For each item on the list, if it is an extern function
258818334Speter     declaration and if it has no associated definition yet, go try to find
258918334Speter     the matching extern definition for the declaration.
259018334Speter
259118334Speter     When looking for the matching function definition, warn the user if we
259218334Speter     fail to find one.
259318334Speter
259418334Speter     If we find more that one function definition also issue a warning.
259518334Speter
259618334Speter     Do the search for the matching definition only once per unique function
259718334Speter     name (and only when absolutely needed) so that we can avoid putting out
259818334Speter     redundant warning messages, and so that we will only put out warning
259918334Speter     messages when there is actually a reference (i.e. a declaration) for
260018334Speter     which we need to find a matching definition.  */
260118334Speter
260218334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
260318334Speter    if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
260418334Speter      {
2605117395Skan	if (first_extern_reference)
2606117395Skan	  {
2607117395Skan	    extern_def_p = find_extern_def (hp->ddip, dd_p);
2608117395Skan	    first_extern_reference = 0;
2609117395Skan	  }
2610117395Skan	((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
261118334Speter      }
261218334Speter
261318334Speter  /* Traverse the list of definitions and declarations for this particular
261418334Speter     function name.  For each item on the list, if it is a static function
261518334Speter     declaration and if it has no associated definition yet, go try to find
261618334Speter     the matching static definition for the declaration within the same file.
261718334Speter
261818334Speter     When looking for the matching function definition, warn the user if we
261918334Speter     fail to find one in the same file with the declaration, and refuse to
262018334Speter     convert this kind of cross-file static function declaration.  After all,
262118334Speter     this is stupid practice and should be discouraged.
262218334Speter
262318334Speter     We don't have to worry about the possibility that there is more than one
262418334Speter     matching function definition in the given file because that would have
262518334Speter     been flagged as an error by the compiler.
262618334Speter
262718334Speter     Do the search for the matching definition only once per unique
262818334Speter     function-name/source-file pair (and only when absolutely needed) so that
262918334Speter     we can avoid putting out redundant warning messages, and so that we will
263018334Speter     only put out warning messages when there is actually a reference (i.e. a
263118334Speter     declaration) for which we actually need to find a matching definition.  */
263218334Speter
263318334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
263418334Speter    if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
263518334Speter      {
2636117395Skan	const def_dec_info *dd_p2;
2637117395Skan	const def_dec_info *static_def;
263818334Speter
2639117395Skan	/* We have now found a single static declaration for which we need to
2640117395Skan	   find a matching definition.  We want to minimize the work (and the
2641117395Skan	   number of warnings), so we will find an appropriate (matching)
2642117395Skan	   static definition for this declaration, and then distribute it
2643117395Skan	   (as the definition for) any and all other static declarations
2644117395Skan	   for this function name which occur within the same file, and which
2645117395Skan	   do not already have definitions.
264618334Speter
2647117395Skan	   Note that a trick is used here to prevent subsequent attempts to
2648117395Skan	   call find_static_definition for a given function-name & file
2649117395Skan	   if the first such call returns NULL.  Essentially, we convert
2650117395Skan	   these NULL return values to -1, and put the -1 into the definition
2651117395Skan	   field for each other static declaration from the same file which
2652117395Skan	   does not already have an associated definition.
2653117395Skan	   This makes these other static declarations look like they are
2654117395Skan	   actually defined already when the outer loop here revisits them
2655117395Skan	   later on.  Thus, the outer loop will skip over them.  Later, we
2656117395Skan	   turn the -1's back to NULL's.  */
265718334Speter
2658117395Skan	((NONCONST def_dec_info *) dd_p)->definition =
2659117395Skan	  (static_def = find_static_definition (dd_p))
2660117395Skan	  ? static_def
2661117395Skan	  : (const def_dec_info *) -1;
266218334Speter
2663117395Skan	for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2664117395Skan	  if (!dd_p2->is_func_def && dd_p2->is_static
2665117395Skan	      && !dd_p2->definition && (dd_p2->file == dd_p->file))
2666117395Skan	    ((NONCONST def_dec_info *) dd_p2)->definition = dd_p->definition;
266718334Speter      }
266818334Speter
266918334Speter  /* Convert any dummy (-1) definitions we created in the step above back to
267018334Speter     NULL's (as they should be).  */
267118334Speter
267218334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
267318334Speter    if (dd_p->definition == (def_dec_info *) -1)
267418334Speter      ((NONCONST def_dec_info *) dd_p)->definition = NULL;
267518334Speter}
267618334Speter
267718334Speter#endif /* !defined (UNPROTOIZE) */
267818334Speter
267918334Speter/* Give a pointer into the clean text buffer, return a number which is the
268018334Speter   original source line number that the given pointer points into.  */
268118334Speter
268218334Speterstatic int
2683132718Skanidentify_lineno (const char *clean_p)
268418334Speter{
268518334Speter  int line_num = 1;
268618334Speter  const char *scan_p;
268718334Speter
268818334Speter  for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
268918334Speter    if (*scan_p == '\n')
269018334Speter      line_num++;
269118334Speter  return line_num;
269218334Speter}
269318334Speter
269418334Speter/* Issue an error message and give up on doing this particular edit.  */
269518334Speter
269618334Speterstatic void
2697132718Skandeclare_source_confusing (const char *clean_p)
269818334Speter{
269918334Speter  if (!quiet_flag)
270018334Speter    {
270118334Speter      if (clean_p == 0)
2702117395Skan	notice ("%s: %d: warning: source too confusing\n",
270352284Sobrien		shortpath (NULL, convert_filename), last_known_line_number);
270418334Speter      else
2705117395Skan	notice ("%s: %d: warning: source too confusing\n",
270652284Sobrien		shortpath (NULL, convert_filename),
270752284Sobrien		identify_lineno (clean_p));
270818334Speter    }
270918334Speter  longjmp (source_confusion_recovery, 1);
271018334Speter}
271118334Speter
271218334Speter/* Check that a condition which is expected to be true in the original source
271318334Speter   code is in fact true.  If not, issue an error message and give up on
271418334Speter   converting this particular source file.  */
271518334Speter
271618334Speterstatic void
2717132718Skancheck_source (int cond, const char *clean_p)
271818334Speter{
271918334Speter  if (!cond)
272018334Speter    declare_source_confusing (clean_p);
272118334Speter}
272218334Speter
272318334Speter/* If we think of the in-core cleaned text buffer as a memory mapped
272418334Speter   file (with the variable last_known_line_start acting as sort of a
272518334Speter   file pointer) then we can imagine doing "seeks" on the buffer.  The
272618334Speter   following routine implements a kind of "seek" operation for the in-core
272718334Speter   (cleaned) copy of the source file.  When finished, it returns a pointer to
272818334Speter   the start of a given (numbered) line in the cleaned text buffer.
272918334Speter
273018334Speter   Note that protoize only has to "seek" in the forward direction on the
273118334Speter   in-core cleaned text file buffers, and it never needs to back up.
273218334Speter
273318334Speter   This routine is made a little bit faster by remembering the line number
273418334Speter   (and pointer value) supplied (and returned) from the previous "seek".
273518334Speter   This prevents us from always having to start all over back at the top
273618334Speter   of the in-core cleaned buffer again.  */
273718334Speter
273818334Speterstatic const char *
2739132718Skanseek_to_line (int n)
274018334Speter{
2741169689Skan  gcc_assert (n >= last_known_line_number);
274218334Speter
274318334Speter  while (n > last_known_line_number)
274418334Speter    {
274518334Speter      while (*last_known_line_start != '\n')
2746117395Skan	check_source (++last_known_line_start < clean_text_limit, 0);
274718334Speter      last_known_line_start++;
274818334Speter      last_known_line_number++;
274918334Speter    }
275018334Speter  return last_known_line_start;
275118334Speter}
275218334Speter
275318334Speter/* Given a pointer to a character in the cleaned text buffer, return a pointer
275418334Speter   to the next non-whitespace character which follows it.  */
275518334Speter
275618334Speterstatic const char *
2757132718Skanforward_to_next_token_char (const char *ptr)
275818334Speter{
275952284Sobrien  for (++ptr; ISSPACE ((const unsigned char)*ptr);
276052284Sobrien       check_source (++ptr < clean_text_limit, 0))
276118334Speter    continue;
276218334Speter  return ptr;
276318334Speter}
276418334Speter
276518334Speter/* Copy a chunk of text of length `len' and starting at `str' to the current
276618334Speter   output buffer.  Note that all attempts to add stuff to the current output
276718334Speter   buffer ultimately go through here.  */
276818334Speter
276918334Speterstatic void
2770132718Skanoutput_bytes (const char *str, size_t len)
277118334Speter{
277218334Speter  if ((repl_write_ptr + 1) + len >= repl_text_limit)
277318334Speter    {
277418334Speter      size_t new_size = (repl_text_limit - repl_text_base) << 1;
2775132718Skan      char *new_buf = xrealloc (repl_text_base, new_size);
277618334Speter
277718334Speter      repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
277818334Speter      repl_text_base = new_buf;
277918334Speter      repl_text_limit = new_buf + new_size;
278018334Speter    }
278118334Speter  memcpy (repl_write_ptr + 1, str, len);
278218334Speter  repl_write_ptr += len;
278318334Speter}
278418334Speter
278518334Speter/* Copy all bytes (except the trailing null) of a null terminated string to
278618334Speter   the current output buffer.  */
278718334Speter
278818334Speterstatic void
2789132718Skanoutput_string (const char *str)
279018334Speter{
279118334Speter  output_bytes (str, strlen (str));
279218334Speter}
279318334Speter
279418334Speter/* Copy some characters from the original text buffer to the current output
279518334Speter   buffer.
279618334Speter
279718334Speter   This routine takes a pointer argument `p' which is assumed to be a pointer
279818334Speter   into the cleaned text buffer.  The bytes which are copied are the `original'
279918334Speter   equivalents for the set of bytes between the last value of `clean_read_ptr'
280018334Speter   and the argument value `p'.
280118334Speter
280218334Speter   The set of bytes copied however, comes *not* from the cleaned text buffer,
280318334Speter   but rather from the direct counterparts of these bytes within the original
280418334Speter   text buffer.
280518334Speter
280618334Speter   Thus, when this function is called, some bytes from the original text
280718334Speter   buffer (which may include original comments and preprocessing directives)
280818334Speter   will be copied into the  output buffer.
280918334Speter
281018334Speter   Note that the request implied when this routine is called includes the
281118334Speter   byte pointed to by the argument pointer `p'.  */
281218334Speter
281318334Speterstatic void
2814132718Skanoutput_up_to (const char *p)
281518334Speter{
281618334Speter  size_t copy_length = (size_t) (p - clean_read_ptr);
281718334Speter  const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
281818334Speter
281918334Speter  if (copy_length == 0)
282018334Speter    return;
282118334Speter
282218334Speter  output_bytes (copy_start, copy_length);
282318334Speter  clean_read_ptr = p;
282418334Speter}
282518334Speter
282618334Speter/* Given a pointer to a def_dec_info record which represents some form of
282718334Speter   definition of a function (perhaps a real definition, or in lieu of that
282818334Speter   perhaps just a declaration with a full prototype) return true if this
282918334Speter   function is one which we should avoid converting.  Return false
283018334Speter   otherwise.  */
283118334Speter
283218334Speterstatic int
2833132718Skanother_variable_style_function (const char *ansi_header)
283418334Speter{
283518334Speter#ifdef UNPROTOIZE
283618334Speter
283718334Speter  /* See if we have a stdarg function, or a function which has stdarg style
283818334Speter     parameters or a stdarg style return type.  */
283918334Speter
2840132718Skan  return strstr (ansi_header, "...") != 0;
284118334Speter
284218334Speter#else /* !defined (UNPROTOIZE) */
284318334Speter
284418334Speter  /* See if we have a varargs function, or a function which has varargs style
284518334Speter     parameters or a varargs style return type.  */
284618334Speter
284718334Speter  const char *p;
284818334Speter  int len = strlen (varargs_style_indicator);
284918334Speter
285018334Speter  for (p = ansi_header; p; )
285118334Speter    {
285218334Speter      const char *candidate;
285318334Speter
2854132718Skan      if ((candidate = strstr (p, varargs_style_indicator)) == 0)
2855117395Skan	return 0;
285618334Speter      else
2857117395Skan	if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
2858117395Skan	  return 1;
2859117395Skan	else
2860117395Skan	  p = candidate + 1;
286118334Speter    }
286218334Speter  return 0;
286318334Speter#endif /* !defined (UNPROTOIZE) */
286418334Speter}
286518334Speter
286618334Speter/* Do the editing operation specifically for a function "declaration".  Note
286718334Speter   that editing for function "definitions" are handled in a separate routine
286818334Speter   below.  */
286918334Speter
287018334Speterstatic void
2871132718Skanedit_fn_declaration (const def_dec_info *def_dec_p,
2872132718Skan		     const char *volatile clean_text_p)
287318334Speter{
287418334Speter  const char *start_formals;
287518334Speter  const char *end_formals;
287618334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
287718334Speter  size_t func_name_len = strlen (function_to_edit);
287818334Speter  const char *end_of_fn_name;
287918334Speter
288018334Speter#ifndef UNPROTOIZE
288118334Speter
288218334Speter  const f_list_chain_item *this_f_list_chain_item;
288318334Speter  const def_dec_info *definition = def_dec_p->definition;
288418334Speter
288518334Speter  /* If we are protoizing, and if we found no corresponding definition for
288618334Speter     this particular function declaration, then just leave this declaration
288718334Speter     exactly as it is.  */
288818334Speter
288918334Speter  if (!definition)
289018334Speter    return;
289118334Speter
289218334Speter  /* If we are protoizing, and if the corresponding definition that we found
289318334Speter     for this particular function declaration defined an old style varargs
289418334Speter     function, then we want to issue a warning and just leave this function
289518334Speter     declaration unconverted.  */
289618334Speter
289718334Speter  if (other_variable_style_function (definition->ansi_decl))
289818334Speter    {
289918334Speter      if (!quiet_flag)
2900117395Skan	notice ("%s: %d: warning: varargs function declaration not converted\n",
290152284Sobrien		shortpath (NULL, def_dec_p->file->hash_entry->symbol),
290252284Sobrien		def_dec_p->line);
290318334Speter      return;
290418334Speter    }
290518334Speter
290618334Speter#endif /* !defined (UNPROTOIZE) */
290718334Speter
290818334Speter  /* Setup here to recover from confusing source code detected during this
290918334Speter     particular "edit".  */
291018334Speter
291118334Speter  save_pointers ();
291218334Speter  if (setjmp (source_confusion_recovery))
291318334Speter    {
291418334Speter      restore_pointers ();
2915169689Skan      notice ("%s: declaration of function '%s' not converted\n",
291652284Sobrien	      pname, function_to_edit);
291718334Speter      return;
291818334Speter    }
291918334Speter
292018334Speter  /* We are editing a function declaration.  The line number we did a seek to
292118334Speter     contains the comma or semicolon which follows the declaration.  Our job
292218334Speter     now is to scan backwards looking for the function name.  This name *must*
292318334Speter     be followed by open paren (ignoring whitespace, of course).  We need to
292418334Speter     replace everything between that open paren and the corresponding closing
292518334Speter     paren.  If we are protoizing, we need to insert the prototype-style
292618334Speter     formals lists.  If we are unprotoizing, we need to just delete everything
292718334Speter     between the pairs of opening and closing parens.  */
292818334Speter
292918334Speter  /* First move up to the end of the line.  */
293018334Speter
293118334Speter  while (*clean_text_p != '\n')
293218334Speter    check_source (++clean_text_p < clean_text_limit, 0);
293318334Speter  clean_text_p--;  /* Point to just before the newline character.  */
293418334Speter
293518334Speter  /* Now we can scan backwards for the function name.  */
293618334Speter
293718334Speter  do
293818334Speter    {
293918334Speter      for (;;)
2940117395Skan	{
2941117395Skan	  /* Scan leftwards until we find some character which can be
2942117395Skan	     part of an identifier.  */
294318334Speter
2944117395Skan	  while (!is_id_char (*clean_text_p))
2945117395Skan	    check_source (--clean_text_p > clean_read_ptr, 0);
294618334Speter
2947117395Skan	  /* Scan backwards until we find a char that cannot be part of an
2948117395Skan	     identifier.  */
294918334Speter
2950117395Skan	  while (is_id_char (*clean_text_p))
2951117395Skan	    check_source (--clean_text_p > clean_read_ptr, 0);
295218334Speter
2953117395Skan	  /* Having found an "id break", see if the following id is the one
2954117395Skan	     that we are looking for.  If so, then exit from this loop.  */
295518334Speter
2956117395Skan	  if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
2957117395Skan	    {
2958117395Skan	      char ch = *(clean_text_p + 1 + func_name_len);
295918334Speter
2960117395Skan	      /* Must also check to see that the name in the source text
2961117395Skan	         ends where it should (in order to prevent bogus matches
2962117395Skan	         on similar but longer identifiers.  */
296318334Speter
2964117395Skan	      if (! is_id_char (ch))
2965117395Skan	        break;			/* exit from loop */
2966117395Skan	    }
2967117395Skan	}
2968117395Skan
296918334Speter      /* We have now found the first perfect match for the function name in
2970117395Skan	 our backward search.  This may or may not be the actual function
2971117395Skan	 name at the start of the actual function declaration (i.e. we could
2972117395Skan	 have easily been mislead).  We will try to avoid getting fooled too
2973117395Skan	 often by looking forward for the open paren which should follow the
2974117395Skan	 identifier we just found.  We ignore whitespace while hunting.  If
2975117395Skan	 the next non-whitespace byte we see is *not* an open left paren,
2976117395Skan	 then we must assume that we have been fooled and we start over
2977117395Skan	 again accordingly.  Note that there is no guarantee, that even if
2978117395Skan	 we do see the open paren, that we are in the right place.
2979117395Skan	 Programmers do the strangest things sometimes!  */
2980117395Skan
298118334Speter      end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
298218334Speter      start_formals = forward_to_next_token_char (end_of_fn_name);
298318334Speter    }
298418334Speter  while (*start_formals != '(');
298518334Speter
298618334Speter  /* start_of_formals now points to the opening left paren which immediately
298718334Speter     follows the name of the function.  */
298818334Speter
298918334Speter  /* Note that there may be several formals lists which need to be modified
299018334Speter     due to the possibility that the return type of this function is a
299118334Speter     pointer-to-function type.  If there are several formals lists, we
299218334Speter     convert them in left-to-right order here.  */
299318334Speter
299418334Speter#ifndef UNPROTOIZE
299518334Speter  this_f_list_chain_item = definition->f_list_chain;
299618334Speter#endif /* !defined (UNPROTOIZE) */
299718334Speter
299818334Speter  for (;;)
299918334Speter    {
300018334Speter      {
3001117395Skan	int depth;
300218334Speter
3003117395Skan	end_formals = start_formals + 1;
3004117395Skan	depth = 1;
3005117395Skan	for (; depth; check_source (++end_formals < clean_text_limit, 0))
3006117395Skan	  {
3007117395Skan	    switch (*end_formals)
3008117395Skan	      {
3009117395Skan	      case '(':
3010117395Skan		depth++;
3011117395Skan		break;
3012117395Skan	      case ')':
3013117395Skan		depth--;
3014117395Skan		break;
3015117395Skan	      }
3016117395Skan	  }
3017117395Skan	end_formals--;
301818334Speter      }
301918334Speter
302018334Speter      /* end_formals now points to the closing right paren of the formals
3021117395Skan	 list whose left paren is pointed to by start_formals.  */
3022117395Skan
302318334Speter      /* Now, if we are protoizing, we insert the new ANSI-style formals list
3024117395Skan	 attached to the associated definition of this function.  If however
3025117395Skan	 we are unprotoizing, then we simply delete any formals list which
3026117395Skan	 may be present.  */
3027117395Skan
302818334Speter      output_up_to (start_formals);
302918334Speter#ifndef UNPROTOIZE
303018334Speter      if (this_f_list_chain_item)
3031117395Skan	{
3032117395Skan	  output_string (this_f_list_chain_item->formals_list);
3033117395Skan	  this_f_list_chain_item = this_f_list_chain_item->chain_next;
3034117395Skan	}
303518334Speter      else
3036117395Skan	{
3037117395Skan	  if (!quiet_flag)
3038169689Skan	    notice ("%s: warning: too many parameter lists in declaration of '%s'\n",
303952284Sobrien		    pname, def_dec_p->hash_entry->symbol);
3040117395Skan	  check_source (0, end_formals);  /* leave the declaration intact */
3041117395Skan	}
304218334Speter#endif /* !defined (UNPROTOIZE) */
304318334Speter      clean_read_ptr = end_formals - 1;
304418334Speter
304518334Speter      /* Now see if it looks like there may be another formals list associated
3046117395Skan	 with the function declaration that we are converting (following the
3047117395Skan	 formals list that we just converted.  */
304818334Speter
304918334Speter      {
3050117395Skan	const char *another_r_paren = forward_to_next_token_char (end_formals);
305118334Speter
3052117395Skan	if ((*another_r_paren != ')')
3053117395Skan	    || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3054117395Skan	  {
305518334Speter#ifndef UNPROTOIZE
3056117395Skan	    if (this_f_list_chain_item)
3057117395Skan	      {
3058117395Skan		if (!quiet_flag)
3059169689Skan		  notice ("\n%s: warning: too few parameter lists in declaration of '%s'\n",
306052284Sobrien			  pname, def_dec_p->hash_entry->symbol);
3061117395Skan		check_source (0, start_formals); /* leave the decl intact */
3062117395Skan	      }
306318334Speter#endif /* !defined (UNPROTOIZE) */
3064117395Skan	    break;
3065117395Skan
3066117395Skan	  }
306718334Speter      }
306818334Speter
306918334Speter      /* There does appear to be yet another formals list, so loop around
3070117395Skan	 again, and convert it also.  */
307118334Speter    }
307218334Speter}
307318334Speter
307418334Speter/* Edit a whole group of formals lists, starting with the rightmost one
307518334Speter   from some set of formals lists.  This routine is called once (from the
307618334Speter   outside) for each function declaration which is converted.  It is
307718334Speter   recursive however, and it calls itself once for each remaining formal
307818334Speter   list that lies to the left of the one it was originally called to work
307918334Speter   on.  Thus, a whole set gets done in right-to-left order.
308018334Speter
3081117395Skan   This routine returns nonzero if it thinks that it should not be trying
308218334Speter   to convert this particular function definition (because the name of the
308318334Speter   function doesn't match the one expected).  */
308418334Speter
308518334Speterstatic int
3086132718Skanedit_formals_lists (const char *end_formals, unsigned int f_list_count,
3087132718Skan		    const def_dec_info *def_dec_p)
308818334Speter{
308918334Speter  const char *start_formals;
309018334Speter  int depth;
309118334Speter
309218334Speter  start_formals = end_formals - 1;
309318334Speter  depth = 1;
309418334Speter  for (; depth; check_source (--start_formals > clean_read_ptr, 0))
309518334Speter    {
309618334Speter      switch (*start_formals)
3097117395Skan	{
3098117395Skan	case '(':
3099117395Skan	  depth--;
3100117395Skan	  break;
3101117395Skan	case ')':
3102117395Skan	  depth++;
3103117395Skan	  break;
3104117395Skan	}
310518334Speter    }
310618334Speter  start_formals++;
310718334Speter
310818334Speter  /* start_formals now points to the opening left paren of the formals list.  */
310918334Speter
311018334Speter  f_list_count--;
311118334Speter
311218334Speter  if (f_list_count)
311318334Speter    {
311418334Speter      const char *next_end;
311518334Speter
311618334Speter      /* There should be more formal lists to the left of here.  */
311718334Speter
311818334Speter      next_end = start_formals - 1;
311918334Speter      check_source (next_end > clean_read_ptr, 0);
312052284Sobrien      while (ISSPACE ((const unsigned char)*next_end))
3121117395Skan	check_source (--next_end > clean_read_ptr, 0);
312218334Speter      check_source (*next_end == ')', next_end);
312318334Speter      check_source (--next_end > clean_read_ptr, 0);
312418334Speter      check_source (*next_end == ')', next_end);
312518334Speter      if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3126117395Skan	return 1;
312718334Speter    }
312818334Speter
312918334Speter  /* Check that the function name in the header we are working on is the same
313018334Speter     as the one we would expect to find.  If not, issue a warning and return
3131117395Skan     nonzero.  */
313218334Speter
313318334Speter  if (f_list_count == 0)
313418334Speter    {
313518334Speter      const char *expected = def_dec_p->hash_entry->symbol;
313618334Speter      const char *func_name_start;
313718334Speter      const char *func_name_limit;
313818334Speter      size_t func_name_len;
313918334Speter
314052284Sobrien      for (func_name_limit = start_formals-1;
314152284Sobrien	   ISSPACE ((const unsigned char)*func_name_limit); )
3142117395Skan	check_source (--func_name_limit > clean_read_ptr, 0);
314318334Speter
314418334Speter      for (func_name_start = func_name_limit++;
3145117395Skan	   is_id_char (*func_name_start);
3146117395Skan	   func_name_start--)
3147117395Skan	check_source (func_name_start > clean_read_ptr, 0);
314818334Speter      func_name_start++;
314918334Speter      func_name_len = func_name_limit - func_name_start;
315018334Speter      if (func_name_len == 0)
3151117395Skan	check_source (0, func_name_start);
315218334Speter      if (func_name_len != strlen (expected)
315318334Speter	  || strncmp (func_name_start, expected, func_name_len))
3154117395Skan	{
3155169689Skan	  notice ("%s: %d: warning: found '%s' but expected '%s'\n",
315652284Sobrien		  shortpath (NULL, def_dec_p->file->hash_entry->symbol),
315752284Sobrien		  identify_lineno (func_name_start),
315852284Sobrien		  dupnstr (func_name_start, func_name_len),
315952284Sobrien		  expected);
3160117395Skan	  return 1;
3161117395Skan	}
316218334Speter    }
316318334Speter
316418334Speter  output_up_to (start_formals);
316518334Speter
316618334Speter#ifdef UNPROTOIZE
316718334Speter  if (f_list_count == 0)
316818334Speter    output_string (def_dec_p->formal_names);
316918334Speter#else /* !defined (UNPROTOIZE) */
317018334Speter  {
317118334Speter    unsigned f_list_depth;
317218334Speter    const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
317318334Speter
317418334Speter    /* At this point, the current value of f_list count says how many
317518334Speter       links we have to follow through the f_list_chain to get to the
317618334Speter       particular formals list that we need to output next.  */
317718334Speter
317818334Speter    for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
317918334Speter      flci_p = flci_p->chain_next;
318018334Speter    output_string (flci_p->formals_list);
318118334Speter  }
318218334Speter#endif /* !defined (UNPROTOIZE) */
318318334Speter
318418334Speter  clean_read_ptr = end_formals - 1;
318518334Speter  return 0;
318618334Speter}
318718334Speter
318850397Sobrien/* Given a pointer to a byte in the clean text buffer which points to
318950397Sobrien   the beginning of a line that contains a "follower" token for a
319050397Sobrien   function definition header, do whatever is necessary to find the
319150397Sobrien   right closing paren for the rightmost formals list of the function
319250397Sobrien   definition header.  */
319318334Speter
319418334Speterstatic const char *
3195132718Skanfind_rightmost_formals_list (const char *clean_text_p)
319618334Speter{
319718334Speter  const char *end_formals;
319818334Speter
319918334Speter  /* We are editing a function definition.  The line number we did a seek
320018334Speter     to contains the first token which immediately follows the entire set of
320118334Speter     formals lists which are part of this particular function definition
320218334Speter     header.
320318334Speter
320418334Speter     Our job now is to scan leftwards in the clean text looking for the
320518334Speter     right-paren which is at the end of the function header's rightmost
320618334Speter     formals list.
320718334Speter
320818334Speter     If we ignore whitespace, this right paren should be the first one we
320918334Speter     see which is (ignoring whitespace) immediately followed either by the
321018334Speter     open curly-brace beginning the function body or by an alphabetic
321118334Speter     character (in the case where the function definition is in old (K&R)
321218334Speter     style and there are some declarations of formal parameters).  */
321318334Speter
321418334Speter   /* It is possible that the right paren we are looking for is on the
321518334Speter      current line (together with its following token).  Just in case that
321618334Speter      might be true, we start out here by skipping down to the right end of
321718334Speter      the current line before starting our scan.  */
321818334Speter
321918334Speter  for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
322018334Speter    continue;
322118334Speter  end_formals--;
322218334Speter
322318334Speter#ifdef UNPROTOIZE
322418334Speter
322518334Speter  /* Now scan backwards while looking for the right end of the rightmost
322618334Speter     formals list associated with this function definition.  */
322718334Speter
322818334Speter  {
322918334Speter    char ch;
323018334Speter    const char *l_brace_p;
323118334Speter
323218334Speter    /* Look leftward and try to find a right-paren.  */
323318334Speter
323418334Speter    while (*end_formals != ')')
323518334Speter      {
323652284Sobrien	if (ISSPACE ((unsigned char)*end_formals))
323752284Sobrien	  while (ISSPACE ((unsigned char)*end_formals))
323818334Speter	    check_source (--end_formals > clean_read_ptr, 0);
323918334Speter	else
324018334Speter	  check_source (--end_formals > clean_read_ptr, 0);
324118334Speter      }
324218334Speter
324318334Speter    ch = *(l_brace_p = forward_to_next_token_char (end_formals));
324418334Speter    /* Since we are unprotoizing an ANSI-style (prototyped) function
324518334Speter       definition, there had better not be anything (except whitespace)
324618334Speter       between the end of the ANSI formals list and the beginning of the
324718334Speter       function body (i.e. the '{').  */
324818334Speter
324918334Speter    check_source (ch == '{', l_brace_p);
325018334Speter  }
325118334Speter
325218334Speter#else /* !defined (UNPROTOIZE) */
325318334Speter
325418334Speter  /* Now scan backwards while looking for the right end of the rightmost
325518334Speter     formals list associated with this function definition.  */
325618334Speter
325718334Speter  while (1)
325818334Speter    {
325918334Speter      char ch;
326018334Speter      const char *l_brace_p;
326118334Speter
326218334Speter      /* Look leftward and try to find a right-paren.  */
326318334Speter
326418334Speter      while (*end_formals != ')')
3265117395Skan	{
3266117395Skan	  if (ISSPACE ((const unsigned char)*end_formals))
3267117395Skan	    while (ISSPACE ((const unsigned char)*end_formals))
3268117395Skan	      check_source (--end_formals > clean_read_ptr, 0);
3269117395Skan	  else
3270117395Skan	    check_source (--end_formals > clean_read_ptr, 0);
3271117395Skan	}
327218334Speter
327318334Speter      ch = *(l_brace_p = forward_to_next_token_char (end_formals));
327418334Speter
327518334Speter      /* Since it is possible that we found a right paren before the starting
3276117395Skan	 '{' of the body which IS NOT the one at the end of the real K&R
3277117395Skan	 formals list (say for instance, we found one embedded inside one of
3278117395Skan	 the old K&R formal parameter declarations) we have to check to be
3279117395Skan	 sure that this is in fact the right paren that we were looking for.
328018334Speter
3281117395Skan	 The one we were looking for *must* be followed by either a '{' or
3282117395Skan	 by an alphabetic character, while others *cannot* validly be followed
3283117395Skan	 by such characters.  */
328418334Speter
328590075Sobrien      if ((ch == '{') || ISALPHA ((unsigned char) ch))
3286117395Skan	break;
328718334Speter
328818334Speter      /* At this point, we have found a right paren, but we know that it is
3289117395Skan	 not the one we were looking for, so backup one character and keep
3290117395Skan	 looking.  */
329118334Speter
329218334Speter      check_source (--end_formals > clean_read_ptr, 0);
329318334Speter    }
329418334Speter
329518334Speter#endif /* !defined (UNPROTOIZE) */
329618334Speter
329718334Speter  return end_formals;
329818334Speter}
329918334Speter
330018334Speter#ifndef UNPROTOIZE
330118334Speter
330218334Speter/* Insert into the output file a totally new declaration for a function
330318334Speter   which (up until now) was being called from within the current block
330418334Speter   without having been declared at any point such that the declaration
330518334Speter   was visible (i.e. in scope) at the point of the call.
330618334Speter
330718334Speter   We need to add in explicit declarations for all such function calls
330818334Speter   in order to get the full benefit of prototype-based function call
330918334Speter   parameter type checking.  */
331018334Speter
331118334Speterstatic void
3312132718Skanadd_local_decl (const def_dec_info *def_dec_p, const char *clean_text_p)
331318334Speter{
331418334Speter  const char *start_of_block;
331518334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
331618334Speter
331718334Speter  /* Don't insert new local explicit declarations unless explicitly requested
331818334Speter     to do so.  */
331918334Speter
332018334Speter  if (!local_flag)
332118334Speter    return;
332218334Speter
332318334Speter  /* Setup here to recover from confusing source code detected during this
332418334Speter     particular "edit".  */
332518334Speter
332618334Speter  save_pointers ();
332718334Speter  if (setjmp (source_confusion_recovery))
332818334Speter    {
332918334Speter      restore_pointers ();
3330169689Skan      notice ("%s: local declaration for function '%s' not inserted\n",
333152284Sobrien	      pname, function_to_edit);
333218334Speter      return;
333318334Speter    }
333418334Speter
333518334Speter  /* We have already done a seek to the start of the line which should
333618334Speter     contain *the* open curly brace which begins the block in which we need
333718334Speter     to insert an explicit function declaration (to replace the implicit one).
333818334Speter
333918334Speter     Now we scan that line, starting from the left, until we find the
334018334Speter     open curly brace we are looking for.  Note that there may actually be
334118334Speter     multiple open curly braces on the given line, but we will be happy
334218334Speter     with the leftmost one no matter what.  */
334318334Speter
334418334Speter  start_of_block = clean_text_p;
334518334Speter  while (*start_of_block != '{' && *start_of_block != '\n')
334618334Speter    check_source (++start_of_block < clean_text_limit, 0);
334718334Speter
334818334Speter  /* Note that the line from the original source could possibly
334918334Speter     contain *no* open curly braces!  This happens if the line contains
335018334Speter     a macro call which expands into a chunk of text which includes a
335118334Speter     block (and that block's associated open and close curly braces).
335218334Speter     In cases like this, we give up, issue a warning, and do nothing.  */
335318334Speter
335418334Speter  if (*start_of_block != '{')
335518334Speter    {
335618334Speter      if (!quiet_flag)
3357169689Skan	notice ("\n%s: %d: warning: can't add declaration of '%s' into macro call\n",
3358117395Skan	  def_dec_p->file->hash_entry->symbol, def_dec_p->line,
3359117395Skan	  def_dec_p->hash_entry->symbol);
336018334Speter      return;
336118334Speter    }
336218334Speter
336318334Speter  /* Figure out what a nice (pretty) indentation would be for the new
336418334Speter     declaration we are adding.  In order to do this, we must scan forward
336518334Speter     from the '{' until we find the first line which starts with some
336618334Speter     non-whitespace characters (i.e. real "token" material).  */
336718334Speter
336818334Speter  {
336918334Speter    const char *ep = forward_to_next_token_char (start_of_block) - 1;
337018334Speter    const char *sp;
337118334Speter
337218334Speter    /* Now we have ep pointing at the rightmost byte of some existing indent
337318334Speter       stuff.  At least that is the hope.
337418334Speter
337518334Speter       We can now just scan backwards and find the left end of the existing
337618334Speter       indentation string, and then copy it to the output buffer.  */
337718334Speter
337852284Sobrien    for (sp = ep; ISSPACE ((const unsigned char)*sp) && *sp != '\n'; sp--)
337918334Speter      continue;
338018334Speter
338118334Speter    /* Now write out the open { which began this block, and any following
338218334Speter       trash up to and including the last byte of the existing indent that
338318334Speter       we just found.  */
338418334Speter
338518334Speter    output_up_to (ep);
3386117395Skan
338718334Speter    /* Now we go ahead and insert the new declaration at this point.
338818334Speter
338918334Speter       If the definition of the given function is in the same file that we
339018334Speter       are currently editing, and if its full ANSI declaration normally
339118334Speter       would start with the keyword `extern', suppress the `extern'.  */
3392117395Skan
339318334Speter    {
339418334Speter      const char *decl = def_dec_p->definition->ansi_decl;
3395117395Skan
339618334Speter      if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3397117395Skan	decl += 7;
339818334Speter      output_string (decl);
339918334Speter    }
340018334Speter
340118334Speter    /* Finally, write out a new indent string, just like the preceding one
340218334Speter       that we found.  This will typically include a newline as the first
340318334Speter       character of the indent string.  */
340418334Speter
340518334Speter    output_bytes (sp, (size_t) (ep - sp) + 1);
340618334Speter  }
340718334Speter}
340818334Speter
340918334Speter/* Given a pointer to a file_info record, and a pointer to the beginning
341018334Speter   of a line (in the clean text buffer) which is assumed to contain the
341118334Speter   first "follower" token for the first function definition header in the
341218334Speter   given file, find a good place to insert some new global function
341318334Speter   declarations (which will replace scattered and imprecise implicit ones)
341418334Speter   and then insert the new explicit declaration at that point in the file.  */
341518334Speter
341618334Speterstatic void
3417132718Skanadd_global_decls (const file_info *file_p, const char *clean_text_p)
341818334Speter{
341918334Speter  const def_dec_info *dd_p;
342018334Speter  const char *scan_p;
342118334Speter
342218334Speter  /* Setup here to recover from confusing source code detected during this
342318334Speter     particular "edit".  */
342418334Speter
342518334Speter  save_pointers ();
342618334Speter  if (setjmp (source_confusion_recovery))
342718334Speter    {
342818334Speter      restore_pointers ();
3429169689Skan      notice ("%s: global declarations for file '%s' not inserted\n",
343052284Sobrien	      pname, shortpath (NULL, file_p->hash_entry->symbol));
343118334Speter      return;
343218334Speter    }
343318334Speter
343418334Speter  /* Start by finding a good location for adding the new explicit function
343518334Speter     declarations.  To do this, we scan backwards, ignoring whitespace
343618334Speter     and comments and other junk until we find either a semicolon, or until
343718334Speter     we hit the beginning of the file.  */
343818334Speter
343918334Speter  scan_p = find_rightmost_formals_list (clean_text_p);
344018334Speter  for (;; --scan_p)
344118334Speter    {
344218334Speter      if (scan_p < clean_text_base)
3443117395Skan	break;
344418334Speter      check_source (scan_p > clean_read_ptr, 0);
344518334Speter      if (*scan_p == ';')
3446117395Skan	break;
344718334Speter    }
344818334Speter
344918334Speter  /* scan_p now points either to a semicolon, or to just before the start
345018334Speter     of the whole file.  */
345118334Speter
345218334Speter  /* Now scan forward for the first non-whitespace character.  In theory,
345318334Speter     this should be the first character of the following function definition
345450397Sobrien     header.  We will put in the added declarations just prior to that.  */
345518334Speter
345618334Speter  scan_p++;
345752284Sobrien  while (ISSPACE ((const unsigned char)*scan_p))
345818334Speter    scan_p++;
345918334Speter  scan_p--;
346018334Speter
346118334Speter  output_up_to (scan_p);
346218334Speter
346318334Speter  /* Now write out full prototypes for all of the things that had been
346418334Speter     implicitly declared in this file (but only those for which we were
346518334Speter     actually able to find unique matching definitions).  Avoid duplicates
346690075Sobrien     by marking things that we write out as we go.  */
346718334Speter
346818334Speter  {
346918334Speter    int some_decls_added = 0;
3470117395Skan
347118334Speter    for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
347218334Speter      if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3473117395Skan	{
3474117395Skan	  const char *decl = dd_p->definition->ansi_decl;
3475117395Skan
3476117395Skan	  /* If the function for which we are inserting a declaration is
3477117395Skan	     actually defined later in the same file, then suppress the
3478117395Skan	     leading `extern' keyword (if there is one).  */
3479117395Skan
3480117395Skan	  if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3481117395Skan	    decl += 7;
3482117395Skan
3483117395Skan	  output_string ("\n");
3484117395Skan	  output_string (decl);
3485117395Skan	  some_decls_added = 1;
3486117395Skan	  ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3487117395Skan	}
348818334Speter    if (some_decls_added)
348918334Speter      output_string ("\n\n");
349018334Speter  }
349118334Speter
349218334Speter  /* Unmark all of the definitions that we just marked.  */
349318334Speter
349418334Speter  for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
349518334Speter    if (dd_p->definition)
349618334Speter      ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
349718334Speter}
349818334Speter
349918334Speter#endif /* !defined (UNPROTOIZE) */
350018334Speter
350118334Speter/* Do the editing operation specifically for a function "definition".  Note
350218334Speter   that editing operations for function "declarations" are handled by a
350318334Speter   separate routine above.  */
350418334Speter
350518334Speterstatic void
3506169689Skanedit_fn_definition (const def_dec_info *def_dec_p,
3507169689Skan		    const char *volatile clean_text_p)
350818334Speter{
350918334Speter  const char *end_formals;
351018334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
351118334Speter
351218334Speter  /* Setup here to recover from confusing source code detected during this
351318334Speter     particular "edit".  */
351418334Speter
351518334Speter  save_pointers ();
351618334Speter  if (setjmp (source_confusion_recovery))
351718334Speter    {
351818334Speter      restore_pointers ();
3519169689Skan      notice ("%s: definition of function '%s' not converted\n",
352052284Sobrien	      pname, function_to_edit);
352118334Speter      return;
352218334Speter    }
352318334Speter
352418334Speter  end_formals = find_rightmost_formals_list (clean_text_p);
352518334Speter
352618334Speter  /* end_of_formals now points to the closing right paren of the rightmost
352718334Speter     formals list which is actually part of the `header' of the function
352818334Speter     definition that we are converting.  */
352918334Speter
353018334Speter  /* If the header of this function definition looks like it declares a
353118334Speter     function with a variable number of arguments, and if the way it does
353218334Speter     that is different from that way we would like it (i.e. varargs vs.
353318334Speter     stdarg) then issue a warning and leave the header unconverted.  */
3534117395Skan
353518334Speter  if (other_variable_style_function (def_dec_p->ansi_decl))
353618334Speter    {
353718334Speter      if (!quiet_flag)
3538117395Skan	notice ("%s: %d: warning: definition of %s not converted\n",
353952284Sobrien		shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3540117395Skan		identify_lineno (end_formals),
354152284Sobrien		other_var_style);
354218334Speter      output_up_to (end_formals);
354318334Speter      return;
354418334Speter    }
354518334Speter
354618334Speter  if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
354718334Speter    {
354818334Speter      restore_pointers ();
3549169689Skan      notice ("%s: definition of function '%s' not converted\n",
355052284Sobrien	      pname, function_to_edit);
355118334Speter      return;
355218334Speter    }
355318334Speter
355418334Speter  /* Have to output the last right paren because this never gets flushed by
355518334Speter     edit_formals_list.  */
355618334Speter
355718334Speter  output_up_to (end_formals);
355818334Speter
355918334Speter#ifdef UNPROTOIZE
356018334Speter  {
356118334Speter    const char *decl_p;
356218334Speter    const char *semicolon_p;
356318334Speter    const char *limit_p;
356418334Speter    const char *scan_p;
356518334Speter    int had_newlines = 0;
356618334Speter
356718334Speter    /* Now write out the K&R style formal declarations, one per line.  */
356818334Speter
356918334Speter    decl_p = def_dec_p->formal_decls;
357018334Speter    limit_p = decl_p + strlen (decl_p);
357118334Speter    for (;decl_p < limit_p; decl_p = semicolon_p + 2)
357218334Speter      {
3573117395Skan	for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3574117395Skan	  continue;
3575117395Skan	output_string ("\n");
3576117395Skan	output_string (indent_string);
3577117395Skan	output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
357818334Speter      }
357918334Speter
358018334Speter    /* If there are no newlines between the end of the formals list and the
358118334Speter       start of the body, we should insert one now.  */
358218334Speter
358318334Speter    for (scan_p = end_formals+1; *scan_p != '{'; )
358418334Speter      {
3585117395Skan	if (*scan_p == '\n')
3586117395Skan	  {
3587117395Skan	    had_newlines = 1;
3588117395Skan	    break;
3589117395Skan	  }
3590117395Skan	check_source (++scan_p < clean_text_limit, 0);
359118334Speter      }
359218334Speter    if (!had_newlines)
359318334Speter      output_string ("\n");
359418334Speter  }
359518334Speter#else /* !defined (UNPROTOIZE) */
359618334Speter  /* If we are protoizing, there may be some flotsam & jetsam (like comments
359718334Speter     and preprocessing directives) after the old formals list but before
359818334Speter     the following { and we would like to preserve that stuff while effectively
359918334Speter     deleting the existing K&R formal parameter declarations.  We do so here
360018334Speter     in a rather tricky way.  Basically, we white out any stuff *except*
360118334Speter     the comments/pp-directives in the original text buffer, then, if there
360218334Speter     is anything in this area *other* than whitespace, we output it.  */
360318334Speter  {
360418334Speter    const char *end_formals_orig;
360518334Speter    const char *start_body;
360618334Speter    const char *start_body_orig;
360718334Speter    const char *scan;
360818334Speter    const char *scan_orig;
360918334Speter    int have_flotsam = 0;
361018334Speter    int have_newlines = 0;
361118334Speter
361218334Speter    for (start_body = end_formals + 1; *start_body != '{';)
361318334Speter      check_source (++start_body < clean_text_limit, 0);
361418334Speter
361518334Speter    end_formals_orig = orig_text_base + (end_formals - clean_text_base);
361618334Speter    start_body_orig = orig_text_base + (start_body - clean_text_base);
361718334Speter    scan = end_formals + 1;
361818334Speter    scan_orig = end_formals_orig + 1;
361918334Speter    for (; scan < start_body; scan++, scan_orig++)
362018334Speter      {
3621117395Skan	if (*scan == *scan_orig)
3622117395Skan	  {
3623117395Skan	    have_newlines |= (*scan_orig == '\n');
3624117395Skan	    /* Leave identical whitespace alone.  */
3625117395Skan	    if (!ISSPACE ((const unsigned char)*scan_orig))
3626117395Skan	      *((NONCONST char *) scan_orig) = ' '; /* identical - so whiteout */
3627117395Skan	  }
3628117395Skan	else
3629117395Skan	  have_flotsam = 1;
363018334Speter      }
363118334Speter    if (have_flotsam)
363218334Speter      output_bytes (end_formals_orig + 1,
363318334Speter		    (size_t) (start_body_orig - end_formals_orig) - 1);
363418334Speter    else
363518334Speter      if (have_newlines)
3636117395Skan	output_string ("\n");
363718334Speter      else
3638117395Skan	output_string (" ");
363918334Speter    clean_read_ptr = start_body - 1;
364018334Speter  }
364118334Speter#endif /* !defined (UNPROTOIZE) */
364218334Speter}
364318334Speter
364418334Speter/* Clean up the clean text buffer.  Do this by converting comments and
364518334Speter   preprocessing directives into spaces.   Also convert line continuations
364618334Speter   into whitespace.  Also, whiteout string and character literals.  */
364718334Speter
364818334Speterstatic void
3649132718Skando_cleaning (char *new_clean_text_base, const char *new_clean_text_limit)
365018334Speter{
365118334Speter  char *scan_p;
365218334Speter  int non_whitespace_since_newline = 0;
365318334Speter
365418334Speter  for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
365518334Speter    {
365618334Speter      switch (*scan_p)
3657117395Skan	{
3658117395Skan	case '/':			/* Handle comments.  */
3659117395Skan	  if (scan_p[1] != '*')
3660117395Skan	    goto regular;
3661117395Skan	  non_whitespace_since_newline = 1;
3662117395Skan	  scan_p[0] = ' ';
3663117395Skan	  scan_p[1] = ' ';
3664117395Skan	  scan_p += 2;
3665117395Skan	  while (scan_p[1] != '/' || scan_p[0] != '*')
3666117395Skan	    {
3667117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3668117395Skan		*scan_p = ' ';
3669169689Skan	      ++scan_p;
3670169689Skan	      gcc_assert (scan_p < new_clean_text_limit);
3671117395Skan	    }
3672117395Skan	  *scan_p++ = ' ';
3673117395Skan	  *scan_p = ' ';
3674117395Skan	  break;
367518334Speter
3676117395Skan	case '#':			/* Handle pp directives.  */
3677117395Skan	  if (non_whitespace_since_newline)
3678117395Skan	    goto regular;
3679117395Skan	  *scan_p = ' ';
3680117395Skan	  while (scan_p[1] != '\n' || scan_p[0] == '\\')
3681117395Skan	    {
3682117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3683117395Skan		*scan_p = ' ';
3684169689Skan	      ++scan_p;
3685169689Skan	      gcc_assert (scan_p < new_clean_text_limit);
3686117395Skan	    }
3687117395Skan	  *scan_p++ = ' ';
3688117395Skan	  break;
368918334Speter
3690117395Skan	case '\'':			/* Handle character literals.  */
3691117395Skan	  non_whitespace_since_newline = 1;
3692117395Skan	  while (scan_p[1] != '\'' || scan_p[0] == '\\')
3693117395Skan	    {
3694117395Skan	      if (scan_p[0] == '\\'
3695117395Skan		  && !ISSPACE ((const unsigned char) scan_p[1]))
3696117395Skan		scan_p[1] = ' ';
3697117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3698117395Skan		*scan_p = ' ';
3699169689Skan	      ++scan_p;
3700169689Skan	      gcc_assert (scan_p < new_clean_text_limit);
3701117395Skan	    }
3702117395Skan	  *scan_p++ = ' ';
3703117395Skan	  break;
370418334Speter
3705117395Skan	case '"':			/* Handle string literals.  */
3706117395Skan	  non_whitespace_since_newline = 1;
3707117395Skan	  while (scan_p[1] != '"' || scan_p[0] == '\\')
3708117395Skan	    {
3709117395Skan	      if (scan_p[0] == '\\'
3710117395Skan		  && !ISSPACE ((const unsigned char) scan_p[1]))
3711117395Skan		scan_p[1] = ' ';
3712117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3713117395Skan		*scan_p = ' ';
3714169689Skan	      ++scan_p;
3715169689Skan	      gcc_assert (scan_p < new_clean_text_limit);
3716117395Skan	    }
3717117395Skan	  if (!ISSPACE ((const unsigned char)*scan_p))
3718117395Skan	    *scan_p = ' ';
3719117395Skan	  scan_p++;
3720117395Skan	  break;
372118334Speter
3722117395Skan	case '\\':			/* Handle line continuations.  */
3723117395Skan	  if (scan_p[1] != '\n')
3724117395Skan	    goto regular;
3725117395Skan	  *scan_p = ' ';
3726117395Skan	  break;
372718334Speter
3728117395Skan	case '\n':
3729117395Skan	  non_whitespace_since_newline = 0;	/* Reset.  */
3730117395Skan	  break;
373118334Speter
3732117395Skan	case ' ':
3733117395Skan	case '\v':
3734117395Skan	case '\t':
3735117395Skan	case '\r':
3736117395Skan	case '\f':
3737117395Skan	case '\b':
3738117395Skan	  break;		/* Whitespace characters.  */
373918334Speter
3740117395Skan	default:
374118334Speterregular:
3742117395Skan	  non_whitespace_since_newline = 1;
3743117395Skan	  break;
3744117395Skan	}
374518334Speter    }
374618334Speter}
374718334Speter
374818334Speter/* Given a pointer to the closing right parenthesis for a particular formals
374918334Speter   list (in the clean text buffer) find the corresponding left parenthesis
375018334Speter   and return a pointer to it.  */
375118334Speter
375218334Speterstatic const char *
3753132718Skancareful_find_l_paren (const char *p)
375418334Speter{
375518334Speter  const char *q;
375618334Speter  int paren_depth;
375718334Speter
375818334Speter  for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
375918334Speter    {
376018334Speter      switch (*q)
3761117395Skan	{
3762117395Skan	case ')':
3763117395Skan	  paren_depth++;
3764117395Skan	  break;
3765117395Skan	case '(':
3766117395Skan	  paren_depth--;
3767117395Skan	  break;
3768117395Skan	}
376918334Speter    }
377018334Speter  return ++q;
377118334Speter}
377218334Speter
377318334Speter/* Scan the clean text buffer for cases of function definitions that we
377418334Speter   don't really know about because they were preprocessed out when the
377518334Speter   aux info files were created.
377618334Speter
377718334Speter   In this version of protoize/unprotoize we just give a warning for each
377818334Speter   one found.  A later version may be able to at least unprotoize such
377918334Speter   missed items.
378018334Speter
378118334Speter   Note that we may easily find all function definitions simply by
378218334Speter   looking for places where there is a left paren which is (ignoring
378318334Speter   whitespace) immediately followed by either a left-brace or by an
378418334Speter   upper or lower case letter.  Whenever we find this combination, we
378518334Speter   have also found a function definition header.
378618334Speter
378718334Speter   Finding function *declarations* using syntactic clues is much harder.
378818334Speter   I will probably try to do this in a later version though.  */
378918334Speter
379018334Speterstatic void
3791132718Skanscan_for_missed_items (const file_info *file_p)
379218334Speter{
379318334Speter  static const char *scan_p;
379418334Speter  const char *limit = clean_text_limit - 3;
379518334Speter  static const char *backup_limit;
379618334Speter
379718334Speter  backup_limit = clean_text_base - 1;
379818334Speter
379918334Speter  for (scan_p = clean_text_base; scan_p < limit; scan_p++)
380018334Speter    {
380118334Speter      if (*scan_p == ')')
3802117395Skan	{
3803117395Skan	  static const char *last_r_paren;
3804117395Skan	  const char *ahead_p;
380518334Speter
3806117395Skan	  last_r_paren = scan_p;
380718334Speter
3808117395Skan	  for (ahead_p = scan_p + 1; ISSPACE ((const unsigned char)*ahead_p); )
3809117395Skan	    check_source (++ahead_p < limit, limit);
381018334Speter
3811117395Skan	  scan_p = ahead_p - 1;
381218334Speter
3813117395Skan	  if (ISALPHA ((const unsigned char)*ahead_p) || *ahead_p == '{')
3814117395Skan	    {
3815117395Skan	      const char *last_l_paren;
3816117395Skan	      const int lineno = identify_lineno (ahead_p);
381718334Speter
3818117395Skan	      if (setjmp (source_confusion_recovery))
3819117395Skan		continue;
382018334Speter
3821117395Skan	      /* We know we have a function definition header.  Now skip
3822117395Skan	         leftwards over all of its associated formals lists.  */
382318334Speter
3824117395Skan	      do
3825117395Skan		{
3826117395Skan		  last_l_paren = careful_find_l_paren (last_r_paren);
3827117395Skan		  for (last_r_paren = last_l_paren-1;
382852284Sobrien		       ISSPACE ((const unsigned char)*last_r_paren); )
3829117395Skan		    check_source (--last_r_paren >= backup_limit, backup_limit);
3830117395Skan		}
3831117395Skan	      while (*last_r_paren == ')');
383218334Speter
3833117395Skan	      if (is_id_char (*last_r_paren))
3834117395Skan		{
3835117395Skan		  const char *id_limit = last_r_paren + 1;
3836117395Skan		  const char *id_start;
3837117395Skan		  size_t id_length;
3838117395Skan		  const def_dec_info *dd_p;
383918334Speter
3840117395Skan		  for (id_start = id_limit-1; is_id_char (*id_start); )
3841117395Skan		    check_source (--id_start >= backup_limit, backup_limit);
3842117395Skan		  id_start++;
3843117395Skan		  backup_limit = id_start;
3844117395Skan		  if ((id_length = (size_t) (id_limit - id_start)) == 0)
3845117395Skan		    goto not_missed;
384618334Speter
384718334Speter		  {
3848132718Skan		    char *func_name = alloca (id_length + 1);
384918334Speter		    static const char * const stmt_keywords[]
385018334Speter		      = { "if", "else", "do", "while", "for", "switch", "case", "return", 0 };
385118334Speter		    const char * const *stmt_keyword;
385218334Speter
385318334Speter		    strncpy (func_name, id_start, id_length);
385418334Speter		    func_name[id_length] = '\0';
385518334Speter
385618334Speter		    /* We must check here to see if we are actually looking at
385718334Speter		       a statement rather than an actual function call.  */
385818334Speter
385918334Speter		    for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
386018334Speter		      if (!strcmp (func_name, *stmt_keyword))
386118334Speter			goto not_missed;
386218334Speter
386318334Speter#if 0
3864169689Skan		    notice ("%s: found definition of '%s' at %s(%d)\n",
386552284Sobrien			    pname,
386652284Sobrien			    func_name,
386752284Sobrien			    shortpath (NULL, file_p->hash_entry->symbol),
386852284Sobrien			    identify_lineno (id_start));
386918334Speter#endif				/* 0 */
387018334Speter		    /* We really should check for a match of the function name
387118334Speter		       here also, but why bother.  */
387218334Speter
387318334Speter		    for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
387418334Speter		      if (dd_p->is_func_def && dd_p->line == lineno)
387518334Speter			goto not_missed;
387618334Speter
387718334Speter		    /* If we make it here, then we did not know about this
387818334Speter		       function definition.  */
387918334Speter
3880169689Skan		    notice ("%s: %d: warning: '%s' excluded by preprocessing\n",
388152284Sobrien			    shortpath (NULL, file_p->hash_entry->symbol),
388252284Sobrien			    identify_lineno (id_start), func_name);
388352284Sobrien		    notice ("%s: function definition not converted\n",
388452284Sobrien			    pname);
388518334Speter		  }
388618334Speter		not_missed: ;
3887117395Skan	        }
3888117395Skan	    }
3889117395Skan	}
389018334Speter    }
389118334Speter}
389218334Speter
389318334Speter/* Do all editing operations for a single source file (either a "base" file
389418334Speter   or an "include" file).  To do this we read the file into memory, keep a
389518334Speter   virgin copy there, make another cleaned in-core copy of the original file
389618334Speter   (i.e. one in which all of the comments and preprocessing directives have
389718334Speter   been replaced with whitespace), then use these two in-core copies of the
389818334Speter   file to make a new edited in-core copy of the file.  Finally, rename the
389918334Speter   original file (as a way of saving it), and then write the edited version
390018334Speter   of the file from core to a disk file of the same name as the original.
390118334Speter
390218334Speter   Note that the trick of making a copy of the original sans comments &
390318334Speter   preprocessing directives make the editing a whole lot easier.  */
3904117395Skan
390518334Speterstatic void
3906132718Skanedit_file (const hash_table_entry *hp)
390718334Speter{
390818334Speter  struct stat stat_buf;
390918334Speter  const file_info *file_p = hp->fip;
391018334Speter  char *new_orig_text_base;
391118334Speter  char *new_orig_text_limit;
391218334Speter  char *new_clean_text_base;
391318334Speter  char *new_clean_text_limit;
391418334Speter  size_t orig_size;
391518334Speter  size_t repl_size;
391618334Speter  int first_definition_in_file;
391718334Speter
391818334Speter  /* If we are not supposed to be converting this file, or if there is
391918334Speter     nothing in there which needs converting, just skip this file.  */
392018334Speter
392118334Speter  if (!needs_to_be_converted (file_p))
392218334Speter    return;
392318334Speter
392418334Speter  convert_filename = file_p->hash_entry->symbol;
392518334Speter
392618334Speter  /* Convert a file if it is in a directory where we want conversion
392718334Speter     and the file is not excluded.  */
392818334Speter
392918334Speter  if (!directory_specified_p (convert_filename)
393018334Speter      || file_excluded_p (convert_filename))
393118334Speter    {
393218334Speter      if (!quiet_flag
393318334Speter#ifdef UNPROTOIZE
3934117395Skan	  /* Don't even mention "system" include files unless we are
3935117395Skan	     protoizing.  If we are protoizing, we mention these as a
3936117395Skan	     gentle way of prodding the user to convert his "system"
3937117395Skan	     include files to prototype format.  */
3938117395Skan	  && !in_system_include_dir (convert_filename)
393918334Speter#endif /* defined (UNPROTOIZE) */
3940117395Skan	  )
3941169689Skan	notice ("%s: '%s' not converted\n",
394252284Sobrien		pname, shortpath (NULL, convert_filename));
394318334Speter      return;
394418334Speter    }
394518334Speter
394618334Speter  /* Let the user know what we are up to.  */
394718334Speter
394818334Speter  if (nochange_flag)
3949169689Skan    notice ("%s: would convert file '%s'\n",
395052284Sobrien	    pname, shortpath (NULL, convert_filename));
395118334Speter  else
3952169689Skan    notice ("%s: converting file '%s'\n",
395352284Sobrien	    pname, shortpath (NULL, convert_filename));
395418334Speter  fflush (stderr);
395518334Speter
395618334Speter  /* Find out the size (in bytes) of the original file.  */
395718334Speter
395818334Speter  /* The cast avoids an erroneous warning on AIX.  */
395990075Sobrien  if (stat (convert_filename, &stat_buf) == -1)
396018334Speter    {
396150397Sobrien      int errno_val = errno;
3962169689Skan      notice ("%s: can't get status for file '%s': %s\n",
396352284Sobrien	      pname, shortpath (NULL, convert_filename),
396452284Sobrien	      xstrerror (errno_val));
396518334Speter      return;
396618334Speter    }
396718334Speter  orig_size = stat_buf.st_size;
396818334Speter
396918334Speter  /* Allocate a buffer to hold the original text.  */
397018334Speter
3971132718Skan  orig_text_base = new_orig_text_base = xmalloc (orig_size + 2);
397218334Speter  orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
397318334Speter
397418334Speter  /* Allocate a buffer to hold the cleaned-up version of the original text.  */
397518334Speter
3976132718Skan  clean_text_base = new_clean_text_base = xmalloc (orig_size + 2);
397718334Speter  clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
397818334Speter  clean_read_ptr = clean_text_base - 1;
397918334Speter
398018334Speter  /* Allocate a buffer that will hopefully be large enough to hold the entire
398118334Speter     converted output text.  As an initial guess for the maximum size of the
398218334Speter     output buffer, use 125% of the size of the original + some extra.  This
398318334Speter     buffer can be expanded later as needed.  */
398418334Speter
398518334Speter  repl_size = orig_size + (orig_size >> 2) + 4096;
3986132718Skan  repl_text_base = xmalloc (repl_size + 2);
398718334Speter  repl_text_limit = repl_text_base + repl_size - 1;
398818334Speter  repl_write_ptr = repl_text_base - 1;
398918334Speter
399018334Speter  {
399118334Speter    int input_file;
399290075Sobrien    int fd_flags;
399318334Speter
399418334Speter    /* Open the file to be converted in READ ONLY mode.  */
399518334Speter
399690075Sobrien    fd_flags = O_RDONLY;
399790075Sobrien#ifdef O_BINARY
399890075Sobrien    /* Use binary mode to avoid having to deal with different EOL characters.  */
399990075Sobrien    fd_flags |= O_BINARY;
400090075Sobrien#endif
400190075Sobrien    if ((input_file = open (convert_filename, fd_flags, 0444)) == -1)
400218334Speter      {
400350397Sobrien	int errno_val = errno;
4004169689Skan	notice ("%s: can't open file '%s' for reading: %s\n",
400552284Sobrien		pname, shortpath (NULL, convert_filename),
400652284Sobrien		xstrerror (errno_val));
4007117395Skan	return;
400818334Speter      }
400918334Speter
401018334Speter    /* Read the entire original source text file into the original text buffer
401118334Speter       in one swell fwoop.  Then figure out where the end of the text is and
401218334Speter       make sure that it ends with a newline followed by a null.  */
401318334Speter
401452284Sobrien    if (safe_read (input_file, new_orig_text_base, orig_size) !=
401552284Sobrien	(int) orig_size)
401618334Speter      {
401750397Sobrien	int errno_val = errno;
4018117395Skan	close (input_file);
4019169689Skan	notice ("\n%s: error reading input file '%s': %s\n",
402052284Sobrien		pname, shortpath (NULL, convert_filename),
402152284Sobrien		xstrerror (errno_val));
4022117395Skan	return;
402318334Speter      }
402418334Speter
402518334Speter    close (input_file);
402618334Speter  }
402718334Speter
402818334Speter  if (orig_size == 0 || orig_text_limit[-1] != '\n')
402918334Speter    {
403018334Speter      *new_orig_text_limit++ = '\n';
403118334Speter      orig_text_limit++;
403218334Speter    }
403318334Speter
403418334Speter  /* Create the cleaned up copy of the original text.  */
403518334Speter
403618334Speter  memcpy (new_clean_text_base, orig_text_base,
403718334Speter	  (size_t) (orig_text_limit - orig_text_base));
403818334Speter  do_cleaning (new_clean_text_base, new_clean_text_limit);
403918334Speter
404018334Speter#if 0
404118334Speter  {
404218334Speter    int clean_file;
404318334Speter    size_t clean_size = orig_text_limit - orig_text_base;
4044132718Skan    char *const clean_filename = alloca (strlen (convert_filename) + 6 + 1);
404518334Speter
404618334Speter    /* Open (and create) the clean file.  */
4047117395Skan
404818334Speter    strcpy (clean_filename, convert_filename);
404918334Speter    strcat (clean_filename, ".clean");
405018334Speter    if ((clean_file = creat (clean_filename, 0666)) == -1)
405118334Speter      {
405250397Sobrien	int errno_val = errno;
4053169689Skan	notice ("%s: can't create/open clean file '%s': %s\n",
405452284Sobrien		pname, shortpath (NULL, clean_filename),
405552284Sobrien		xstrerror (errno_val));
4056117395Skan	return;
405718334Speter      }
4058117395Skan
405918334Speter    /* Write the clean file.  */
4060117395Skan
406118334Speter    safe_write (clean_file, new_clean_text_base, clean_size, clean_filename);
4062117395Skan
406318334Speter    close (clean_file);
406418334Speter  }
406518334Speter#endif /* 0 */
406618334Speter
406718334Speter  /* Do a simplified scan of the input looking for things that were not
406818334Speter     mentioned in the aux info files because of the fact that they were
406918334Speter     in a region of the source which was preprocessed-out (via #if or
407018334Speter     via #ifdef).  */
407118334Speter
407218334Speter  scan_for_missed_items (file_p);
407318334Speter
407418334Speter  /* Setup to do line-oriented forward seeking in the clean text buffer.  */
407518334Speter
407618334Speter  last_known_line_number = 1;
407718334Speter  last_known_line_start = clean_text_base;
407818334Speter
407918334Speter  /* Now get down to business and make all of the necessary edits.  */
408018334Speter
408118334Speter  {
408218334Speter    const def_dec_info *def_dec_p;
408318334Speter
408418334Speter    first_definition_in_file = 1;
408518334Speter    def_dec_p = file_p->defs_decs;
408618334Speter    for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
408718334Speter      {
4088117395Skan	const char *clean_text_p = seek_to_line (def_dec_p->line);
4089117395Skan
4090117395Skan	/* clean_text_p now points to the first character of the line which
4091117395Skan	   contains the `terminator' for the declaration or definition that
4092117395Skan	   we are about to process.  */
4093117395Skan
409418334Speter#ifndef UNPROTOIZE
409518334Speter
4096117395Skan	if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4097117395Skan	  {
4098117395Skan	    add_global_decls (def_dec_p->file, clean_text_p);
4099117395Skan	    first_definition_in_file = 0;
4100117395Skan	  }
410118334Speter
4102117395Skan	/* Don't edit this item if it is already in prototype format or if it
4103117395Skan	   is a function declaration and we have found no corresponding
4104117395Skan	   definition.  */
410518334Speter
4106117395Skan	if (def_dec_p->prototyped
4107117395Skan	    || (!def_dec_p->is_func_def && !def_dec_p->definition))
4108117395Skan	  continue;
4109117395Skan
411018334Speter#endif /* !defined (UNPROTOIZE) */
411118334Speter
4112117395Skan	if (def_dec_p->is_func_def)
4113117395Skan	  edit_fn_definition (def_dec_p, clean_text_p);
4114117395Skan	else
411518334Speter#ifndef UNPROTOIZE
4116117395Skan	if (def_dec_p->is_implicit)
4117117395Skan	  add_local_decl (def_dec_p, clean_text_p);
4118117395Skan	else
411918334Speter#endif /* !defined (UNPROTOIZE) */
4120117395Skan	  edit_fn_declaration (def_dec_p, clean_text_p);
412118334Speter      }
412218334Speter  }
412318334Speter
412418334Speter  /* Finalize things.  Output the last trailing part of the original text.  */
412518334Speter
412618334Speter  output_up_to (clean_text_limit - 1);
412718334Speter
412818334Speter  /* If this is just a test run, stop now and just deallocate the buffers.  */
412918334Speter
413018334Speter  if (nochange_flag)
413118334Speter    {
413218334Speter      free (new_orig_text_base);
413318334Speter      free (new_clean_text_base);
413418334Speter      free (repl_text_base);
413518334Speter      return;
413618334Speter    }
413718334Speter
413818334Speter  /* Change the name of the original input file.  This is just a quick way of
413918334Speter     saving the original file.  */
414018334Speter
414118334Speter  if (!nosave_flag)
414218334Speter    {
414350397Sobrien      char *new_filename
4144132718Skan	= xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
4145117395Skan
414618334Speter      strcpy (new_filename, convert_filename);
414790075Sobrien#ifdef __MSDOS__
414890075Sobrien      /* MSDOS filenames are restricted to 8.3 format, so we save `foo.c'
4149117395Skan	 as `foo.<save_suffix>'.  */
415090075Sobrien      new_filename[(strlen (convert_filename) - 1] = '\0';
415190075Sobrien#endif
415218334Speter      strcat (new_filename, save_suffix);
415390075Sobrien
415490075Sobrien      /* Don't overwrite existing file.  */
415590075Sobrien      if (access (new_filename, F_OK) == 0)
415690075Sobrien	{
415790075Sobrien	  if (!quiet_flag)
4158169689Skan	    notice ("%s: warning: file '%s' already saved in '%s'\n",
415990075Sobrien		    pname,
416090075Sobrien		    shortpath (NULL, convert_filename),
416190075Sobrien		    shortpath (NULL, new_filename));
416290075Sobrien	}
416390075Sobrien      else if (rename (convert_filename, new_filename) == -1)
4164117395Skan	{
416550397Sobrien	  int errno_val = errno;
4166169689Skan	  notice ("%s: can't link file '%s' to '%s': %s\n",
416790075Sobrien		  pname,
416890075Sobrien		  shortpath (NULL, convert_filename),
416990075Sobrien		  shortpath (NULL, new_filename),
417090075Sobrien		  xstrerror (errno_val));
417190075Sobrien	  return;
4172117395Skan	}
417318334Speter    }
417418334Speter
417590075Sobrien  if (unlink (convert_filename) == -1)
417618334Speter    {
417750397Sobrien      int errno_val = errno;
417890075Sobrien      /* The file may have already been renamed.  */
417990075Sobrien      if (errno_val != ENOENT)
4180117395Skan	{
4181169689Skan	  notice ("%s: can't delete file '%s': %s\n",
418290075Sobrien		  pname, shortpath (NULL, convert_filename),
418390075Sobrien		  xstrerror (errno_val));
418490075Sobrien	  return;
418590075Sobrien	}
418618334Speter    }
418718334Speter
418818334Speter  {
418918334Speter    int output_file;
419018334Speter
419118334Speter    /* Open (and create) the output file.  */
4192117395Skan
419318334Speter    if ((output_file = creat (convert_filename, 0666)) == -1)
419418334Speter      {
419550397Sobrien	int errno_val = errno;
4196169689Skan	notice ("%s: can't create/open output file '%s': %s\n",
419752284Sobrien		pname, shortpath (NULL, convert_filename),
419852284Sobrien		xstrerror (errno_val));
4199117395Skan	return;
420018334Speter      }
420190075Sobrien#ifdef O_BINARY
420290075Sobrien    /* Use binary mode to avoid changing the existing EOL character.  */
420390075Sobrien    setmode (output_file, O_BINARY);
420490075Sobrien#endif
4205117395Skan
420618334Speter    /* Write the output file.  */
4207117395Skan
420818334Speter    {
420918334Speter      unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4210117395Skan
421118334Speter      safe_write (output_file, repl_text_base, out_size, convert_filename);
421218334Speter    }
4213117395Skan
421418334Speter    close (output_file);
421518334Speter  }
421618334Speter
421718334Speter  /* Deallocate the conversion buffers.  */
421818334Speter
421918334Speter  free (new_orig_text_base);
422018334Speter  free (new_clean_text_base);
422118334Speter  free (repl_text_base);
422218334Speter
422318334Speter  /* Change the mode of the output file to match the original file.  */
422418334Speter
422518334Speter  /* The cast avoids an erroneous warning on AIX.  */
422690075Sobrien  if (chmod (convert_filename, stat_buf.st_mode) == -1)
422750397Sobrien    {
422850397Sobrien      int errno_val = errno;
4229169689Skan      notice ("%s: can't change mode of file '%s': %s\n",
423052284Sobrien	      pname, shortpath (NULL, convert_filename),
423152284Sobrien	      xstrerror (errno_val));
423250397Sobrien    }
423318334Speter
423418334Speter  /* Note:  We would try to change the owner and group of the output file
423518334Speter     to match those of the input file here, except that may not be a good
423618334Speter     thing to do because it might be misleading.  Also, it might not even
423718334Speter     be possible to do that (on BSD systems with quotas for instance).  */
423818334Speter}
423918334Speter
424018334Speter/* Do all of the individual steps needed to do the protoization (or
424118334Speter   unprotoization) of the files referenced in the aux_info files given
424218334Speter   in the command line.  */
424318334Speter
424418334Speterstatic void
4245132718Skando_processing (void)
424618334Speter{
424718334Speter  const char * const *base_pp;
424818334Speter  const char * const * const end_pps
424918334Speter    = &base_source_filenames[n_base_source_files];
425018334Speter
425118334Speter#ifndef UNPROTOIZE
425218334Speter  int syscalls_len;
425318334Speter#endif /* !defined (UNPROTOIZE) */
425418334Speter
425518334Speter  /* One-by-one, check (and create if necessary), open, and read all of the
425618334Speter     stuff in each aux_info file.  After reading each aux_info file, the
425718334Speter     aux_info_file just read will be automatically deleted unless the
425818334Speter     keep_flag is set.  */
425918334Speter
426018334Speter  for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
426118334Speter    process_aux_info_file (*base_pp, keep_flag, 0);
426218334Speter
426318334Speter#ifndef UNPROTOIZE
426418334Speter
426518334Speter  /* Also open and read the special SYSCALLS.c aux_info file which gives us
426618334Speter     the prototypes for all of the standard system-supplied functions.  */
426718334Speter
426818334Speter  if (nondefault_syscalls_dir)
426918334Speter    {
427018334Speter      syscalls_absolute_filename
4271132718Skan	= xmalloc (strlen (nondefault_syscalls_dir) + 1
4272132718Skan		   + sizeof (syscalls_filename));
427318334Speter      strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
427418334Speter    }
427518334Speter  else
427618334Speter    {
4277117395Skan      GET_ENVIRONMENT (default_syscalls_dir, "GCC_EXEC_PREFIX");
427890075Sobrien      if (!default_syscalls_dir)
427990075Sobrien	{
428090075Sobrien	  default_syscalls_dir = standard_exec_prefix;
428190075Sobrien	}
428218334Speter      syscalls_absolute_filename
4283132718Skan	= xmalloc (strlen (default_syscalls_dir) + 0
4284132718Skan		   + strlen (target_machine) + 1
4285132718Skan		   + strlen (target_version) + 1
4286132718Skan		   + sizeof (syscalls_filename));
428718334Speter      strcpy (syscalls_absolute_filename, default_syscalls_dir);
428890075Sobrien      strcat (syscalls_absolute_filename, target_machine);
428990075Sobrien      strcat (syscalls_absolute_filename, "/");
429090075Sobrien      strcat (syscalls_absolute_filename, target_version);
429190075Sobrien      strcat (syscalls_absolute_filename, "/");
429218334Speter    }
429318334Speter
429418334Speter  syscalls_len = strlen (syscalls_absolute_filename);
429590075Sobrien  if (! IS_DIR_SEPARATOR (*(syscalls_absolute_filename + syscalls_len - 1)))
429618334Speter    {
429790075Sobrien      *(syscalls_absolute_filename + syscalls_len++) = DIR_SEPARATOR;
429818334Speter      *(syscalls_absolute_filename + syscalls_len) = '\0';
429918334Speter    }
430018334Speter  strcat (syscalls_absolute_filename, syscalls_filename);
4301117395Skan
430218334Speter  /* Call process_aux_info_file in such a way that it does not try to
430318334Speter     delete the SYSCALLS aux_info file.  */
430418334Speter
430518334Speter  process_aux_info_file (syscalls_absolute_filename, 1, 1);
430618334Speter
430718334Speter#endif /* !defined (UNPROTOIZE) */
430818334Speter
430918334Speter  /* When we first read in all of the information from the aux_info files
431018334Speter     we saved in it descending line number order, because that was likely to
431118334Speter     be faster.  Now however, we want the chains of def & dec records to
431218334Speter     appear in ascending line number order as we get further away from the
431318334Speter     file_info record that they hang from.  The following line causes all of
431418334Speter     these lists to be rearranged into ascending line number order.  */
431518334Speter
431618334Speter  visit_each_hash_node (filename_primary, reverse_def_dec_list);
431718334Speter
431818334Speter#ifndef UNPROTOIZE
431918334Speter
432018334Speter  /* Now do the "real" work.  The following line causes each declaration record
432118334Speter     to be "visited".  For each of these nodes, an attempt is made to match
432218334Speter     up the function declaration with a corresponding function definition,
432318334Speter     which should have a full prototype-format formals list with it.  Once
432418334Speter     these match-ups are made, the conversion of the function declarations
432518334Speter     to prototype format can be made.  */
432618334Speter
432718334Speter  visit_each_hash_node (function_name_primary, connect_defs_and_decs);
432818334Speter
432918334Speter#endif /* !defined (UNPROTOIZE) */
433018334Speter
433118334Speter  /* Now convert each file that can be converted (and needs to be).  */
433218334Speter
433318334Speter  visit_each_hash_node (filename_primary, edit_file);
433418334Speter
433518334Speter#ifndef UNPROTOIZE
433618334Speter
433718334Speter  /* If we are working in cplusplus mode, try to rename all .c files to .C
433818334Speter     files.  Don't panic if some of the renames don't work.  */
433918334Speter
434018334Speter  if (cplusplus_flag && !nochange_flag)
434118334Speter    visit_each_hash_node (filename_primary, rename_c_file);
434218334Speter
434318334Speter#endif /* !defined (UNPROTOIZE) */
434418334Speter}
434518334Speter
434690075Sobrienstatic const struct option longopts[] =
434718334Speter{
434818334Speter  {"version", 0, 0, 'V'},
434918334Speter  {"file_name", 0, 0, 'p'},
435018334Speter  {"quiet", 0, 0, 'q'},
435118334Speter  {"silent", 0, 0, 'q'},
435218334Speter  {"force", 0, 0, 'f'},
435318334Speter  {"keep", 0, 0, 'k'},
435418334Speter  {"nosave", 0, 0, 'N'},
435518334Speter  {"nochange", 0, 0, 'n'},
435618334Speter  {"compiler-options", 1, 0, 'c'},
435718334Speter  {"exclude", 1, 0, 'x'},
435818334Speter  {"directory", 1, 0, 'd'},
435918334Speter#ifdef UNPROTOIZE
436018334Speter  {"indent", 1, 0, 'i'},
436118334Speter#else
436218334Speter  {"local", 0, 0, 'l'},
436318334Speter  {"global", 0, 0, 'g'},
436418334Speter  {"c++", 0, 0, 'C'},
436518334Speter  {"syscalls-dir", 1, 0, 'B'},
436618334Speter#endif
436718334Speter  {0, 0, 0, 0}
436818334Speter};
436918334Speter
4370132718Skanextern int main (int, char **const);
437190075Sobrien
437218334Speterint
4373132718Skanmain (int argc, char **const argv)
437418334Speter{
437518334Speter  int longind;
437618334Speter  int c;
437718334Speter  const char *params = "";
437818334Speter
437990075Sobrien  pname = strrchr (argv[0], DIR_SEPARATOR);
438090075Sobrien#ifdef DIR_SEPARATOR_2
438190075Sobrien  {
438290075Sobrien    char *slash;
438390075Sobrien
438490075Sobrien    slash = strrchr (pname ? pname : argv[0], DIR_SEPARATOR_2);
438590075Sobrien    if (slash)
438690075Sobrien      pname = slash;
438790075Sobrien  }
438890075Sobrien#endif
438918334Speter  pname = pname ? pname+1 : argv[0];
439018334Speter
439190075Sobrien#ifdef SIGCHLD
439290075Sobrien  /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
439390075Sobrien     receive the signal.  A different setting is inheritable */
439490075Sobrien  signal (SIGCHLD, SIG_DFL);
439552284Sobrien#endif
439652284Sobrien
4397169689Skan  /* Unlock the stdio streams.  */
4398169689Skan  unlock_std_streams ();
4399169689Skan
440090075Sobrien  gcc_init_libintl ();
440190075Sobrien
440218334Speter  cwd_buffer = getpwd ();
440318334Speter  if (!cwd_buffer)
440418334Speter    {
440552284Sobrien      notice ("%s: cannot get working directory: %s\n",
440652284Sobrien	      pname, xstrerror(errno));
440790075Sobrien      return (FATAL_EXIT_CODE);
440818334Speter    }
440918334Speter
441018334Speter  /* By default, convert the files in the current directory.  */
441118334Speter  directory_list = string_list_cons (cwd_buffer, NULL);
441218334Speter
441318334Speter  while ((c = getopt_long (argc, argv,
441418334Speter#ifdef UNPROTOIZE
441518334Speter			   "c:d:i:knNp:qvVx:",
441618334Speter#else
441718334Speter			   "B:c:Cd:gklnNp:qvVx:",
441818334Speter#endif
441918334Speter			   longopts, &longind)) != EOF)
442018334Speter    {
442150397Sobrien      if (c == 0)		/* Long option.  */
442218334Speter	c = longopts[longind].val;
442318334Speter      switch (c)
442418334Speter	{
442518334Speter	case 'p':
442618334Speter	  compiler_file_name = optarg;
442718334Speter	  break;
442818334Speter	case 'd':
442918334Speter	  directory_list
443018334Speter	    = string_list_cons (abspath (NULL, optarg), directory_list);
443118334Speter	  break;
443218334Speter	case 'x':
443318334Speter	  exclude_list = string_list_cons (optarg, exclude_list);
443418334Speter	  break;
4435117395Skan
443618334Speter	case 'v':
443718334Speter	case 'V':
443818334Speter	  version_flag = 1;
443918334Speter	  break;
444018334Speter	case 'q':
444118334Speter	  quiet_flag = 1;
444218334Speter	  break;
444318334Speter#if 0
444418334Speter	case 'f':
444518334Speter	  force_flag = 1;
444618334Speter	  break;
444718334Speter#endif
444818334Speter	case 'n':
444918334Speter	  nochange_flag = 1;
445018334Speter	  keep_flag = 1;
445118334Speter	  break;
445218334Speter	case 'N':
445318334Speter	  nosave_flag = 1;
445418334Speter	  break;
445518334Speter	case 'k':
445618334Speter	  keep_flag = 1;
445718334Speter	  break;
445818334Speter	case 'c':
445918334Speter	  params = optarg;
446018334Speter	  break;
446118334Speter#ifdef UNPROTOIZE
446218334Speter	case 'i':
446318334Speter	  indent_string = optarg;
446418334Speter	  break;
446518334Speter#else				/* !defined (UNPROTOIZE) */
446618334Speter	case 'l':
446718334Speter	  local_flag = 1;
446818334Speter	  break;
446918334Speter	case 'g':
447018334Speter	  global_flag = 1;
447118334Speter	  break;
447218334Speter	case 'C':
447318334Speter	  cplusplus_flag = 1;
447418334Speter	  break;
447518334Speter	case 'B':
447618334Speter	  nondefault_syscalls_dir = optarg;
447718334Speter	  break;
447818334Speter#endif				/* !defined (UNPROTOIZE) */
447918334Speter	default:
448018334Speter	  usage ();
448118334Speter	}
448218334Speter    }
4483117395Skan
448418334Speter  /* Set up compile_params based on -p and -c options.  */
448518334Speter  munge_compile_params (params);
448618334Speter
448718334Speter  n_base_source_files = argc - optind;
448818334Speter
448918334Speter  /* Now actually make a list of the base source filenames.  */
449018334Speter
449150397Sobrien  base_source_filenames
4492132718Skan    = xmalloc ((n_base_source_files + 1) * sizeof (char *));
449318334Speter  n_base_source_files = 0;
449418334Speter  for (; optind < argc; optind++)
449518334Speter    {
449618334Speter      const char *path = abspath (NULL, argv[optind]);
449718334Speter      int len = strlen (path);
449818334Speter
449918334Speter      if (path[len-1] == 'c' && path[len-2] == '.')
450018334Speter	base_source_filenames[n_base_source_files++] = path;
450118334Speter      else
450218334Speter	{
450352284Sobrien	  notice ("%s: input file names must have .c suffixes: %s\n",
450452284Sobrien		  pname, shortpath (NULL, path));
450518334Speter	  errors++;
450618334Speter	}
450718334Speter    }
450818334Speter
450918334Speter#ifndef UNPROTOIZE
451018334Speter  /* We are only interested in the very first identifier token in the
451118334Speter     definition of `va_list', so if there is more junk after that first
451218334Speter     identifier token, delete it from the `varargs_style_indicator'.  */
451318334Speter  {
451418334Speter    const char *cp;
451518334Speter
451690075Sobrien    for (cp = varargs_style_indicator; ISIDNUM (*cp); cp++)
451718334Speter      continue;
451818334Speter    if (*cp != 0)
451918334Speter      varargs_style_indicator = savestring (varargs_style_indicator,
452018334Speter					    cp - varargs_style_indicator);
452118334Speter  }
452218334Speter#endif /* !defined (UNPROTOIZE) */
452318334Speter
452418334Speter  if (errors)
452518334Speter    usage ();
452618334Speter  else
452718334Speter    {
452818334Speter      if (version_flag)
4529117395Skan	fprintf (stderr, "%s: %s\n", pname, version_string);
453018334Speter      do_processing ();
453118334Speter    }
453250397Sobrien
453390075Sobrien  return (errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
453418334Speter}
4535