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