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