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