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