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