]>
Commit | Line | Data |
---|---|---|
7936052f PB |
1 | /* patch-header.c - Make C header file suitable for C++. |
2 | Copyright (C) 1993 Free Software Foundation, Inc. | |
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: | |
62 | patch-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE | |
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 | |
7936052f PB |
81 | #include "obstack.h" |
82 | #include "scan.h" | |
83 | ||
7936052f PB |
84 | sstring buf; |
85 | int verbose = 0; | |
86 | int partial_count = 0; | |
87 | int missing_extern_C_count = 0; | |
b156894e | 88 | int missing_errno = 0; |
7936052f PB |
89 | |
90 | #include "xsys-protos.h" | |
91 | ||
05227b51 PB |
92 | char *inf_buffer; |
93 | char *inf_limit; | |
94 | char *inf_ptr; | |
05227b51 | 95 | |
7936052f PB |
96 | /* Certain standard files get extra treatment */ |
97 | ||
98 | enum special_file | |
99 | { | |
100 | no_special, | |
101 | errno_special, | |
102 | sys_stat_special | |
103 | }; | |
104 | ||
105 | enum special_file special_file_handling = no_special; | |
106 | ||
107 | /* The following are only used when handling sys/stat.h */ | |
108 | /* They are set if the corresponding macro has been seen. */ | |
109 | int seen_S_IFBLK = 0, seen_S_ISBLK = 0; | |
110 | int seen_S_IFCHR = 0, seen_S_ISCHR = 0; | |
111 | int seen_S_IFDIR = 0, seen_S_ISDIR = 0; | |
112 | int seen_S_IFIFO = 0, seen_S_ISFIFO = 0; | |
113 | int seen_S_IFLNK = 0, seen_S_ISLNK = 0; | |
114 | int seen_S_IFREG = 0, seen_S_ISREG = 0; | |
115 | ||
7936052f PB |
116 | /* Wrapper around free, to avoid prototype clashes. */ |
117 | ||
118 | void xfree (ptr) | |
119 | char *ptr; | |
120 | { | |
c2b6b9a1 | 121 | free (ptr); |
7936052f PB |
122 | } |
123 | ||
124 | #define obstack_chunk_alloc xmalloc | |
125 | #define obstack_chunk_free xfree | |
126 | struct obstack scan_file_obstack; | |
127 | ||
128 | /* NOTE: If you edit this, also edit gen-protos.c !! */ | |
129 | struct fn_decl * | |
130 | lookup_std_proto (name) | |
131 | char *name; | |
132 | { | |
c2b6b9a1 | 133 | int i = hash (name) % HASH_SIZE; |
7936052f PB |
134 | int i0 = i; |
135 | for (;;) | |
136 | { | |
137 | struct fn_decl *fn; | |
138 | if (hash_tab[i] == 0) | |
139 | return NULL; | |
140 | fn = &std_protos[hash_tab[i]]; | |
141 | if (strcmp (fn->fname, name) == 0) | |
142 | return fn; | |
143 | i = (i+1) % HASH_SIZE; | |
144 | if (i == i0) | |
c2b6b9a1 | 145 | abort (); |
7936052f PB |
146 | } |
147 | } | |
148 | ||
149 | char *inc_filename; | |
150 | int inc_filename_length; | |
151 | char *progname = "patch-header"; | |
152 | FILE *outf; | |
153 | sstring buf; | |
154 | sstring line; | |
155 | ||
156 | int lbrac_line, rbrac_line; | |
157 | ||
158 | char **required_functions; | |
159 | int required_unseen_count; | |
160 | ||
161 | int | |
162 | write_lbrac () | |
163 | { | |
b156894e RS |
164 | |
165 | if (missing_extern_C_count + required_unseen_count > 0) | |
166 | fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); | |
7936052f PB |
167 | |
168 | if (partial_count) | |
169 | { | |
170 | fprintf (outf, "#ifndef _PARAMS\n"); | |
171 | fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n"); | |
172 | fprintf (outf, "#define _PARAMS(ARGS) ARGS\n"); | |
173 | fprintf (outf, "#else\n"); | |
174 | fprintf (outf, "#define _PARAMS(ARGS) ()\n"); | |
175 | fprintf (outf, "#endif\n#endif /* _PARAMS */\n"); | |
176 | } | |
177 | } | |
178 | ||
179 | struct partial_proto | |
180 | { | |
181 | struct partial_proto *next; | |
182 | char *fname; /* name of function */ | |
183 | char *rtype; /* return type */ | |
184 | struct fn_decl *fn; | |
185 | int line_seen; | |
186 | }; | |
187 | ||
188 | struct partial_proto *partial_proto_list = NULL; | |
189 | ||
190 | struct partial_proto required_dummy_proto; | |
191 | #define REQUIRED(FN) ((FN)->partial == &required_dummy_proto) | |
192 | #define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto) | |
193 | #define CLEAR_REQUIRED(FN) ((FN)->partial = 0) | |
194 | ||
195 | void | |
05227b51 PB |
196 | recognized_macro (fname) |
197 | char *fname; | |
7936052f | 198 | { |
05227b51 PB |
199 | /* The original include file defines fname as a macro. */ |
200 | struct fn_decl *fn = lookup_std_proto (fname); | |
7936052f | 201 | |
05227b51 PB |
202 | /* Since fname is a macro, don't require a prototype for it. */ |
203 | if (fn && REQUIRED (fn)) | |
7936052f | 204 | { |
c2b6b9a1 | 205 | CLEAR_REQUIRED (fn); |
05227b51 PB |
206 | required_unseen_count--; |
207 | } | |
7936052f | 208 | |
05227b51 PB |
209 | switch (special_file_handling) |
210 | { | |
211 | case errno_special: | |
b156894e | 212 | if (strcmp (fname, "errno") == 0) missing_errno = 0; |
05227b51 PB |
213 | break; |
214 | case sys_stat_special: | |
215 | if (fname[0] == 'S' && fname[1] == '_') | |
7936052f | 216 | { |
05227b51 PB |
217 | if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++; |
218 | else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++; | |
219 | else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++; | |
220 | else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++; | |
221 | else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++; | |
222 | else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++; | |
223 | else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++; | |
224 | else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++; | |
225 | else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++; | |
226 | else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++; | |
227 | else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++; | |
228 | else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++; | |
7936052f | 229 | } |
05227b51 PB |
230 | } |
231 | } | |
7936052f | 232 | |
05227b51 PB |
233 | void |
234 | recognized_extern (name, type) | |
235 | char *name; | |
236 | char *type; | |
237 | { | |
238 | switch (special_file_handling) | |
239 | { | |
240 | case errno_special: | |
b156894e | 241 | if (strcmp (name, "errno") == 0) missing_errno = 0; |
05227b51 PB |
242 | break; |
243 | } | |
244 | } | |
7936052f | 245 | |
05227b51 PB |
246 | /* Called by scan_decls if it saw a function definition for a function |
247 | named FNAME, with return type RTYPE, and argument list ARGS, | |
248 | in source file FILE_SEEN on line LINE_SEEN. | |
249 | KIND is 'I' for an inline function; | |
250 | 'F' if a normal function declaration preceded by 'extern "C"' | |
251 | (or nested inside 'extern "C"' braces); or | |
252 | 'f' for other function declarations. */ | |
7936052f | 253 | |
05227b51 PB |
254 | void |
255 | recognized_function (fname, kind, rtype, args, file_seen, line_seen) | |
256 | char *fname; | |
257 | int kind; /* One of 'f' 'F' or 'I' */ | |
258 | char *rtype; | |
259 | char *args; | |
260 | char *file_seen; | |
261 | int line_seen; | |
262 | { | |
263 | struct partial_proto *partial; | |
264 | int i; | |
265 | struct fn_decl *fn; | |
266 | if (kind == 'f') | |
267 | missing_extern_C_count++; | |
7936052f | 268 | |
05227b51 | 269 | fn = lookup_std_proto (fname); |
7936052f | 270 | |
05227b51 PB |
271 | /* Remove the function from the list of required function. */ |
272 | if (fn && REQUIRED (fn)) | |
273 | { | |
c2b6b9a1 | 274 | CLEAR_REQUIRED (fn); |
05227b51 PB |
275 | required_unseen_count--; |
276 | } | |
e9cd0b25 | 277 | |
05227b51 PB |
278 | /* If we have a full prototype, we're done. */ |
279 | if (args[0] != '\0') | |
280 | return; | |
281 | ||
282 | if (kind == 'I') /* don't edit inline function */ | |
283 | return; | |
284 | ||
285 | /* If the partial prototype was included from some other file, | |
286 | we don't need to patch it up (in this run). */ | |
287 | i = strlen (file_seen); | |
288 | if (i < inc_filename_length | |
289 | || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0) | |
290 | return; | |
291 | ||
292 | if (fn == NULL) | |
293 | return; | |
c2b6b9a1 | 294 | if (fn->params[0] == '\0' || strcmp (fn->params, "void") == 0) |
05227b51 PB |
295 | return; |
296 | ||
297 | /* We only have a partial function declaration, | |
298 | so remember that we have to add a complete prototype. */ | |
299 | partial_count++; | |
300 | partial = (struct partial_proto*) | |
c2b6b9a1 RS |
301 | obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto)); |
302 | partial->fname = obstack_alloc (&scan_file_obstack, strlen (fname) + 1); | |
05227b51 | 303 | strcpy (partial->fname, fname); |
c2b6b9a1 | 304 | partial->rtype = obstack_alloc (&scan_file_obstack, strlen (rtype) + 1); |
05227b51 PB |
305 | strcpy (partial->rtype, rtype); |
306 | partial->line_seen = line_seen; | |
307 | partial->fn = fn; | |
308 | fn->partial = partial; | |
309 | partial->next = partial_proto_list; | |
310 | partial_proto_list = partial; | |
311 | if (verbose) | |
312 | { | |
313 | fprintf (stderr, "(%s: %s non-prototype function declaration.)\n", | |
314 | inc_filename, fname); | |
315 | } | |
316 | } | |
7936052f | 317 | |
05227b51 PB |
318 | void |
319 | read_scan_file (scan_file) | |
320 | FILE *scan_file; | |
321 | { | |
322 | char **rptr; | |
c2b6b9a1 | 323 | obstack_init (&scan_file_obstack); |
7936052f | 324 | |
05227b51 | 325 | scan_decls (scan_file); |
7936052f PB |
326 | |
327 | if (missing_extern_C_count + required_unseen_count + partial_count | |
b156894e | 328 | + missing_errno == 0) |
7936052f PB |
329 | { |
330 | if (verbose) | |
331 | fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename); | |
332 | exit (0); | |
333 | } | |
e9cd0b25 PB |
334 | if (!verbose) |
335 | fprintf (stderr, "%s: fixing %s\n", progname, inc_filename); | |
336 | else | |
337 | { | |
338 | if (required_unseen_count) | |
339 | fprintf (stderr, "%s: %d missing function declarations.\n", | |
340 | inc_filename, required_unseen_count); | |
341 | if (partial_count) | |
342 | fprintf (stderr, "%s: %d non-prototype function declarations.\n", | |
343 | inc_filename, partial_count); | |
344 | if (missing_extern_C_count) | |
345 | fprintf (stderr, | |
346 | "%s: %d declarations not protected by extern \"C\".\n", | |
347 | inc_filename, missing_extern_C_count); | |
348 | } | |
7936052f PB |
349 | } |
350 | ||
351 | write_rbrac () | |
352 | { | |
353 | struct fn_decl *fn; | |
354 | char **rptr; | |
355 | register struct partial_proto *partial; | |
356 | ||
357 | if (required_unseen_count) | |
358 | fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n"); | |
359 | ||
360 | /* Now we print out prototypes for those functions that we haven't seen. */ | |
361 | for (rptr = required_functions; *rptr; rptr++) | |
362 | { | |
363 | fn = lookup_std_proto (*rptr); | |
364 | if (fn == NULL || !REQUIRED (fn)) | |
365 | continue; | |
366 | fprintf (outf, "extern %s %s (%s);\n", | |
367 | fn->rtype, fn->fname, fn->params); | |
368 | } | |
369 | if (required_unseen_count) | |
370 | fprintf (outf, | |
371 | "#endif /* defined(__STDC__) || defined(__cplusplus) */\n"); | |
372 | ||
373 | switch (special_file_handling) | |
374 | { | |
375 | case errno_special: | |
b156894e | 376 | if (missing_errno) |
7936052f PB |
377 | fprintf (outf, "extern int errno;\n"); |
378 | break; | |
379 | case sys_stat_special: | |
380 | if (!seen_S_ISBLK && seen_S_IFBLK) | |
381 | fprintf (outf, | |
382 | "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n"); | |
383 | if (!seen_S_ISCHR && seen_S_IFCHR) | |
384 | fprintf (outf, | |
385 | "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n"); | |
386 | if (!seen_S_ISDIR && seen_S_IFDIR) | |
387 | fprintf (outf, | |
388 | "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n"); | |
389 | if (!seen_S_ISFIFO && seen_S_IFIFO) | |
390 | fprintf (outf, | |
391 | "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n"); | |
392 | if (!seen_S_ISLNK && seen_S_IFLNK) | |
393 | fprintf (outf, | |
394 | "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n"); | |
395 | if (!seen_S_ISREG && seen_S_IFREG) | |
396 | fprintf (outf, | |
397 | "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n"); | |
398 | break; | |
399 | } | |
400 | ||
401 | ||
b156894e RS |
402 | if (missing_extern_C_count + required_unseen_count > 0) |
403 | fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n"); | |
7936052f PB |
404 | } |
405 | ||
406 | char * | |
407 | strdup (str) | |
408 | char *str; | |
409 | { | |
c2b6b9a1 RS |
410 | char *copy = (char *) xmalloc (strlen (str) + 1); |
411 | strcpy (copy, str); | |
412 | return copy; | |
7936052f PB |
413 | } |
414 | ||
415 | /* Returns 1 iff the file is properly protected from multiple inclusion: | |
416 | #ifndef PROTECT_NAME | |
417 | #define PROTECT_NAME | |
418 | #endif | |
419 | ||
420 | */ | |
421 | ||
05227b51 | 422 | #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF) |
c2b6b9a1 | 423 | #define INF_UNGET(c) ((c)!=EOF && inf_ptr--) |
05227b51 PB |
424 | |
425 | int | |
426 | inf_skip_spaces (c) | |
427 | int c; | |
428 | { | |
429 | for (;;) | |
430 | { | |
431 | if (c == ' ' || c == '\t') | |
c2b6b9a1 | 432 | c = INF_GET (); |
05227b51 PB |
433 | else if (c == '/') |
434 | { | |
c2b6b9a1 | 435 | c = INF_GET (); |
05227b51 PB |
436 | if (c != '*') |
437 | { | |
c2b6b9a1 | 438 | INF_UNGET (c); |
05227b51 PB |
439 | return '/'; |
440 | } | |
c2b6b9a1 | 441 | c = INF_GET (); |
05227b51 PB |
442 | for (;;) |
443 | { | |
444 | if (c == EOF) | |
445 | return EOF; | |
446 | else if (c != '*') | |
447 | { | |
448 | if (c == '\n') | |
449 | source_lineno++, lineno++; | |
450 | c = INF_GET (); | |
451 | } | |
c2b6b9a1 RS |
452 | else if ((c = INF_GET ()) == '/') |
453 | return INF_GET (); | |
05227b51 PB |
454 | } |
455 | } | |
456 | else | |
457 | break; | |
458 | } | |
459 | return c; | |
460 | } | |
461 | ||
462 | /* Read into STR from inf_buffer upto DELIM. */ | |
463 | ||
464 | int | |
465 | inf_read_upto (str, delim) | |
466 | sstring *str; | |
467 | int delim; | |
468 | { | |
469 | int ch; | |
470 | for (;;) | |
471 | { | |
472 | ch = INF_GET (); | |
473 | if (ch == EOF || ch == delim) | |
474 | break; | |
c2b6b9a1 | 475 | SSTRING_PUT (str, ch); |
05227b51 | 476 | } |
c2b6b9a1 | 477 | MAKE_SSTRING_SPACE (str, 1); |
05227b51 PB |
478 | *str->ptr = 0; |
479 | return ch; | |
480 | } | |
481 | ||
7936052f | 482 | int |
05227b51 PB |
483 | inf_scan_ident (s, c) |
484 | register sstring *s; | |
485 | int c; | |
486 | { | |
487 | s->ptr = s->base; | |
c2b6b9a1 | 488 | if (isalpha (c) || c == '_') |
05227b51 PB |
489 | { |
490 | for (;;) | |
491 | { | |
c2b6b9a1 | 492 | SSTRING_PUT (s, c); |
05227b51 | 493 | c = INF_GET (); |
c2b6b9a1 | 494 | if (c == EOF || !(isalnum (c) || c == '_')) |
05227b51 PB |
495 | break; |
496 | } | |
497 | } | |
c2b6b9a1 | 498 | MAKE_SSTRING_SPACE (s, 1); |
05227b51 PB |
499 | *s->ptr = 0; |
500 | return c; | |
501 | } | |
502 | ||
503 | /* Returns 1 if the file is correctly protected against multiple | |
504 | inclusion, setting *ifndef_line to the line number of the initial #ifndef | |
505 | and setting *endif_line to the final #endif. | |
506 | Otherwise return 0. */ | |
507 | ||
508 | int | |
509 | check_protection (ifndef_line, endif_line) | |
7936052f PB |
510 | int *ifndef_line, *endif_line; |
511 | { | |
512 | int c; | |
513 | int if_nesting = 1; /* Level of nesting of #if's */ | |
514 | char *protect_name = NULL; /* Identifier following initial #ifndef */ | |
515 | int define_seen = 0; | |
516 | ||
517 | /* Skip initial white space (including comments). */ | |
518 | for (;; lineno++) | |
519 | { | |
05227b51 | 520 | c = inf_skip_spaces (' '); |
7936052f PB |
521 | if (c == EOF) |
522 | return 0; | |
523 | if (c != '\n') | |
524 | break; | |
525 | } | |
526 | if (c != '#') | |
527 | return 0; | |
05227b51 | 528 | c = inf_scan_ident (&buf, inf_skip_spaces (' ')); |
c2b6b9a1 | 529 | if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0) |
7936052f PB |
530 | return 0; |
531 | ||
532 | /* So far so good: We've seen an initial #ifndef. */ | |
533 | *ifndef_line = lineno; | |
05227b51 | 534 | c = inf_scan_ident (&buf, inf_skip_spaces (c)); |
c2b6b9a1 | 535 | if (SSTRING_LENGTH (&buf) == 0 || c == EOF) |
7936052f PB |
536 | return 0; |
537 | protect_name = strdup (buf.base); | |
538 | ||
c2b6b9a1 | 539 | INF_UNGET (c); |
05227b51 | 540 | c = inf_read_upto (&buf, '\n'); |
7936052f PB |
541 | if (c == EOF) |
542 | return 0; | |
543 | lineno++; | |
544 | ||
545 | for (;;) | |
546 | { | |
c2b6b9a1 | 547 | c = inf_skip_spaces (' '); |
7936052f PB |
548 | if (c == EOF) |
549 | return 0; | |
550 | if (c == '\n') | |
551 | { | |
552 | lineno++; | |
553 | continue; | |
554 | } | |
555 | if (c != '#') | |
556 | goto skip_to_eol; | |
05227b51 | 557 | c = inf_scan_ident (&buf, inf_skip_spaces (' ')); |
c2b6b9a1 | 558 | if (SSTRING_LENGTH (&buf) == 0) |
7936052f PB |
559 | ; |
560 | else if (!strcmp (buf.base, "ifndef") | |
561 | || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if")) | |
562 | { | |
563 | if_nesting++; | |
564 | } | |
565 | else if (!strcmp (buf.base, "endif")) | |
566 | { | |
567 | if_nesting--; | |
568 | if (if_nesting == 0) | |
569 | break; | |
570 | } | |
571 | else if (!strcmp (buf.base, "else")) | |
572 | { | |
573 | if (if_nesting == 1) | |
574 | return 0; | |
575 | } | |
576 | else if (!strcmp (buf.base, "define")) | |
577 | { | |
578 | if (if_nesting != 1) | |
579 | goto skip_to_eol; | |
05227b51 PB |
580 | c = inf_skip_spaces (c); |
581 | c = inf_scan_ident (&buf, c); | |
c2b6b9a1 | 582 | if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0) |
7936052f PB |
583 | define_seen = 1; |
584 | } | |
585 | skip_to_eol: | |
586 | for (;;) | |
587 | { | |
588 | if (c == '\n' || c == EOF) | |
589 | break; | |
c2b6b9a1 | 590 | c = INF_GET (); |
7936052f PB |
591 | } |
592 | if (c == EOF) | |
593 | return 0; | |
594 | lineno++; | |
595 | } | |
596 | ||
597 | if (!define_seen) | |
598 | return 0; | |
599 | *endif_line = lineno; | |
600 | /* Skip final white space (including comments). */ | |
601 | for (;;) | |
602 | { | |
05227b51 | 603 | c = inf_skip_spaces (' '); |
7936052f PB |
604 | if (c == EOF) |
605 | break; | |
606 | if (c != '\n') | |
607 | return 0; | |
608 | } | |
609 | ||
610 | return 1; | |
611 | } | |
612 | ||
613 | int | |
c2b6b9a1 | 614 | main (argc, argv) |
7936052f PB |
615 | int argc; |
616 | char **argv; | |
617 | { | |
05227b51 PB |
618 | int inf_fd; |
619 | struct stat sbuf; | |
7936052f PB |
620 | int c; |
621 | int i, done; | |
622 | char *cptr, *cptr0, **pptr; | |
623 | int ifndef_line; | |
05227b51 PB |
624 | int endif_line; |
625 | long to_read; | |
c2b6b9a1 | 626 | long int inf_size; |
7936052f PB |
627 | |
628 | if (argv[0] && argv[0][0]) | |
9bbd1091 RS |
629 | { |
630 | register char *p; | |
631 | ||
632 | progname = 0; | |
633 | for (p = argv[0]; *p; p++) | |
634 | if (*p == '/') | |
635 | progname = p; | |
636 | progname = progname ? progname+1 : argv[0]; | |
637 | } | |
7936052f PB |
638 | |
639 | if (argc < 4) | |
640 | { | |
641 | fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n", | |
642 | progname); | |
643 | exit (-1); | |
644 | } | |
645 | ||
646 | inc_filename = argv[1]; | |
647 | inc_filename_length = strlen (inc_filename); | |
648 | if (strcmp (inc_filename, "sys/stat.h") == 0) | |
649 | special_file_handling = sys_stat_special; | |
650 | else if (strcmp (inc_filename, "errno.h") == 0) | |
b156894e | 651 | special_file_handling = errno_special, missing_errno = 1; |
7936052f PB |
652 | |
653 | /* Calculate an upper bound of the number of function names in argv[4] */ | |
654 | for (i = 1, cptr = argv[4]; *cptr; cptr++) | |
655 | if (*cptr == ' ') i++; | |
656 | /* Find the list of prototypes required for this include file. */ | |
c2b6b9a1 | 657 | required_functions = (char**)xmalloc ((i+1) * sizeof (char*)); |
7936052f PB |
658 | for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; |
659 | !done; cptr++) | |
660 | { | |
661 | done = *cptr == '\0'; | |
662 | if (*cptr == ' ' || done) | |
663 | { | |
664 | *cptr = '\0'; | |
665 | if (cptr > cptr0) | |
666 | { | |
c2b6b9a1 | 667 | struct fn_decl *fn = lookup_std_proto (cptr0); |
7936052f PB |
668 | *pptr++ = cptr0; |
669 | if (fn == NULL) | |
670 | fprintf (stderr, "Internal error: No prototype for %s\n", | |
671 | cptr0); | |
672 | else | |
c2b6b9a1 | 673 | SET_REQUIRED (fn); |
7936052f PB |
674 | } |
675 | cptr0 = cptr + 1; | |
676 | } | |
677 | } | |
678 | required_unseen_count = pptr - required_functions; | |
679 | *pptr = 0; | |
680 | ||
681 | read_scan_file (stdin); | |
682 | ||
05227b51 PB |
683 | inf_fd = open (argv[2], O_RDONLY, 0666); |
684 | if (inf_fd < 0) | |
7936052f PB |
685 | { |
686 | fprintf (stderr, "%s: Cannot open '%s' for reading -", | |
687 | progname, argv[2]); | |
688 | perror (NULL); | |
689 | exit (-1); | |
690 | } | |
05227b51 PB |
691 | if (fstat (inf_fd, &sbuf) < 0) |
692 | { | |
693 | fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]); | |
694 | perror (NULL); | |
695 | exit (-1); | |
696 | } | |
697 | inf_size = sbuf.st_size; | |
698 | inf_buffer = (char*) xmalloc (inf_size + 2); | |
699 | inf_buffer[inf_size] = '\n'; | |
700 | inf_buffer[inf_size + 1] = '\0'; | |
701 | inf_limit = inf_buffer + inf_size; | |
702 | inf_ptr = inf_buffer; | |
703 | ||
704 | to_read = inf_size; | |
705 | while (to_read > 0) | |
706 | { | |
707 | long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read); | |
708 | if (i < 0) | |
709 | { | |
710 | fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]); | |
711 | perror (NULL); | |
712 | exit (-1); | |
713 | } | |
714 | if (i == 0) | |
715 | { | |
716 | inf_size -= to_read; | |
717 | break; | |
718 | } | |
719 | to_read -= i; | |
720 | } | |
721 | ||
722 | close (inf_fd); | |
7936052f | 723 | |
c2b6b9a1 RS |
724 | /* If file doesn't end with '\n', add one. */ |
725 | if (inf_limit > inf_buffer && inf_limit[-1] != '\n') | |
726 | inf_limit++; | |
727 | ||
9bbd1091 | 728 | unlink (argv[3]); |
7936052f PB |
729 | outf = fopen (argv[3], "w"); |
730 | if (outf == NULL) | |
731 | { | |
732 | fprintf (stderr, "%s: Cannot open '%s' for writing -", | |
733 | progname, argv[3]); | |
734 | perror (NULL); | |
735 | exit (-1); | |
736 | } | |
737 | ||
05227b51 PB |
738 | lineno = 1; |
739 | ||
740 | if (check_protection (&ifndef_line, &endif_line)) | |
7936052f PB |
741 | { |
742 | #if 0 | |
c2b6b9a1 RS |
743 | fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n", |
744 | protect_name, ifndef_line, endif_line); | |
7936052f PB |
745 | #endif |
746 | lbrac_line = ifndef_line+1; | |
747 | rbrac_line = endif_line; | |
748 | } | |
749 | else | |
750 | { | |
751 | lbrac_line = 1; | |
752 | rbrac_line = -1; | |
753 | } | |
754 | ||
05227b51 PB |
755 | /* Reset input file. */ |
756 | inf_ptr = inf_buffer; | |
7936052f PB |
757 | lineno = 1; |
758 | ||
759 | for (;;) | |
760 | { | |
761 | if (lineno == lbrac_line) | |
762 | write_lbrac (); | |
763 | if (lineno == rbrac_line) | |
764 | write_rbrac (); | |
765 | for (;;) | |
766 | { | |
767 | struct fn_decl *fn; | |
c2b6b9a1 | 768 | c = INF_GET (); |
7936052f PB |
769 | if (c == EOF) |
770 | break; | |
771 | if (isalpha (c) || c == '_') | |
772 | { | |
773 | struct partial_proto *partial; | |
05227b51 | 774 | c = inf_scan_ident (&buf, c); |
c2b6b9a1 | 775 | INF_UNGET (c); |
7936052f PB |
776 | fputs (buf.base, outf); |
777 | fn = lookup_std_proto (buf.base); | |
778 | /* We only want to edit the declaration matching the one | |
779 | seen by scan-decls, as there can be multiple | |
780 | declarations, selected by #ifdef __STDC__ or whatever. */ | |
781 | if (fn && fn->partial && fn->partial->line_seen == lineno) | |
782 | { | |
05227b51 | 783 | c = inf_skip_spaces (' '); |
7936052f PB |
784 | if (c == EOF) |
785 | break; | |
786 | if (c == '(') | |
787 | { | |
05227b51 | 788 | c = inf_skip_spaces (' '); |
7936052f PB |
789 | if (c == ')') |
790 | { | |
791 | fprintf (outf, " _PARAMS((%s))", fn->params); | |
792 | } | |
793 | else | |
794 | { | |
795 | putc ('(', outf); | |
c2b6b9a1 | 796 | INF_UNGET (c); |
7936052f PB |
797 | } |
798 | } | |
799 | else | |
e9cd0b25 | 800 | fprintf (outf, " %c", c); |
7936052f PB |
801 | } |
802 | } | |
803 | else | |
05227b51 PB |
804 | { |
805 | putc (c, outf); | |
806 | if (c == '\n') | |
807 | break; | |
808 | } | |
7936052f PB |
809 | } |
810 | if (c == EOF) | |
811 | break; | |
812 | lineno++; | |
813 | } | |
814 | if (rbrac_line < 0) | |
815 | write_rbrac (); | |
816 | ||
7936052f PB |
817 | fclose (outf); |
818 | ||
819 | return 0; | |
820 | } |