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