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