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