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