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