]>
Commit | Line | Data |
---|---|---|
e7f9bcdc | 1 | /* fix-header.c - Make C header file suitable for C++. |
55575a9d | 2 | Copyright (C) 1993, 1994 Free Software Foundation, Inc. |
7936052f PB |
3 | |
4 | This program is free software; you can redistribute it and/or modify it | |
5 | under the terms of the GNU General Public License as published by the | |
6 | Free Software Foundation; either version 2, or (at your option) any | |
7 | later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
17 | ||
18 | /* This program massages a system include file (such as stdio.h), | |
19 | into a form more conformant with ANSI/POSIX, and more suitable for C++: | |
20 | ||
21 | * extern "C" { ... } braces are added (inside #ifndef __cplusplus), | |
05227b51 | 22 | if they seem to be needed. These prevent C++ compilers from name |
7936052f PB |
23 | mangling the functions inside the braces. |
24 | ||
25 | * If an old-style incomplete function declaration is seen (without | |
26 | an argument list), and it is a "standard" function listed in | |
27 | the file sys-protos.h (and with a non-empty argument list), then | |
28 | the declaration is converted to a complete prototype by replacing | |
29 | the empty parameter list with the argument lust from sys-protos.h. | |
30 | ||
31 | * The program can be given a list of (names of) required standard | |
32 | functions (such as fclose for stdio.h). If a reqquired function | |
33 | is not seen in the input, then a prototype for it will be | |
34 | written to the output. | |
35 | ||
36 | * If all of the non-comment code of the original file is protected | |
37 | against multiple inclusion: | |
38 | #ifndef FOO | |
39 | #define FOO | |
40 | <body of include file> | |
41 | #endif | |
42 | then extra matter added to the include file is placed inside the <body>. | |
43 | ||
44 | * If the input file is OK (nothing needs to be done); | |
45 | the output file is not written (nor removed if it exists). | |
46 | ||
47 | There are also some special actions that are done for certain | |
48 | well-known standard include files: | |
49 | ||
50 | * If argv[1] is "sys/stat.h", the Posix.1 macros | |
51 | S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if | |
52 | they were missing, and the corresponding "traditional" S_IFxxx | |
53 | macros were defined. | |
54 | ||
55 | * If argv[1] is "errno.h", errno is declared if it was missing. | |
56 | ||
57 | * TODO: The input file should be read complete into memory, because: | |
58 | a) it needs to be scanned twice anyway, and | |
59 | b) it would be nice to allow update in place. | |
60 | ||
61 | Usage: | |
e7f9bcdc | 62 | fix-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE |
7936052f PB |
63 | where: |
64 | * FOO.H is the relative file name of the include file, | |
65 | as it would be #include'd by a C file. (E.g. stdio.h) | |
66 | * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h) | |
67 | * OUTFILE.H is the full pathname for where to write the output file, | |
68 | if anything needs to be done. (e.g. ./include/stdio.h) | |
69 | * SCAN-FILE is the output of the scan-decls program. | |
70 | * REQUIRED_FUNCS is a list of required function (e.g. fclose for stdio.h). | |
71 | ||
72 | Written by Per Bothner <bothner@cygnus.com>, July 1993. */ | |
73 | ||
74 | #include <stdio.h> | |
75 | #include <ctype.h> | |
05227b51 | 76 | #include <sys/types.h> |
49d3ca5c | 77 | #include <sys/stat.h> |
05227b51 PB |
78 | #ifndef O_RDONLY |
79 | #define O_RDONLY 0 | |
80 | #endif | |
39eda06e | 81 | #include "hconfig.h" |
7936052f PB |
82 | #include "obstack.h" |
83 | #include "scan.h" | |
84 | ||
8fb0620c PB |
85 | extern sstring buf; |
86 | ||
7936052f PB |
87 | int verbose = 0; |
88 | int partial_count = 0; | |
af86171d JW |
89 | #if 0 |
90 | /* All uses of this are ifdefed out. This is no longer needed, because | |
91 | cccp.c implicitly forces the standard include files to be treated as C. | |
92 | Adding an explicit extern "C" is undesireable as it breaks the SunOS 4.x | |
93 | sun4c/romvec.h file. */ | |
7936052f | 94 | int missing_extern_C_count = 0; |
af86171d | 95 | #endif |
b156894e | 96 | int missing_errno = 0; |
7936052f PB |
97 | |
98 | #include "xsys-protos.h" | |
99 | ||
05227b51 PB |
100 | char *inf_buffer; |
101 | char *inf_limit; | |
102 | char *inf_ptr; | |
05227b51 | 103 | |
7936052f PB |
104 | /* Certain standard files get extra treatment */ |
105 | ||
106 | enum special_file | |
107 | { | |
108 | no_special, | |
109 | errno_special, | |
110 | sys_stat_special | |
111 | }; | |
112 | ||
113 | enum special_file special_file_handling = no_special; | |
114 | ||
115 | /* The following are only used when handling sys/stat.h */ | |
116 | /* They are set if the corresponding macro has been seen. */ | |
117 | int seen_S_IFBLK = 0, seen_S_ISBLK = 0; | |
118 | int seen_S_IFCHR = 0, seen_S_ISCHR = 0; | |
119 | int seen_S_IFDIR = 0, seen_S_ISDIR = 0; | |
120 | int seen_S_IFIFO = 0, seen_S_ISFIFO = 0; | |
121 | int seen_S_IFLNK = 0, seen_S_ISLNK = 0; | |
122 | int seen_S_IFREG = 0, seen_S_ISREG = 0; | |
10b8b0ba | 123 | \f |
7936052f PB |
124 | /* Wrapper around free, to avoid prototype clashes. */ |
125 | ||
10b8b0ba RS |
126 | void |
127 | xfree (ptr) | |
7936052f PB |
128 | char *ptr; |
129 | { | |
c2b6b9a1 | 130 | free (ptr); |
7936052f PB |
131 | } |
132 | ||
10b8b0ba RS |
133 | /* Avoid error if config defines abort as fancy_abort. |
134 | It's not worth "really" implementing this because ordinary | |
135 | compiler users never run fix-header. */ | |
136 | ||
137 | void | |
138 | fancy_abort () | |
139 | { | |
140 | abort (); | |
141 | } | |
142 | \f | |
7936052f PB |
143 | #define obstack_chunk_alloc xmalloc |
144 | #define obstack_chunk_free xfree | |
145 | struct obstack scan_file_obstack; | |
146 | ||
147 | /* NOTE: If you edit this, also edit gen-protos.c !! */ | |
148 | struct fn_decl * | |
149 | lookup_std_proto (name) | |
150 | char *name; | |
151 | { | |
c2b6b9a1 | 152 | int i = hash (name) % HASH_SIZE; |
7936052f PB |
153 | int i0 = i; |
154 | for (;;) | |
155 | { | |
156 | struct fn_decl *fn; | |
157 | if (hash_tab[i] == 0) | |
158 | return NULL; | |
159 | fn = &std_protos[hash_tab[i]]; | |
160 | if (strcmp (fn->fname, name) == 0) | |
161 | return fn; | |
162 | i = (i+1) % HASH_SIZE; | |
163 | if (i == i0) | |
c2b6b9a1 | 164 | abort (); |
7936052f PB |
165 | } |
166 | } | |
167 | ||
168 | char *inc_filename; | |
169 | int inc_filename_length; | |
e7f9bcdc | 170 | char *progname = "fix-header"; |
7936052f | 171 | FILE *outf; |
7936052f PB |
172 | sstring line; |
173 | ||
174 | int lbrac_line, rbrac_line; | |
175 | ||
176 | char **required_functions; | |
177 | int required_unseen_count; | |
178 | ||
179 | int | |
180 | write_lbrac () | |
181 | { | |
b156894e | 182 | |
af86171d | 183 | #if 0 |
b156894e RS |
184 | if (missing_extern_C_count + required_unseen_count > 0) |
185 | fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); | |
af86171d | 186 | #endif |
7936052f PB |
187 | |
188 | if (partial_count) | |
189 | { | |
190 | fprintf (outf, "#ifndef _PARAMS\n"); | |
191 | fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n"); | |
192 | fprintf (outf, "#define _PARAMS(ARGS) ARGS\n"); | |
193 | fprintf (outf, "#else\n"); | |
194 | fprintf (outf, "#define _PARAMS(ARGS) ()\n"); | |
195 | fprintf (outf, "#endif\n#endif /* _PARAMS */\n"); | |
196 | } | |
197 | } | |
198 | ||
199 | struct partial_proto | |
200 | { | |
201 | struct partial_proto *next; | |
202 | char *fname; /* name of function */ | |
203 | char *rtype; /* return type */ | |
204 | struct fn_decl *fn; | |
205 | int line_seen; | |
206 | }; | |
207 | ||
208 | struct partial_proto *partial_proto_list = NULL; | |
209 | ||
210 | struct partial_proto required_dummy_proto; | |
211 | #define REQUIRED(FN) ((FN)->partial == &required_dummy_proto) | |
212 | #define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto) | |
213 | #define CLEAR_REQUIRED(FN) ((FN)->partial = 0) | |
214 | ||
215 | void | |
05227b51 PB |
216 | recognized_macro (fname) |
217 | char *fname; | |
7936052f | 218 | { |
05227b51 PB |
219 | /* The original include file defines fname as a macro. */ |
220 | struct fn_decl *fn = lookup_std_proto (fname); | |
7936052f | 221 | |
05227b51 PB |
222 | /* Since fname is a macro, don't require a prototype for it. */ |
223 | if (fn && REQUIRED (fn)) | |
7936052f | 224 | { |
c2b6b9a1 | 225 | CLEAR_REQUIRED (fn); |
05227b51 PB |
226 | required_unseen_count--; |
227 | } | |
7936052f | 228 | |
05227b51 PB |
229 | switch (special_file_handling) |
230 | { | |
231 | case errno_special: | |
b156894e | 232 | if (strcmp (fname, "errno") == 0) missing_errno = 0; |
05227b51 PB |
233 | break; |
234 | case sys_stat_special: | |
235 | if (fname[0] == 'S' && fname[1] == '_') | |
7936052f | 236 | { |
05227b51 PB |
237 | if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++; |
238 | else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++; | |
239 | else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++; | |
240 | else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++; | |
241 | else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++; | |
242 | else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++; | |
243 | else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++; | |
244 | else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++; | |
245 | else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++; | |
246 | else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++; | |
247 | else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++; | |
248 | else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++; | |
7936052f | 249 | } |
05227b51 PB |
250 | } |
251 | } | |
7936052f | 252 | |
05227b51 PB |
253 | void |
254 | recognized_extern (name, type) | |
255 | char *name; | |
256 | char *type; | |
257 | { | |
258 | switch (special_file_handling) | |
259 | { | |
260 | case errno_special: | |
b156894e | 261 | if (strcmp (name, "errno") == 0) missing_errno = 0; |
05227b51 PB |
262 | break; |
263 | } | |
264 | } | |
7936052f | 265 | |
05227b51 PB |
266 | /* Called by scan_decls if it saw a function definition for a function |
267 | named FNAME, with return type RTYPE, and argument list ARGS, | |
268 | in source file FILE_SEEN on line LINE_SEEN. | |
269 | KIND is 'I' for an inline function; | |
270 | 'F' if a normal function declaration preceded by 'extern "C"' | |
271 | (or nested inside 'extern "C"' braces); or | |
272 | 'f' for other function declarations. */ | |
7936052f | 273 | |
05227b51 PB |
274 | void |
275 | recognized_function (fname, kind, rtype, args, file_seen, line_seen) | |
276 | char *fname; | |
277 | int kind; /* One of 'f' 'F' or 'I' */ | |
278 | char *rtype; | |
279 | char *args; | |
280 | char *file_seen; | |
281 | int line_seen; | |
282 | { | |
283 | struct partial_proto *partial; | |
284 | int i; | |
285 | struct fn_decl *fn; | |
af86171d | 286 | #if 0 |
05227b51 PB |
287 | if (kind == 'f') |
288 | missing_extern_C_count++; | |
af86171d | 289 | #endif |
7936052f | 290 | |
05227b51 | 291 | fn = lookup_std_proto (fname); |
7936052f | 292 | |
05227b51 PB |
293 | /* Remove the function from the list of required function. */ |
294 | if (fn && REQUIRED (fn)) | |
295 | { | |
c2b6b9a1 | 296 | CLEAR_REQUIRED (fn); |
05227b51 PB |
297 | required_unseen_count--; |
298 | } | |
e9cd0b25 | 299 | |
05227b51 PB |
300 | /* If we have a full prototype, we're done. */ |
301 | if (args[0] != '\0') | |
302 | return; | |
303 | ||
304 | if (kind == 'I') /* don't edit inline function */ | |
305 | return; | |
306 | ||
307 | /* If the partial prototype was included from some other file, | |
308 | we don't need to patch it up (in this run). */ | |
309 | i = strlen (file_seen); | |
310 | if (i < inc_filename_length | |
311 | || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0) | |
312 | return; | |
313 | ||
314 | if (fn == NULL) | |
315 | return; | |
c2b6b9a1 | 316 | if (fn->params[0] == '\0' || strcmp (fn->params, "void") == 0) |
05227b51 PB |
317 | return; |
318 | ||
319 | /* We only have a partial function declaration, | |
320 | so remember that we have to add a complete prototype. */ | |
321 | partial_count++; | |
322 | partial = (struct partial_proto*) | |
c2b6b9a1 RS |
323 | obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto)); |
324 | partial->fname = obstack_alloc (&scan_file_obstack, strlen (fname) + 1); | |
05227b51 | 325 | strcpy (partial->fname, fname); |
c2b6b9a1 | 326 | partial->rtype = obstack_alloc (&scan_file_obstack, strlen (rtype) + 1); |
05227b51 PB |
327 | strcpy (partial->rtype, rtype); |
328 | partial->line_seen = line_seen; | |
329 | partial->fn = fn; | |
330 | fn->partial = partial; | |
331 | partial->next = partial_proto_list; | |
332 | partial_proto_list = partial; | |
333 | if (verbose) | |
334 | { | |
335 | fprintf (stderr, "(%s: %s non-prototype function declaration.)\n", | |
336 | inc_filename, fname); | |
337 | } | |
338 | } | |
7936052f | 339 | |
05227b51 PB |
340 | void |
341 | read_scan_file (scan_file) | |
342 | FILE *scan_file; | |
343 | { | |
c2b6b9a1 | 344 | obstack_init (&scan_file_obstack); |
7936052f | 345 | |
05227b51 | 346 | scan_decls (scan_file); |
7936052f | 347 | |
af86171d JW |
348 | if (required_unseen_count + partial_count + missing_errno |
349 | #if 0 | |
350 | + missing_extern_C_count | |
351 | #endif | |
352 | == 0) | |
7936052f PB |
353 | { |
354 | if (verbose) | |
355 | fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename); | |
356 | exit (0); | |
357 | } | |
e9cd0b25 PB |
358 | if (!verbose) |
359 | fprintf (stderr, "%s: fixing %s\n", progname, inc_filename); | |
360 | else | |
361 | { | |
362 | if (required_unseen_count) | |
363 | fprintf (stderr, "%s: %d missing function declarations.\n", | |
364 | inc_filename, required_unseen_count); | |
365 | if (partial_count) | |
366 | fprintf (stderr, "%s: %d non-prototype function declarations.\n", | |
367 | inc_filename, partial_count); | |
af86171d | 368 | #if 0 |
e9cd0b25 PB |
369 | if (missing_extern_C_count) |
370 | fprintf (stderr, | |
371 | "%s: %d declarations not protected by extern \"C\".\n", | |
372 | inc_filename, missing_extern_C_count); | |
af86171d | 373 | #endif |
e9cd0b25 | 374 | } |
7936052f PB |
375 | } |
376 | ||
377 | write_rbrac () | |
378 | { | |
379 | struct fn_decl *fn; | |
380 | char **rptr; | |
7936052f PB |
381 | |
382 | if (required_unseen_count) | |
2ee370da | 383 | fprintf (outf, "#ifdef __cplusplus\n"); |
7936052f PB |
384 | |
385 | /* Now we print out prototypes for those functions that we haven't seen. */ | |
386 | for (rptr = required_functions; *rptr; rptr++) | |
387 | { | |
10b8b0ba RS |
388 | int macro_protect = 0; |
389 | ||
7936052f PB |
390 | fn = lookup_std_proto (*rptr); |
391 | if (fn == NULL || !REQUIRED (fn)) | |
392 | continue; | |
10b8b0ba RS |
393 | |
394 | /* In the case of memmove, protect in case the application | |
395 | defines it as a macro before including the header. */ | |
5881bacc RS |
396 | if (!strcmp (fn->fname, "memmove") |
397 | || !strcmp (fn->fname, "vprintf") | |
398 | || !strcmp (fn->fname, "vfprintf") | |
4bc38260 RS |
399 | || !strcmp (fn->fname, "vsprintf") |
400 | || !strcmp (fn->fname, "rewinddir")) | |
10b8b0ba RS |
401 | macro_protect = 1; |
402 | ||
403 | if (macro_protect) | |
404 | fprintf (outf, "#ifndef %s\n", fn->fname); | |
7936052f PB |
405 | fprintf (outf, "extern %s %s (%s);\n", |
406 | fn->rtype, fn->fname, fn->params); | |
10b8b0ba RS |
407 | if (macro_protect) |
408 | fprintf (outf, "#endif\n"); | |
7936052f PB |
409 | } |
410 | if (required_unseen_count) | |
411 | fprintf (outf, | |
2ee370da | 412 | "#endif /* defined(__cplusplus) */\n"); |
7936052f PB |
413 | |
414 | switch (special_file_handling) | |
415 | { | |
416 | case errno_special: | |
b156894e | 417 | if (missing_errno) |
7936052f PB |
418 | fprintf (outf, "extern int errno;\n"); |
419 | break; | |
420 | case sys_stat_special: | |
421 | if (!seen_S_ISBLK && seen_S_IFBLK) | |
422 | fprintf (outf, | |
423 | "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n"); | |
424 | if (!seen_S_ISCHR && seen_S_IFCHR) | |
425 | fprintf (outf, | |
426 | "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n"); | |
427 | if (!seen_S_ISDIR && seen_S_IFDIR) | |
428 | fprintf (outf, | |
429 | "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n"); | |
430 | if (!seen_S_ISFIFO && seen_S_IFIFO) | |
431 | fprintf (outf, | |
432 | "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n"); | |
433 | if (!seen_S_ISLNK && seen_S_IFLNK) | |
434 | fprintf (outf, | |
435 | "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n"); | |
436 | if (!seen_S_ISREG && seen_S_IFREG) | |
437 | fprintf (outf, | |
438 | "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n"); | |
439 | break; | |
440 | } | |
441 | ||
442 | ||
af86171d | 443 | #if 0 |
b156894e RS |
444 | if (missing_extern_C_count + required_unseen_count > 0) |
445 | fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n"); | |
af86171d | 446 | #endif |
7936052f PB |
447 | } |
448 | ||
449 | char * | |
450 | strdup (str) | |
451 | char *str; | |
452 | { | |
c2b6b9a1 RS |
453 | char *copy = (char *) xmalloc (strlen (str) + 1); |
454 | strcpy (copy, str); | |
455 | return copy; | |
7936052f PB |
456 | } |
457 | ||
458 | /* Returns 1 iff the file is properly protected from multiple inclusion: | |
459 | #ifndef PROTECT_NAME | |
460 | #define PROTECT_NAME | |
461 | #endif | |
462 | ||
463 | */ | |
464 | ||
05227b51 | 465 | #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF) |
c2b6b9a1 | 466 | #define INF_UNGET(c) ((c)!=EOF && inf_ptr--) |
05227b51 PB |
467 | |
468 | int | |
469 | inf_skip_spaces (c) | |
470 | int c; | |
471 | { | |
472 | for (;;) | |
473 | { | |
474 | if (c == ' ' || c == '\t') | |
c2b6b9a1 | 475 | c = INF_GET (); |
05227b51 PB |
476 | else if (c == '/') |
477 | { | |
c2b6b9a1 | 478 | c = INF_GET (); |
05227b51 PB |
479 | if (c != '*') |
480 | { | |
c2b6b9a1 | 481 | INF_UNGET (c); |
05227b51 PB |
482 | return '/'; |
483 | } | |
c2b6b9a1 | 484 | c = INF_GET (); |
05227b51 PB |
485 | for (;;) |
486 | { | |
487 | if (c == EOF) | |
488 | return EOF; | |
489 | else if (c != '*') | |
490 | { | |
491 | if (c == '\n') | |
492 | source_lineno++, lineno++; | |
493 | c = INF_GET (); | |
494 | } | |
c2b6b9a1 RS |
495 | else if ((c = INF_GET ()) == '/') |
496 | return INF_GET (); | |
05227b51 PB |
497 | } |
498 | } | |
499 | else | |
500 | break; | |
501 | } | |
502 | return c; | |
503 | } | |
504 | ||
505 | /* Read into STR from inf_buffer upto DELIM. */ | |
506 | ||
507 | int | |
508 | inf_read_upto (str, delim) | |
509 | sstring *str; | |
510 | int delim; | |
511 | { | |
512 | int ch; | |
513 | for (;;) | |
514 | { | |
515 | ch = INF_GET (); | |
516 | if (ch == EOF || ch == delim) | |
517 | break; | |
c2b6b9a1 | 518 | SSTRING_PUT (str, ch); |
05227b51 | 519 | } |
c2b6b9a1 | 520 | MAKE_SSTRING_SPACE (str, 1); |
05227b51 PB |
521 | *str->ptr = 0; |
522 | return ch; | |
523 | } | |
524 | ||
7936052f | 525 | int |
05227b51 PB |
526 | inf_scan_ident (s, c) |
527 | register sstring *s; | |
528 | int c; | |
529 | { | |
530 | s->ptr = s->base; | |
c2b6b9a1 | 531 | if (isalpha (c) || c == '_') |
05227b51 PB |
532 | { |
533 | for (;;) | |
534 | { | |
c2b6b9a1 | 535 | SSTRING_PUT (s, c); |
05227b51 | 536 | c = INF_GET (); |
c2b6b9a1 | 537 | if (c == EOF || !(isalnum (c) || c == '_')) |
05227b51 PB |
538 | break; |
539 | } | |
540 | } | |
c2b6b9a1 | 541 | MAKE_SSTRING_SPACE (s, 1); |
05227b51 PB |
542 | *s->ptr = 0; |
543 | return c; | |
544 | } | |
545 | ||
546 | /* Returns 1 if the file is correctly protected against multiple | |
547 | inclusion, setting *ifndef_line to the line number of the initial #ifndef | |
548 | and setting *endif_line to the final #endif. | |
549 | Otherwise return 0. */ | |
550 | ||
551 | int | |
552 | check_protection (ifndef_line, endif_line) | |
7936052f PB |
553 | int *ifndef_line, *endif_line; |
554 | { | |
555 | int c; | |
556 | int if_nesting = 1; /* Level of nesting of #if's */ | |
557 | char *protect_name = NULL; /* Identifier following initial #ifndef */ | |
558 | int define_seen = 0; | |
559 | ||
560 | /* Skip initial white space (including comments). */ | |
561 | for (;; lineno++) | |
562 | { | |
05227b51 | 563 | c = inf_skip_spaces (' '); |
7936052f PB |
564 | if (c == EOF) |
565 | return 0; | |
566 | if (c != '\n') | |
567 | break; | |
568 | } | |
569 | if (c != '#') | |
570 | return 0; | |
05227b51 | 571 | c = inf_scan_ident (&buf, inf_skip_spaces (' ')); |
c2b6b9a1 | 572 | if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0) |
7936052f PB |
573 | return 0; |
574 | ||
575 | /* So far so good: We've seen an initial #ifndef. */ | |
576 | *ifndef_line = lineno; | |
05227b51 | 577 | c = inf_scan_ident (&buf, inf_skip_spaces (c)); |
c2b6b9a1 | 578 | if (SSTRING_LENGTH (&buf) == 0 || c == EOF) |
7936052f PB |
579 | return 0; |
580 | protect_name = strdup (buf.base); | |
581 | ||
c2b6b9a1 | 582 | INF_UNGET (c); |
05227b51 | 583 | c = inf_read_upto (&buf, '\n'); |
7936052f PB |
584 | if (c == EOF) |
585 | return 0; | |
586 | lineno++; | |
587 | ||
588 | for (;;) | |
589 | { | |
c2b6b9a1 | 590 | c = inf_skip_spaces (' '); |
7936052f PB |
591 | if (c == EOF) |
592 | return 0; | |
593 | if (c == '\n') | |
594 | { | |
595 | lineno++; | |
596 | continue; | |
597 | } | |
598 | if (c != '#') | |
599 | goto skip_to_eol; | |
05227b51 | 600 | c = inf_scan_ident (&buf, inf_skip_spaces (' ')); |
c2b6b9a1 | 601 | if (SSTRING_LENGTH (&buf) == 0) |
7936052f PB |
602 | ; |
603 | else if (!strcmp (buf.base, "ifndef") | |
604 | || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if")) | |
605 | { | |
606 | if_nesting++; | |
607 | } | |
608 | else if (!strcmp (buf.base, "endif")) | |
609 | { | |
610 | if_nesting--; | |
611 | if (if_nesting == 0) | |
612 | break; | |
613 | } | |
614 | else if (!strcmp (buf.base, "else")) | |
615 | { | |
616 | if (if_nesting == 1) | |
617 | return 0; | |
618 | } | |
619 | else if (!strcmp (buf.base, "define")) | |
620 | { | |
621 | if (if_nesting != 1) | |
622 | goto skip_to_eol; | |
05227b51 PB |
623 | c = inf_skip_spaces (c); |
624 | c = inf_scan_ident (&buf, c); | |
c2b6b9a1 | 625 | if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0) |
7936052f PB |
626 | define_seen = 1; |
627 | } | |
628 | skip_to_eol: | |
629 | for (;;) | |
630 | { | |
631 | if (c == '\n' || c == EOF) | |
632 | break; | |
c2b6b9a1 | 633 | c = INF_GET (); |
7936052f PB |
634 | } |
635 | if (c == EOF) | |
636 | return 0; | |
637 | lineno++; | |
638 | } | |
639 | ||
640 | if (!define_seen) | |
641 | return 0; | |
642 | *endif_line = lineno; | |
643 | /* Skip final white space (including comments). */ | |
644 | for (;;) | |
645 | { | |
05227b51 | 646 | c = inf_skip_spaces (' '); |
7936052f PB |
647 | if (c == EOF) |
648 | break; | |
649 | if (c != '\n') | |
650 | return 0; | |
651 | } | |
652 | ||
653 | return 1; | |
654 | } | |
655 | ||
656 | int | |
c2b6b9a1 | 657 | main (argc, argv) |
7936052f PB |
658 | int argc; |
659 | char **argv; | |
660 | { | |
05227b51 PB |
661 | int inf_fd; |
662 | struct stat sbuf; | |
7936052f PB |
663 | int c; |
664 | int i, done; | |
665 | char *cptr, *cptr0, **pptr; | |
666 | int ifndef_line; | |
05227b51 PB |
667 | int endif_line; |
668 | long to_read; | |
c2b6b9a1 | 669 | long int inf_size; |
7936052f PB |
670 | |
671 | if (argv[0] && argv[0][0]) | |
9bbd1091 RS |
672 | { |
673 | register char *p; | |
674 | ||
675 | progname = 0; | |
676 | for (p = argv[0]; *p; p++) | |
677 | if (*p == '/') | |
678 | progname = p; | |
679 | progname = progname ? progname+1 : argv[0]; | |
680 | } | |
7936052f PB |
681 | |
682 | if (argc < 4) | |
683 | { | |
684 | fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n", | |
685 | progname); | |
686 | exit (-1); | |
687 | } | |
688 | ||
689 | inc_filename = argv[1]; | |
690 | inc_filename_length = strlen (inc_filename); | |
691 | if (strcmp (inc_filename, "sys/stat.h") == 0) | |
692 | special_file_handling = sys_stat_special; | |
693 | else if (strcmp (inc_filename, "errno.h") == 0) | |
b156894e | 694 | special_file_handling = errno_special, missing_errno = 1; |
7936052f PB |
695 | |
696 | /* Calculate an upper bound of the number of function names in argv[4] */ | |
697 | for (i = 1, cptr = argv[4]; *cptr; cptr++) | |
698 | if (*cptr == ' ') i++; | |
699 | /* Find the list of prototypes required for this include file. */ | |
c2b6b9a1 | 700 | required_functions = (char**)xmalloc ((i+1) * sizeof (char*)); |
7936052f PB |
701 | for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; |
702 | !done; cptr++) | |
703 | { | |
704 | done = *cptr == '\0'; | |
705 | if (*cptr == ' ' || done) | |
706 | { | |
707 | *cptr = '\0'; | |
708 | if (cptr > cptr0) | |
709 | { | |
c2b6b9a1 | 710 | struct fn_decl *fn = lookup_std_proto (cptr0); |
7936052f PB |
711 | *pptr++ = cptr0; |
712 | if (fn == NULL) | |
713 | fprintf (stderr, "Internal error: No prototype for %s\n", | |
714 | cptr0); | |
715 | else | |
c2b6b9a1 | 716 | SET_REQUIRED (fn); |
7936052f PB |
717 | } |
718 | cptr0 = cptr + 1; | |
719 | } | |
720 | } | |
721 | required_unseen_count = pptr - required_functions; | |
722 | *pptr = 0; | |
723 | ||
724 | read_scan_file (stdin); | |
725 | ||
05227b51 PB |
726 | inf_fd = open (argv[2], O_RDONLY, 0666); |
727 | if (inf_fd < 0) | |
7936052f PB |
728 | { |
729 | fprintf (stderr, "%s: Cannot open '%s' for reading -", | |
730 | progname, argv[2]); | |
731 | perror (NULL); | |
732 | exit (-1); | |
733 | } | |
05227b51 PB |
734 | if (fstat (inf_fd, &sbuf) < 0) |
735 | { | |
736 | fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]); | |
737 | perror (NULL); | |
738 | exit (-1); | |
739 | } | |
740 | inf_size = sbuf.st_size; | |
741 | inf_buffer = (char*) xmalloc (inf_size + 2); | |
742 | inf_buffer[inf_size] = '\n'; | |
743 | inf_buffer[inf_size + 1] = '\0'; | |
744 | inf_limit = inf_buffer + inf_size; | |
745 | inf_ptr = inf_buffer; | |
746 | ||
747 | to_read = inf_size; | |
748 | while (to_read > 0) | |
749 | { | |
750 | long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read); | |
751 | if (i < 0) | |
752 | { | |
753 | fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]); | |
754 | perror (NULL); | |
755 | exit (-1); | |
756 | } | |
757 | if (i == 0) | |
758 | { | |
759 | inf_size -= to_read; | |
760 | break; | |
761 | } | |
762 | to_read -= i; | |
763 | } | |
764 | ||
765 | close (inf_fd); | |
7936052f | 766 | |
c2b6b9a1 RS |
767 | /* If file doesn't end with '\n', add one. */ |
768 | if (inf_limit > inf_buffer && inf_limit[-1] != '\n') | |
769 | inf_limit++; | |
770 | ||
9bbd1091 | 771 | unlink (argv[3]); |
7936052f PB |
772 | outf = fopen (argv[3], "w"); |
773 | if (outf == NULL) | |
774 | { | |
775 | fprintf (stderr, "%s: Cannot open '%s' for writing -", | |
776 | progname, argv[3]); | |
777 | perror (NULL); | |
778 | exit (-1); | |
779 | } | |
780 | ||
05227b51 PB |
781 | lineno = 1; |
782 | ||
783 | if (check_protection (&ifndef_line, &endif_line)) | |
7936052f PB |
784 | { |
785 | #if 0 | |
c2b6b9a1 RS |
786 | fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n", |
787 | protect_name, ifndef_line, endif_line); | |
7936052f PB |
788 | #endif |
789 | lbrac_line = ifndef_line+1; | |
790 | rbrac_line = endif_line; | |
791 | } | |
792 | else | |
793 | { | |
794 | lbrac_line = 1; | |
795 | rbrac_line = -1; | |
796 | } | |
797 | ||
05227b51 PB |
798 | /* Reset input file. */ |
799 | inf_ptr = inf_buffer; | |
7936052f PB |
800 | lineno = 1; |
801 | ||
802 | for (;;) | |
803 | { | |
804 | if (lineno == lbrac_line) | |
805 | write_lbrac (); | |
806 | if (lineno == rbrac_line) | |
807 | write_rbrac (); | |
808 | for (;;) | |
809 | { | |
810 | struct fn_decl *fn; | |
c2b6b9a1 | 811 | c = INF_GET (); |
7936052f PB |
812 | if (c == EOF) |
813 | break; | |
814 | if (isalpha (c) || c == '_') | |
815 | { | |
05227b51 | 816 | c = inf_scan_ident (&buf, c); |
c2b6b9a1 | 817 | INF_UNGET (c); |
7936052f PB |
818 | fputs (buf.base, outf); |
819 | fn = lookup_std_proto (buf.base); | |
820 | /* We only want to edit the declaration matching the one | |
821 | seen by scan-decls, as there can be multiple | |
822 | declarations, selected by #ifdef __STDC__ or whatever. */ | |
823 | if (fn && fn->partial && fn->partial->line_seen == lineno) | |
824 | { | |
05227b51 | 825 | c = inf_skip_spaces (' '); |
7936052f PB |
826 | if (c == EOF) |
827 | break; | |
828 | if (c == '(') | |
829 | { | |
05227b51 | 830 | c = inf_skip_spaces (' '); |
7936052f PB |
831 | if (c == ')') |
832 | { | |
833 | fprintf (outf, " _PARAMS((%s))", fn->params); | |
834 | } | |
835 | else | |
836 | { | |
837 | putc ('(', outf); | |
c2b6b9a1 | 838 | INF_UNGET (c); |
7936052f PB |
839 | } |
840 | } | |
841 | else | |
e9cd0b25 | 842 | fprintf (outf, " %c", c); |
7936052f PB |
843 | } |
844 | } | |
845 | else | |
05227b51 PB |
846 | { |
847 | putc (c, outf); | |
848 | if (c == '\n') | |
849 | break; | |
850 | } | |
7936052f PB |
851 | } |
852 | if (c == EOF) | |
853 | break; | |
854 | lineno++; | |
855 | } | |
856 | if (rbrac_line < 0) | |
857 | write_rbrac (); | |
858 | ||
7936052f PB |
859 | fclose (outf); |
860 | ||
861 | return 0; | |
862 | } |