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