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