protoize.c revision 117395
118334Speter/* Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
290075Sobrien   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
390075Sobrien   1999, 2000, 2001, 2002 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
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2118334Speter
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
2490075Sobrien#include "intl.h"
2596263Sobrien#include "cppdefault.h"
2618334Speter
2790075Sobrien#include <setjmp.h>
2890075Sobrien#include <signal.h>
2990075Sobrien#if ! defined( SIGCHLD ) && defined( SIGCLD )
3090075Sobrien#  define SIGCHLD SIGCLD
3118334Speter#endif
3290075Sobrien#ifdef HAVE_UNISTD_H
3390075Sobrien#include <unistd.h>
3418334Speter#endif
3590075Sobrien#undef abort
3690075Sobrien#include "version.h"
3718334Speter
3890075Sobrien/* Include getopt.h for the sake of getopt_long.  */
3990075Sobrien#include "getopt.h"
4018334Speter
4190075Sobrien/* Macro to see if the path elements match.  */
4290075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
4390075Sobrien#define IS_SAME_PATH_CHAR(a,b) (TOUPPER (a) == TOUPPER (b))
4490075Sobrien#else
4590075Sobrien#define IS_SAME_PATH_CHAR(a,b) ((a) == (b))
4618334Speter#endif
4718334Speter
4890075Sobrien/* Macro to see if the paths match.  */
4990075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
5090075Sobrien#define IS_SAME_PATH(a,b) (strcasecmp (a, b) == 0)
5190075Sobrien#else
5290075Sobrien#define IS_SAME_PATH(a,b) (strcmp (a, b) == 0)
5318334Speter#endif
5418334Speter
5590075Sobrien/* Suffix for aux-info files.  */
5690075Sobrien#ifdef __MSDOS__
5790075Sobrien#define AUX_INFO_SUFFIX "X"
5818334Speter#else
5990075Sobrien#define AUX_INFO_SUFFIX ".X"
6018334Speter#endif
6118334Speter
6290075Sobrien/* Suffix for saved files.  */
6390075Sobrien#ifdef __MSDOS__
6490075Sobrien#define SAVE_SUFFIX "sav"
6590075Sobrien#else
6690075Sobrien#define SAVE_SUFFIX ".save"
6750397Sobrien#endif
6850397Sobrien
6990075Sobrien/* Suffix for renamed C++ files.  */
7090075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
7190075Sobrien#define CPLUS_FILE_SUFFIX "cc"
7250397Sobrien#else
7390075Sobrien#define CPLUS_FILE_SUFFIX "C"
7450397Sobrien#endif
7518334Speter
7690075Sobrienstatic void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
7790075Sobrienstatic void aux_info_corrupted PARAMS ((void)) ATTRIBUTE_NORETURN;
7890075Sobrienstatic void declare_source_confusing PARAMS ((const char *)) ATTRIBUTE_NORETURN;
7990075Sobrienstatic const char *shortpath PARAMS ((const char *, const char *));
8090075Sobrienextern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
8190075Sobrienstatic void notice PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1;
8290075Sobrienstatic char *savestring PARAMS ((const char *, unsigned int));
8390075Sobrienstatic char *dupnstr PARAMS ((const char *, size_t));
8490075Sobrienstatic const char *substr PARAMS ((const char *, const char * const));
8590075Sobrienstatic int safe_read PARAMS ((int, PTR, int));
8690075Sobrienstatic void safe_write PARAMS ((int, PTR, int, const char *));
8790075Sobrienstatic void save_pointers PARAMS ((void));
8890075Sobrienstatic void restore_pointers PARAMS ((void));
8990075Sobrienstatic int is_id_char PARAMS ((int));
9090075Sobrienstatic int in_system_include_dir PARAMS ((const char *));
9190075Sobrienstatic int directory_specified_p PARAMS ((const char *));
9290075Sobrienstatic int file_excluded_p PARAMS ((const char *));
9390075Sobrienstatic char *unexpand_if_needed PARAMS ((const char *));
9490075Sobrienstatic char *abspath PARAMS ((const char *, const char *));
9590075Sobrienstatic int is_abspath PARAMS ((const char *));
9690075Sobrienstatic void check_aux_info PARAMS ((int));
9790075Sobrienstatic const char *find_corresponding_lparen PARAMS ((const char *));
9890075Sobrienstatic int referenced_file_is_newer PARAMS ((const char *, time_t));
9990075Sobrienstatic void save_def_or_dec PARAMS ((const char *, int));
10090075Sobrienstatic void munge_compile_params PARAMS ((const char *));
10190075Sobrienstatic int gen_aux_info_file PARAMS ((const char *));
10290075Sobrienstatic void process_aux_info_file PARAMS ((const char *, int, int));
10390075Sobrienstatic int identify_lineno PARAMS ((const char *));
10490075Sobrienstatic void check_source PARAMS ((int, const char *));
10590075Sobrienstatic const char *seek_to_line PARAMS ((int));
10690075Sobrienstatic const char *forward_to_next_token_char PARAMS ((const char *));
10790075Sobrienstatic void output_bytes PARAMS ((const char *, size_t));
10890075Sobrienstatic void output_string PARAMS ((const char *));
10990075Sobrienstatic void output_up_to PARAMS ((const char *));
11090075Sobrienstatic int other_variable_style_function PARAMS ((const char *));
11190075Sobrienstatic const char *find_rightmost_formals_list PARAMS ((const char *));
11290075Sobrienstatic void do_cleaning PARAMS ((char *, const char *));
11390075Sobrienstatic const char *careful_find_l_paren PARAMS ((const char *));
11490075Sobrienstatic void do_processing PARAMS ((void));
11518334Speter
11690075Sobrien/* Look for these where the `const' qualifier is intentionally cast aside.  */
11790075Sobrien#define NONCONST
11850397Sobrien
11990075Sobrien/* Define a default place to find the SYSCALLS.X file.  */
12018334Speter
12190075Sobrien#ifndef UNPROTOIZE
12218334Speter
12390075Sobrien#ifndef STANDARD_EXEC_PREFIX
12490075Sobrien#define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-lib/"
12590075Sobrien#endif /* !defined STANDARD_EXEC_PREFIX */
12618334Speter
12790075Sobrienstatic const char * const standard_exec_prefix = STANDARD_EXEC_PREFIX;
12890075Sobrienstatic const char * const target_machine = DEFAULT_TARGET_MACHINE;
12990075Sobrienstatic const char * const target_version = DEFAULT_TARGET_VERSION;
13018334Speter
13190075Sobrien#endif /* !defined (UNPROTOIZE) */
13218334Speter
13390075Sobrien/* Suffix of aux_info files.  */
13418334Speter
13590075Sobrienstatic const char * const aux_info_suffix = AUX_INFO_SUFFIX;
13618334Speter
13790075Sobrien/* String to attach to filenames for saved versions of original files.  */
13818334Speter
13990075Sobrienstatic const char * const save_suffix = SAVE_SUFFIX;
14018334Speter
14190075Sobrien/* String to attach to C filenames renamed to C++.  */
14218334Speter
14390075Sobrienstatic const char * const cplus_suffix = CPLUS_FILE_SUFFIX;
14418334Speter
14518334Speter#ifndef UNPROTOIZE
14618334Speter
14718334Speter/* File name of the file which contains descriptions of standard system
14818334Speter   routines.  Note that we never actually do anything with this file per se,
14918334Speter   but we do read in its corresponding aux_info file.  */
15018334Speter
15118334Speterstatic const char syscalls_filename[] = "SYSCALLS.c";
15218334Speter
15318334Speter/* Default place to find the above file.  */
15418334Speter
15590075Sobrienstatic const char * default_syscalls_dir;
15618334Speter
15718334Speter/* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
15818334Speter   file.  */
15918334Speter
16018334Speterstatic char * syscalls_absolute_filename;
16118334Speter
16218334Speter#endif /* !defined (UNPROTOIZE) */
16318334Speter
16450397Sobrien/* Type of the structure that holds information about macro unexpansions.  */
16518334Speter
16618334Speterstruct unexpansion_struct {
16790075Sobrien  const char *const expanded;
16890075Sobrien  const char *const contracted;
16918334Speter};
17018334Spetertypedef struct unexpansion_struct unexpansion;
17118334Speter
17218334Speter/* A table of conversions that may need to be made for some (stupid) older
17318334Speter   operating systems where these types are preprocessor macros rather than
17418334Speter   typedefs (as they really ought to be).
17518334Speter
17618334Speter   WARNING: The contracted forms must be as small (or smaller) as the
17718334Speter   expanded forms, or else havoc will ensue.  */
17818334Speter
17918334Speterstatic const unexpansion unexpansions[] = {
18018334Speter  { "struct _iobuf", "FILE" },
18118334Speter  { 0, 0 }
18218334Speter};
18318334Speter
18418334Speter/* The number of "primary" slots in the hash tables for filenames and for
18518334Speter   function names.  This can be as big or as small as you like, except that
18618334Speter   it must be a power of two.  */
18718334Speter
18818334Speter#define HASH_TABLE_SIZE		(1 << 9)
18918334Speter
19018334Speter/* Bit mask to use when computing hash values.  */
19118334Speter
19218334Speterstatic const int hash_mask = (HASH_TABLE_SIZE - 1);
19318334Speter
19418334Speter
19518334Speter/* Datatype for lists of directories or filenames.  */
19618334Speterstruct string_list
19718334Speter{
19890075Sobrien  const char *name;
19918334Speter  struct string_list *next;
20018334Speter};
20118334Speter
20290075Sobrienstatic struct string_list *string_list_cons PARAMS ((const char *,
20390075Sobrien						     struct string_list *));
20490075Sobrien
20518334Speter/* List of directories in which files should be converted.  */
20618334Speter
20718334Speterstruct string_list *directory_list;
20818334Speter
20918334Speter/* List of file names which should not be converted.
21018334Speter   A file is excluded if the end of its name, following a /,
21118334Speter   matches one of the names in this list.  */
21218334Speter
21318334Speterstruct string_list *exclude_list;
21418334Speter
21518334Speter/* The name of the other style of variable-number-of-parameters functions
21618334Speter   (i.e. the style that we want to leave unconverted because we don't yet
21718334Speter   know how to convert them to this style.  This string is used in warning
21818334Speter   messages.  */
21918334Speter
22018334Speter/* Also define here the string that we can search for in the parameter lists
22118334Speter   taken from the .X files which will unambiguously indicate that we have
22218334Speter   found a varargs style function.  */
22318334Speter
22418334Speter#ifdef UNPROTOIZE
22518334Speterstatic const char * const other_var_style = "stdarg";
22618334Speter#else /* !defined (UNPROTOIZE) */
22718334Speterstatic const char * const other_var_style = "varargs";
22818334Speter/* Note that this is a string containing the expansion of va_alist.
22918334Speter   But in `main' we discard all but the first token.  */
23090075Sobrienstatic const char *varargs_style_indicator = STRINGX (va_alist);
23118334Speter#endif /* !defined (UNPROTOIZE) */
23218334Speter
23318334Speter/* The following two types are used to create hash tables.  In this program,
23418334Speter   there are two hash tables which are used to store and quickly lookup two
23518334Speter   different classes of strings.  The first type of strings stored in the
23618334Speter   first hash table are absolute filenames of files which protoize needs to
23718334Speter   know about.  The second type of strings (stored in the second hash table)
23818334Speter   are function names.  It is this second class of strings which really
23918334Speter   inspired the use of the hash tables, because there may be a lot of them.  */
24018334Speter
24118334Spetertypedef struct hash_table_entry_struct hash_table_entry;
24218334Speter
24318334Speter/* Do some typedefs so that we don't have to write "struct" so often.  */
24418334Speter
24518334Spetertypedef struct def_dec_info_struct def_dec_info;
24618334Spetertypedef struct file_info_struct file_info;
24718334Spetertypedef struct f_list_chain_item_struct f_list_chain_item;
24818334Speter
24990075Sobrien#ifndef UNPROTOIZE
25090075Sobrienstatic int is_syscalls_file PARAMS ((const file_info *));
25190075Sobrienstatic void rename_c_file PARAMS ((const hash_table_entry *));
25290075Sobrienstatic const def_dec_info *find_extern_def PARAMS ((const def_dec_info *,
25390075Sobrien						    const def_dec_info *));
25490075Sobrienstatic const def_dec_info *find_static_definition PARAMS ((const def_dec_info *));
25590075Sobrienstatic void connect_defs_and_decs PARAMS ((const hash_table_entry *));
25690075Sobrienstatic void add_local_decl PARAMS ((const def_dec_info *, const char *));
25790075Sobrienstatic void add_global_decls PARAMS ((const file_info *, const char *));
25890075Sobrien#endif /* ! UNPROTOIZE */
25990075Sobrienstatic int needs_to_be_converted PARAMS ((const file_info *));
26090075Sobrienstatic void visit_each_hash_node PARAMS ((const hash_table_entry *,
26190075Sobrien					  void (*)(const hash_table_entry *)));
26290075Sobrienstatic hash_table_entry *add_symbol PARAMS ((hash_table_entry *, const char *));
26390075Sobrienstatic hash_table_entry *lookup PARAMS ((hash_table_entry *, const char *));
26490075Sobrienstatic void free_def_dec PARAMS ((def_dec_info *));
26590075Sobrienstatic file_info *find_file PARAMS ((const char *, int));
26690075Sobrienstatic void reverse_def_dec_list PARAMS ((const hash_table_entry *));
26790075Sobrienstatic void edit_fn_declaration PARAMS ((const def_dec_info *, const char *));
26890075Sobrienstatic int edit_formals_lists PARAMS ((const char *, unsigned int,
26990075Sobrien				       const def_dec_info *));
27090075Sobrienstatic void edit_fn_definition PARAMS ((const def_dec_info *, const char *));
27190075Sobrienstatic void scan_for_missed_items PARAMS ((const file_info *));
27290075Sobrienstatic void edit_file PARAMS ((const hash_table_entry *));
27390075Sobrien
27418334Speter/* In the struct below, note that the "_info" field has two different uses
27518334Speter   depending on the type of hash table we are in (i.e. either the filenames
27618334Speter   hash table or the function names hash table).  In the filenames hash table
27718334Speter   the info fields of the entries point to the file_info struct which is
27818334Speter   associated with each filename (1 per filename).  In the function names
27918334Speter   hash table, the info field points to the head of a singly linked list of
28018334Speter   def_dec_info entries which are all defs or decs of the function whose
28118334Speter   name is pointed to by the "symbol" field.  Keeping all of the defs/decs
28218334Speter   for a given function name on a special list specifically for that function
28318334Speter   name makes it quick and easy to find out all of the important information
28418334Speter   about a given (named) function.  */
28518334Speter
28618334Speterstruct hash_table_entry_struct {
28718334Speter  hash_table_entry *		hash_next;	/* -> to secondary entries */
28818334Speter  const char *			symbol;		/* -> to the hashed string */
28918334Speter  union {
29018334Speter    const def_dec_info *	_ddip;
29118334Speter    file_info *			_fip;
29218334Speter  } _info;
29318334Speter};
29418334Speter#define ddip _info._ddip
29518334Speter#define fip _info._fip
29618334Speter
29718334Speter/* Define a type specifically for our two hash tables.  */
29818334Speter
29918334Spetertypedef hash_table_entry hash_table[HASH_TABLE_SIZE];
30018334Speter
30118334Speter/* The following struct holds all of the important information about any
30218334Speter   single filename (e.g. file) which we need to know about.  */
30318334Speter
30418334Speterstruct file_info_struct {
30518334Speter  const hash_table_entry *	hash_entry; /* -> to associated hash entry */
30618334Speter  const def_dec_info *		defs_decs;  /* -> to chain of defs/decs */
30718334Speter  time_t			mtime;      /* Time of last modification.  */
30818334Speter};
30918334Speter
31018334Speter/* Due to the possibility that functions may return pointers to functions,
31118334Speter   (which may themselves have their own parameter lists) and due to the
31218334Speter   fact that returned pointers-to-functions may be of type "pointer-to-
31318334Speter   function-returning-pointer-to-function" (ad nauseum) we have to keep
31418334Speter   an entire chain of ANSI style formal parameter lists for each function.
31518334Speter
31618334Speter   Normally, for any given function, there will only be one formals list
31718334Speter   on the chain, but you never know.
31818334Speter
31918334Speter   Note that the head of each chain of formals lists is pointed to by the
32018334Speter   `f_list_chain' field of the corresponding def_dec_info record.
32118334Speter
32218334Speter   For any given chain, the item at the head of the chain is the *leftmost*
32318334Speter   parameter list seen in the actual C language function declaration.  If
32418334Speter   there are other members of the chain, then these are linked in left-to-right
32518334Speter   order from the head of the chain.  */
32618334Speter
32718334Speterstruct f_list_chain_item_struct {
32818334Speter  const f_list_chain_item *	chain_next;	/* -> to next item on chain */
32918334Speter  const char *			formals_list;	/* -> to formals list string */
33018334Speter};
33118334Speter
33218334Speter/* The following struct holds all of the important information about any
33318334Speter   single function definition or declaration which we need to know about.
33418334Speter   Note that for unprotoize we don't need to know very much because we
33518334Speter   never even create records for stuff that we don't intend to convert
33618334Speter   (like for instance defs and decs which are already in old K&R format
33718334Speter   and "implicit" function declarations).  */
33818334Speter
33918334Speterstruct def_dec_info_struct {
34018334Speter  const def_dec_info *	next_in_file;	/* -> to rest of chain for file */
34118334Speter  file_info *        	file;		/* -> file_info for containing file */
34218334Speter  int        		line;		/* source line number of def/dec */
34318334Speter  const char *		ansi_decl;	/* -> left end of ansi decl */
34418334Speter  hash_table_entry *	hash_entry;	/* -> hash entry for function name */
34518334Speter  unsigned int        	is_func_def;	/* = 0 means this is a declaration */
34618334Speter  const def_dec_info *	next_for_func;	/* -> to rest of chain for func name */
34718334Speter  unsigned int		f_list_count;	/* count of formals lists we expect */
34818334Speter  char			prototyped;	/* = 0 means already prototyped */
34918334Speter#ifndef UNPROTOIZE
35018334Speter  const f_list_chain_item * f_list_chain;	/* -> chain of formals lists */
35118334Speter  const def_dec_info *	definition;	/* -> def/dec containing related def */
35218334Speter  char	        	is_static;	/* = 0 means visibility is "extern"  */
35318334Speter  char			is_implicit;	/* != 0 for implicit func decl's */
35418334Speter  char			written;	/* != 0 means written for implicit */
35518334Speter#else /* !defined (UNPROTOIZE) */
35618334Speter  const char *		formal_names;	/* -> to list of names of formals */
35718334Speter  const char *		formal_decls;	/* -> to string of formal declarations */
35818334Speter#endif /* !defined (UNPROTOIZE) */
35918334Speter};
36018334Speter
36118334Speter/* Pointer to the tail component of the filename by which this program was
36218334Speter   invoked.  Used everywhere in error and warning messages.  */
36318334Speter
36418334Speterstatic const char *pname;
36518334Speter
366117395Skan/* Error counter.  Will be nonzero if we should give up at the next convenient
36718334Speter   stopping point.  */
36818334Speter
36918334Speterstatic int errors = 0;
37018334Speter
37118334Speter/* Option flags.  */
37218334Speter/* ??? These comments should say what the flag mean as well as the options
37318334Speter   that set them.  */
37418334Speter
37518334Speter/* File name to use for running gcc.  Allows GCC 2 to be named
37618334Speter   something other than gcc.  */
37718334Speterstatic const char *compiler_file_name = "gcc";
37818334Speter
37918334Speterstatic int version_flag = 0;		/* Print our version number.  */
38018334Speterstatic int quiet_flag = 0;		/* Don't print messages normally.  */
38118334Speterstatic int nochange_flag = 0;		/* Don't convert, just say what files
38218334Speter					   we would have converted.  */
38318334Speterstatic int nosave_flag = 0;		/* Don't save the old version.  */
38418334Speterstatic int keep_flag = 0;		/* Don't delete the .X files.  */
38518334Speterstatic const char ** compile_params = 0;	/* Option string for gcc.  */
38618334Speter#ifdef UNPROTOIZE
38718334Speterstatic const char *indent_string = "     ";	/* Indentation for newly
38818334Speter						   inserted parm decls.  */
38918334Speter#else /* !defined (UNPROTOIZE) */
39018334Speterstatic int local_flag = 0;		/* Insert new local decls (when?).  */
39118334Speterstatic int global_flag = 0;		/* set by -g option */
39218334Speterstatic int cplusplus_flag = 0;		/* Rename converted files to *.C.  */
39350397Sobrienstatic const char *nondefault_syscalls_dir = 0; /* Dir to look for
39418334Speter						   SYSCALLS.c.X in.  */
39518334Speter#endif /* !defined (UNPROTOIZE) */
39618334Speter
39718334Speter/* An index into the compile_params array where we should insert the source
39818334Speter   file name when we are ready to exec the C compiler.  A zero value indicates
39918334Speter   that we have not yet called munge_compile_params.  */
40018334Speter
40118334Speterstatic int input_file_name_index = 0;
40218334Speter
40318334Speter/* An index into the compile_params array where we should insert the filename
40418334Speter   for the aux info file, when we run the C compiler.  */
40518334Speterstatic int aux_info_file_name_index = 0;
40618334Speter
40718334Speter/* Count of command line arguments which were "filename" arguments.  */
40818334Speter
40918334Speterstatic int n_base_source_files = 0;
41018334Speter
41118334Speter/* Points to a malloc'ed list of pointers to all of the filenames of base
41218334Speter   source files which were specified on the command line.  */
41318334Speter
41418334Speterstatic const char **base_source_filenames;
41518334Speter
41618334Speter/* Line number of the line within the current aux_info file that we
41718334Speter   are currently processing.  Used for error messages in case the prototypes
41818334Speter   info file is corrupted somehow.  */
41918334Speter
42018334Speterstatic int current_aux_info_lineno;
42118334Speter
42218334Speter/* Pointer to the name of the source file currently being converted.  */
42318334Speter
42418334Speterstatic const char *convert_filename;
42518334Speter
42618334Speter/* Pointer to relative root string (taken from aux_info file) which indicates
42718334Speter   where directory the user was in when he did the compilation step that
42850397Sobrien   produced the containing aux_info file.  */
42918334Speter
43018334Speterstatic const char *invocation_filename;
43118334Speter
43218334Speter/* Pointer to the base of the input buffer that holds the original text for the
43318334Speter   source file currently being converted.  */
43418334Speter
43518334Speterstatic const char *orig_text_base;
43618334Speter
43718334Speter/* Pointer to the byte just beyond the end of the input buffer that holds the
43818334Speter   original text for the source file currently being converted.  */
43918334Speter
44018334Speterstatic const char *orig_text_limit;
44118334Speter
44218334Speter/* Pointer to the base of the input buffer that holds the cleaned text for the
44318334Speter   source file currently being converted.  */
44418334Speter
44518334Speterstatic const char *clean_text_base;
44618334Speter
44718334Speter/* Pointer to the byte just beyond the end of the input buffer that holds the
44818334Speter   cleaned text for the source file currently being converted.  */
44918334Speter
45018334Speterstatic const char *clean_text_limit;
45118334Speter
45218334Speter/* Pointer to the last byte in the cleaned text buffer that we have already
45318334Speter   (virtually) copied to the output buffer (or decided to ignore).  */
45418334Speter
45518334Speterstatic const char * clean_read_ptr;
45618334Speter
45718334Speter/* Pointer to the base of the output buffer that holds the replacement text
45818334Speter   for the source file currently being converted.  */
45918334Speter
46018334Speterstatic char *repl_text_base;
46118334Speter
46218334Speter/* Pointer to the byte just beyond the end of the output buffer that holds the
46318334Speter   replacement text for the source file currently being converted.  */
46418334Speter
46518334Speterstatic char *repl_text_limit;
46618334Speter
46718334Speter/* Pointer to the last byte which has been stored into the output buffer.
46818334Speter   The next byte to be stored should be stored just past where this points
46918334Speter   to.  */
47018334Speter
47118334Speterstatic char * repl_write_ptr;
47218334Speter
47318334Speter/* Pointer into the cleaned text buffer for the source file we are currently
47418334Speter   converting.  This points to the first character of the line that we last
47518334Speter   did a "seek_to_line" to (see below).  */
47618334Speter
47718334Speterstatic const char *last_known_line_start;
47818334Speter
47918334Speter/* Number of the line (in the cleaned text buffer) that we last did a
48018334Speter   "seek_to_line" to.  Will be one if we just read a new source file
48118334Speter   into the cleaned text buffer.  */
48218334Speter
48318334Speterstatic int last_known_line_number;
48418334Speter
48518334Speter/* The filenames hash table.  */
48618334Speter
48718334Speterstatic hash_table filename_primary;
48818334Speter
48918334Speter/* The function names hash table.  */
49018334Speter
49118334Speterstatic hash_table function_name_primary;
49218334Speter
49318334Speter/* The place to keep the recovery address which is used only in cases where
49418334Speter   we get hopelessly confused by something in the cleaned original text.  */
49518334Speter
49618334Speterstatic jmp_buf source_confusion_recovery;
49718334Speter
49818334Speter/* A pointer to the current directory filename (used by abspath).  */
49918334Speter
50018334Speterstatic char *cwd_buffer;
50118334Speter
50218334Speter/* A place to save the read pointer until we are sure that an individual
50318334Speter   attempt at editing will succeed.  */
50418334Speter
50518334Speterstatic const char * saved_clean_read_ptr;
50618334Speter
50718334Speter/* A place to save the write pointer until we are sure that an individual
50818334Speter   attempt at editing will succeed.  */
50918334Speter
51018334Speterstatic char * saved_repl_write_ptr;
51118334Speter
51252284Sobrien/* Translate and output an error message.  */
51352284Sobrienstatic void
51490075Sobriennotice VPARAMS ((const char *msgid, ...))
51552284Sobrien{
51690075Sobrien  VA_OPEN (ap, msgid);
51790075Sobrien  VA_FIXEDARG (ap, const char *, msgid);
51852284Sobrien
51952284Sobrien  vfprintf (stderr, _(msgid), ap);
52090075Sobrien  VA_CLOSE (ap);
52152284Sobrien}
52252284Sobrien
52352284Sobrien
52418334Speter/* Make a copy of a string INPUT with size SIZE.  */
52518334Speter
52618334Speterstatic char *
52718334Spetersavestring (input, size)
52818334Speter     const char *input;
52918334Speter     unsigned int size;
53018334Speter{
53118334Speter  char *output = (char *) xmalloc (size + 1);
53218334Speter  strcpy (output, input);
53318334Speter  return output;
53418334Speter}
53518334Speter
53618334Speter/* More 'friendly' abort that prints the line and file.
53718334Speter   config.h can #define abort fancy_abort if you like that sort of thing.  */
53818334Speter
53918334Spetervoid
54018334Speterfancy_abort ()
54118334Speter{
54252284Sobrien  notice ("%s: internal abort\n", pname);
54350397Sobrien  exit (FATAL_EXIT_CODE);
54418334Speter}
54518334Speter
54618334Speter/* Make a duplicate of the first N bytes of a given string in a newly
54718334Speter   allocated area.  */
54818334Speter
54918334Speterstatic char *
55018334Speterdupnstr (s, n)
55118334Speter     const char *s;
55218334Speter     size_t n;
55318334Speter{
55418334Speter  char *ret_val = (char *) xmalloc (n + 1);
55518334Speter
55618334Speter  strncpy (ret_val, s, n);
55718334Speter  ret_val[n] = '\0';
55818334Speter  return ret_val;
55918334Speter}
56018334Speter
56118334Speter/* Return a pointer to the first occurrence of s2 within s1 or NULL if s2
56218334Speter   does not occur within s1.  Assume neither s1 nor s2 are null pointers.  */
56318334Speter
56418334Speterstatic const char *
56518334Spetersubstr (s1, s2)
56618334Speter     const char *s1;
56718334Speter     const char *const s2;
56818334Speter{
56918334Speter  for (; *s1 ; s1++)
57018334Speter    {
57118334Speter      const char *p1;
57218334Speter      const char *p2;
57318334Speter      int c;
57418334Speter
57550397Sobrien      for (p1 = s1, p2 = s2; (c = *p2); p1++, p2++)
576117395Skan	if (*p1 != c)
577117395Skan	  goto outer;
57818334Speter      return s1;
57918334Speterouter:
58018334Speter      ;
58118334Speter    }
58218334Speter  return 0;
58318334Speter}
58418334Speter
58518334Speter/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
58618334Speter   retrying if necessary.  Return the actual number of bytes read.  */
58718334Speter
58818334Speterstatic int
58918334Spetersafe_read (desc, ptr, len)
59018334Speter     int desc;
59190075Sobrien     PTR ptr;
59218334Speter     int len;
59318334Speter{
59418334Speter  int left = len;
59518334Speter  while (left > 0) {
59618334Speter    int nchars = read (desc, ptr, left);
59718334Speter    if (nchars < 0)
59818334Speter      {
59918334Speter#ifdef EINTR
60018334Speter	if (errno == EINTR)
60118334Speter	  continue;
60218334Speter#endif
60318334Speter	return nchars;
60418334Speter      }
60518334Speter    if (nchars == 0)
60618334Speter      break;
60790075Sobrien    /* Arithmetic on void pointers is a gcc extension.  */
60890075Sobrien    ptr = (char *) ptr + nchars;
60918334Speter    left -= nchars;
61018334Speter  }
61118334Speter  return len - left;
61218334Speter}
61318334Speter
61418334Speter/* Write LEN bytes at PTR to descriptor DESC,
61518334Speter   retrying if necessary, and treating any real error as fatal.  */
61618334Speter
61718334Speterstatic void
61818334Spetersafe_write (desc, ptr, len, out_fname)
61918334Speter     int desc;
62090075Sobrien     PTR ptr;
62118334Speter     int len;
62290075Sobrien     const char *out_fname;
62318334Speter{
62418334Speter  while (len > 0) {
62518334Speter    int written = write (desc, ptr, len);
62618334Speter    if (written < 0)
62718334Speter      {
62850397Sobrien	int errno_val = errno;
62918334Speter#ifdef EINTR
63050397Sobrien	if (errno_val == EINTR)
63118334Speter	  continue;
63218334Speter#endif
63352284Sobrien	notice ("%s: error writing file `%s': %s\n",
63452284Sobrien		pname, shortpath (NULL, out_fname), xstrerror (errno_val));
63518334Speter	return;
63618334Speter      }
63790075Sobrien    /* Arithmetic on void pointers is a gcc extension.  */
63890075Sobrien    ptr = (char *) ptr + written;
63918334Speter    len -= written;
64018334Speter  }
64118334Speter}
64218334Speter
64318334Speter/* Get setup to recover in case the edit we are about to do goes awry.  */
64418334Speter
64590075Sobrienstatic void
64618334Spetersave_pointers ()
64718334Speter{
64818334Speter  saved_clean_read_ptr = clean_read_ptr;
64918334Speter  saved_repl_write_ptr = repl_write_ptr;
65018334Speter}
65118334Speter
65218334Speter/* Call this routine to recover our previous state whenever something looks
65318334Speter   too confusing in the source code we are trying to edit.  */
65418334Speter
65590075Sobrienstatic void
65618334Speterrestore_pointers ()
65718334Speter{
65818334Speter  clean_read_ptr = saved_clean_read_ptr;
65918334Speter  repl_write_ptr = saved_repl_write_ptr;
66018334Speter}
66118334Speter
66218334Speter/* Return true if the given character is a valid identifier character.  */
66318334Speter
66418334Speterstatic int
66518334Speteris_id_char (ch)
66690075Sobrien     int ch;
66718334Speter{
66890075Sobrien  return (ISIDNUM (ch) || (ch == '$'));
66918334Speter}
67018334Speter
67118334Speter/* Give a message indicating the proper way to invoke this program and then
672117395Skan   exit with nonzero status.  */
67318334Speter
67418334Speterstatic void
67518334Speterusage ()
67618334Speter{
67718334Speter#ifdef UNPROTOIZE
67852284Sobrien  notice ("%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
67952284Sobrien	  pname, pname);
68018334Speter#else /* !defined (UNPROTOIZE) */
68152284Sobrien  notice ("%s: usage '%s [ -VqfnkNlgC ] [ -B <dirname> ] [ filename ... ]'\n",
68252284Sobrien	  pname, pname);
68318334Speter#endif /* !defined (UNPROTOIZE) */
68450397Sobrien  exit (FATAL_EXIT_CODE);
68518334Speter}
68618334Speter
68718334Speter/* Return true if the given filename (assumed to be an absolute filename)
68818334Speter   designates a file residing anywhere beneath any one of the "system"
68918334Speter   include directories.  */
69018334Speter
69118334Speterstatic int
69218334Speterin_system_include_dir (path)
69318334Speter     const char *path;
69418334Speter{
69590075Sobrien  const struct default_include *p;
69618334Speter
69790075Sobrien  if (! is_abspath (path))
69818334Speter    abort ();		/* Must be an absolutized filename.  */
69918334Speter
70096263Sobrien  for (p = cpp_include_defaults; p->fname; p++)
70118334Speter    if (!strncmp (path, p->fname, strlen (p->fname))
70290075Sobrien	&& IS_DIR_SEPARATOR (path[strlen (p->fname)]))
70318334Speter      return 1;
70418334Speter  return 0;
70518334Speter}
70618334Speter
70718334Speter#if 0
70818334Speter/* Return true if the given filename designates a file that the user has
70918334Speter   read access to and for which the user has write access to the containing
71018334Speter   directory.  */
71118334Speter
71218334Speterstatic int
71318334Speterfile_could_be_converted (const char *path)
71418334Speter{
71518334Speter  char *const dir_name = (char *) alloca (strlen (path) + 1);
71618334Speter
71790075Sobrien  if (access (path, R_OK))
71818334Speter    return 0;
71918334Speter
72018334Speter  {
72118334Speter    char *dir_last_slash;
72218334Speter
72318334Speter    strcpy (dir_name, path);
72490075Sobrien    dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
72590075Sobrien#ifdef DIR_SEPARATOR_2
72690075Sobrien    {
72790075Sobrien      char *slash;
72890075Sobrien
729117395Skan      slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
730117395Skan		       DIR_SEPARATOR_2);
73190075Sobrien      if (slash)
73290075Sobrien	dir_last_slash = slash;
73390075Sobrien    }
73490075Sobrien#endif
73518334Speter    if (dir_last_slash)
73618334Speter      *dir_last_slash = '\0';
73718334Speter    else
73818334Speter      abort ();  /* Should have been an absolutized filename.  */
73918334Speter  }
74018334Speter
74190075Sobrien  if (access (path, W_OK))
74218334Speter    return 0;
74318334Speter
74418334Speter  return 1;
74518334Speter}
74618334Speter
74718334Speter/* Return true if the given filename designates a file that we are allowed
74818334Speter   to modify.  Files which we should not attempt to modify are (a) "system"
74918334Speter   include files, and (b) files which the user doesn't have write access to,
75018334Speter   and (c) files which reside in directories which the user doesn't have
75118334Speter   write access to.  Unless requested to be quiet, give warnings about
75218334Speter   files that we will not try to convert for one reason or another.  An
75318334Speter   exception is made for "system" include files, which we never try to
75418334Speter   convert and for which we don't issue the usual warnings.  */
75518334Speter
75618334Speterstatic int
75718334Speterfile_normally_convertible (const char *path)
75818334Speter{
75918334Speter  char *const dir_name = alloca (strlen (path) + 1);
76018334Speter
76118334Speter  if (in_system_include_dir (path))
76218334Speter    return 0;
76318334Speter
76418334Speter  {
76518334Speter    char *dir_last_slash;
76618334Speter
76718334Speter    strcpy (dir_name, path);
76890075Sobrien    dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
76990075Sobrien#ifdef DIR_SEPARATOR_2
77090075Sobrien    {
77190075Sobrien      char *slash;
77290075Sobrien
773117395Skan      slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
774117395Skan		       DIR_SEPARATOR_2);
77590075Sobrien      if (slash)
77690075Sobrien	dir_last_slash = slash;
77790075Sobrien    }
77890075Sobrien#endif
77918334Speter    if (dir_last_slash)
78018334Speter      *dir_last_slash = '\0';
78118334Speter    else
78218334Speter      abort ();  /* Should have been an absolutized filename.  */
78318334Speter  }
78418334Speter
78590075Sobrien  if (access (path, R_OK))
78618334Speter    {
78718334Speter      if (!quiet_flag)
788117395Skan	notice ("%s: warning: no read access for file `%s'\n",
78952284Sobrien		pname, shortpath (NULL, path));
79018334Speter      return 0;
79118334Speter    }
79218334Speter
79390075Sobrien  if (access (path, W_OK))
79418334Speter    {
79518334Speter      if (!quiet_flag)
796117395Skan	notice ("%s: warning: no write access for file `%s'\n",
79752284Sobrien		pname, shortpath (NULL, path));
79818334Speter      return 0;
79918334Speter    }
80018334Speter
80190075Sobrien  if (access (dir_name, W_OK))
80218334Speter    {
80318334Speter      if (!quiet_flag)
804117395Skan	notice ("%s: warning: no write access for dir containing `%s'\n",
80552284Sobrien		pname, shortpath (NULL, path));
80618334Speter      return 0;
80718334Speter    }
80818334Speter
80918334Speter  return 1;
81018334Speter}
81118334Speter#endif /* 0 */
81218334Speter
81318334Speter#ifndef UNPROTOIZE
81418334Speter
81518334Speter/* Return true if the given file_info struct refers to the special SYSCALLS.c.X
81618334Speter   file.  Return false otherwise.  */
81718334Speter
81818334Speterstatic int
81918334Speteris_syscalls_file (fi_p)
82018334Speter     const file_info *fi_p;
82118334Speter{
82218334Speter  char const *f = fi_p->hash_entry->symbol;
82318334Speter  size_t fl = strlen (f), sysl = sizeof (syscalls_filename) - 1;
82418334Speter  return sysl <= fl  &&  strcmp (f + fl - sysl, syscalls_filename) == 0;
82518334Speter}
82618334Speter
82718334Speter#endif /* !defined (UNPROTOIZE) */
82818334Speter
82918334Speter/* Check to see if this file will need to have anything done to it on this
83018334Speter   run.  If there is nothing in the given file which both needs conversion
83118334Speter   and for which we have the necessary stuff to do the conversion, return
83218334Speter   false.  Otherwise, return true.
83318334Speter
83418334Speter   Note that (for protoize) it is only valid to call this function *after*
83518334Speter   the connections between declarations and definitions have all been made
83618334Speter   by connect_defs_and_decs.  */
83718334Speter
83818334Speterstatic int
83918334Speterneeds_to_be_converted (file_p)
84018334Speter     const file_info *file_p;
84118334Speter{
84218334Speter  const def_dec_info *ddp;
84318334Speter
84418334Speter#ifndef UNPROTOIZE
84518334Speter
84618334Speter  if (is_syscalls_file (file_p))
84718334Speter    return 0;
84818334Speter
84918334Speter#endif /* !defined (UNPROTOIZE) */
85018334Speter
85118334Speter  for (ddp = file_p->defs_decs; ddp; ddp = ddp->next_in_file)
85218334Speter
85318334Speter    if (
85418334Speter
85518334Speter#ifndef UNPROTOIZE
85618334Speter
85750397Sobrien      /* ... and if we a protoizing and this function is in old style ...  */
85818334Speter      !ddp->prototyped
85950397Sobrien      /* ... and if this a definition or is a decl with an associated def ...  */
86018334Speter      && (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
86118334Speter
86218334Speter#else /* defined (UNPROTOIZE) */
86318334Speter
86450397Sobrien      /* ... and if we are unprotoizing and this function is in new style ...  */
86518334Speter      ddp->prototyped
86618334Speter
86718334Speter#endif /* defined (UNPROTOIZE) */
86818334Speter      )
869117395Skan	  /* ... then the containing file needs converting.  */
870117395Skan	  return -1;
87118334Speter  return 0;
87218334Speter}
87318334Speter
87418334Speter/* Return 1 if the file name NAME is in a directory
87518334Speter   that should be converted.  */
87618334Speter
87718334Speterstatic int
87818334Speterdirectory_specified_p (name)
87918334Speter     const char *name;
88018334Speter{
88118334Speter  struct string_list *p;
88218334Speter
88318334Speter  for (p = directory_list; p; p = p->next)
88418334Speter    if (!strncmp (name, p->name, strlen (p->name))
88590075Sobrien	&& IS_DIR_SEPARATOR (name[strlen (p->name)]))
88618334Speter      {
88718334Speter	const char *q = name + strlen (p->name) + 1;
88818334Speter
88918334Speter	/* If there are more slashes, it's in a subdir, so
89018334Speter	   this match doesn't count.  */
89190075Sobrien	while (*q++)
89290075Sobrien	  if (IS_DIR_SEPARATOR (*(q-1)))
89318334Speter	    goto lose;
89418334Speter	return 1;
89518334Speter
89618334Speter      lose: ;
89718334Speter      }
89818334Speter
89918334Speter  return 0;
90018334Speter}
90118334Speter
90218334Speter/* Return 1 if the file named NAME should be excluded from conversion.  */
90318334Speter
90418334Speterstatic int
90518334Speterfile_excluded_p (name)
90618334Speter     const char *name;
90718334Speter{
90818334Speter  struct string_list *p;
90918334Speter  int len = strlen (name);
91018334Speter
91118334Speter  for (p = exclude_list; p; p = p->next)
91218334Speter    if (!strcmp (name + len - strlen (p->name), p->name)
91390075Sobrien	&& IS_DIR_SEPARATOR (name[len - strlen (p->name) - 1]))
91418334Speter      return 1;
91518334Speter
91618334Speter  return 0;
91718334Speter}
91818334Speter
91918334Speter/* Construct a new element of a string_list.
92018334Speter   STRING is the new element value, and REST holds the remaining elements.  */
92118334Speter
92218334Speterstatic struct string_list *
92318334Speterstring_list_cons (string, rest)
92490075Sobrien     const char *string;
92518334Speter     struct string_list *rest;
92618334Speter{
92718334Speter  struct string_list *temp
92818334Speter    = (struct string_list *) xmalloc (sizeof (struct string_list));
92918334Speter
93018334Speter  temp->next = rest;
93118334Speter  temp->name = string;
93218334Speter  return temp;
93318334Speter}
93418334Speter
93518334Speter/* ??? The GNU convention for mentioning function args in its comments
93618334Speter   is to capitalize them.  So change "hash_tab_p" to HASH_TAB_P below.
93718334Speter   Likewise for all the other functions.  */
93818334Speter
93918334Speter/* Given a hash table, apply some function to each node in the table. The
94018334Speter   table to traverse is given as the "hash_tab_p" argument, and the
94118334Speter   function to be applied to each node in the table is given as "func"
94218334Speter   argument.  */
94318334Speter
94418334Speterstatic void
94518334Spetervisit_each_hash_node (hash_tab_p, func)
94618334Speter     const hash_table_entry *hash_tab_p;
94790075Sobrien     void (*func) PARAMS ((const hash_table_entry *));
94818334Speter{
94918334Speter  const hash_table_entry *primary;
95018334Speter
95118334Speter  for (primary = hash_tab_p; primary < &hash_tab_p[HASH_TABLE_SIZE]; primary++)
95218334Speter    if (primary->symbol)
95318334Speter      {
954117395Skan	hash_table_entry *second;
95518334Speter
956117395Skan	(*func)(primary);
957117395Skan	for (second = primary->hash_next; second; second = second->hash_next)
958117395Skan	  (*func) (second);
95918334Speter      }
96018334Speter}
96118334Speter
96218334Speter/* Initialize all of the fields of a new hash table entry, pointed
96318334Speter   to by the "p" parameter.  Note that the space to hold the entry
96418334Speter   is assumed to have already been allocated before this routine is
96518334Speter   called.  */
96618334Speter
96718334Speterstatic hash_table_entry *
96818334Speteradd_symbol (p, s)
96918334Speter     hash_table_entry *p;
97018334Speter     const char *s;
97118334Speter{
97218334Speter  p->hash_next = NULL;
97390075Sobrien  p->symbol = xstrdup (s);
97418334Speter  p->ddip = NULL;
97518334Speter  p->fip = NULL;
97618334Speter  return p;
97718334Speter}
97818334Speter
97918334Speter/* Look for a particular function name or filename in the particular
98018334Speter   hash table indicated by "hash_tab_p".  If the name is not in the
98118334Speter   given hash table, add it.  Either way, return a pointer to the
98218334Speter   hash table entry for the given name.  */
98318334Speter
98418334Speterstatic hash_table_entry *
98518334Speterlookup (hash_tab_p, search_symbol)
98618334Speter     hash_table_entry *hash_tab_p;
98718334Speter     const char *search_symbol;
98818334Speter{
98918334Speter  int hash_value = 0;
99018334Speter  const char *search_symbol_char_p = search_symbol;
99118334Speter  hash_table_entry *p;
99218334Speter
99318334Speter  while (*search_symbol_char_p)
99418334Speter    hash_value += *search_symbol_char_p++;
99518334Speter  hash_value &= hash_mask;
99618334Speter  p = &hash_tab_p[hash_value];
99718334Speter  if (! p->symbol)
99818334Speter      return add_symbol (p, search_symbol);
99918334Speter  if (!strcmp (p->symbol, search_symbol))
100018334Speter    return p;
100118334Speter  while (p->hash_next)
100218334Speter    {
100318334Speter      p = p->hash_next;
100418334Speter      if (!strcmp (p->symbol, search_symbol))
1005117395Skan	return p;
100618334Speter    }
100718334Speter  p->hash_next = (hash_table_entry *) xmalloc (sizeof (hash_table_entry));
100818334Speter  p = p->hash_next;
100918334Speter  return add_symbol (p, search_symbol);
101018334Speter}
101118334Speter
101218334Speter/* Throw a def/dec record on the junk heap.
101318334Speter
101418334Speter   Also, since we are not using this record anymore, free up all of the
101518334Speter   stuff it pointed to.  */
101618334Speter
101718334Speterstatic void
101818334Speterfree_def_dec (p)
101918334Speter     def_dec_info *p;
102018334Speter{
102190075Sobrien  free ((NONCONST PTR) p->ansi_decl);
102218334Speter
102318334Speter#ifndef UNPROTOIZE
102418334Speter  {
102518334Speter    const f_list_chain_item * curr;
102618334Speter    const f_list_chain_item * next;
102718334Speter
102818334Speter    for (curr = p->f_list_chain; curr; curr = next)
102918334Speter      {
1030117395Skan	next = curr->chain_next;
1031117395Skan	free ((NONCONST PTR) curr);
103218334Speter      }
103318334Speter  }
103418334Speter#endif /* !defined (UNPROTOIZE) */
103518334Speter
103690075Sobrien  free (p);
103718334Speter}
103818334Speter
103918334Speter/* Unexpand as many macro symbol as we can find.
104018334Speter
104118334Speter   If the given line must be unexpanded, make a copy of it in the heap and
104218334Speter   return a pointer to the unexpanded copy.  Otherwise return NULL.  */
104318334Speter
104418334Speterstatic char *
104518334Speterunexpand_if_needed (aux_info_line)
104618334Speter     const char *aux_info_line;
104718334Speter{
104818334Speter  static char *line_buf = 0;
104918334Speter  static int line_buf_size = 0;
105050397Sobrien  const unexpansion *unexp_p;
105118334Speter  int got_unexpanded = 0;
105218334Speter  const char *s;
105318334Speter  char *copy_p = line_buf;
105418334Speter
105518334Speter  if (line_buf == 0)
105618334Speter    {
105718334Speter      line_buf_size = 1024;
105818334Speter      line_buf = (char *) xmalloc (line_buf_size);
105918334Speter    }
106018334Speter
106118334Speter  copy_p = line_buf;
106218334Speter
106318334Speter  /* Make a copy of the input string in line_buf, expanding as necessary.  */
106418334Speter
106518334Speter  for (s = aux_info_line; *s != '\n'; )
106618334Speter    {
106718334Speter      for (unexp_p = unexpansions; unexp_p->expanded; unexp_p++)
1068117395Skan	{
1069117395Skan	  const char *in_p = unexp_p->expanded;
1070117395Skan	  size_t len = strlen (in_p);
107118334Speter
1072117395Skan	  if (*s == *in_p && !strncmp (s, in_p, len) && !is_id_char (s[len]))
1073117395Skan	    {
107418334Speter	      int size = strlen (unexp_p->contracted);
1075117395Skan	      got_unexpanded = 1;
107618334Speter	      if (copy_p + size - line_buf >= line_buf_size)
107718334Speter		{
107818334Speter		  int offset = copy_p - line_buf;
107918334Speter		  line_buf_size *= 2;
108018334Speter		  line_buf_size += size;
108118334Speter		  line_buf = (char *) xrealloc (line_buf, line_buf_size);
108218334Speter		  copy_p = line_buf + offset;
108318334Speter		}
1084117395Skan	      strcpy (copy_p, unexp_p->contracted);
1085117395Skan	      copy_p += size;
108618334Speter
1087117395Skan	      /* Assume that there will not be another replacement required
1088117395Skan	         within the text just replaced.  */
108918334Speter
1090117395Skan	      s += len;
1091117395Skan	      goto continue_outer;
1092117395Skan	    }
1093117395Skan	}
109418334Speter      if (copy_p - line_buf == line_buf_size)
109518334Speter	{
109618334Speter	  int offset = copy_p - line_buf;
109718334Speter	  line_buf_size *= 2;
109818334Speter	  line_buf = (char *) xrealloc (line_buf, line_buf_size);
109918334Speter	  copy_p = line_buf + offset;
110018334Speter	}
110118334Speter      *copy_p++ = *s++;
110218334Spetercontinue_outer: ;
110318334Speter    }
110418334Speter  if (copy_p + 2 - line_buf >= line_buf_size)
110518334Speter    {
110618334Speter      int offset = copy_p - line_buf;
110718334Speter      line_buf_size *= 2;
110818334Speter      line_buf = (char *) xrealloc (line_buf, line_buf_size);
110918334Speter      copy_p = line_buf + offset;
111018334Speter    }
111118334Speter  *copy_p++ = '\n';
111218334Speter  *copy_p = '\0';
111318334Speter
111418334Speter  return (got_unexpanded ? savestring (line_buf, copy_p - line_buf) : 0);
111518334Speter}
111618334Speter
111790075Sobrien/* Return 1 if pathname is absolute.  */
111890075Sobrien
111990075Sobrienstatic int
112090075Sobrienis_abspath (path)
112190075Sobrien     const char *path;
112290075Sobrien{
112390075Sobrien  return (IS_DIR_SEPARATOR (path[0])
112490075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1125117395Skan	  /* Check for disk name on MS-DOS-based systems.  */
1126117395Skan	  || (path[0] && path[1] == ':' && IS_DIR_SEPARATOR (path[2]))
112790075Sobrien#endif
1128117395Skan	  );
112990075Sobrien}
113090075Sobrien
113118334Speter/* Return the absolutized filename for the given relative
113218334Speter   filename.  Note that if that filename is already absolute, it may
113318334Speter   still be returned in a modified form because this routine also
113418334Speter   eliminates redundant slashes and single dots and eliminates double
113518334Speter   dots to get a shortest possible filename from the given input
113618334Speter   filename.  The absolutization of relative filenames is made by
113718334Speter   assuming that the given filename is to be taken as relative to
113818334Speter   the first argument (cwd) or to the current directory if cwd is
113918334Speter   NULL.  */
114018334Speter
114118334Speterstatic char *
114218334Speterabspath (cwd, rel_filename)
114318334Speter     const char *cwd;
114418334Speter     const char *rel_filename;
114518334Speter{
114618334Speter  /* Setup the current working directory as needed.  */
114790075Sobrien  const char *const cwd2 = (cwd) ? cwd : cwd_buffer;
114818334Speter  char *const abs_buffer
114918334Speter    = (char *) alloca (strlen (cwd2) + strlen (rel_filename) + 2);
115018334Speter  char *endp = abs_buffer;
115118334Speter  char *outp, *inp;
115218334Speter
115318334Speter  /* Copy the  filename (possibly preceded by the current working
115418334Speter     directory name) into the absolutization buffer.  */
115518334Speter
115618334Speter  {
115718334Speter    const char *src_p;
115818334Speter
115990075Sobrien    if (! is_abspath (rel_filename))
116018334Speter      {
1161117395Skan	src_p = cwd2;
1162117395Skan	while ((*endp++ = *src_p++))
1163117395Skan	  continue;
1164117395Skan	*(endp-1) = DIR_SEPARATOR;     		/* overwrite null */
116518334Speter      }
116690075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
116790075Sobrien    else if (IS_DIR_SEPARATOR (rel_filename[0]))
116890075Sobrien      {
1169117395Skan	/* A path starting with a directory separator is considered absolute
1170117395Skan	   for dos based filesystems, but it's really not -- it's just the
117190075Sobrien	   convention used throughout GCC and it works. However, in this
117290075Sobrien	   case, we still need to prepend the drive spec from cwd_buffer.  */
117390075Sobrien	*endp++ = cwd2[0];
117490075Sobrien	*endp++ = cwd2[1];
117590075Sobrien      }
117690075Sobrien#endif
117718334Speter    src_p = rel_filename;
117850397Sobrien    while ((*endp++ = *src_p++))
117918334Speter      continue;
118018334Speter  }
118118334Speter
118218334Speter  /* Now make a copy of abs_buffer into abs_buffer, shortening the
118318334Speter     filename (by taking out slashes and dots) as we go.  */
118418334Speter
118518334Speter  outp = inp = abs_buffer;
118618334Speter  *outp++ = *inp++;        	/* copy first slash */
118752284Sobrien#if defined (apollo) || defined (_WIN32) || defined (__INTERIX)
118890075Sobrien  if (IS_DIR_SEPARATOR (inp[0]))
118918334Speter    *outp++ = *inp++;        	/* copy second slash */
119018334Speter#endif
119118334Speter  for (;;)
119218334Speter    {
119318334Speter      if (!inp[0])
1194117395Skan	break;
119590075Sobrien      else if (IS_DIR_SEPARATOR (inp[0]) && IS_DIR_SEPARATOR (outp[-1]))
1196117395Skan	{
1197117395Skan	  inp++;
1198117395Skan	  continue;
1199117395Skan	}
120090075Sobrien      else if (inp[0] == '.' && IS_DIR_SEPARATOR (outp[-1]))
1201117395Skan	{
1202117395Skan	  if (!inp[1])
1203117395Skan	    break;
1204117395Skan	  else if (IS_DIR_SEPARATOR (inp[1]))
1205117395Skan	    {
1206117395Skan	      inp += 2;
1207117395Skan	      continue;
1208117395Skan	    }
1209117395Skan	  else if ((inp[1] == '.') && (inp[2] == 0
121090075Sobrien	                               || IS_DIR_SEPARATOR (inp[2])))
1211117395Skan	    {
1212117395Skan	      inp += (IS_DIR_SEPARATOR (inp[2])) ? 3 : 2;
1213117395Skan	      outp -= 2;
1214117395Skan	      while (outp >= abs_buffer && ! IS_DIR_SEPARATOR (*outp))
1215117395Skan	      	outp--;
1216117395Skan	      if (outp < abs_buffer)
1217117395Skan		{
1218117395Skan		  /* Catch cases like /.. where we try to backup to a
1219117395Skan		     point above the absolute root of the logical file
1220117395Skan		     system.  */
122118334Speter
1222117395Skan		  notice ("%s: invalid file name: %s\n",
1223117395Skan			  pname, rel_filename);
1224117395Skan		  exit (FATAL_EXIT_CODE);
1225117395Skan		}
1226117395Skan	      *++outp = '\0';
1227117395Skan	      continue;
1228117395Skan	    }
1229117395Skan	}
123018334Speter      *outp++ = *inp++;
123118334Speter    }
123218334Speter
123318334Speter  /* On exit, make sure that there is a trailing null, and make sure that
123418334Speter     the last character of the returned string is *not* a slash.  */
123518334Speter
123618334Speter  *outp = '\0';
123790075Sobrien  if (IS_DIR_SEPARATOR (outp[-1]))
123818334Speter    *--outp  = '\0';
123918334Speter
124018334Speter  /* Make a copy (in the heap) of the stuff left in the absolutization
124118334Speter     buffer and return a pointer to the copy.  */
124218334Speter
124318334Speter  return savestring (abs_buffer, outp - abs_buffer);
124418334Speter}
124518334Speter
124618334Speter/* Given a filename (and possibly a directory name from which the filename
124718334Speter   is relative) return a string which is the shortest possible
124818334Speter   equivalent for the corresponding full (absolutized) filename.  The
124918334Speter   shortest possible equivalent may be constructed by converting the
125018334Speter   absolutized filename to be a relative filename (i.e. relative to
125118334Speter   the actual current working directory).  However if a relative filename
125218334Speter   is longer, then the full absolute filename is returned.
125318334Speter
125418334Speter   KNOWN BUG:
125518334Speter
125618334Speter   Note that "simple-minded" conversion of any given type of filename (either
125718334Speter   relative or absolute) may not result in a valid equivalent filename if any
125818334Speter   subpart of the original filename is actually a symbolic link.  */
125918334Speter
126018334Speterstatic const char *
126118334Spetershortpath (cwd, filename)
126218334Speter     const char *cwd;
126318334Speter     const char *filename;
126418334Speter{
126518334Speter  char *rel_buffer;
126618334Speter  char *rel_buf_p;
126718334Speter  char *cwd_p = cwd_buffer;
126818334Speter  char *path_p;
126918334Speter  int unmatched_slash_count = 0;
127018334Speter  size_t filename_len = strlen (filename);
127118334Speter
127218334Speter  path_p = abspath (cwd, filename);
127318334Speter  rel_buf_p = rel_buffer = (char *) xmalloc (filename_len);
127418334Speter
127590075Sobrien  while (*cwd_p && IS_SAME_PATH_CHAR (*cwd_p, *path_p))
127618334Speter    {
127718334Speter      cwd_p++;
127818334Speter      path_p++;
127918334Speter    }
128090075Sobrien  if (!*cwd_p && (!*path_p || IS_DIR_SEPARATOR (*path_p)))
128118334Speter    {
128290075Sobrien      /* whole pwd matched */
128318334Speter      if (!*path_p)        	/* input *is* the current path! */
1284117395Skan	return ".";
128518334Speter      else
1286117395Skan	return ++path_p;
128718334Speter    }
128818334Speter  else
128918334Speter    {
129018334Speter      if (*path_p)
1291117395Skan	{
1292117395Skan	  --cwd_p;
1293117395Skan	  --path_p;
1294117395Skan	  while (! IS_DIR_SEPARATOR (*cwd_p))     /* backup to last slash */
1295117395Skan	    {
1296117395Skan	      --cwd_p;
1297117395Skan	      --path_p;
1298117395Skan	    }
1299117395Skan	  cwd_p++;
1300117395Skan	  path_p++;
1301117395Skan	  unmatched_slash_count++;
1302117395Skan	}
130318334Speter
130418334Speter      /* Find out how many directory levels in cwd were *not* matched.  */
130590075Sobrien      while (*cwd_p++)
1306117395Skan	if (IS_DIR_SEPARATOR (*(cwd_p-1)))
130718334Speter	  unmatched_slash_count++;
130818334Speter
130918334Speter      /* Now we know how long the "short name" will be.
131018334Speter	 Reject it if longer than the input.  */
131118334Speter      if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
131218334Speter	return filename;
131318334Speter
131418334Speter      /* For each of them, put a `../' at the beginning of the short name.  */
131518334Speter      while (unmatched_slash_count--)
1316117395Skan	{
131718334Speter	  /* Give up if the result gets to be longer
131818334Speter	     than the absolute path name.  */
131918334Speter	  if (rel_buffer + filename_len <= rel_buf_p + 3)
132018334Speter	    return filename;
1321117395Skan	  *rel_buf_p++ = '.';
1322117395Skan	  *rel_buf_p++ = '.';
1323117395Skan	  *rel_buf_p++ = DIR_SEPARATOR;
1324117395Skan	}
132518334Speter
132618334Speter      /* Then tack on the unmatched part of the desired file's name.  */
132718334Speter      do
132818334Speter	{
132918334Speter	  if (rel_buffer + filename_len <= rel_buf_p)
133018334Speter	    return filename;
133118334Speter	}
133250397Sobrien      while ((*rel_buf_p++ = *path_p++));
133318334Speter
133418334Speter      --rel_buf_p;
133590075Sobrien      if (IS_DIR_SEPARATOR (*(rel_buf_p-1)))
1336117395Skan	*--rel_buf_p = '\0';
133718334Speter      return rel_buffer;
133818334Speter    }
133918334Speter}
134018334Speter
134118334Speter/* Lookup the given filename in the hash table for filenames.  If it is a
134218334Speter   new one, then the hash table info pointer will be null.  In this case,
134318334Speter   we create a new file_info record to go with the filename, and we initialize
134418334Speter   that record with some reasonable values.  */
134518334Speter
134618334Speter/* FILENAME was const, but that causes a warning on AIX when calling stat.
134718334Speter   That is probably a bug in AIX, but might as well avoid the warning.  */
134818334Speter
134918334Speterstatic file_info *
135018334Speterfind_file (filename, do_not_stat)
135190075Sobrien     const char *filename;
135218334Speter     int do_not_stat;
135318334Speter{
135418334Speter  hash_table_entry *hash_entry_p;
135518334Speter
135618334Speter  hash_entry_p = lookup (filename_primary, filename);
135718334Speter  if (hash_entry_p->fip)
135818334Speter    return hash_entry_p->fip;
135918334Speter  else
136018334Speter    {
136118334Speter      struct stat stat_buf;
136218334Speter      file_info *file_p = (file_info *) xmalloc (sizeof (file_info));
136318334Speter
136418334Speter      /* If we cannot get status on any given source file, give a warning
1365117395Skan	 and then just set its time of last modification to infinity.  */
136618334Speter
136718334Speter      if (do_not_stat)
1368117395Skan	stat_buf.st_mtime = (time_t) 0;
136918334Speter      else
1370117395Skan	{
1371117395Skan	  if (stat (filename, &stat_buf) == -1)
1372117395Skan	    {
137350397Sobrien	      int errno_val = errno;
1374117395Skan	      notice ("%s: %s: can't get status: %s\n",
137552284Sobrien		      pname, shortpath (NULL, filename),
137652284Sobrien		      xstrerror (errno_val));
1377117395Skan	      stat_buf.st_mtime = (time_t) -1;
1378117395Skan	    }
1379117395Skan	}
138018334Speter
138118334Speter      hash_entry_p->fip = file_p;
138218334Speter      file_p->hash_entry = hash_entry_p;
138318334Speter      file_p->defs_decs = NULL;
138418334Speter      file_p->mtime = stat_buf.st_mtime;
138518334Speter      return file_p;
138618334Speter    }
138718334Speter}
138818334Speter
138918334Speter/* Generate a fatal error because some part of the aux_info file is
139018334Speter   messed up.  */
139118334Speter
139218334Speterstatic void
139318334Speteraux_info_corrupted ()
139418334Speter{
139552284Sobrien  notice ("\n%s: fatal error: aux info file corrupted at line %d\n",
139652284Sobrien	  pname, current_aux_info_lineno);
139750397Sobrien  exit (FATAL_EXIT_CODE);
139818334Speter}
139918334Speter
140018334Speter/* ??? This comment is vague.  Say what the condition is for.  */
140118334Speter/* Check to see that a condition is true.  This is kind of like an assert.  */
140218334Speter
140318334Speterstatic void
140418334Spetercheck_aux_info (cond)
140518334Speter     int cond;
140618334Speter{
140718334Speter  if (! cond)
140818334Speter    aux_info_corrupted ();
140918334Speter}
141018334Speter
141118334Speter/* Given a pointer to the closing right parenthesis for a particular formals
141218334Speter   list (in an aux_info file) find the corresponding left parenthesis and
141318334Speter   return a pointer to it.  */
141418334Speter
141518334Speterstatic const char *
141618334Speterfind_corresponding_lparen (p)
141718334Speter     const char *p;
141818334Speter{
141918334Speter  const char *q;
142018334Speter  int paren_depth;
142118334Speter
142218334Speter  for (paren_depth = 1, q = p-1; paren_depth; q--)
142318334Speter    {
142418334Speter      switch (*q)
1425117395Skan	{
1426117395Skan	case ')':
1427117395Skan	  paren_depth++;
1428117395Skan	  break;
1429117395Skan	case '(':
1430117395Skan	  paren_depth--;
1431117395Skan	  break;
1432117395Skan	}
143318334Speter    }
143418334Speter  return ++q;
143518334Speter}
143618334Speter
143718334Speter/* Given a line from  an aux info file, and a time at which the aux info
143818334Speter   file it came from was created, check to see if the item described in
143918334Speter   the line comes from a file which has been modified since the aux info
1440117395Skan   file was created.  If so, return nonzero, else return zero.  */
144118334Speter
144218334Speterstatic int
144318334Speterreferenced_file_is_newer (l, aux_info_mtime)
144418334Speter     const char *l;
144518334Speter     time_t aux_info_mtime;
144618334Speter{
144718334Speter  const char *p;
144818334Speter  file_info *fi_p;
144918334Speter  char *filename;
145018334Speter
145118334Speter  check_aux_info (l[0] == '/');
145218334Speter  check_aux_info (l[1] == '*');
145318334Speter  check_aux_info (l[2] == ' ');
145418334Speter
145518334Speter  {
145618334Speter    const char *filename_start = p = l + 3;
145718334Speter
145890075Sobrien    while (*p != ':'
145990075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1460117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
146190075Sobrien#endif
1462117395Skan	   )
146318334Speter      p++;
146418334Speter    filename = (char *) alloca ((size_t) (p - filename_start) + 1);
146518334Speter    strncpy (filename, filename_start, (size_t) (p - filename_start));
146618334Speter    filename[p-filename_start] = '\0';
146718334Speter  }
146818334Speter
146918334Speter  /* Call find_file to find the file_info record associated with the file
147018334Speter     which contained this particular def or dec item.  Note that this call
147118334Speter     may cause a new file_info record to be created if this is the first time
147218334Speter     that we have ever known about this particular file.  */
147318334Speter
147418334Speter  fi_p = find_file (abspath (invocation_filename, filename), 0);
147518334Speter
147618334Speter  return (fi_p->mtime > aux_info_mtime);
147718334Speter}
147818334Speter
147918334Speter/* Given a line of info from the aux_info file, create a new
148018334Speter   def_dec_info record to remember all of the important information about
148118334Speter   a function definition or declaration.
148218334Speter
148318334Speter   Link this record onto the list of such records for the particular file in
148418334Speter   which it occurred in proper (descending) line number order (for now).
148518334Speter
148618334Speter   If there is an identical record already on the list for the file, throw
148718334Speter   this one away.  Doing so takes care of the (useless and troublesome)
148818334Speter   duplicates which are bound to crop up due to multiple inclusions of any
148918334Speter   given individual header file.
149018334Speter
149118334Speter   Finally, link the new def_dec record onto the list of such records
149218334Speter   pertaining to this particular function name.  */
149318334Speter
149418334Speterstatic void
149518334Spetersave_def_or_dec (l, is_syscalls)
149618334Speter     const char *l;
149718334Speter     int is_syscalls;
149818334Speter{
149918334Speter  const char *p;
150018334Speter  const char *semicolon_p;
150118334Speter  def_dec_info *def_dec_p = (def_dec_info *) xmalloc (sizeof (def_dec_info));
150218334Speter
150318334Speter#ifndef UNPROTOIZE
150418334Speter  def_dec_p->written = 0;
150518334Speter#endif /* !defined (UNPROTOIZE) */
150618334Speter
150718334Speter  /* Start processing the line by picking off 5 pieces of information from
150818334Speter     the left hand end of the line.  These are filename, line number,
150918334Speter     new/old/implicit flag (new = ANSI prototype format), definition or
151018334Speter     declaration flag, and extern/static flag).  */
151118334Speter
151218334Speter  check_aux_info (l[0] == '/');
151318334Speter  check_aux_info (l[1] == '*');
151418334Speter  check_aux_info (l[2] == ' ');
151518334Speter
151618334Speter  {
151718334Speter    const char *filename_start = p = l + 3;
151818334Speter    char *filename;
151918334Speter
152090075Sobrien    while (*p != ':'
152190075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1522117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
152390075Sobrien#endif
1524117395Skan	   )
152518334Speter      p++;
152618334Speter    filename = (char *) alloca ((size_t) (p - filename_start) + 1);
152718334Speter    strncpy (filename, filename_start, (size_t) (p - filename_start));
152818334Speter    filename[p-filename_start] = '\0';
152918334Speter
153018334Speter    /* Call find_file to find the file_info record associated with the file
153118334Speter       which contained this particular def or dec item.  Note that this call
153218334Speter       may cause a new file_info record to be created if this is the first time
153318334Speter       that we have ever known about this particular file.
1534117395Skan
153518334Speter       Note that we started out by forcing all of the base source file names
153618334Speter       (i.e. the names of the aux_info files with the .X stripped off) into the
153718334Speter       filenames hash table, and we simultaneously setup file_info records for
153818334Speter       all of these base file names (even if they may be useless later).
153918334Speter       The file_info records for all of these "base" file names (properly)
154018334Speter       act as file_info records for the "original" (i.e. un-included) files
154118334Speter       which were submitted to gcc for compilation (when the -aux-info
154218334Speter       option was used).  */
1543117395Skan
154418334Speter    def_dec_p->file = find_file (abspath (invocation_filename, filename), is_syscalls);
154518334Speter  }
154618334Speter
154718334Speter  {
154818334Speter    const char *line_number_start = ++p;
154918334Speter    char line_number[10];
155018334Speter
155190075Sobrien    while (*p != ':'
155290075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
1553117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
155490075Sobrien#endif
1555117395Skan	   )
155618334Speter      p++;
155718334Speter    strncpy (line_number, line_number_start, (size_t) (p - line_number_start));
155818334Speter    line_number[p-line_number_start] = '\0';
155918334Speter    def_dec_p->line = atoi (line_number);
156018334Speter  }
156118334Speter
156218334Speter  /* Check that this record describes a new-style, old-style, or implicit
156318334Speter     definition or declaration.  */
156418334Speter
156550397Sobrien  p++;	/* Skip over the `:'.  */
156618334Speter  check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
156718334Speter
156818334Speter  /* Is this a new style (ANSI prototyped) definition or declaration? */
156918334Speter
157018334Speter  def_dec_p->prototyped = (*p == 'N');
157118334Speter
157218334Speter#ifndef UNPROTOIZE
157318334Speter
157418334Speter  /* Is this an implicit declaration? */
157518334Speter
157618334Speter  def_dec_p->is_implicit = (*p == 'I');
157718334Speter
157818334Speter#endif /* !defined (UNPROTOIZE) */
157918334Speter
158018334Speter  p++;
158118334Speter
158218334Speter  check_aux_info ((*p == 'C') || (*p == 'F'));
158318334Speter
158418334Speter  /* Is this item a function definition (F) or a declaration (C).  Note that
158518334Speter     we treat item taken from the syscalls file as though they were function
158618334Speter     definitions regardless of what the stuff in the file says.  */
158718334Speter
158818334Speter  def_dec_p->is_func_def = ((*p++ == 'F') || is_syscalls);
158918334Speter
159018334Speter#ifndef UNPROTOIZE
159118334Speter  def_dec_p->definition = 0;	/* Fill this in later if protoizing.  */
159218334Speter#endif /* !defined (UNPROTOIZE) */
159318334Speter
159418334Speter  check_aux_info (*p++ == ' ');
159518334Speter  check_aux_info (*p++ == '*');
159618334Speter  check_aux_info (*p++ == '/');
159718334Speter  check_aux_info (*p++ == ' ');
159818334Speter
159918334Speter#ifdef UNPROTOIZE
160018334Speter  check_aux_info ((!strncmp (p, "static", 6)) || (!strncmp (p, "extern", 6)));
160118334Speter#else /* !defined (UNPROTOIZE) */
160218334Speter  if (!strncmp (p, "static", 6))
160318334Speter    def_dec_p->is_static = -1;
160418334Speter  else if (!strncmp (p, "extern", 6))
160518334Speter    def_dec_p->is_static = 0;
160618334Speter  else
160718334Speter    check_aux_info (0);	/* Didn't find either `extern' or `static'.  */
160818334Speter#endif /* !defined (UNPROTOIZE) */
160918334Speter
161018334Speter  {
161118334Speter    const char *ansi_start = p;
161218334Speter
161318334Speter    p += 6;	/* Pass over the "static" or "extern".  */
161418334Speter
161518334Speter    /* We are now past the initial stuff.  Search forward from here to find
161618334Speter       the terminating semicolon that should immediately follow the entire
161718334Speter       ANSI format function declaration.  */
161818334Speter
161918334Speter    while (*++p != ';')
162018334Speter      continue;
162118334Speter
162218334Speter    semicolon_p = p;
162318334Speter
162418334Speter    /* Make a copy of the ansi declaration part of the line from the aux_info
162518334Speter       file.  */
162618334Speter
162718334Speter    def_dec_p->ansi_decl
162818334Speter      = dupnstr (ansi_start, (size_t) ((semicolon_p+1) - ansi_start));
162918334Speter
163018334Speter    /* Backup and point at the final right paren of the final argument list.  */
163118334Speter
163218334Speter    p--;
163318334Speter
163418334Speter#ifndef UNPROTOIZE
163518334Speter    def_dec_p->f_list_chain = NULL;
163618334Speter#endif /* !defined (UNPROTOIZE) */
163718334Speter
163818334Speter    while (p != ansi_start && (p[-1] == ' ' || p[-1] == '\t')) p--;
163918334Speter    if (*p != ')')
164018334Speter      {
164118334Speter	free_def_dec (def_dec_p);
164218334Speter	return;
164318334Speter      }
164418334Speter  }
164518334Speter
164618334Speter  /* Now isolate a whole set of formal argument lists, one-by-one.  Normally,
164718334Speter     there will only be one list to isolate, but there could be more.  */
164818334Speter
164918334Speter  def_dec_p->f_list_count = 0;
165018334Speter
165118334Speter  for (;;)
165218334Speter    {
165318334Speter      const char *left_paren_p = find_corresponding_lparen (p);
165418334Speter#ifndef UNPROTOIZE
165518334Speter      {
1656117395Skan	f_list_chain_item *cip
165750397Sobrien	  = (f_list_chain_item *) xmalloc (sizeof (f_list_chain_item));
165818334Speter
1659117395Skan	cip->formals_list
166018334Speter	  = dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
166118334Speter
1662117395Skan	/* Add the new chain item at the head of the current list.  */
1663117395Skan
1664117395Skan	cip->chain_next = def_dec_p->f_list_chain;
1665117395Skan	def_dec_p->f_list_chain = cip;
166618334Speter      }
166718334Speter#endif /* !defined (UNPROTOIZE) */
166818334Speter      def_dec_p->f_list_count++;
166918334Speter
167018334Speter      p = left_paren_p - 2;
167118334Speter
167218334Speter      /* p must now point either to another right paren, or to the last
1673117395Skan	 character of the name of the function that was declared/defined.
1674117395Skan	 If p points to another right paren, then this indicates that we
1675117395Skan	 are dealing with multiple formals lists.  In that case, there
1676117395Skan	 really should be another right paren preceding this right paren.  */
167718334Speter
167818334Speter      if (*p != ')')
1679117395Skan	break;
168018334Speter      else
1681117395Skan	check_aux_info (*--p == ')');
168218334Speter    }
168318334Speter
168418334Speter
168518334Speter  {
168618334Speter    const char *past_fn = p + 1;
168718334Speter
168818334Speter    check_aux_info (*past_fn == ' ');
168918334Speter
169018334Speter    /* Scan leftwards over the identifier that names the function.  */
169118334Speter
169218334Speter    while (is_id_char (*p))
169318334Speter      p--;
169418334Speter    p++;
169518334Speter
169618334Speter    /* p now points to the leftmost character of the function name.  */
169718334Speter
169818334Speter    {
169918334Speter      char *fn_string = (char *) alloca (past_fn - p + 1);
170018334Speter
170118334Speter      strncpy (fn_string, p, (size_t) (past_fn - p));
170218334Speter      fn_string[past_fn-p] = '\0';
170318334Speter      def_dec_p->hash_entry = lookup (function_name_primary, fn_string);
170418334Speter    }
170518334Speter  }
170618334Speter
170718334Speter  /* Look at all of the defs and decs for this function name that we have
170818334Speter     collected so far.  If there is already one which is at the same
170918334Speter     line number in the same file, then we can discard this new def_dec_info
171018334Speter     record.
171118334Speter
171218334Speter     As an extra assurance that any such pair of (nominally) identical
171318334Speter     function declarations are in fact identical, we also compare the
171418334Speter     ansi_decl parts of the lines from the aux_info files just to be on
171518334Speter     the safe side.
171618334Speter
171718334Speter     This comparison will fail if (for instance) the user was playing
171818334Speter     messy games with the preprocessor which ultimately causes one
171918334Speter     function declaration in one header file to look differently when
172018334Speter     that file is included by two (or more) other files.  */
172118334Speter
172218334Speter  {
172318334Speter    const def_dec_info *other;
172418334Speter
172518334Speter    for (other = def_dec_p->hash_entry->ddip; other; other = other->next_for_func)
172618334Speter      {
1727117395Skan	if (def_dec_p->line == other->line && def_dec_p->file == other->file)
1728117395Skan	  {
1729117395Skan	    if (strcmp (def_dec_p->ansi_decl, other->ansi_decl))
1730117395Skan	      {
1731117395Skan	        notice ("%s:%d: declaration of function `%s' takes different forms\n",
173252284Sobrien			def_dec_p->file->hash_entry->symbol,
173352284Sobrien			def_dec_p->line,
173452284Sobrien			def_dec_p->hash_entry->symbol);
1735117395Skan	        exit (FATAL_EXIT_CODE);
1736117395Skan	      }
1737117395Skan	    free_def_dec (def_dec_p);
1738117395Skan	    return;
1739117395Skan	  }
174018334Speter      }
174118334Speter  }
174218334Speter
174318334Speter#ifdef UNPROTOIZE
174418334Speter
174518334Speter  /* If we are doing unprotoizing, we must now setup the pointers that will
174618334Speter     point to the K&R name list and to the K&R argument declarations list.
174718334Speter
174818334Speter     Note that if this is only a function declaration, then we should not
174918334Speter     expect to find any K&R style formals list following the ANSI-style
175018334Speter     formals list.  This is because GCC knows that such information is
175118334Speter     useless in the case of function declarations (function definitions
175218334Speter     are a different story however).
175318334Speter
175418334Speter     Since we are unprotoizing, we don't need any such lists anyway.
175518334Speter     All we plan to do is to delete all characters between ()'s in any
175618334Speter     case.  */
175718334Speter
175818334Speter  def_dec_p->formal_names = NULL;
175918334Speter  def_dec_p->formal_decls = NULL;
176018334Speter
176118334Speter  if (def_dec_p->is_func_def)
176218334Speter    {
176318334Speter      p = semicolon_p;
176418334Speter      check_aux_info (*++p == ' ');
176518334Speter      check_aux_info (*++p == '/');
176618334Speter      check_aux_info (*++p == '*');
176718334Speter      check_aux_info (*++p == ' ');
176818334Speter      check_aux_info (*++p == '(');
176918334Speter
177018334Speter      {
1771117395Skan	const char *kr_names_start = ++p;   /* Point just inside '('.  */
177218334Speter
1773117395Skan	while (*p++ != ')')
1774117395Skan	  continue;
1775117395Skan	p--;		/* point to closing right paren */
177618334Speter
1777117395Skan	/* Make a copy of the K&R parameter names list.  */
177818334Speter
1779117395Skan	def_dec_p->formal_names
178018334Speter	  = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
178118334Speter      }
178218334Speter
178318334Speter      check_aux_info (*++p == ' ');
178418334Speter      p++;
178518334Speter
178618334Speter      /* p now points to the first character of the K&R style declarations
1787117395Skan	 list (if there is one) or to the star-slash combination that ends
1788117395Skan	 the comment in which such lists get embedded.  */
178918334Speter
179018334Speter      /* Make a copy of the K&R formal decls list and set the def_dec record
1791117395Skan	 to point to it.  */
179218334Speter
179318334Speter      if (*p == '*')		/* Are there no K&R declarations? */
1794117395Skan	{
1795117395Skan	  check_aux_info (*++p == '/');
1796117395Skan	  def_dec_p->formal_decls = "";
1797117395Skan	}
179818334Speter      else
1799117395Skan	{
1800117395Skan	  const char *kr_decls_start = p;
180118334Speter
1802117395Skan	  while (p[0] != '*' || p[1] != '/')
1803117395Skan	    p++;
1804117395Skan	  p--;
180518334Speter
1806117395Skan	  check_aux_info (*p == ' ');
180718334Speter
1808117395Skan	  def_dec_p->formal_decls
180918334Speter	    = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1810117395Skan	}
181118334Speter
181218334Speter      /* Handle a special case.  If we have a function definition marked as
1813117395Skan	 being in "old" style, and if its formal names list is empty, then
1814117395Skan	 it may actually have the string "void" in its real formals list
1815117395Skan	 in the original source code.  Just to make sure, we will get setup
1816117395Skan	 to convert such things anyway.
181718334Speter
1818117395Skan	 This kludge only needs to be here because of an insurmountable
1819117395Skan	 problem with generating .X files.  */
182018334Speter
182118334Speter      if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1822117395Skan	def_dec_p->prototyped = 1;
182318334Speter    }
182418334Speter
182518334Speter  /* Since we are unprotoizing, if this item is already in old (K&R) style,
182618334Speter     we can just ignore it.  If that is true, throw away the itme now.  */
182718334Speter
182818334Speter  if (!def_dec_p->prototyped)
182918334Speter    {
183018334Speter      free_def_dec (def_dec_p);
183118334Speter      return;
183218334Speter    }
183318334Speter
183418334Speter#endif /* defined (UNPROTOIZE) */
183518334Speter
183618334Speter  /* Add this record to the head of the list of records pertaining to this
183718334Speter     particular function name.  */
183818334Speter
183918334Speter  def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
184018334Speter  def_dec_p->hash_entry->ddip = def_dec_p;
184118334Speter
184218334Speter  /* Add this new def_dec_info record to the sorted list of def_dec_info
184318334Speter     records for this file.  Note that we don't have to worry about duplicates
184418334Speter     (caused by multiple inclusions of header files) here because we have
184518334Speter     already eliminated duplicates above.  */
184618334Speter
184718334Speter  if (!def_dec_p->file->defs_decs)
184818334Speter    {
184918334Speter      def_dec_p->file->defs_decs = def_dec_p;
185018334Speter      def_dec_p->next_in_file = NULL;
185118334Speter    }
185218334Speter  else
185318334Speter    {
185418334Speter      int line = def_dec_p->line;
185518334Speter      const def_dec_info *prev = NULL;
185618334Speter      const def_dec_info *curr = def_dec_p->file->defs_decs;
185718334Speter      const def_dec_info *next = curr->next_in_file;
185818334Speter
185918334Speter      while (next && (line < curr->line))
1860117395Skan	{
1861117395Skan	  prev = curr;
1862117395Skan	  curr = next;
1863117395Skan	  next = next->next_in_file;
1864117395Skan	}
186518334Speter      if (line >= curr->line)
1866117395Skan	{
1867117395Skan	  def_dec_p->next_in_file = curr;
1868117395Skan	  if (prev)
1869117395Skan	    ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1870117395Skan	  else
1871117395Skan	    def_dec_p->file->defs_decs = def_dec_p;
1872117395Skan	}
187318334Speter      else	/* assert (next == NULL); */
1874117395Skan	{
1875117395Skan	  ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1876117395Skan	  /* assert (next == NULL); */
1877117395Skan	  def_dec_p->next_in_file = next;
1878117395Skan	}
187918334Speter    }
188018334Speter}
188118334Speter
188218334Speter/* Set up the vector COMPILE_PARAMS which is the argument list for running GCC.
188318334Speter   Also set input_file_name_index and aux_info_file_name_index
188418334Speter   to the indices of the slots where the file names should go.  */
188518334Speter
188618334Speter/* We initialize the vector by  removing -g, -O, -S, -c, and -o options,
188718334Speter   and adding '-aux-info AUXFILE -S  -o /dev/null INFILE' at the end.  */
188818334Speter
188918334Speterstatic void
189018334Spetermunge_compile_params (params_list)
189118334Speter     const char *params_list;
189218334Speter{
189318334Speter  /* Build up the contents in a temporary vector
189418334Speter     that is so big that to has to be big enough.  */
189518334Speter  const char **temp_params
189618334Speter    = (const char **) alloca ((strlen (params_list) + 8) * sizeof (char *));
189718334Speter  int param_count = 0;
189818334Speter  const char *param;
189990075Sobrien  struct stat st;
190018334Speter
190118334Speter  temp_params[param_count++] = compiler_file_name;
190218334Speter  for (;;)
190318334Speter    {
190452284Sobrien      while (ISSPACE ((const unsigned char)*params_list))
1905117395Skan	params_list++;
190618334Speter      if (!*params_list)
1907117395Skan	break;
190818334Speter      param = params_list;
190952284Sobrien      while (*params_list && !ISSPACE ((const unsigned char)*params_list))
1910117395Skan	params_list++;
191118334Speter      if (param[0] != '-')
1912117395Skan	temp_params[param_count++]
191318334Speter	  = dupnstr (param, (size_t) (params_list - param));
191418334Speter      else
1915117395Skan	{
1916117395Skan	  switch (param[1])
1917117395Skan	    {
1918117395Skan	    case 'g':
1919117395Skan	    case 'O':
1920117395Skan	    case 'S':
1921117395Skan	    case 'c':
1922117395Skan	      break;		/* Don't copy these.  */
1923117395Skan	    case 'o':
1924117395Skan	      while (ISSPACE ((const unsigned char)*params_list))
1925117395Skan		params_list++;
1926117395Skan	      while (*params_list
1927117395Skan		     && !ISSPACE ((const unsigned char)*params_list))
1928117395Skan		params_list++;
1929117395Skan	      break;
1930117395Skan	    default:
1931117395Skan	      temp_params[param_count++]
1932117395Skan		= dupnstr (param, (size_t) (params_list - param));
1933117395Skan	    }
1934117395Skan	}
193518334Speter      if (!*params_list)
1936117395Skan	break;
193718334Speter    }
193818334Speter  temp_params[param_count++] = "-aux-info";
193918334Speter
194018334Speter  /* Leave room for the aux-info file name argument.  */
194118334Speter  aux_info_file_name_index = param_count;
194218334Speter  temp_params[param_count++] = NULL;
194318334Speter
194418334Speter  temp_params[param_count++] = "-S";
194518334Speter  temp_params[param_count++] = "-o";
1946117395Skan
194790075Sobrien  if ((stat (HOST_BIT_BUCKET, &st) == 0)
194890075Sobrien      && (!S_ISDIR (st.st_mode))
194990075Sobrien      && (access (HOST_BIT_BUCKET, W_OK) == 0))
195090075Sobrien    temp_params[param_count++] = HOST_BIT_BUCKET;
195190075Sobrien  else
195290075Sobrien    /* FIXME: This is hardly likely to be right, if HOST_BIT_BUCKET is not
195390075Sobrien       writable.  But until this is rejigged to use make_temp_file(), this
195490075Sobrien       is the best we can do.  */
195590075Sobrien    temp_params[param_count++] = "/dev/null";
195618334Speter
195718334Speter  /* Leave room for the input file name argument.  */
195818334Speter  input_file_name_index = param_count;
195918334Speter  temp_params[param_count++] = NULL;
196018334Speter  /* Terminate the list.  */
196118334Speter  temp_params[param_count++] = NULL;
196218334Speter
196318334Speter  /* Make a copy of the compile_params in heap space.  */
196418334Speter
196518334Speter  compile_params
196618334Speter    = (const char **) xmalloc (sizeof (char *) * (param_count+1));
196718334Speter  memcpy (compile_params, temp_params, sizeof (char *) * param_count);
196818334Speter}
196918334Speter
197018334Speter/* Do a recompilation for the express purpose of generating a new aux_info
197150397Sobrien   file to go with a specific base source file.
197218334Speter
197350397Sobrien   The result is a boolean indicating success.  */
197450397Sobrien
197518334Speterstatic int
197618334Spetergen_aux_info_file (base_filename)
197718334Speter     const char *base_filename;
197818334Speter{
197918334Speter  if (!input_file_name_index)
198018334Speter    munge_compile_params ("");
198118334Speter
198218334Speter  /* Store the full source file name in the argument vector.  */
198318334Speter  compile_params[input_file_name_index] = shortpath (NULL, base_filename);
198418334Speter  /* Add .X to source file name to get aux-info file name.  */
198590075Sobrien  compile_params[aux_info_file_name_index] =
198690075Sobrien    concat (compile_params[input_file_name_index], aux_info_suffix, NULL);
1987117395Skan
198818334Speter  if (!quiet_flag)
198952284Sobrien    notice ("%s: compiling `%s'\n",
199052284Sobrien	    pname, compile_params[input_file_name_index]);
199118334Speter
199250397Sobrien  {
199350397Sobrien    char *errmsg_fmt, *errmsg_arg;
199450397Sobrien    int wait_status, pid;
199518334Speter
199650397Sobrien    pid = pexecute (compile_params[0], (char * const *) compile_params,
199790075Sobrien		    pname, NULL, &errmsg_fmt, &errmsg_arg,
199850397Sobrien		    PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH);
199918334Speter
200050397Sobrien    if (pid == -1)
200150397Sobrien      {
200250397Sobrien	int errno_val = errno;
200350397Sobrien	fprintf (stderr, "%s: ", pname);
200450397Sobrien	fprintf (stderr, errmsg_fmt, errmsg_arg);
200552284Sobrien	fprintf (stderr, ": %s\n", xstrerror (errno_val));
200650397Sobrien	return 0;
200750397Sobrien      }
200818334Speter
200950397Sobrien    pid = pwait (pid, &wait_status, 0);
201050397Sobrien    if (pid == -1)
201118334Speter      {
201252284Sobrien	notice ("%s: wait: %s\n", pname, xstrerror (errno));
201350397Sobrien	return 0;
201450397Sobrien      }
201550397Sobrien    if (WIFSIGNALED (wait_status))
201650397Sobrien      {
201752284Sobrien	notice ("%s: subprocess got fatal signal %d\n",
201852284Sobrien		pname, WTERMSIG (wait_status));
201950397Sobrien	return 0;
202050397Sobrien      }
202150397Sobrien    if (WIFEXITED (wait_status))
202250397Sobrien      {
202350397Sobrien	if (WEXITSTATUS (wait_status) != 0)
202418334Speter	  {
202552284Sobrien	    notice ("%s: %s exited with status %d\n",
202652284Sobrien		    pname, compile_params[0], WEXITSTATUS (wait_status));
202718334Speter	    return 0;
202818334Speter	  }
202918334Speter	return 1;
203018334Speter      }
203150397Sobrien    abort ();
203250397Sobrien  }
203318334Speter}
203418334Speter
203518334Speter/* Read in all of the information contained in a single aux_info file.
203618334Speter   Save all of the important stuff for later.  */
203718334Speter
203818334Speterstatic void
203918334Speterprocess_aux_info_file (base_source_filename, keep_it, is_syscalls)
204018334Speter     const char *base_source_filename;
204118334Speter     int keep_it;
204218334Speter     int is_syscalls;
204318334Speter{
204418334Speter  size_t base_len = strlen (base_source_filename);
204518334Speter  char * aux_info_filename
204618334Speter    = (char *) alloca (base_len + strlen (aux_info_suffix) + 1);
204718334Speter  char *aux_info_base;
204818334Speter  char *aux_info_limit;
204918334Speter  char *aux_info_relocated_name;
205018334Speter  const char *aux_info_second_line;
205118334Speter  time_t aux_info_mtime;
205218334Speter  size_t aux_info_size;
205318334Speter  int must_create;
205418334Speter
205518334Speter  /* Construct the aux_info filename from the base source filename.  */
205618334Speter
205718334Speter  strcpy (aux_info_filename, base_source_filename);
205818334Speter  strcat (aux_info_filename, aux_info_suffix);
205918334Speter
206018334Speter  /* Check that the aux_info file exists and is readable.  If it does not
206118334Speter     exist, try to create it (once only).  */
206218334Speter
206318334Speter  /* If file doesn't exist, set must_create.
206418334Speter     Likewise if it exists and we can read it but it is obsolete.
206518334Speter     Otherwise, report an error.  */
206618334Speter  must_create = 0;
206718334Speter
206818334Speter  /* Come here with must_create set to 1 if file is out of date.  */
206918334Speterstart_over: ;
207018334Speter
207190075Sobrien  if (access (aux_info_filename, R_OK) == -1)
207218334Speter    {
207318334Speter      if (errno == ENOENT)
207418334Speter	{
207518334Speter	  if (is_syscalls)
207618334Speter	    {
207752284Sobrien	      notice ("%s: warning: missing SYSCALLS file `%s'\n",
207852284Sobrien		      pname, aux_info_filename);
207918334Speter	      return;
208018334Speter	    }
208118334Speter	  must_create = 1;
208218334Speter	}
208318334Speter      else
208418334Speter	{
208550397Sobrien	  int errno_val = errno;
208652284Sobrien	  notice ("%s: can't read aux info file `%s': %s\n",
208752284Sobrien		  pname, shortpath (NULL, aux_info_filename),
208852284Sobrien		  xstrerror (errno_val));
208918334Speter	  errors++;
209018334Speter	  return;
209118334Speter	}
209218334Speter    }
209318334Speter#if 0 /* There is code farther down to take care of this.  */
209418334Speter  else
209518334Speter    {
209618334Speter      struct stat s1, s2;
209718334Speter      stat (aux_info_file_name, &s1);
209818334Speter      stat (base_source_file_name, &s2);
209918334Speter      if (s2.st_mtime > s1.st_mtime)
210018334Speter	must_create = 1;
210118334Speter    }
210218334Speter#endif /* 0 */
210318334Speter
210418334Speter  /* If we need a .X file, create it, and verify we can read it.  */
210518334Speter  if (must_create)
210618334Speter    {
210718334Speter      if (!gen_aux_info_file (base_source_filename))
210818334Speter	{
210918334Speter	  errors++;
211018334Speter	  return;
211118334Speter	}
211290075Sobrien      if (access (aux_info_filename, R_OK) == -1)
211318334Speter	{
211450397Sobrien	  int errno_val = errno;
211552284Sobrien	  notice ("%s: can't read aux info file `%s': %s\n",
211652284Sobrien		  pname, shortpath (NULL, aux_info_filename),
211752284Sobrien		  xstrerror (errno_val));
211818334Speter	  errors++;
211918334Speter	  return;
212018334Speter	}
212118334Speter    }
212218334Speter
212318334Speter  {
212418334Speter    struct stat stat_buf;
212518334Speter
212618334Speter    /* Get some status information about this aux_info file.  */
2127117395Skan
212890075Sobrien    if (stat (aux_info_filename, &stat_buf) == -1)
212918334Speter      {
213050397Sobrien	int errno_val = errno;
2131117395Skan	notice ("%s: can't get status of aux info file `%s': %s\n",
213252284Sobrien		pname, shortpath (NULL, aux_info_filename),
213352284Sobrien		xstrerror (errno_val));
2134117395Skan	errors++;
2135117395Skan	return;
213618334Speter      }
2137117395Skan
213818334Speter    /* Check on whether or not this aux_info file is zero length.  If it is,
213918334Speter       then just ignore it and return.  */
2140117395Skan
214118334Speter    if ((aux_info_size = stat_buf.st_size) == 0)
214218334Speter      return;
2143117395Skan
214418334Speter    /* Get the date/time of last modification for this aux_info file and
214518334Speter       remember it.  We will have to check that any source files that it
214618334Speter       contains information about are at least this old or older.  */
2147117395Skan
214818334Speter    aux_info_mtime = stat_buf.st_mtime;
214918334Speter
215018334Speter    if (!is_syscalls)
215118334Speter      {
215218334Speter	/* Compare mod time with the .c file; update .X file if obsolete.
215318334Speter	   The code later on can fail to check the .c file
215418334Speter	   if it did not directly define any functions.  */
215518334Speter
215690075Sobrien	if (stat (base_source_filename, &stat_buf) == -1)
215718334Speter	  {
215850397Sobrien	    int errno_val = errno;
215952284Sobrien	    notice ("%s: can't get status of aux info file `%s': %s\n",
216052284Sobrien		    pname, shortpath (NULL, base_source_filename),
216152284Sobrien		    xstrerror (errno_val));
216218334Speter	    errors++;
216318334Speter	    return;
216418334Speter	  }
216518334Speter	if (stat_buf.st_mtime > aux_info_mtime)
216618334Speter	  {
216718334Speter	    must_create = 1;
216818334Speter	    goto start_over;
216918334Speter	  }
217018334Speter      }
217118334Speter  }
217218334Speter
217318334Speter  {
217418334Speter    int aux_info_file;
217590075Sobrien    int fd_flags;
217618334Speter
217718334Speter    /* Open the aux_info file.  */
2178117395Skan
217990075Sobrien    fd_flags = O_RDONLY;
218090075Sobrien#ifdef O_BINARY
218190075Sobrien    /* Use binary mode to avoid having to deal with different EOL characters.  */
218290075Sobrien    fd_flags |= O_BINARY;
218390075Sobrien#endif
218490075Sobrien    if ((aux_info_file = open (aux_info_filename, fd_flags, 0444 )) == -1)
218518334Speter      {
218650397Sobrien	int errno_val = errno;
2187117395Skan	notice ("%s: can't open aux info file `%s' for reading: %s\n",
218852284Sobrien		pname, shortpath (NULL, aux_info_filename),
218952284Sobrien		xstrerror (errno_val));
2190117395Skan	return;
219118334Speter      }
2192117395Skan
219318334Speter    /* Allocate space to hold the aux_info file in memory.  */
2194117395Skan
219518334Speter    aux_info_base = xmalloc (aux_info_size + 1);
219618334Speter    aux_info_limit = aux_info_base + aux_info_size;
219718334Speter    *aux_info_limit = '\0';
2198117395Skan
219918334Speter    /* Read the aux_info file into memory.  */
2200117395Skan
220152284Sobrien    if (safe_read (aux_info_file, aux_info_base, aux_info_size) !=
220252284Sobrien	(int) aux_info_size)
220318334Speter      {
220450397Sobrien	int errno_val = errno;
2205117395Skan	notice ("%s: error reading aux info file `%s': %s\n",
220652284Sobrien		pname, shortpath (NULL, aux_info_filename),
220752284Sobrien		xstrerror (errno_val));
2208117395Skan	free (aux_info_base);
2209117395Skan	close (aux_info_file);
2210117395Skan	return;
221118334Speter      }
2212117395Skan
221318334Speter    /* Close the aux info file.  */
2214117395Skan
221518334Speter    if (close (aux_info_file))
221618334Speter      {
221750397Sobrien	int errno_val = errno;
2218117395Skan	notice ("%s: error closing aux info file `%s': %s\n",
221952284Sobrien		pname, shortpath (NULL, aux_info_filename),
222052284Sobrien		xstrerror (errno_val));
2221117395Skan	free (aux_info_base);
2222117395Skan	close (aux_info_file);
2223117395Skan	return;
222418334Speter      }
222518334Speter  }
222618334Speter
222718334Speter  /* Delete the aux_info file (unless requested not to).  If the deletion
222818334Speter     fails for some reason, don't even worry about it.  */
222918334Speter
223018334Speter  if (must_create && !keep_it)
223190075Sobrien    if (unlink (aux_info_filename) == -1)
223250397Sobrien      {
223350397Sobrien	int errno_val = errno;
223452284Sobrien	notice ("%s: can't delete aux info file `%s': %s\n",
223552284Sobrien		pname, shortpath (NULL, aux_info_filename),
223652284Sobrien		xstrerror (errno_val));
223750397Sobrien      }
223818334Speter
223918334Speter  /* Save a pointer into the first line of the aux_info file which
224018334Speter     contains the filename of the directory from which the compiler
224118334Speter     was invoked when the associated source file was compiled.
224218334Speter     This information is used later to help create complete
224318334Speter     filenames out of the (potentially) relative filenames in
224418334Speter     the aux_info file.  */
224518334Speter
224618334Speter  {
224718334Speter    char *p = aux_info_base;
224818334Speter
224990075Sobrien    while (*p != ':'
225090075Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
2251117395Skan	   || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
225290075Sobrien#endif
2253117395Skan	   )
225418334Speter      p++;
225518334Speter    p++;
225618334Speter    while (*p == ' ')
225718334Speter      p++;
225818334Speter    invocation_filename = p;	/* Save a pointer to first byte of path.  */
225918334Speter    while (*p != ' ')
226018334Speter      p++;
226190075Sobrien    *p++ = DIR_SEPARATOR;
226218334Speter    *p++ = '\0';
226318334Speter    while (*p++ != '\n')
226418334Speter      continue;
226518334Speter    aux_info_second_line = p;
226618334Speter    aux_info_relocated_name = 0;
226790075Sobrien    if (! is_abspath (invocation_filename))
226818334Speter      {
226918334Speter	/* INVOCATION_FILENAME is relative;
227018334Speter	   append it to BASE_SOURCE_FILENAME's dir.  */
227118334Speter	char *dir_end;
227218334Speter	aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
227318334Speter	strcpy (aux_info_relocated_name, base_source_filename);
227490075Sobrien	dir_end = strrchr (aux_info_relocated_name, DIR_SEPARATOR);
227590075Sobrien#ifdef DIR_SEPARATOR_2
227690075Sobrien	{
227790075Sobrien	  char *slash;
227890075Sobrien
2279117395Skan	  slash = strrchr (dir_end ? dir_end : aux_info_relocated_name,
2280117395Skan			   DIR_SEPARATOR_2);
228190075Sobrien	  if (slash)
228290075Sobrien	    dir_end = slash;
228390075Sobrien	}
228490075Sobrien#endif
228518334Speter	if (dir_end)
228618334Speter	  dir_end++;
228718334Speter	else
228818334Speter	  dir_end = aux_info_relocated_name;
228918334Speter	strcpy (dir_end, invocation_filename);
229018334Speter	invocation_filename = aux_info_relocated_name;
229118334Speter      }
229218334Speter  }
229318334Speter
229418334Speter
229518334Speter  {
229618334Speter    const char *aux_info_p;
229718334Speter
229818334Speter    /* Do a pre-pass on the lines in the aux_info file, making sure that all
229918334Speter       of the source files referenced in there are at least as old as this
230018334Speter       aux_info file itself.  If not, go back and regenerate the aux_info
230118334Speter       file anew.  Don't do any of this for the syscalls file.  */
230218334Speter
230318334Speter    if (!is_syscalls)
230418334Speter      {
2305117395Skan	current_aux_info_lineno = 2;
2306117395Skan
2307117395Skan	for (aux_info_p = aux_info_second_line; *aux_info_p; )
2308117395Skan	  {
2309117395Skan	    if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2310117395Skan	      {
2311117395Skan		free (aux_info_base);
231290075Sobrien		free (aux_info_relocated_name);
2313117395Skan		if (keep_it && unlink (aux_info_filename) == -1)
2314117395Skan		  {
231550397Sobrien		    int errno_val = errno;
2316117395Skan	            notice ("%s: can't delete file `%s': %s\n",
231752284Sobrien			    pname, shortpath (NULL, aux_info_filename),
231852284Sobrien			    xstrerror (errno_val));
2319117395Skan	            return;
2320117395Skan	          }
232118334Speter		must_create = 1;
2322117395Skan	        goto start_over;
2323117395Skan	      }
2324117395Skan
2325117395Skan	    /* Skip over the rest of this line to start of next line.  */
2326117395Skan
2327117395Skan	    while (*aux_info_p != '\n')
2328117395Skan	      aux_info_p++;
2329117395Skan	    aux_info_p++;
2330117395Skan	    current_aux_info_lineno++;
2331117395Skan	  }
233218334Speter      }
233318334Speter
233418334Speter    /* Now do the real pass on the aux_info lines.  Save their information in
233518334Speter       the in-core data base.  */
2336117395Skan
233718334Speter    current_aux_info_lineno = 2;
2338117395Skan
233918334Speter    for (aux_info_p = aux_info_second_line; *aux_info_p;)
234018334Speter      {
2341117395Skan	char *unexpanded_line = unexpand_if_needed (aux_info_p);
2342117395Skan
2343117395Skan	if (unexpanded_line)
2344117395Skan	  {
2345117395Skan	    save_def_or_dec (unexpanded_line, is_syscalls);
2346117395Skan	    free (unexpanded_line);
2347117395Skan	  }
2348117395Skan	else
2349117395Skan	  save_def_or_dec (aux_info_p, is_syscalls);
2350117395Skan
2351117395Skan	/* Skip over the rest of this line and get to start of next line.  */
2352117395Skan
2353117395Skan	while (*aux_info_p != '\n')
2354117395Skan	  aux_info_p++;
2355117395Skan	aux_info_p++;
2356117395Skan	current_aux_info_lineno++;
235718334Speter      }
235818334Speter  }
235918334Speter
236018334Speter  free (aux_info_base);
236190075Sobrien  free (aux_info_relocated_name);
236218334Speter}
236318334Speter
236418334Speter#ifndef UNPROTOIZE
236518334Speter
236618334Speter/* Check an individual filename for a .c suffix.  If the filename has this
236718334Speter   suffix, rename the file such that its suffix is changed to .C.  This
236818334Speter   function implements the -C option.  */
236918334Speter
237018334Speterstatic void
237118334Speterrename_c_file (hp)
237218334Speter     const hash_table_entry *hp;
237318334Speter{
237418334Speter  const char *filename = hp->symbol;
237518334Speter  int last_char_index = strlen (filename) - 1;
2376117395Skan  char *const new_filename = (char *) alloca (strlen (filename)
2377117395Skan	                                      + strlen (cplus_suffix) + 1);
237818334Speter
237918334Speter  /* Note that we don't care here if the given file was converted or not.  It
238018334Speter     is possible that the given file was *not* converted, simply because there
238118334Speter     was nothing in it which actually required conversion.  Even in this case,
238218334Speter     we want to do the renaming.  Note that we only rename files with the .c
238390075Sobrien     suffix (except for the syscalls file, which is left alone).  */
238418334Speter
238590075Sobrien  if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.'
238690075Sobrien      || IS_SAME_PATH (syscalls_absolute_filename, filename))
238718334Speter    return;
238818334Speter
238918334Speter  strcpy (new_filename, filename);
239090075Sobrien  strcpy (&new_filename[last_char_index], cplus_suffix);
239118334Speter
239290075Sobrien  if (rename (filename, new_filename) == -1)
239318334Speter    {
239450397Sobrien      int errno_val = errno;
239590075Sobrien      notice ("%s: warning: can't rename file `%s' to `%s': %s\n",
239652284Sobrien	      pname, shortpath (NULL, filename),
239752284Sobrien	      shortpath (NULL, new_filename), xstrerror (errno_val));
239818334Speter      errors++;
239918334Speter      return;
240018334Speter    }
240118334Speter}
240218334Speter
240318334Speter#endif /* !defined (UNPROTOIZE) */
240418334Speter
240518334Speter/* Take the list of definitions and declarations attached to a particular
240618334Speter   file_info node and reverse the order of the list.  This should get the
240718334Speter   list into an order such that the item with the lowest associated line
240818334Speter   number is nearest the head of the list.  When these lists are originally
240918334Speter   built, they are in the opposite order.  We want to traverse them in
241018334Speter   normal line number order later (i.e. lowest to highest) so reverse the
241118334Speter   order here.  */
241218334Speter
241318334Speterstatic void
241418334Speterreverse_def_dec_list (hp)
241518334Speter     const hash_table_entry *hp;
241618334Speter{
241718334Speter  file_info *file_p = hp->fip;
241818334Speter  def_dec_info *prev = NULL;
241990075Sobrien  def_dec_info *current = (def_dec_info *) file_p->defs_decs;
242018334Speter
242118334Speter  if (!current)
242218334Speter    return;        		/* no list to reverse */
242318334Speter
242418334Speter  prev = current;
242590075Sobrien  if (! (current = (def_dec_info *) current->next_in_file))
242618334Speter    return;        		/* can't reverse a single list element */
242718334Speter
242818334Speter  prev->next_in_file = NULL;
242918334Speter
243018334Speter  while (current)
243118334Speter    {
243290075Sobrien      def_dec_info *next = (def_dec_info *) current->next_in_file;
243318334Speter
243418334Speter      current->next_in_file = prev;
243518334Speter      prev = current;
243618334Speter      current = next;
243718334Speter    }
243818334Speter
243918334Speter  file_p->defs_decs = prev;
244018334Speter}
244118334Speter
244218334Speter#ifndef UNPROTOIZE
244318334Speter
244418334Speter/* Find the (only?) extern definition for a particular function name, starting
244518334Speter   from the head of the linked list of entries for the given name.  If we
244618334Speter   cannot find an extern definition for the given function name, issue a
244718334Speter   warning and scrounge around for the next best thing, i.e. an extern
244818334Speter   function declaration with a prototype attached to it.  Note that we only
244918334Speter   allow such substitutions for extern declarations and never for static
245018334Speter   declarations.  That's because the only reason we allow them at all is
245118334Speter   to let un-prototyped function declarations for system-supplied library
245218334Speter   functions get their prototypes from our own extra SYSCALLS.c.X file which
245318334Speter   contains all of the correct prototypes for system functions.  */
245418334Speter
245518334Speterstatic const def_dec_info *
245618334Speterfind_extern_def (head, user)
245718334Speter     const def_dec_info *head;
245818334Speter     const def_dec_info *user;
245918334Speter{
246018334Speter  const def_dec_info *dd_p;
246118334Speter  const def_dec_info *extern_def_p = NULL;
246218334Speter  int conflict_noted = 0;
246318334Speter
246418334Speter  /* Don't act too stupid here.  Somebody may try to convert an entire system
246518334Speter     in one swell fwoop (rather than one program at a time, as should be done)
246618334Speter     and in that case, we may find that there are multiple extern definitions
246718334Speter     of a given function name in the entire set of source files that we are
246818334Speter     converting.  If however one of these definitions resides in exactly the
246918334Speter     same source file as the reference we are trying to satisfy then in that
247018334Speter     case it would be stupid for us to fail to realize that this one definition
247118334Speter     *must* be the precise one we are looking for.
247218334Speter
247318334Speter     To make sure that we don't miss an opportunity to make this "same file"
247418334Speter     leap of faith, we do a prescan of the list of records relating to the
247518334Speter     given function name, and we look (on this first scan) *only* for a
247618334Speter     definition of the function which is in the same file as the reference
247718334Speter     we are currently trying to satisfy.  */
247818334Speter
247918334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
248018334Speter    if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
248118334Speter      return dd_p;
248218334Speter
248318334Speter  /* Now, since we have not found a definition in the same file as the
248418334Speter     reference, we scan the list again and consider all possibilities from
248518334Speter     all files.  Here we may get conflicts with the things listed in the
248618334Speter     SYSCALLS.c.X file, but if that happens it only means that the source
248718334Speter     code being converted contains its own definition of a function which
248818334Speter     could have been supplied by libc.a.  In such cases, we should avoid
248918334Speter     issuing the normal warning, and defer to the definition given in the
249090075Sobrien     user's own code.  */
249118334Speter
249218334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
249318334Speter    if (dd_p->is_func_def && !dd_p->is_static)
249418334Speter      {
2495117395Skan	if (!extern_def_p)	/* Previous definition? */
2496117395Skan	  extern_def_p = dd_p;	/* Remember the first definition found.  */
2497117395Skan	else
2498117395Skan	  {
2499117395Skan	    /* Ignore definition just found if it came from SYSCALLS.c.X.  */
250018334Speter
2501117395Skan	    if (is_syscalls_file (dd_p->file))
2502117395Skan	      continue;
250318334Speter
2504117395Skan	    /* Quietly replace the definition previously found with the one
2505117395Skan	       just found if the previous one was from SYSCALLS.c.X.  */
250618334Speter
2507117395Skan	    if (is_syscalls_file (extern_def_p->file))
2508117395Skan	      {
2509117395Skan	        extern_def_p = dd_p;
2510117395Skan	        continue;
2511117395Skan	      }
251218334Speter
2513117395Skan	    /* If we get here, then there is a conflict between two function
2514117395Skan	       declarations for the same function, both of which came from the
2515117395Skan	       user's own code.  */
251618334Speter
2517117395Skan	    if (!conflict_noted)	/* first time we noticed? */
2518117395Skan	      {
2519117395Skan		conflict_noted = 1;
2520117395Skan		notice ("%s: conflicting extern definitions of '%s'\n",
252152284Sobrien			pname, head->hash_entry->symbol);
2522117395Skan		if (!quiet_flag)
2523117395Skan		  {
2524117395Skan		    notice ("%s: declarations of '%s' will not be converted\n",
252552284Sobrien			    pname, head->hash_entry->symbol);
2526117395Skan		    notice ("%s: conflict list for '%s' follows:\n",
252752284Sobrien			    pname, head->hash_entry->symbol);
2528117395Skan		    fprintf (stderr, "%s:     %s(%d): %s\n",
252918334Speter			     pname,
253018334Speter			     shortpath (NULL, extern_def_p->file->hash_entry->symbol),
253118334Speter			     extern_def_p->line, extern_def_p->ansi_decl);
2532117395Skan		  }
2533117395Skan	      }
2534117395Skan	    if (!quiet_flag)
2535117395Skan	      fprintf (stderr, "%s:     %s(%d): %s\n",
253618334Speter		       pname,
253718334Speter		       shortpath (NULL, dd_p->file->hash_entry->symbol),
253818334Speter		       dd_p->line, dd_p->ansi_decl);
2539117395Skan	  }
254018334Speter      }
254118334Speter
254218334Speter  /* We want to err on the side of caution, so if we found multiple conflicting
254318334Speter     definitions for the same function, treat this as being that same as if we
254418334Speter     had found no definitions (i.e. return NULL).  */
254518334Speter
254618334Speter  if (conflict_noted)
254718334Speter    return NULL;
254818334Speter
254918334Speter  if (!extern_def_p)
255018334Speter    {
255118334Speter      /* We have no definitions for this function so do the next best thing.
2552117395Skan	 Search for an extern declaration already in prototype form.  */
255318334Speter
255418334Speter      for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2555117395Skan	if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2556117395Skan	  {
2557117395Skan	    extern_def_p = dd_p;	/* save a pointer to the definition */
2558117395Skan	    if (!quiet_flag)
2559117395Skan	      notice ("%s: warning: using formals list from %s(%d) for function `%s'\n",
256052284Sobrien		      pname,
256152284Sobrien		      shortpath (NULL, dd_p->file->hash_entry->symbol),
256252284Sobrien		      dd_p->line, dd_p->hash_entry->symbol);
2563117395Skan	    break;
2564117395Skan	  }
256518334Speter
256618334Speter      /* Gripe about unprototyped function declarations that we found no
2567117395Skan	 corresponding definition (or other source of prototype information)
2568117395Skan	 for.
256918334Speter
2570117395Skan	 Gripe even if the unprototyped declaration we are worried about
2571117395Skan	 exists in a file in one of the "system" include directories.  We
2572117395Skan	 can gripe about these because we should have at least found a
2573117395Skan	 corresponding (pseudo) definition in the SYSCALLS.c.X file.  If we
257418334Speter	 didn't, then that means that the SYSCALLS.c.X file is missing some
2575117395Skan	 needed prototypes for this particular system.  That is worth telling
2576117395Skan	 the user about!  */
257718334Speter
257818334Speter      if (!extern_def_p)
2579117395Skan	{
2580117395Skan	  const char *file = user->file->hash_entry->symbol;
258118334Speter
2582117395Skan	  if (!quiet_flag)
2583117395Skan	    if (in_system_include_dir (file))
2584117395Skan	      {
258518334Speter		/* Why copy this string into `needed' at all?
258618334Speter		   Why not just use user->ansi_decl without copying?  */
258718334Speter		char *needed = (char *) alloca (strlen (user->ansi_decl) + 1);
2588117395Skan	        char *p;
258918334Speter
2590117395Skan	        strcpy (needed, user->ansi_decl);
2591117395Skan	        p = (NONCONST char *) substr (needed, user->hash_entry->symbol)
2592117395Skan	            + strlen (user->hash_entry->symbol) + 2;
259318334Speter		/* Avoid having ??? in the string.  */
259418334Speter		*p++ = '?';
259518334Speter		*p++ = '?';
259618334Speter		*p++ = '?';
2597117395Skan	        strcpy (p, ");");
259818334Speter
2599117395Skan	        notice ("%s: %d: `%s' used but missing from SYSCALLS\n",
260052284Sobrien			shortpath (NULL, file), user->line,
260152284Sobrien			needed+7);	/* Don't print "extern " */
2602117395Skan	      }
260318334Speter#if 0
2604117395Skan	    else
2605117395Skan	      notice ("%s: %d: warning: no extern definition for `%s'\n",
260652284Sobrien		      shortpath (NULL, file), user->line,
260752284Sobrien		      user->hash_entry->symbol);
260818334Speter#endif
2609117395Skan	}
261018334Speter    }
261118334Speter  return extern_def_p;
261218334Speter}
261318334Speter
261418334Speter/* Find the (only?) static definition for a particular function name in a
261518334Speter   given file.  Here we get the function-name and the file info indirectly
261650397Sobrien   from the def_dec_info record pointer which is passed in.  */
261718334Speter
261818334Speterstatic const def_dec_info *
261918334Speterfind_static_definition (user)
262018334Speter     const def_dec_info *user;
262118334Speter{
262218334Speter  const def_dec_info *head = user->hash_entry->ddip;
262318334Speter  const def_dec_info *dd_p;
262418334Speter  int num_static_defs = 0;
262518334Speter  const def_dec_info *static_def_p = NULL;
262618334Speter
262718334Speter  for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
262818334Speter    if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
262918334Speter      {
2630117395Skan	static_def_p = dd_p;	/* save a pointer to the definition */
2631117395Skan	num_static_defs++;
263218334Speter      }
263318334Speter  if (num_static_defs == 0)
263418334Speter    {
263518334Speter      if (!quiet_flag)
2636117395Skan	notice ("%s: warning: no static definition for `%s' in file `%s'\n",
263752284Sobrien		pname, head->hash_entry->symbol,
263852284Sobrien		shortpath (NULL, user->file->hash_entry->symbol));
263918334Speter    }
264018334Speter  else if (num_static_defs > 1)
264118334Speter    {
264252284Sobrien      notice ("%s: multiple static defs of `%s' in file `%s'\n",
264352284Sobrien	      pname, head->hash_entry->symbol,
264452284Sobrien	      shortpath (NULL, user->file->hash_entry->symbol));
264518334Speter      return NULL;
264618334Speter    }
264718334Speter  return static_def_p;
264818334Speter}
264918334Speter
265018334Speter/* Find good prototype style formal argument lists for all of the function
265118334Speter   declarations which didn't have them before now.
265218334Speter
265318334Speter   To do this we consider each function name one at a time.  For each function
265418334Speter   name, we look at the items on the linked list of def_dec_info records for
265518334Speter   that particular name.
265618334Speter
265718334Speter   Somewhere on this list we should find one (and only one) def_dec_info
265818334Speter   record which represents the actual function definition, and this record
265918334Speter   should have a nice formal argument list already associated with it.
266018334Speter
266118334Speter   Thus, all we have to do is to connect up all of the other def_dec_info
266218334Speter   records for this particular function name to the special one which has
266318334Speter   the full-blown formals list.
266418334Speter
266518334Speter   Of course it is a little more complicated than just that.  See below for
266618334Speter   more details.  */
266718334Speter
266818334Speterstatic void
266918334Speterconnect_defs_and_decs (hp)
267018334Speter     const hash_table_entry *hp;
267118334Speter{
267218334Speter  const def_dec_info *dd_p;
267318334Speter  const def_dec_info *extern_def_p = NULL;
267418334Speter  int first_extern_reference = 1;
267518334Speter
267618334Speter  /* Traverse the list of definitions and declarations for this particular
267718334Speter     function name.  For each item on the list, if it is a function
267818334Speter     definition (either old style or new style) then GCC has already been
267918334Speter     kind enough to produce a prototype for us, and it is associated with
268018334Speter     the item already, so declare the item as its own associated "definition".
268118334Speter
268218334Speter     Also, for each item which is only a function declaration, but which
268318334Speter     nonetheless has its own prototype already (obviously supplied by the user)
268450397Sobrien     declare the item as its own definition.
268518334Speter
268618334Speter     Note that when/if there are multiple user-supplied prototypes already
268718334Speter     present for multiple declarations of any given function, these multiple
268818334Speter     prototypes *should* all match exactly with one another and with the
268918334Speter     prototype for the actual function definition.  We don't check for this
269018334Speter     here however, since we assume that the compiler must have already done
269118334Speter     this consistency checking when it was creating the .X files.  */
269218334Speter
269318334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
269418334Speter    if (dd_p->prototyped)
269518334Speter      ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
269618334Speter
269718334Speter  /* Traverse the list of definitions and declarations for this particular
269818334Speter     function name.  For each item on the list, if it is an extern function
269918334Speter     declaration and if it has no associated definition yet, go try to find
270018334Speter     the matching extern definition for the declaration.
270118334Speter
270218334Speter     When looking for the matching function definition, warn the user if we
270318334Speter     fail to find one.
270418334Speter
270518334Speter     If we find more that one function definition also issue a warning.
270618334Speter
270718334Speter     Do the search for the matching definition only once per unique function
270818334Speter     name (and only when absolutely needed) so that we can avoid putting out
270918334Speter     redundant warning messages, and so that we will only put out warning
271018334Speter     messages when there is actually a reference (i.e. a declaration) for
271118334Speter     which we need to find a matching definition.  */
271218334Speter
271318334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
271418334Speter    if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
271518334Speter      {
2716117395Skan	if (first_extern_reference)
2717117395Skan	  {
2718117395Skan	    extern_def_p = find_extern_def (hp->ddip, dd_p);
2719117395Skan	    first_extern_reference = 0;
2720117395Skan	  }
2721117395Skan	((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
272218334Speter      }
272318334Speter
272418334Speter  /* Traverse the list of definitions and declarations for this particular
272518334Speter     function name.  For each item on the list, if it is a static function
272618334Speter     declaration and if it has no associated definition yet, go try to find
272718334Speter     the matching static definition for the declaration within the same file.
272818334Speter
272918334Speter     When looking for the matching function definition, warn the user if we
273018334Speter     fail to find one in the same file with the declaration, and refuse to
273118334Speter     convert this kind of cross-file static function declaration.  After all,
273218334Speter     this is stupid practice and should be discouraged.
273318334Speter
273418334Speter     We don't have to worry about the possibility that there is more than one
273518334Speter     matching function definition in the given file because that would have
273618334Speter     been flagged as an error by the compiler.
273718334Speter
273818334Speter     Do the search for the matching definition only once per unique
273918334Speter     function-name/source-file pair (and only when absolutely needed) so that
274018334Speter     we can avoid putting out redundant warning messages, and so that we will
274118334Speter     only put out warning messages when there is actually a reference (i.e. a
274218334Speter     declaration) for which we actually need to find a matching definition.  */
274318334Speter
274418334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
274518334Speter    if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
274618334Speter      {
2747117395Skan	const def_dec_info *dd_p2;
2748117395Skan	const def_dec_info *static_def;
274918334Speter
2750117395Skan	/* We have now found a single static declaration for which we need to
2751117395Skan	   find a matching definition.  We want to minimize the work (and the
2752117395Skan	   number of warnings), so we will find an appropriate (matching)
2753117395Skan	   static definition for this declaration, and then distribute it
2754117395Skan	   (as the definition for) any and all other static declarations
2755117395Skan	   for this function name which occur within the same file, and which
2756117395Skan	   do not already have definitions.
275718334Speter
2758117395Skan	   Note that a trick is used here to prevent subsequent attempts to
2759117395Skan	   call find_static_definition for a given function-name & file
2760117395Skan	   if the first such call returns NULL.  Essentially, we convert
2761117395Skan	   these NULL return values to -1, and put the -1 into the definition
2762117395Skan	   field for each other static declaration from the same file which
2763117395Skan	   does not already have an associated definition.
2764117395Skan	   This makes these other static declarations look like they are
2765117395Skan	   actually defined already when the outer loop here revisits them
2766117395Skan	   later on.  Thus, the outer loop will skip over them.  Later, we
2767117395Skan	   turn the -1's back to NULL's.  */
276818334Speter
2769117395Skan	((NONCONST def_dec_info *) dd_p)->definition =
2770117395Skan	  (static_def = find_static_definition (dd_p))
2771117395Skan	  ? static_def
2772117395Skan	  : (const def_dec_info *) -1;
277318334Speter
2774117395Skan	for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2775117395Skan	  if (!dd_p2->is_func_def && dd_p2->is_static
2776117395Skan	      && !dd_p2->definition && (dd_p2->file == dd_p->file))
2777117395Skan	    ((NONCONST def_dec_info *) dd_p2)->definition = dd_p->definition;
277818334Speter      }
277918334Speter
278018334Speter  /* Convert any dummy (-1) definitions we created in the step above back to
278118334Speter     NULL's (as they should be).  */
278218334Speter
278318334Speter  for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
278418334Speter    if (dd_p->definition == (def_dec_info *) -1)
278518334Speter      ((NONCONST def_dec_info *) dd_p)->definition = NULL;
278618334Speter}
278718334Speter
278818334Speter#endif /* !defined (UNPROTOIZE) */
278918334Speter
279018334Speter/* Give a pointer into the clean text buffer, return a number which is the
279118334Speter   original source line number that the given pointer points into.  */
279218334Speter
279318334Speterstatic int
279418334Speteridentify_lineno (clean_p)
279518334Speter     const char *clean_p;
279618334Speter{
279718334Speter  int line_num = 1;
279818334Speter  const char *scan_p;
279918334Speter
280018334Speter  for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
280118334Speter    if (*scan_p == '\n')
280218334Speter      line_num++;
280318334Speter  return line_num;
280418334Speter}
280518334Speter
280618334Speter/* Issue an error message and give up on doing this particular edit.  */
280718334Speter
280818334Speterstatic void
280918334Speterdeclare_source_confusing (clean_p)
281018334Speter     const char *clean_p;
281118334Speter{
281218334Speter  if (!quiet_flag)
281318334Speter    {
281418334Speter      if (clean_p == 0)
2815117395Skan	notice ("%s: %d: warning: source too confusing\n",
281652284Sobrien		shortpath (NULL, convert_filename), last_known_line_number);
281718334Speter      else
2818117395Skan	notice ("%s: %d: warning: source too confusing\n",
281952284Sobrien		shortpath (NULL, convert_filename),
282052284Sobrien		identify_lineno (clean_p));
282118334Speter    }
282218334Speter  longjmp (source_confusion_recovery, 1);
282318334Speter}
282418334Speter
282518334Speter/* Check that a condition which is expected to be true in the original source
282618334Speter   code is in fact true.  If not, issue an error message and give up on
282718334Speter   converting this particular source file.  */
282818334Speter
282918334Speterstatic void
283018334Spetercheck_source (cond, clean_p)
283118334Speter     int cond;
283218334Speter     const char *clean_p;
283318334Speter{
283418334Speter  if (!cond)
283518334Speter    declare_source_confusing (clean_p);
283618334Speter}
283718334Speter
283818334Speter/* If we think of the in-core cleaned text buffer as a memory mapped
283918334Speter   file (with the variable last_known_line_start acting as sort of a
284018334Speter   file pointer) then we can imagine doing "seeks" on the buffer.  The
284118334Speter   following routine implements a kind of "seek" operation for the in-core
284218334Speter   (cleaned) copy of the source file.  When finished, it returns a pointer to
284318334Speter   the start of a given (numbered) line in the cleaned text buffer.
284418334Speter
284518334Speter   Note that protoize only has to "seek" in the forward direction on the
284618334Speter   in-core cleaned text file buffers, and it never needs to back up.
284718334Speter
284818334Speter   This routine is made a little bit faster by remembering the line number
284918334Speter   (and pointer value) supplied (and returned) from the previous "seek".
285018334Speter   This prevents us from always having to start all over back at the top
285118334Speter   of the in-core cleaned buffer again.  */
285218334Speter
285318334Speterstatic const char *
285418334Speterseek_to_line (n)
285518334Speter     int n;
285618334Speter{
285718334Speter  if (n < last_known_line_number)
285818334Speter    abort ();
285918334Speter
286018334Speter  while (n > last_known_line_number)
286118334Speter    {
286218334Speter      while (*last_known_line_start != '\n')
2863117395Skan	check_source (++last_known_line_start < clean_text_limit, 0);
286418334Speter      last_known_line_start++;
286518334Speter      last_known_line_number++;
286618334Speter    }
286718334Speter  return last_known_line_start;
286818334Speter}
286918334Speter
287018334Speter/* Given a pointer to a character in the cleaned text buffer, return a pointer
287118334Speter   to the next non-whitespace character which follows it.  */
287218334Speter
287318334Speterstatic const char *
287418334Speterforward_to_next_token_char (ptr)
287518334Speter     const char *ptr;
287618334Speter{
287752284Sobrien  for (++ptr; ISSPACE ((const unsigned char)*ptr);
287852284Sobrien       check_source (++ptr < clean_text_limit, 0))
287918334Speter    continue;
288018334Speter  return ptr;
288118334Speter}
288218334Speter
288318334Speter/* Copy a chunk of text of length `len' and starting at `str' to the current
288418334Speter   output buffer.  Note that all attempts to add stuff to the current output
288518334Speter   buffer ultimately go through here.  */
288618334Speter
288718334Speterstatic void
288818334Speteroutput_bytes (str, len)
288918334Speter     const char *str;
289018334Speter     size_t len;
289118334Speter{
289218334Speter  if ((repl_write_ptr + 1) + len >= repl_text_limit)
289318334Speter    {
289418334Speter      size_t new_size = (repl_text_limit - repl_text_base) << 1;
289518334Speter      char *new_buf = (char *) xrealloc (repl_text_base, new_size);
289618334Speter
289718334Speter      repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
289818334Speter      repl_text_base = new_buf;
289918334Speter      repl_text_limit = new_buf + new_size;
290018334Speter    }
290118334Speter  memcpy (repl_write_ptr + 1, str, len);
290218334Speter  repl_write_ptr += len;
290318334Speter}
290418334Speter
290518334Speter/* Copy all bytes (except the trailing null) of a null terminated string to
290618334Speter   the current output buffer.  */
290718334Speter
290818334Speterstatic void
290918334Speteroutput_string (str)
291018334Speter     const char *str;
291118334Speter{
291218334Speter  output_bytes (str, strlen (str));
291318334Speter}
291418334Speter
291518334Speter/* Copy some characters from the original text buffer to the current output
291618334Speter   buffer.
291718334Speter
291818334Speter   This routine takes a pointer argument `p' which is assumed to be a pointer
291918334Speter   into the cleaned text buffer.  The bytes which are copied are the `original'
292018334Speter   equivalents for the set of bytes between the last value of `clean_read_ptr'
292118334Speter   and the argument value `p'.
292218334Speter
292318334Speter   The set of bytes copied however, comes *not* from the cleaned text buffer,
292418334Speter   but rather from the direct counterparts of these bytes within the original
292518334Speter   text buffer.
292618334Speter
292718334Speter   Thus, when this function is called, some bytes from the original text
292818334Speter   buffer (which may include original comments and preprocessing directives)
292918334Speter   will be copied into the  output buffer.
293018334Speter
293118334Speter   Note that the request implied when this routine is called includes the
293218334Speter   byte pointed to by the argument pointer `p'.  */
293318334Speter
293418334Speterstatic void
293518334Speteroutput_up_to (p)
293618334Speter     const char *p;
293718334Speter{
293818334Speter  size_t copy_length = (size_t) (p - clean_read_ptr);
293918334Speter  const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
294018334Speter
294118334Speter  if (copy_length == 0)
294218334Speter    return;
294318334Speter
294418334Speter  output_bytes (copy_start, copy_length);
294518334Speter  clean_read_ptr = p;
294618334Speter}
294718334Speter
294818334Speter/* Given a pointer to a def_dec_info record which represents some form of
294918334Speter   definition of a function (perhaps a real definition, or in lieu of that
295018334Speter   perhaps just a declaration with a full prototype) return true if this
295118334Speter   function is one which we should avoid converting.  Return false
295218334Speter   otherwise.  */
295318334Speter
295418334Speterstatic int
295518334Speterother_variable_style_function (ansi_header)
295618334Speter     const char *ansi_header;
295718334Speter{
295818334Speter#ifdef UNPROTOIZE
295918334Speter
296018334Speter  /* See if we have a stdarg function, or a function which has stdarg style
296118334Speter     parameters or a stdarg style return type.  */
296218334Speter
296318334Speter  return substr (ansi_header, "...") != 0;
296418334Speter
296518334Speter#else /* !defined (UNPROTOIZE) */
296618334Speter
296718334Speter  /* See if we have a varargs function, or a function which has varargs style
296818334Speter     parameters or a varargs style return type.  */
296918334Speter
297018334Speter  const char *p;
297118334Speter  int len = strlen (varargs_style_indicator);
297218334Speter
297318334Speter  for (p = ansi_header; p; )
297418334Speter    {
297518334Speter      const char *candidate;
297618334Speter
297718334Speter      if ((candidate = substr (p, varargs_style_indicator)) == 0)
2978117395Skan	return 0;
297918334Speter      else
2980117395Skan	if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
2981117395Skan	  return 1;
2982117395Skan	else
2983117395Skan	  p = candidate + 1;
298418334Speter    }
298518334Speter  return 0;
298618334Speter#endif /* !defined (UNPROTOIZE) */
298718334Speter}
298818334Speter
298918334Speter/* Do the editing operation specifically for a function "declaration".  Note
299018334Speter   that editing for function "definitions" are handled in a separate routine
299118334Speter   below.  */
299218334Speter
299318334Speterstatic void
299418334Speteredit_fn_declaration (def_dec_p, clean_text_p)
299518334Speter     const def_dec_info *def_dec_p;
299618334Speter     const char *volatile clean_text_p;
299718334Speter{
299818334Speter  const char *start_formals;
299918334Speter  const char *end_formals;
300018334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
300118334Speter  size_t func_name_len = strlen (function_to_edit);
300218334Speter  const char *end_of_fn_name;
300318334Speter
300418334Speter#ifndef UNPROTOIZE
300518334Speter
300618334Speter  const f_list_chain_item *this_f_list_chain_item;
300718334Speter  const def_dec_info *definition = def_dec_p->definition;
300818334Speter
300918334Speter  /* If we are protoizing, and if we found no corresponding definition for
301018334Speter     this particular function declaration, then just leave this declaration
301118334Speter     exactly as it is.  */
301218334Speter
301318334Speter  if (!definition)
301418334Speter    return;
301518334Speter
301618334Speter  /* If we are protoizing, and if the corresponding definition that we found
301718334Speter     for this particular function declaration defined an old style varargs
301818334Speter     function, then we want to issue a warning and just leave this function
301918334Speter     declaration unconverted.  */
302018334Speter
302118334Speter  if (other_variable_style_function (definition->ansi_decl))
302218334Speter    {
302318334Speter      if (!quiet_flag)
3024117395Skan	notice ("%s: %d: warning: varargs function declaration not converted\n",
302552284Sobrien		shortpath (NULL, def_dec_p->file->hash_entry->symbol),
302652284Sobrien		def_dec_p->line);
302718334Speter      return;
302818334Speter    }
302918334Speter
303018334Speter#endif /* !defined (UNPROTOIZE) */
303118334Speter
303218334Speter  /* Setup here to recover from confusing source code detected during this
303318334Speter     particular "edit".  */
303418334Speter
303518334Speter  save_pointers ();
303618334Speter  if (setjmp (source_confusion_recovery))
303718334Speter    {
303818334Speter      restore_pointers ();
303952284Sobrien      notice ("%s: declaration of function `%s' not converted\n",
304052284Sobrien	      pname, function_to_edit);
304118334Speter      return;
304218334Speter    }
304318334Speter
304418334Speter  /* We are editing a function declaration.  The line number we did a seek to
304518334Speter     contains the comma or semicolon which follows the declaration.  Our job
304618334Speter     now is to scan backwards looking for the function name.  This name *must*
304718334Speter     be followed by open paren (ignoring whitespace, of course).  We need to
304818334Speter     replace everything between that open paren and the corresponding closing
304918334Speter     paren.  If we are protoizing, we need to insert the prototype-style
305018334Speter     formals lists.  If we are unprotoizing, we need to just delete everything
305118334Speter     between the pairs of opening and closing parens.  */
305218334Speter
305318334Speter  /* First move up to the end of the line.  */
305418334Speter
305518334Speter  while (*clean_text_p != '\n')
305618334Speter    check_source (++clean_text_p < clean_text_limit, 0);
305718334Speter  clean_text_p--;  /* Point to just before the newline character.  */
305818334Speter
305918334Speter  /* Now we can scan backwards for the function name.  */
306018334Speter
306118334Speter  do
306218334Speter    {
306318334Speter      for (;;)
3064117395Skan	{
3065117395Skan	  /* Scan leftwards until we find some character which can be
3066117395Skan	     part of an identifier.  */
306718334Speter
3068117395Skan	  while (!is_id_char (*clean_text_p))
3069117395Skan	    check_source (--clean_text_p > clean_read_ptr, 0);
307018334Speter
3071117395Skan	  /* Scan backwards until we find a char that cannot be part of an
3072117395Skan	     identifier.  */
307318334Speter
3074117395Skan	  while (is_id_char (*clean_text_p))
3075117395Skan	    check_source (--clean_text_p > clean_read_ptr, 0);
307618334Speter
3077117395Skan	  /* Having found an "id break", see if the following id is the one
3078117395Skan	     that we are looking for.  If so, then exit from this loop.  */
307918334Speter
3080117395Skan	  if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
3081117395Skan	    {
3082117395Skan	      char ch = *(clean_text_p + 1 + func_name_len);
308318334Speter
3084117395Skan	      /* Must also check to see that the name in the source text
3085117395Skan	         ends where it should (in order to prevent bogus matches
3086117395Skan	         on similar but longer identifiers.  */
308718334Speter
3088117395Skan	      if (! is_id_char (ch))
3089117395Skan	        break;			/* exit from loop */
3090117395Skan	    }
3091117395Skan	}
3092117395Skan
309318334Speter      /* We have now found the first perfect match for the function name in
3094117395Skan	 our backward search.  This may or may not be the actual function
3095117395Skan	 name at the start of the actual function declaration (i.e. we could
3096117395Skan	 have easily been mislead).  We will try to avoid getting fooled too
3097117395Skan	 often by looking forward for the open paren which should follow the
3098117395Skan	 identifier we just found.  We ignore whitespace while hunting.  If
3099117395Skan	 the next non-whitespace byte we see is *not* an open left paren,
3100117395Skan	 then we must assume that we have been fooled and we start over
3101117395Skan	 again accordingly.  Note that there is no guarantee, that even if
3102117395Skan	 we do see the open paren, that we are in the right place.
3103117395Skan	 Programmers do the strangest things sometimes!  */
3104117395Skan
310518334Speter      end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
310618334Speter      start_formals = forward_to_next_token_char (end_of_fn_name);
310718334Speter    }
310818334Speter  while (*start_formals != '(');
310918334Speter
311018334Speter  /* start_of_formals now points to the opening left paren which immediately
311118334Speter     follows the name of the function.  */
311218334Speter
311318334Speter  /* Note that there may be several formals lists which need to be modified
311418334Speter     due to the possibility that the return type of this function is a
311518334Speter     pointer-to-function type.  If there are several formals lists, we
311618334Speter     convert them in left-to-right order here.  */
311718334Speter
311818334Speter#ifndef UNPROTOIZE
311918334Speter  this_f_list_chain_item = definition->f_list_chain;
312018334Speter#endif /* !defined (UNPROTOIZE) */
312118334Speter
312218334Speter  for (;;)
312318334Speter    {
312418334Speter      {
3125117395Skan	int depth;
312618334Speter
3127117395Skan	end_formals = start_formals + 1;
3128117395Skan	depth = 1;
3129117395Skan	for (; depth; check_source (++end_formals < clean_text_limit, 0))
3130117395Skan	  {
3131117395Skan	    switch (*end_formals)
3132117395Skan	      {
3133117395Skan	      case '(':
3134117395Skan		depth++;
3135117395Skan		break;
3136117395Skan	      case ')':
3137117395Skan		depth--;
3138117395Skan		break;
3139117395Skan	      }
3140117395Skan	  }
3141117395Skan	end_formals--;
314218334Speter      }
314318334Speter
314418334Speter      /* end_formals now points to the closing right paren of the formals
3145117395Skan	 list whose left paren is pointed to by start_formals.  */
3146117395Skan
314718334Speter      /* Now, if we are protoizing, we insert the new ANSI-style formals list
3148117395Skan	 attached to the associated definition of this function.  If however
3149117395Skan	 we are unprotoizing, then we simply delete any formals list which
3150117395Skan	 may be present.  */
3151117395Skan
315218334Speter      output_up_to (start_formals);
315318334Speter#ifndef UNPROTOIZE
315418334Speter      if (this_f_list_chain_item)
3155117395Skan	{
3156117395Skan	  output_string (this_f_list_chain_item->formals_list);
3157117395Skan	  this_f_list_chain_item = this_f_list_chain_item->chain_next;
3158117395Skan	}
315918334Speter      else
3160117395Skan	{
3161117395Skan	  if (!quiet_flag)
3162117395Skan	    notice ("%s: warning: too many parameter lists in declaration of `%s'\n",
316352284Sobrien		    pname, def_dec_p->hash_entry->symbol);
3164117395Skan	  check_source (0, end_formals);  /* leave the declaration intact */
3165117395Skan	}
316618334Speter#endif /* !defined (UNPROTOIZE) */
316718334Speter      clean_read_ptr = end_formals - 1;
316818334Speter
316918334Speter      /* Now see if it looks like there may be another formals list associated
3170117395Skan	 with the function declaration that we are converting (following the
3171117395Skan	 formals list that we just converted.  */
317218334Speter
317318334Speter      {
3174117395Skan	const char *another_r_paren = forward_to_next_token_char (end_formals);
317518334Speter
3176117395Skan	if ((*another_r_paren != ')')
3177117395Skan	    || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3178117395Skan	  {
317918334Speter#ifndef UNPROTOIZE
3180117395Skan	    if (this_f_list_chain_item)
3181117395Skan	      {
3182117395Skan		if (!quiet_flag)
3183117395Skan		  notice ("\n%s: warning: too few parameter lists in declaration of `%s'\n",
318452284Sobrien			  pname, def_dec_p->hash_entry->symbol);
3185117395Skan		check_source (0, start_formals); /* leave the decl intact */
3186117395Skan	      }
318718334Speter#endif /* !defined (UNPROTOIZE) */
3188117395Skan	    break;
3189117395Skan
3190117395Skan	  }
319118334Speter      }
319218334Speter
319318334Speter      /* There does appear to be yet another formals list, so loop around
3194117395Skan	 again, and convert it also.  */
319518334Speter    }
319618334Speter}
319718334Speter
319818334Speter/* Edit a whole group of formals lists, starting with the rightmost one
319918334Speter   from some set of formals lists.  This routine is called once (from the
320018334Speter   outside) for each function declaration which is converted.  It is
320118334Speter   recursive however, and it calls itself once for each remaining formal
320218334Speter   list that lies to the left of the one it was originally called to work
320318334Speter   on.  Thus, a whole set gets done in right-to-left order.
320418334Speter
3205117395Skan   This routine returns nonzero if it thinks that it should not be trying
320618334Speter   to convert this particular function definition (because the name of the
320718334Speter   function doesn't match the one expected).  */
320818334Speter
320918334Speterstatic int
321018334Speteredit_formals_lists (end_formals, f_list_count, def_dec_p)
321118334Speter     const char *end_formals;
321218334Speter     unsigned int f_list_count;
321318334Speter     const def_dec_info *def_dec_p;
321418334Speter{
321518334Speter  const char *start_formals;
321618334Speter  int depth;
321718334Speter
321818334Speter  start_formals = end_formals - 1;
321918334Speter  depth = 1;
322018334Speter  for (; depth; check_source (--start_formals > clean_read_ptr, 0))
322118334Speter    {
322218334Speter      switch (*start_formals)
3223117395Skan	{
3224117395Skan	case '(':
3225117395Skan	  depth--;
3226117395Skan	  break;
3227117395Skan	case ')':
3228117395Skan	  depth++;
3229117395Skan	  break;
3230117395Skan	}
323118334Speter    }
323218334Speter  start_formals++;
323318334Speter
323418334Speter  /* start_formals now points to the opening left paren of the formals list.  */
323518334Speter
323618334Speter  f_list_count--;
323718334Speter
323818334Speter  if (f_list_count)
323918334Speter    {
324018334Speter      const char *next_end;
324118334Speter
324218334Speter      /* There should be more formal lists to the left of here.  */
324318334Speter
324418334Speter      next_end = start_formals - 1;
324518334Speter      check_source (next_end > clean_read_ptr, 0);
324652284Sobrien      while (ISSPACE ((const unsigned char)*next_end))
3247117395Skan	check_source (--next_end > clean_read_ptr, 0);
324818334Speter      check_source (*next_end == ')', next_end);
324918334Speter      check_source (--next_end > clean_read_ptr, 0);
325018334Speter      check_source (*next_end == ')', next_end);
325118334Speter      if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3252117395Skan	return 1;
325318334Speter    }
325418334Speter
325518334Speter  /* Check that the function name in the header we are working on is the same
325618334Speter     as the one we would expect to find.  If not, issue a warning and return
3257117395Skan     nonzero.  */
325818334Speter
325918334Speter  if (f_list_count == 0)
326018334Speter    {
326118334Speter      const char *expected = def_dec_p->hash_entry->symbol;
326218334Speter      const char *func_name_start;
326318334Speter      const char *func_name_limit;
326418334Speter      size_t func_name_len;
326518334Speter
326652284Sobrien      for (func_name_limit = start_formals-1;
326752284Sobrien	   ISSPACE ((const unsigned char)*func_name_limit); )
3268117395Skan	check_source (--func_name_limit > clean_read_ptr, 0);
326918334Speter
327018334Speter      for (func_name_start = func_name_limit++;
3271117395Skan	   is_id_char (*func_name_start);
3272117395Skan	   func_name_start--)
3273117395Skan	check_source (func_name_start > clean_read_ptr, 0);
327418334Speter      func_name_start++;
327518334Speter      func_name_len = func_name_limit - func_name_start;
327618334Speter      if (func_name_len == 0)
3277117395Skan	check_source (0, func_name_start);
327818334Speter      if (func_name_len != strlen (expected)
327918334Speter	  || strncmp (func_name_start, expected, func_name_len))
3280117395Skan	{
3281117395Skan	  notice ("%s: %d: warning: found `%s' but expected `%s'\n",
328252284Sobrien		  shortpath (NULL, def_dec_p->file->hash_entry->symbol),
328352284Sobrien		  identify_lineno (func_name_start),
328452284Sobrien		  dupnstr (func_name_start, func_name_len),
328552284Sobrien		  expected);
3286117395Skan	  return 1;
3287117395Skan	}
328818334Speter    }
328918334Speter
329018334Speter  output_up_to (start_formals);
329118334Speter
329218334Speter#ifdef UNPROTOIZE
329318334Speter  if (f_list_count == 0)
329418334Speter    output_string (def_dec_p->formal_names);
329518334Speter#else /* !defined (UNPROTOIZE) */
329618334Speter  {
329718334Speter    unsigned f_list_depth;
329818334Speter    const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
329918334Speter
330018334Speter    /* At this point, the current value of f_list count says how many
330118334Speter       links we have to follow through the f_list_chain to get to the
330218334Speter       particular formals list that we need to output next.  */
330318334Speter
330418334Speter    for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
330518334Speter      flci_p = flci_p->chain_next;
330618334Speter    output_string (flci_p->formals_list);
330718334Speter  }
330818334Speter#endif /* !defined (UNPROTOIZE) */
330918334Speter
331018334Speter  clean_read_ptr = end_formals - 1;
331118334Speter  return 0;
331218334Speter}
331318334Speter
331450397Sobrien/* Given a pointer to a byte in the clean text buffer which points to
331550397Sobrien   the beginning of a line that contains a "follower" token for a
331650397Sobrien   function definition header, do whatever is necessary to find the
331750397Sobrien   right closing paren for the rightmost formals list of the function
331850397Sobrien   definition header.  */
331918334Speter
332018334Speterstatic const char *
332118334Speterfind_rightmost_formals_list (clean_text_p)
332218334Speter     const char *clean_text_p;
332318334Speter{
332418334Speter  const char *end_formals;
332518334Speter
332618334Speter  /* We are editing a function definition.  The line number we did a seek
332718334Speter     to contains the first token which immediately follows the entire set of
332818334Speter     formals lists which are part of this particular function definition
332918334Speter     header.
333018334Speter
333118334Speter     Our job now is to scan leftwards in the clean text looking for the
333218334Speter     right-paren which is at the end of the function header's rightmost
333318334Speter     formals list.
333418334Speter
333518334Speter     If we ignore whitespace, this right paren should be the first one we
333618334Speter     see which is (ignoring whitespace) immediately followed either by the
333718334Speter     open curly-brace beginning the function body or by an alphabetic
333818334Speter     character (in the case where the function definition is in old (K&R)
333918334Speter     style and there are some declarations of formal parameters).  */
334018334Speter
334118334Speter   /* It is possible that the right paren we are looking for is on the
334218334Speter      current line (together with its following token).  Just in case that
334318334Speter      might be true, we start out here by skipping down to the right end of
334418334Speter      the current line before starting our scan.  */
334518334Speter
334618334Speter  for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
334718334Speter    continue;
334818334Speter  end_formals--;
334918334Speter
335018334Speter#ifdef UNPROTOIZE
335118334Speter
335218334Speter  /* Now scan backwards while looking for the right end of the rightmost
335318334Speter     formals list associated with this function definition.  */
335418334Speter
335518334Speter  {
335618334Speter    char ch;
335718334Speter    const char *l_brace_p;
335818334Speter
335918334Speter    /* Look leftward and try to find a right-paren.  */
336018334Speter
336118334Speter    while (*end_formals != ')')
336218334Speter      {
336352284Sobrien	if (ISSPACE ((unsigned char)*end_formals))
336452284Sobrien	  while (ISSPACE ((unsigned char)*end_formals))
336518334Speter	    check_source (--end_formals > clean_read_ptr, 0);
336618334Speter	else
336718334Speter	  check_source (--end_formals > clean_read_ptr, 0);
336818334Speter      }
336918334Speter
337018334Speter    ch = *(l_brace_p = forward_to_next_token_char (end_formals));
337118334Speter    /* Since we are unprotoizing an ANSI-style (prototyped) function
337218334Speter       definition, there had better not be anything (except whitespace)
337318334Speter       between the end of the ANSI formals list and the beginning of the
337418334Speter       function body (i.e. the '{').  */
337518334Speter
337618334Speter    check_source (ch == '{', l_brace_p);
337718334Speter  }
337818334Speter
337918334Speter#else /* !defined (UNPROTOIZE) */
338018334Speter
338118334Speter  /* Now scan backwards while looking for the right end of the rightmost
338218334Speter     formals list associated with this function definition.  */
338318334Speter
338418334Speter  while (1)
338518334Speter    {
338618334Speter      char ch;
338718334Speter      const char *l_brace_p;
338818334Speter
338918334Speter      /* Look leftward and try to find a right-paren.  */
339018334Speter
339118334Speter      while (*end_formals != ')')
3392117395Skan	{
3393117395Skan	  if (ISSPACE ((const unsigned char)*end_formals))
3394117395Skan	    while (ISSPACE ((const unsigned char)*end_formals))
3395117395Skan	      check_source (--end_formals > clean_read_ptr, 0);
3396117395Skan	  else
3397117395Skan	    check_source (--end_formals > clean_read_ptr, 0);
3398117395Skan	}
339918334Speter
340018334Speter      ch = *(l_brace_p = forward_to_next_token_char (end_formals));
340118334Speter
340218334Speter      /* Since it is possible that we found a right paren before the starting
3403117395Skan	 '{' of the body which IS NOT the one at the end of the real K&R
3404117395Skan	 formals list (say for instance, we found one embedded inside one of
3405117395Skan	 the old K&R formal parameter declarations) we have to check to be
3406117395Skan	 sure that this is in fact the right paren that we were looking for.
340718334Speter
3408117395Skan	 The one we were looking for *must* be followed by either a '{' or
3409117395Skan	 by an alphabetic character, while others *cannot* validly be followed
3410117395Skan	 by such characters.  */
341118334Speter
341290075Sobrien      if ((ch == '{') || ISALPHA ((unsigned char) ch))
3413117395Skan	break;
341418334Speter
341518334Speter      /* At this point, we have found a right paren, but we know that it is
3416117395Skan	 not the one we were looking for, so backup one character and keep
3417117395Skan	 looking.  */
341818334Speter
341918334Speter      check_source (--end_formals > clean_read_ptr, 0);
342018334Speter    }
342118334Speter
342218334Speter#endif /* !defined (UNPROTOIZE) */
342318334Speter
342418334Speter  return end_formals;
342518334Speter}
342618334Speter
342718334Speter#ifndef UNPROTOIZE
342818334Speter
342918334Speter/* Insert into the output file a totally new declaration for a function
343018334Speter   which (up until now) was being called from within the current block
343118334Speter   without having been declared at any point such that the declaration
343218334Speter   was visible (i.e. in scope) at the point of the call.
343318334Speter
343418334Speter   We need to add in explicit declarations for all such function calls
343518334Speter   in order to get the full benefit of prototype-based function call
343618334Speter   parameter type checking.  */
343718334Speter
343818334Speterstatic void
343918334Speteradd_local_decl (def_dec_p, clean_text_p)
344018334Speter     const def_dec_info *def_dec_p;
344118334Speter     const char *clean_text_p;
344218334Speter{
344318334Speter  const char *start_of_block;
344418334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
344518334Speter
344618334Speter  /* Don't insert new local explicit declarations unless explicitly requested
344718334Speter     to do so.  */
344818334Speter
344918334Speter  if (!local_flag)
345018334Speter    return;
345118334Speter
345218334Speter  /* Setup here to recover from confusing source code detected during this
345318334Speter     particular "edit".  */
345418334Speter
345518334Speter  save_pointers ();
345618334Speter  if (setjmp (source_confusion_recovery))
345718334Speter    {
345818334Speter      restore_pointers ();
345952284Sobrien      notice ("%s: local declaration for function `%s' not inserted\n",
346052284Sobrien	      pname, function_to_edit);
346118334Speter      return;
346218334Speter    }
346318334Speter
346418334Speter  /* We have already done a seek to the start of the line which should
346518334Speter     contain *the* open curly brace which begins the block in which we need
346618334Speter     to insert an explicit function declaration (to replace the implicit one).
346718334Speter
346818334Speter     Now we scan that line, starting from the left, until we find the
346918334Speter     open curly brace we are looking for.  Note that there may actually be
347018334Speter     multiple open curly braces on the given line, but we will be happy
347118334Speter     with the leftmost one no matter what.  */
347218334Speter
347318334Speter  start_of_block = clean_text_p;
347418334Speter  while (*start_of_block != '{' && *start_of_block != '\n')
347518334Speter    check_source (++start_of_block < clean_text_limit, 0);
347618334Speter
347718334Speter  /* Note that the line from the original source could possibly
347818334Speter     contain *no* open curly braces!  This happens if the line contains
347918334Speter     a macro call which expands into a chunk of text which includes a
348018334Speter     block (and that block's associated open and close curly braces).
348118334Speter     In cases like this, we give up, issue a warning, and do nothing.  */
348218334Speter
348318334Speter  if (*start_of_block != '{')
348418334Speter    {
348518334Speter      if (!quiet_flag)
3486117395Skan	notice ("\n%s: %d: warning: can't add declaration of `%s' into macro call\n",
3487117395Skan	  def_dec_p->file->hash_entry->symbol, def_dec_p->line,
3488117395Skan	  def_dec_p->hash_entry->symbol);
348918334Speter      return;
349018334Speter    }
349118334Speter
349218334Speter  /* Figure out what a nice (pretty) indentation would be for the new
349318334Speter     declaration we are adding.  In order to do this, we must scan forward
349418334Speter     from the '{' until we find the first line which starts with some
349518334Speter     non-whitespace characters (i.e. real "token" material).  */
349618334Speter
349718334Speter  {
349818334Speter    const char *ep = forward_to_next_token_char (start_of_block) - 1;
349918334Speter    const char *sp;
350018334Speter
350118334Speter    /* Now we have ep pointing at the rightmost byte of some existing indent
350218334Speter       stuff.  At least that is the hope.
350318334Speter
350418334Speter       We can now just scan backwards and find the left end of the existing
350518334Speter       indentation string, and then copy it to the output buffer.  */
350618334Speter
350752284Sobrien    for (sp = ep; ISSPACE ((const unsigned char)*sp) && *sp != '\n'; sp--)
350818334Speter      continue;
350918334Speter
351018334Speter    /* Now write out the open { which began this block, and any following
351118334Speter       trash up to and including the last byte of the existing indent that
351218334Speter       we just found.  */
351318334Speter
351418334Speter    output_up_to (ep);
3515117395Skan
351618334Speter    /* Now we go ahead and insert the new declaration at this point.
351718334Speter
351818334Speter       If the definition of the given function is in the same file that we
351918334Speter       are currently editing, and if its full ANSI declaration normally
352018334Speter       would start with the keyword `extern', suppress the `extern'.  */
3521117395Skan
352218334Speter    {
352318334Speter      const char *decl = def_dec_p->definition->ansi_decl;
3524117395Skan
352518334Speter      if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3526117395Skan	decl += 7;
352718334Speter      output_string (decl);
352818334Speter    }
352918334Speter
353018334Speter    /* Finally, write out a new indent string, just like the preceding one
353118334Speter       that we found.  This will typically include a newline as the first
353218334Speter       character of the indent string.  */
353318334Speter
353418334Speter    output_bytes (sp, (size_t) (ep - sp) + 1);
353518334Speter  }
353618334Speter}
353718334Speter
353818334Speter/* Given a pointer to a file_info record, and a pointer to the beginning
353918334Speter   of a line (in the clean text buffer) which is assumed to contain the
354018334Speter   first "follower" token for the first function definition header in the
354118334Speter   given file, find a good place to insert some new global function
354218334Speter   declarations (which will replace scattered and imprecise implicit ones)
354318334Speter   and then insert the new explicit declaration at that point in the file.  */
354418334Speter
354518334Speterstatic void
354618334Speteradd_global_decls (file_p, clean_text_p)
354718334Speter     const file_info *file_p;
354818334Speter     const char *clean_text_p;
354918334Speter{
355018334Speter  const def_dec_info *dd_p;
355118334Speter  const char *scan_p;
355218334Speter
355318334Speter  /* Setup here to recover from confusing source code detected during this
355418334Speter     particular "edit".  */
355518334Speter
355618334Speter  save_pointers ();
355718334Speter  if (setjmp (source_confusion_recovery))
355818334Speter    {
355918334Speter      restore_pointers ();
356052284Sobrien      notice ("%s: global declarations for file `%s' not inserted\n",
356152284Sobrien	      pname, shortpath (NULL, file_p->hash_entry->symbol));
356218334Speter      return;
356318334Speter    }
356418334Speter
356518334Speter  /* Start by finding a good location for adding the new explicit function
356618334Speter     declarations.  To do this, we scan backwards, ignoring whitespace
356718334Speter     and comments and other junk until we find either a semicolon, or until
356818334Speter     we hit the beginning of the file.  */
356918334Speter
357018334Speter  scan_p = find_rightmost_formals_list (clean_text_p);
357118334Speter  for (;; --scan_p)
357218334Speter    {
357318334Speter      if (scan_p < clean_text_base)
3574117395Skan	break;
357518334Speter      check_source (scan_p > clean_read_ptr, 0);
357618334Speter      if (*scan_p == ';')
3577117395Skan	break;
357818334Speter    }
357918334Speter
358018334Speter  /* scan_p now points either to a semicolon, or to just before the start
358118334Speter     of the whole file.  */
358218334Speter
358318334Speter  /* Now scan forward for the first non-whitespace character.  In theory,
358418334Speter     this should be the first character of the following function definition
358550397Sobrien     header.  We will put in the added declarations just prior to that.  */
358618334Speter
358718334Speter  scan_p++;
358852284Sobrien  while (ISSPACE ((const unsigned char)*scan_p))
358918334Speter    scan_p++;
359018334Speter  scan_p--;
359118334Speter
359218334Speter  output_up_to (scan_p);
359318334Speter
359418334Speter  /* Now write out full prototypes for all of the things that had been
359518334Speter     implicitly declared in this file (but only those for which we were
359618334Speter     actually able to find unique matching definitions).  Avoid duplicates
359790075Sobrien     by marking things that we write out as we go.  */
359818334Speter
359918334Speter  {
360018334Speter    int some_decls_added = 0;
3601117395Skan
360218334Speter    for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
360318334Speter      if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3604117395Skan	{
3605117395Skan	  const char *decl = dd_p->definition->ansi_decl;
3606117395Skan
3607117395Skan	  /* If the function for which we are inserting a declaration is
3608117395Skan	     actually defined later in the same file, then suppress the
3609117395Skan	     leading `extern' keyword (if there is one).  */
3610117395Skan
3611117395Skan	  if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3612117395Skan	    decl += 7;
3613117395Skan
3614117395Skan	  output_string ("\n");
3615117395Skan	  output_string (decl);
3616117395Skan	  some_decls_added = 1;
3617117395Skan	  ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3618117395Skan	}
361918334Speter    if (some_decls_added)
362018334Speter      output_string ("\n\n");
362118334Speter  }
362218334Speter
362318334Speter  /* Unmark all of the definitions that we just marked.  */
362418334Speter
362518334Speter  for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
362618334Speter    if (dd_p->definition)
362718334Speter      ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
362818334Speter}
362918334Speter
363018334Speter#endif /* !defined (UNPROTOIZE) */
363118334Speter
363218334Speter/* Do the editing operation specifically for a function "definition".  Note
363318334Speter   that editing operations for function "declarations" are handled by a
363418334Speter   separate routine above.  */
363518334Speter
363618334Speterstatic void
363718334Speteredit_fn_definition (def_dec_p, clean_text_p)
363818334Speter     const def_dec_info *def_dec_p;
363918334Speter     const char *clean_text_p;
364018334Speter{
364118334Speter  const char *end_formals;
364218334Speter  const char *function_to_edit = def_dec_p->hash_entry->symbol;
364318334Speter
364418334Speter  /* Setup here to recover from confusing source code detected during this
364518334Speter     particular "edit".  */
364618334Speter
364718334Speter  save_pointers ();
364818334Speter  if (setjmp (source_confusion_recovery))
364918334Speter    {
365018334Speter      restore_pointers ();
365152284Sobrien      notice ("%s: definition of function `%s' not converted\n",
365252284Sobrien	      pname, function_to_edit);
365318334Speter      return;
365418334Speter    }
365518334Speter
365618334Speter  end_formals = find_rightmost_formals_list (clean_text_p);
365718334Speter
365818334Speter  /* end_of_formals now points to the closing right paren of the rightmost
365918334Speter     formals list which is actually part of the `header' of the function
366018334Speter     definition that we are converting.  */
366118334Speter
366218334Speter  /* If the header of this function definition looks like it declares a
366318334Speter     function with a variable number of arguments, and if the way it does
366418334Speter     that is different from that way we would like it (i.e. varargs vs.
366518334Speter     stdarg) then issue a warning and leave the header unconverted.  */
3666117395Skan
366718334Speter  if (other_variable_style_function (def_dec_p->ansi_decl))
366818334Speter    {
366918334Speter      if (!quiet_flag)
3670117395Skan	notice ("%s: %d: warning: definition of %s not converted\n",
367152284Sobrien		shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3672117395Skan		identify_lineno (end_formals),
367352284Sobrien		other_var_style);
367418334Speter      output_up_to (end_formals);
367518334Speter      return;
367618334Speter    }
367718334Speter
367818334Speter  if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
367918334Speter    {
368018334Speter      restore_pointers ();
368152284Sobrien      notice ("%s: definition of function `%s' not converted\n",
368252284Sobrien	      pname, function_to_edit);
368318334Speter      return;
368418334Speter    }
368518334Speter
368618334Speter  /* Have to output the last right paren because this never gets flushed by
368718334Speter     edit_formals_list.  */
368818334Speter
368918334Speter  output_up_to (end_formals);
369018334Speter
369118334Speter#ifdef UNPROTOIZE
369218334Speter  {
369318334Speter    const char *decl_p;
369418334Speter    const char *semicolon_p;
369518334Speter    const char *limit_p;
369618334Speter    const char *scan_p;
369718334Speter    int had_newlines = 0;
369818334Speter
369918334Speter    /* Now write out the K&R style formal declarations, one per line.  */
370018334Speter
370118334Speter    decl_p = def_dec_p->formal_decls;
370218334Speter    limit_p = decl_p + strlen (decl_p);
370318334Speter    for (;decl_p < limit_p; decl_p = semicolon_p + 2)
370418334Speter      {
3705117395Skan	for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3706117395Skan	  continue;
3707117395Skan	output_string ("\n");
3708117395Skan	output_string (indent_string);
3709117395Skan	output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
371018334Speter      }
371118334Speter
371218334Speter    /* If there are no newlines between the end of the formals list and the
371318334Speter       start of the body, we should insert one now.  */
371418334Speter
371518334Speter    for (scan_p = end_formals+1; *scan_p != '{'; )
371618334Speter      {
3717117395Skan	if (*scan_p == '\n')
3718117395Skan	  {
3719117395Skan	    had_newlines = 1;
3720117395Skan	    break;
3721117395Skan	  }
3722117395Skan	check_source (++scan_p < clean_text_limit, 0);
372318334Speter      }
372418334Speter    if (!had_newlines)
372518334Speter      output_string ("\n");
372618334Speter  }
372718334Speter#else /* !defined (UNPROTOIZE) */
372818334Speter  /* If we are protoizing, there may be some flotsam & jetsam (like comments
372918334Speter     and preprocessing directives) after the old formals list but before
373018334Speter     the following { and we would like to preserve that stuff while effectively
373118334Speter     deleting the existing K&R formal parameter declarations.  We do so here
373218334Speter     in a rather tricky way.  Basically, we white out any stuff *except*
373318334Speter     the comments/pp-directives in the original text buffer, then, if there
373418334Speter     is anything in this area *other* than whitespace, we output it.  */
373518334Speter  {
373618334Speter    const char *end_formals_orig;
373718334Speter    const char *start_body;
373818334Speter    const char *start_body_orig;
373918334Speter    const char *scan;
374018334Speter    const char *scan_orig;
374118334Speter    int have_flotsam = 0;
374218334Speter    int have_newlines = 0;
374318334Speter
374418334Speter    for (start_body = end_formals + 1; *start_body != '{';)
374518334Speter      check_source (++start_body < clean_text_limit, 0);
374618334Speter
374718334Speter    end_formals_orig = orig_text_base + (end_formals - clean_text_base);
374818334Speter    start_body_orig = orig_text_base + (start_body - clean_text_base);
374918334Speter    scan = end_formals + 1;
375018334Speter    scan_orig = end_formals_orig + 1;
375118334Speter    for (; scan < start_body; scan++, scan_orig++)
375218334Speter      {
3753117395Skan	if (*scan == *scan_orig)
3754117395Skan	  {
3755117395Skan	    have_newlines |= (*scan_orig == '\n');
3756117395Skan	    /* Leave identical whitespace alone.  */
3757117395Skan	    if (!ISSPACE ((const unsigned char)*scan_orig))
3758117395Skan	      *((NONCONST char *) scan_orig) = ' '; /* identical - so whiteout */
3759117395Skan	  }
3760117395Skan	else
3761117395Skan	  have_flotsam = 1;
376218334Speter      }
376318334Speter    if (have_flotsam)
376418334Speter      output_bytes (end_formals_orig + 1,
376518334Speter		    (size_t) (start_body_orig - end_formals_orig) - 1);
376618334Speter    else
376718334Speter      if (have_newlines)
3768117395Skan	output_string ("\n");
376918334Speter      else
3770117395Skan	output_string (" ");
377118334Speter    clean_read_ptr = start_body - 1;
377218334Speter  }
377318334Speter#endif /* !defined (UNPROTOIZE) */
377418334Speter}
377518334Speter
377618334Speter/* Clean up the clean text buffer.  Do this by converting comments and
377718334Speter   preprocessing directives into spaces.   Also convert line continuations
377818334Speter   into whitespace.  Also, whiteout string and character literals.  */
377918334Speter
378018334Speterstatic void
378118334Speterdo_cleaning (new_clean_text_base, new_clean_text_limit)
378218334Speter     char *new_clean_text_base;
378390075Sobrien     const char *new_clean_text_limit;
378418334Speter{
378518334Speter  char *scan_p;
378618334Speter  int non_whitespace_since_newline = 0;
378718334Speter
378818334Speter  for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
378918334Speter    {
379018334Speter      switch (*scan_p)
3791117395Skan	{
3792117395Skan	case '/':			/* Handle comments.  */
3793117395Skan	  if (scan_p[1] != '*')
3794117395Skan	    goto regular;
3795117395Skan	  non_whitespace_since_newline = 1;
3796117395Skan	  scan_p[0] = ' ';
3797117395Skan	  scan_p[1] = ' ';
3798117395Skan	  scan_p += 2;
3799117395Skan	  while (scan_p[1] != '/' || scan_p[0] != '*')
3800117395Skan	    {
3801117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3802117395Skan		*scan_p = ' ';
3803117395Skan	      if (++scan_p >= new_clean_text_limit)
3804117395Skan		abort ();
3805117395Skan	    }
3806117395Skan	  *scan_p++ = ' ';
3807117395Skan	  *scan_p = ' ';
3808117395Skan	  break;
380918334Speter
3810117395Skan	case '#':			/* Handle pp directives.  */
3811117395Skan	  if (non_whitespace_since_newline)
3812117395Skan	    goto regular;
3813117395Skan	  *scan_p = ' ';
3814117395Skan	  while (scan_p[1] != '\n' || scan_p[0] == '\\')
3815117395Skan	    {
3816117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3817117395Skan		*scan_p = ' ';
3818117395Skan	      if (++scan_p >= new_clean_text_limit)
3819117395Skan		abort ();
3820117395Skan	    }
3821117395Skan	  *scan_p++ = ' ';
3822117395Skan	  break;
382318334Speter
3824117395Skan	case '\'':			/* Handle character literals.  */
3825117395Skan	  non_whitespace_since_newline = 1;
3826117395Skan	  while (scan_p[1] != '\'' || scan_p[0] == '\\')
3827117395Skan	    {
3828117395Skan	      if (scan_p[0] == '\\'
3829117395Skan		  && !ISSPACE ((const unsigned char) scan_p[1]))
3830117395Skan		scan_p[1] = ' ';
3831117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3832117395Skan		*scan_p = ' ';
3833117395Skan	      if (++scan_p >= new_clean_text_limit)
3834117395Skan		abort ();
3835117395Skan	    }
3836117395Skan	  *scan_p++ = ' ';
3837117395Skan	  break;
383818334Speter
3839117395Skan	case '"':			/* Handle string literals.  */
3840117395Skan	  non_whitespace_since_newline = 1;
3841117395Skan	  while (scan_p[1] != '"' || scan_p[0] == '\\')
3842117395Skan	    {
3843117395Skan	      if (scan_p[0] == '\\'
3844117395Skan		  && !ISSPACE ((const unsigned char) scan_p[1]))
3845117395Skan		scan_p[1] = ' ';
3846117395Skan	      if (!ISSPACE ((const unsigned char)*scan_p))
3847117395Skan		*scan_p = ' ';
3848117395Skan	      if (++scan_p >= new_clean_text_limit)
3849117395Skan		abort ();
3850117395Skan	    }
3851117395Skan	  if (!ISSPACE ((const unsigned char)*scan_p))
3852117395Skan	    *scan_p = ' ';
3853117395Skan	  scan_p++;
3854117395Skan	  break;
385518334Speter
3856117395Skan	case '\\':			/* Handle line continuations.  */
3857117395Skan	  if (scan_p[1] != '\n')
3858117395Skan	    goto regular;
3859117395Skan	  *scan_p = ' ';
3860117395Skan	  break;
386118334Speter
3862117395Skan	case '\n':
3863117395Skan	  non_whitespace_since_newline = 0;	/* Reset.  */
3864117395Skan	  break;
386518334Speter
3866117395Skan	case ' ':
3867117395Skan	case '\v':
3868117395Skan	case '\t':
3869117395Skan	case '\r':
3870117395Skan	case '\f':
3871117395Skan	case '\b':
3872117395Skan	  break;		/* Whitespace characters.  */
387318334Speter
3874117395Skan	default:
387518334Speterregular:
3876117395Skan	  non_whitespace_since_newline = 1;
3877117395Skan	  break;
3878117395Skan	}
387918334Speter    }
388018334Speter}
388118334Speter
388218334Speter/* Given a pointer to the closing right parenthesis for a particular formals
388318334Speter   list (in the clean text buffer) find the corresponding left parenthesis
388418334Speter   and return a pointer to it.  */
388518334Speter
388618334Speterstatic const char *
388718334Spetercareful_find_l_paren (p)
388818334Speter     const char *p;
388918334Speter{
389018334Speter  const char *q;
389118334Speter  int paren_depth;
389218334Speter
389318334Speter  for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
389418334Speter    {
389518334Speter      switch (*q)
3896117395Skan	{
3897117395Skan	case ')':
3898117395Skan	  paren_depth++;
3899117395Skan	  break;
3900117395Skan	case '(':
3901117395Skan	  paren_depth--;
3902117395Skan	  break;
3903117395Skan	}
390418334Speter    }
390518334Speter  return ++q;
390618334Speter}
390718334Speter
390818334Speter/* Scan the clean text buffer for cases of function definitions that we
390918334Speter   don't really know about because they were preprocessed out when the
391018334Speter   aux info files were created.
391118334Speter
391218334Speter   In this version of protoize/unprotoize we just give a warning for each
391318334Speter   one found.  A later version may be able to at least unprotoize such
391418334Speter   missed items.
391518334Speter
391618334Speter   Note that we may easily find all function definitions simply by
391718334Speter   looking for places where there is a left paren which is (ignoring
391818334Speter   whitespace) immediately followed by either a left-brace or by an
391918334Speter   upper or lower case letter.  Whenever we find this combination, we
392018334Speter   have also found a function definition header.
392118334Speter
392218334Speter   Finding function *declarations* using syntactic clues is much harder.
392318334Speter   I will probably try to do this in a later version though.  */
392418334Speter
392518334Speterstatic void
392618334Speterscan_for_missed_items (file_p)
392718334Speter     const file_info *file_p;
392818334Speter{
392918334Speter  static const char *scan_p;
393018334Speter  const char *limit = clean_text_limit - 3;
393118334Speter  static const char *backup_limit;
393218334Speter
393318334Speter  backup_limit = clean_text_base - 1;
393418334Speter
393518334Speter  for (scan_p = clean_text_base; scan_p < limit; scan_p++)
393618334Speter    {
393718334Speter      if (*scan_p == ')')
3938117395Skan	{
3939117395Skan	  static const char *last_r_paren;
3940117395Skan	  const char *ahead_p;
394118334Speter
3942117395Skan	  last_r_paren = scan_p;
394318334Speter
3944117395Skan	  for (ahead_p = scan_p + 1; ISSPACE ((const unsigned char)*ahead_p); )
3945117395Skan	    check_source (++ahead_p < limit, limit);
394618334Speter
3947117395Skan	  scan_p = ahead_p - 1;
394818334Speter
3949117395Skan	  if (ISALPHA ((const unsigned char)*ahead_p) || *ahead_p == '{')
3950117395Skan	    {
3951117395Skan	      const char *last_l_paren;
3952117395Skan	      const int lineno = identify_lineno (ahead_p);
395318334Speter
3954117395Skan	      if (setjmp (source_confusion_recovery))
3955117395Skan		continue;
395618334Speter
3957117395Skan	      /* We know we have a function definition header.  Now skip
3958117395Skan	         leftwards over all of its associated formals lists.  */
395918334Speter
3960117395Skan	      do
3961117395Skan		{
3962117395Skan		  last_l_paren = careful_find_l_paren (last_r_paren);
3963117395Skan		  for (last_r_paren = last_l_paren-1;
396452284Sobrien		       ISSPACE ((const unsigned char)*last_r_paren); )
3965117395Skan		    check_source (--last_r_paren >= backup_limit, backup_limit);
3966117395Skan		}
3967117395Skan	      while (*last_r_paren == ')');
396818334Speter
3969117395Skan	      if (is_id_char (*last_r_paren))
3970117395Skan		{
3971117395Skan		  const char *id_limit = last_r_paren + 1;
3972117395Skan		  const char *id_start;
3973117395Skan		  size_t id_length;
3974117395Skan		  const def_dec_info *dd_p;
397518334Speter
3976117395Skan		  for (id_start = id_limit-1; is_id_char (*id_start); )
3977117395Skan		    check_source (--id_start >= backup_limit, backup_limit);
3978117395Skan		  id_start++;
3979117395Skan		  backup_limit = id_start;
3980117395Skan		  if ((id_length = (size_t) (id_limit - id_start)) == 0)
3981117395Skan		    goto not_missed;
398218334Speter
398318334Speter		  {
398418334Speter		    char *func_name = (char *) alloca (id_length + 1);
398518334Speter		    static const char * const stmt_keywords[]
398618334Speter		      = { "if", "else", "do", "while", "for", "switch", "case", "return", 0 };
398718334Speter		    const char * const *stmt_keyword;
398818334Speter
398918334Speter		    strncpy (func_name, id_start, id_length);
399018334Speter		    func_name[id_length] = '\0';
399118334Speter
399218334Speter		    /* We must check here to see if we are actually looking at
399318334Speter		       a statement rather than an actual function call.  */
399418334Speter
399518334Speter		    for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
399618334Speter		      if (!strcmp (func_name, *stmt_keyword))
399718334Speter			goto not_missed;
399818334Speter
399918334Speter#if 0
400052284Sobrien		    notice ("%s: found definition of `%s' at %s(%d)\n",
400152284Sobrien			    pname,
400252284Sobrien			    func_name,
400352284Sobrien			    shortpath (NULL, file_p->hash_entry->symbol),
400452284Sobrien			    identify_lineno (id_start));
400518334Speter#endif				/* 0 */
400618334Speter		    /* We really should check for a match of the function name
400718334Speter		       here also, but why bother.  */
400818334Speter
400918334Speter		    for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
401018334Speter		      if (dd_p->is_func_def && dd_p->line == lineno)
401118334Speter			goto not_missed;
401218334Speter
401318334Speter		    /* If we make it here, then we did not know about this
401418334Speter		       function definition.  */
401518334Speter
401652284Sobrien		    notice ("%s: %d: warning: `%s' excluded by preprocessing\n",
401752284Sobrien			    shortpath (NULL, file_p->hash_entry->symbol),
401852284Sobrien			    identify_lineno (id_start), func_name);
401952284Sobrien		    notice ("%s: function definition not converted\n",
402052284Sobrien			    pname);
402118334Speter		  }
402218334Speter		not_missed: ;
4023117395Skan	        }
4024117395Skan	    }
4025117395Skan	}
402618334Speter    }
402718334Speter}
402818334Speter
402918334Speter/* Do all editing operations for a single source file (either a "base" file
403018334Speter   or an "include" file).  To do this we read the file into memory, keep a
403118334Speter   virgin copy there, make another cleaned in-core copy of the original file
403218334Speter   (i.e. one in which all of the comments and preprocessing directives have
403318334Speter   been replaced with whitespace), then use these two in-core copies of the
403418334Speter   file to make a new edited in-core copy of the file.  Finally, rename the
403518334Speter   original file (as a way of saving it), and then write the edited version
403618334Speter   of the file from core to a disk file of the same name as the original.
403718334Speter
403818334Speter   Note that the trick of making a copy of the original sans comments &
403918334Speter   preprocessing directives make the editing a whole lot easier.  */
4040117395Skan
404118334Speterstatic void
404218334Speteredit_file (hp)
404318334Speter     const hash_table_entry *hp;
404418334Speter{
404518334Speter  struct stat stat_buf;
404618334Speter  const file_info *file_p = hp->fip;
404718334Speter  char *new_orig_text_base;
404818334Speter  char *new_orig_text_limit;
404918334Speter  char *new_clean_text_base;
405018334Speter  char *new_clean_text_limit;
405118334Speter  size_t orig_size;
405218334Speter  size_t repl_size;
405318334Speter  int first_definition_in_file;
405418334Speter
405518334Speter  /* If we are not supposed to be converting this file, or if there is
405618334Speter     nothing in there which needs converting, just skip this file.  */
405718334Speter
405818334Speter  if (!needs_to_be_converted (file_p))
405918334Speter    return;
406018334Speter
406118334Speter  convert_filename = file_p->hash_entry->symbol;
406218334Speter
406318334Speter  /* Convert a file if it is in a directory where we want conversion
406418334Speter     and the file is not excluded.  */
406518334Speter
406618334Speter  if (!directory_specified_p (convert_filename)
406718334Speter      || file_excluded_p (convert_filename))
406818334Speter    {
406918334Speter      if (!quiet_flag
407018334Speter#ifdef UNPROTOIZE
4071117395Skan	  /* Don't even mention "system" include files unless we are
4072117395Skan	     protoizing.  If we are protoizing, we mention these as a
4073117395Skan	     gentle way of prodding the user to convert his "system"
4074117395Skan	     include files to prototype format.  */
4075117395Skan	  && !in_system_include_dir (convert_filename)
407618334Speter#endif /* defined (UNPROTOIZE) */
4077117395Skan	  )
4078117395Skan	notice ("%s: `%s' not converted\n",
407952284Sobrien		pname, shortpath (NULL, convert_filename));
408018334Speter      return;
408118334Speter    }
408218334Speter
408318334Speter  /* Let the user know what we are up to.  */
408418334Speter
408518334Speter  if (nochange_flag)
408652284Sobrien    notice ("%s: would convert file `%s'\n",
408752284Sobrien	    pname, shortpath (NULL, convert_filename));
408818334Speter  else
408952284Sobrien    notice ("%s: converting file `%s'\n",
409052284Sobrien	    pname, shortpath (NULL, convert_filename));
409118334Speter  fflush (stderr);
409218334Speter
409318334Speter  /* Find out the size (in bytes) of the original file.  */
409418334Speter
409518334Speter  /* The cast avoids an erroneous warning on AIX.  */
409690075Sobrien  if (stat (convert_filename, &stat_buf) == -1)
409718334Speter    {
409850397Sobrien      int errno_val = errno;
409952284Sobrien      notice ("%s: can't get status for file `%s': %s\n",
410052284Sobrien	      pname, shortpath (NULL, convert_filename),
410152284Sobrien	      xstrerror (errno_val));
410218334Speter      return;
410318334Speter    }
410418334Speter  orig_size = stat_buf.st_size;
410518334Speter
410618334Speter  /* Allocate a buffer to hold the original text.  */
410718334Speter
410818334Speter  orig_text_base = new_orig_text_base = (char *) xmalloc (orig_size + 2);
410918334Speter  orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
411018334Speter
411118334Speter  /* Allocate a buffer to hold the cleaned-up version of the original text.  */
411218334Speter
411318334Speter  clean_text_base = new_clean_text_base = (char *) xmalloc (orig_size + 2);
411418334Speter  clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
411518334Speter  clean_read_ptr = clean_text_base - 1;
411618334Speter
411718334Speter  /* Allocate a buffer that will hopefully be large enough to hold the entire
411818334Speter     converted output text.  As an initial guess for the maximum size of the
411918334Speter     output buffer, use 125% of the size of the original + some extra.  This
412018334Speter     buffer can be expanded later as needed.  */
412118334Speter
412218334Speter  repl_size = orig_size + (orig_size >> 2) + 4096;
412318334Speter  repl_text_base = (char *) xmalloc (repl_size + 2);
412418334Speter  repl_text_limit = repl_text_base + repl_size - 1;
412518334Speter  repl_write_ptr = repl_text_base - 1;
412618334Speter
412718334Speter  {
412818334Speter    int input_file;
412990075Sobrien    int fd_flags;
413018334Speter
413118334Speter    /* Open the file to be converted in READ ONLY mode.  */
413218334Speter
413390075Sobrien    fd_flags = O_RDONLY;
413490075Sobrien#ifdef O_BINARY
413590075Sobrien    /* Use binary mode to avoid having to deal with different EOL characters.  */
413690075Sobrien    fd_flags |= O_BINARY;
413790075Sobrien#endif
413890075Sobrien    if ((input_file = open (convert_filename, fd_flags, 0444)) == -1)
413918334Speter      {
414050397Sobrien	int errno_val = errno;
4141117395Skan	notice ("%s: can't open file `%s' for reading: %s\n",
414252284Sobrien		pname, shortpath (NULL, convert_filename),
414352284Sobrien		xstrerror (errno_val));
4144117395Skan	return;
414518334Speter      }
414618334Speter
414718334Speter    /* Read the entire original source text file into the original text buffer
414818334Speter       in one swell fwoop.  Then figure out where the end of the text is and
414918334Speter       make sure that it ends with a newline followed by a null.  */
415018334Speter
415152284Sobrien    if (safe_read (input_file, new_orig_text_base, orig_size) !=
415252284Sobrien	(int) orig_size)
415318334Speter      {
415450397Sobrien	int errno_val = errno;
4155117395Skan	close (input_file);
4156117395Skan	notice ("\n%s: error reading input file `%s': %s\n",
415752284Sobrien		pname, shortpath (NULL, convert_filename),
415852284Sobrien		xstrerror (errno_val));
4159117395Skan	return;
416018334Speter      }
416118334Speter
416218334Speter    close (input_file);
416318334Speter  }
416418334Speter
416518334Speter  if (orig_size == 0 || orig_text_limit[-1] != '\n')
416618334Speter    {
416718334Speter      *new_orig_text_limit++ = '\n';
416818334Speter      orig_text_limit++;
416918334Speter    }
417018334Speter
417118334Speter  /* Create the cleaned up copy of the original text.  */
417218334Speter
417318334Speter  memcpy (new_clean_text_base, orig_text_base,
417418334Speter	  (size_t) (orig_text_limit - orig_text_base));
417518334Speter  do_cleaning (new_clean_text_base, new_clean_text_limit);
417618334Speter
417718334Speter#if 0
417818334Speter  {
417918334Speter    int clean_file;
418018334Speter    size_t clean_size = orig_text_limit - orig_text_base;
418118334Speter    char *const clean_filename = (char *) alloca (strlen (convert_filename) + 6 + 1);
418218334Speter
418318334Speter    /* Open (and create) the clean file.  */
4184117395Skan
418518334Speter    strcpy (clean_filename, convert_filename);
418618334Speter    strcat (clean_filename, ".clean");
418718334Speter    if ((clean_file = creat (clean_filename, 0666)) == -1)
418818334Speter      {
418950397Sobrien	int errno_val = errno;
4190117395Skan	notice ("%s: can't create/open clean file `%s': %s\n",
419152284Sobrien		pname, shortpath (NULL, clean_filename),
419252284Sobrien		xstrerror (errno_val));
4193117395Skan	return;
419418334Speter      }
4195117395Skan
419618334Speter    /* Write the clean file.  */
4197117395Skan
419818334Speter    safe_write (clean_file, new_clean_text_base, clean_size, clean_filename);
4199117395Skan
420018334Speter    close (clean_file);
420118334Speter  }
420218334Speter#endif /* 0 */
420318334Speter
420418334Speter  /* Do a simplified scan of the input looking for things that were not
420518334Speter     mentioned in the aux info files because of the fact that they were
420618334Speter     in a region of the source which was preprocessed-out (via #if or
420718334Speter     via #ifdef).  */
420818334Speter
420918334Speter  scan_for_missed_items (file_p);
421018334Speter
421118334Speter  /* Setup to do line-oriented forward seeking in the clean text buffer.  */
421218334Speter
421318334Speter  last_known_line_number = 1;
421418334Speter  last_known_line_start = clean_text_base;
421518334Speter
421618334Speter  /* Now get down to business and make all of the necessary edits.  */
421718334Speter
421818334Speter  {
421918334Speter    const def_dec_info *def_dec_p;
422018334Speter
422118334Speter    first_definition_in_file = 1;
422218334Speter    def_dec_p = file_p->defs_decs;
422318334Speter    for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
422418334Speter      {
4225117395Skan	const char *clean_text_p = seek_to_line (def_dec_p->line);
4226117395Skan
4227117395Skan	/* clean_text_p now points to the first character of the line which
4228117395Skan	   contains the `terminator' for the declaration or definition that
4229117395Skan	   we are about to process.  */
4230117395Skan
423118334Speter#ifndef UNPROTOIZE
423218334Speter
4233117395Skan	if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4234117395Skan	  {
4235117395Skan	    add_global_decls (def_dec_p->file, clean_text_p);
4236117395Skan	    first_definition_in_file = 0;
4237117395Skan	  }
423818334Speter
4239117395Skan	/* Don't edit this item if it is already in prototype format or if it
4240117395Skan	   is a function declaration and we have found no corresponding
4241117395Skan	   definition.  */
424218334Speter
4243117395Skan	if (def_dec_p->prototyped
4244117395Skan	    || (!def_dec_p->is_func_def && !def_dec_p->definition))
4245117395Skan	  continue;
4246117395Skan
424718334Speter#endif /* !defined (UNPROTOIZE) */
424818334Speter
4249117395Skan	if (def_dec_p->is_func_def)
4250117395Skan	  edit_fn_definition (def_dec_p, clean_text_p);
4251117395Skan	else
425218334Speter#ifndef UNPROTOIZE
4253117395Skan	if (def_dec_p->is_implicit)
4254117395Skan	  add_local_decl (def_dec_p, clean_text_p);
4255117395Skan	else
425618334Speter#endif /* !defined (UNPROTOIZE) */
4257117395Skan	  edit_fn_declaration (def_dec_p, clean_text_p);
425818334Speter      }
425918334Speter  }
426018334Speter
426118334Speter  /* Finalize things.  Output the last trailing part of the original text.  */
426218334Speter
426318334Speter  output_up_to (clean_text_limit - 1);
426418334Speter
426518334Speter  /* If this is just a test run, stop now and just deallocate the buffers.  */
426618334Speter
426718334Speter  if (nochange_flag)
426818334Speter    {
426918334Speter      free (new_orig_text_base);
427018334Speter      free (new_clean_text_base);
427118334Speter      free (repl_text_base);
427218334Speter      return;
427318334Speter    }
427418334Speter
427518334Speter  /* Change the name of the original input file.  This is just a quick way of
427618334Speter     saving the original file.  */
427718334Speter
427818334Speter  if (!nosave_flag)
427918334Speter    {
428050397Sobrien      char *new_filename
428150397Sobrien	= (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
4282117395Skan
428318334Speter      strcpy (new_filename, convert_filename);
428490075Sobrien#ifdef __MSDOS__
428590075Sobrien      /* MSDOS filenames are restricted to 8.3 format, so we save `foo.c'
4286117395Skan	 as `foo.<save_suffix>'.  */
428790075Sobrien      new_filename[(strlen (convert_filename) - 1] = '\0';
428890075Sobrien#endif
428918334Speter      strcat (new_filename, save_suffix);
429090075Sobrien
429190075Sobrien      /* Don't overwrite existing file.  */
429290075Sobrien      if (access (new_filename, F_OK) == 0)
429390075Sobrien	{
429490075Sobrien	  if (!quiet_flag)
429590075Sobrien	    notice ("%s: warning: file `%s' already saved in `%s'\n",
429690075Sobrien		    pname,
429790075Sobrien		    shortpath (NULL, convert_filename),
429890075Sobrien		    shortpath (NULL, new_filename));
429990075Sobrien	}
430090075Sobrien      else if (rename (convert_filename, new_filename) == -1)
4301117395Skan	{
430250397Sobrien	  int errno_val = errno;
430390075Sobrien	  notice ("%s: can't link file `%s' to `%s': %s\n",
430490075Sobrien		  pname,
430590075Sobrien		  shortpath (NULL, convert_filename),
430690075Sobrien		  shortpath (NULL, new_filename),
430790075Sobrien		  xstrerror (errno_val));
430890075Sobrien	  return;
4309117395Skan	}
431018334Speter    }
431118334Speter
431290075Sobrien  if (unlink (convert_filename) == -1)
431318334Speter    {
431450397Sobrien      int errno_val = errno;
431590075Sobrien      /* The file may have already been renamed.  */
431690075Sobrien      if (errno_val != ENOENT)
4317117395Skan	{
431890075Sobrien	  notice ("%s: can't delete file `%s': %s\n",
431990075Sobrien		  pname, shortpath (NULL, convert_filename),
432090075Sobrien		  xstrerror (errno_val));
432190075Sobrien	  return;
432290075Sobrien	}
432318334Speter    }
432418334Speter
432518334Speter  {
432618334Speter    int output_file;
432718334Speter
432818334Speter    /* Open (and create) the output file.  */
4329117395Skan
433018334Speter    if ((output_file = creat (convert_filename, 0666)) == -1)
433118334Speter      {
433250397Sobrien	int errno_val = errno;
4333117395Skan	notice ("%s: can't create/open output file `%s': %s\n",
433452284Sobrien		pname, shortpath (NULL, convert_filename),
433552284Sobrien		xstrerror (errno_val));
4336117395Skan	return;
433718334Speter      }
433890075Sobrien#ifdef O_BINARY
433990075Sobrien    /* Use binary mode to avoid changing the existing EOL character.  */
434090075Sobrien    setmode (output_file, O_BINARY);
434190075Sobrien#endif
4342117395Skan
434318334Speter    /* Write the output file.  */
4344117395Skan
434518334Speter    {
434618334Speter      unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4347117395Skan
434818334Speter      safe_write (output_file, repl_text_base, out_size, convert_filename);
434918334Speter    }
4350117395Skan
435118334Speter    close (output_file);
435218334Speter  }
435318334Speter
435418334Speter  /* Deallocate the conversion buffers.  */
435518334Speter
435618334Speter  free (new_orig_text_base);
435718334Speter  free (new_clean_text_base);
435818334Speter  free (repl_text_base);
435918334Speter
436018334Speter  /* Change the mode of the output file to match the original file.  */
436118334Speter
436218334Speter  /* The cast avoids an erroneous warning on AIX.  */
436390075Sobrien  if (chmod (convert_filename, stat_buf.st_mode) == -1)
436450397Sobrien    {
436550397Sobrien      int errno_val = errno;
436652284Sobrien      notice ("%s: can't change mode of file `%s': %s\n",
436752284Sobrien	      pname, shortpath (NULL, convert_filename),
436852284Sobrien	      xstrerror (errno_val));
436950397Sobrien    }
437018334Speter
437118334Speter  /* Note:  We would try to change the owner and group of the output file
437218334Speter     to match those of the input file here, except that may not be a good
437318334Speter     thing to do because it might be misleading.  Also, it might not even
437418334Speter     be possible to do that (on BSD systems with quotas for instance).  */
437518334Speter}
437618334Speter
437718334Speter/* Do all of the individual steps needed to do the protoization (or
437818334Speter   unprotoization) of the files referenced in the aux_info files given
437918334Speter   in the command line.  */
438018334Speter
438118334Speterstatic void
438218334Speterdo_processing ()
438318334Speter{
438418334Speter  const char * const *base_pp;
438518334Speter  const char * const * const end_pps
438618334Speter    = &base_source_filenames[n_base_source_files];
438718334Speter
438818334Speter#ifndef UNPROTOIZE
438918334Speter  int syscalls_len;
439018334Speter#endif /* !defined (UNPROTOIZE) */
439118334Speter
439218334Speter  /* One-by-one, check (and create if necessary), open, and read all of the
439318334Speter     stuff in each aux_info file.  After reading each aux_info file, the
439418334Speter     aux_info_file just read will be automatically deleted unless the
439518334Speter     keep_flag is set.  */
439618334Speter
439718334Speter  for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
439818334Speter    process_aux_info_file (*base_pp, keep_flag, 0);
439918334Speter
440018334Speter#ifndef UNPROTOIZE
440118334Speter
440218334Speter  /* Also open and read the special SYSCALLS.c aux_info file which gives us
440318334Speter     the prototypes for all of the standard system-supplied functions.  */
440418334Speter
440518334Speter  if (nondefault_syscalls_dir)
440618334Speter    {
440718334Speter      syscalls_absolute_filename
4408117395Skan	= (char *) xmalloc (strlen (nondefault_syscalls_dir) + 1
4409117395Skan	                    + sizeof (syscalls_filename));
441018334Speter      strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
441118334Speter    }
441218334Speter  else
441318334Speter    {
4414117395Skan      GET_ENVIRONMENT (default_syscalls_dir, "GCC_EXEC_PREFIX");
441590075Sobrien      if (!default_syscalls_dir)
441690075Sobrien	{
441790075Sobrien	  default_syscalls_dir = standard_exec_prefix;
441890075Sobrien	}
441918334Speter      syscalls_absolute_filename
4420117395Skan	= (char *) xmalloc (strlen (default_syscalls_dir) + 0
442190075Sobrien			    + strlen (target_machine) + 1
442290075Sobrien			    + strlen (target_version) + 1
4423117395Skan	                    + sizeof (syscalls_filename));
442418334Speter      strcpy (syscalls_absolute_filename, default_syscalls_dir);
442590075Sobrien      strcat (syscalls_absolute_filename, target_machine);
442690075Sobrien      strcat (syscalls_absolute_filename, "/");
442790075Sobrien      strcat (syscalls_absolute_filename, target_version);
442890075Sobrien      strcat (syscalls_absolute_filename, "/");
442918334Speter    }
443018334Speter
443118334Speter  syscalls_len = strlen (syscalls_absolute_filename);
443290075Sobrien  if (! IS_DIR_SEPARATOR (*(syscalls_absolute_filename + syscalls_len - 1)))
443318334Speter    {
443490075Sobrien      *(syscalls_absolute_filename + syscalls_len++) = DIR_SEPARATOR;
443518334Speter      *(syscalls_absolute_filename + syscalls_len) = '\0';
443618334Speter    }
443718334Speter  strcat (syscalls_absolute_filename, syscalls_filename);
4438117395Skan
443918334Speter  /* Call process_aux_info_file in such a way that it does not try to
444018334Speter     delete the SYSCALLS aux_info file.  */
444118334Speter
444218334Speter  process_aux_info_file (syscalls_absolute_filename, 1, 1);
444318334Speter
444418334Speter#endif /* !defined (UNPROTOIZE) */
444518334Speter
444618334Speter  /* When we first read in all of the information from the aux_info files
444718334Speter     we saved in it descending line number order, because that was likely to
444818334Speter     be faster.  Now however, we want the chains of def & dec records to
444918334Speter     appear in ascending line number order as we get further away from the
445018334Speter     file_info record that they hang from.  The following line causes all of
445118334Speter     these lists to be rearranged into ascending line number order.  */
445218334Speter
445318334Speter  visit_each_hash_node (filename_primary, reverse_def_dec_list);
445418334Speter
445518334Speter#ifndef UNPROTOIZE
445618334Speter
445718334Speter  /* Now do the "real" work.  The following line causes each declaration record
445818334Speter     to be "visited".  For each of these nodes, an attempt is made to match
445918334Speter     up the function declaration with a corresponding function definition,
446018334Speter     which should have a full prototype-format formals list with it.  Once
446118334Speter     these match-ups are made, the conversion of the function declarations
446218334Speter     to prototype format can be made.  */
446318334Speter
446418334Speter  visit_each_hash_node (function_name_primary, connect_defs_and_decs);
446518334Speter
446618334Speter#endif /* !defined (UNPROTOIZE) */
446718334Speter
446818334Speter  /* Now convert each file that can be converted (and needs to be).  */
446918334Speter
447018334Speter  visit_each_hash_node (filename_primary, edit_file);
447118334Speter
447218334Speter#ifndef UNPROTOIZE
447318334Speter
447418334Speter  /* If we are working in cplusplus mode, try to rename all .c files to .C
447518334Speter     files.  Don't panic if some of the renames don't work.  */
447618334Speter
447718334Speter  if (cplusplus_flag && !nochange_flag)
447818334Speter    visit_each_hash_node (filename_primary, rename_c_file);
447918334Speter
448018334Speter#endif /* !defined (UNPROTOIZE) */
448118334Speter}
448218334Speter
448390075Sobrienstatic const struct option longopts[] =
448418334Speter{
448518334Speter  {"version", 0, 0, 'V'},
448618334Speter  {"file_name", 0, 0, 'p'},
448718334Speter  {"quiet", 0, 0, 'q'},
448818334Speter  {"silent", 0, 0, 'q'},
448918334Speter  {"force", 0, 0, 'f'},
449018334Speter  {"keep", 0, 0, 'k'},
449118334Speter  {"nosave", 0, 0, 'N'},
449218334Speter  {"nochange", 0, 0, 'n'},
449318334Speter  {"compiler-options", 1, 0, 'c'},
449418334Speter  {"exclude", 1, 0, 'x'},
449518334Speter  {"directory", 1, 0, 'd'},
449618334Speter#ifdef UNPROTOIZE
449718334Speter  {"indent", 1, 0, 'i'},
449818334Speter#else
449918334Speter  {"local", 0, 0, 'l'},
450018334Speter  {"global", 0, 0, 'g'},
450118334Speter  {"c++", 0, 0, 'C'},
450218334Speter  {"syscalls-dir", 1, 0, 'B'},
450318334Speter#endif
450418334Speter  {0, 0, 0, 0}
450518334Speter};
450618334Speter
450790075Sobrienextern int main PARAMS ((int, char **const));
450890075Sobrien
450918334Speterint
451018334Spetermain (argc, argv)
451118334Speter     int argc;
451218334Speter     char **const argv;
451318334Speter{
451418334Speter  int longind;
451518334Speter  int c;
451618334Speter  const char *params = "";
451718334Speter
451890075Sobrien  pname = strrchr (argv[0], DIR_SEPARATOR);
451990075Sobrien#ifdef DIR_SEPARATOR_2
452090075Sobrien  {
452190075Sobrien    char *slash;
452290075Sobrien
452390075Sobrien    slash = strrchr (pname ? pname : argv[0], DIR_SEPARATOR_2);
452490075Sobrien    if (slash)
452590075Sobrien      pname = slash;
452690075Sobrien  }
452790075Sobrien#endif
452818334Speter  pname = pname ? pname+1 : argv[0];
452918334Speter
453090075Sobrien#ifdef SIGCHLD
453190075Sobrien  /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
453290075Sobrien     receive the signal.  A different setting is inheritable */
453390075Sobrien  signal (SIGCHLD, SIG_DFL);
453452284Sobrien#endif
453552284Sobrien
453690075Sobrien  gcc_init_libintl ();
453790075Sobrien
453818334Speter  cwd_buffer = getpwd ();
453918334Speter  if (!cwd_buffer)
454018334Speter    {
454152284Sobrien      notice ("%s: cannot get working directory: %s\n",
454252284Sobrien	      pname, xstrerror(errno));
454390075Sobrien      return (FATAL_EXIT_CODE);
454418334Speter    }
454518334Speter
454618334Speter  /* By default, convert the files in the current directory.  */
454718334Speter  directory_list = string_list_cons (cwd_buffer, NULL);
454818334Speter
454918334Speter  while ((c = getopt_long (argc, argv,
455018334Speter#ifdef UNPROTOIZE
455118334Speter			   "c:d:i:knNp:qvVx:",
455218334Speter#else
455318334Speter			   "B:c:Cd:gklnNp:qvVx:",
455418334Speter#endif
455518334Speter			   longopts, &longind)) != EOF)
455618334Speter    {
455750397Sobrien      if (c == 0)		/* Long option.  */
455818334Speter	c = longopts[longind].val;
455918334Speter      switch (c)
456018334Speter	{
456118334Speter	case 'p':
456218334Speter	  compiler_file_name = optarg;
456318334Speter	  break;
456418334Speter	case 'd':
456518334Speter	  directory_list
456618334Speter	    = string_list_cons (abspath (NULL, optarg), directory_list);
456718334Speter	  break;
456818334Speter	case 'x':
456918334Speter	  exclude_list = string_list_cons (optarg, exclude_list);
457018334Speter	  break;
4571117395Skan
457218334Speter	case 'v':
457318334Speter	case 'V':
457418334Speter	  version_flag = 1;
457518334Speter	  break;
457618334Speter	case 'q':
457718334Speter	  quiet_flag = 1;
457818334Speter	  break;
457918334Speter#if 0
458018334Speter	case 'f':
458118334Speter	  force_flag = 1;
458218334Speter	  break;
458318334Speter#endif
458418334Speter	case 'n':
458518334Speter	  nochange_flag = 1;
458618334Speter	  keep_flag = 1;
458718334Speter	  break;
458818334Speter	case 'N':
458918334Speter	  nosave_flag = 1;
459018334Speter	  break;
459118334Speter	case 'k':
459218334Speter	  keep_flag = 1;
459318334Speter	  break;
459418334Speter	case 'c':
459518334Speter	  params = optarg;
459618334Speter	  break;
459718334Speter#ifdef UNPROTOIZE
459818334Speter	case 'i':
459918334Speter	  indent_string = optarg;
460018334Speter	  break;
460118334Speter#else				/* !defined (UNPROTOIZE) */
460218334Speter	case 'l':
460318334Speter	  local_flag = 1;
460418334Speter	  break;
460518334Speter	case 'g':
460618334Speter	  global_flag = 1;
460718334Speter	  break;
460818334Speter	case 'C':
460918334Speter	  cplusplus_flag = 1;
461018334Speter	  break;
461118334Speter	case 'B':
461218334Speter	  nondefault_syscalls_dir = optarg;
461318334Speter	  break;
461418334Speter#endif				/* !defined (UNPROTOIZE) */
461518334Speter	default:
461618334Speter	  usage ();
461718334Speter	}
461818334Speter    }
4619117395Skan
462018334Speter  /* Set up compile_params based on -p and -c options.  */
462118334Speter  munge_compile_params (params);
462218334Speter
462318334Speter  n_base_source_files = argc - optind;
462418334Speter
462518334Speter  /* Now actually make a list of the base source filenames.  */
462618334Speter
462750397Sobrien  base_source_filenames
462850397Sobrien    = (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
462918334Speter  n_base_source_files = 0;
463018334Speter  for (; optind < argc; optind++)
463118334Speter    {
463218334Speter      const char *path = abspath (NULL, argv[optind]);
463318334Speter      int len = strlen (path);
463418334Speter
463518334Speter      if (path[len-1] == 'c' && path[len-2] == '.')
463618334Speter	base_source_filenames[n_base_source_files++] = path;
463718334Speter      else
463818334Speter	{
463952284Sobrien	  notice ("%s: input file names must have .c suffixes: %s\n",
464052284Sobrien		  pname, shortpath (NULL, path));
464118334Speter	  errors++;
464218334Speter	}
464318334Speter    }
464418334Speter
464518334Speter#ifndef UNPROTOIZE
464618334Speter  /* We are only interested in the very first identifier token in the
464718334Speter     definition of `va_list', so if there is more junk after that first
464818334Speter     identifier token, delete it from the `varargs_style_indicator'.  */
464918334Speter  {
465018334Speter    const char *cp;
465118334Speter
465290075Sobrien    for (cp = varargs_style_indicator; ISIDNUM (*cp); cp++)
465318334Speter      continue;
465418334Speter    if (*cp != 0)
465518334Speter      varargs_style_indicator = savestring (varargs_style_indicator,
465618334Speter					    cp - varargs_style_indicator);
465718334Speter  }
465818334Speter#endif /* !defined (UNPROTOIZE) */
465918334Speter
466018334Speter  if (errors)
466118334Speter    usage ();
466218334Speter  else
466318334Speter    {
466418334Speter      if (version_flag)
4665117395Skan	fprintf (stderr, "%s: %s\n", pname, version_string);
466618334Speter      do_processing ();
466718334Speter    }
466850397Sobrien
466990075Sobrien  return (errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
467018334Speter}
4671