Add Ansi2knr handling
Showing
5 changed files
with
725 additions
and
0 deletions
1 | 1999-11-15 Jeff Bailey <jbailey@nisa.net> | ||
2 | |||
3 | * lib/ansi2knr*: Add | ||
4 | |||
5 | * configure.in: Add AM_C_PROTOTYPES | ||
6 | |||
7 | * libmailbox/Makefile.am: Add ansi2knr handling | ||
8 | |||
1 | 1999-11-08 Sean 'Shaleh' Perry <shaleh@debian.org> | 9 | 1999-11-08 Sean 'Shaleh' Perry <shaleh@debian.org> |
2 | 10 | ||
3 | * cleaned up some of the auto{make,conf} magic for non-Linux | 11 | * cleaned up some of the auto{make,conf} magic for non-Linux | ... | ... |
... | @@ -20,6 +20,7 @@ AC_ARG_ENABLE(pam, | ... | @@ -20,6 +20,7 @@ AC_ARG_ENABLE(pam, |
20 | 20 | ||
21 | dnl Check for headers | 21 | dnl Check for headers |
22 | AC_HEADER_STDC | 22 | AC_HEADER_STDC |
23 | AM_C_PROTOTYPES | ||
23 | AC_CHECK_HEADERS(malloc.h stdlib.h stdio.h errno.h unistd.h\ | 24 | AC_CHECK_HEADERS(malloc.h stdlib.h stdio.h errno.h unistd.h\ |
24 | paths.h sys/file.h syslog.h shadow.h) | 25 | paths.h sys/file.h syslog.h shadow.h) |
25 | AC_CHECK_HEADERS(string.h strings.h, break) | 26 | AC_CHECK_HEADERS(string.h strings.h, break) | ... | ... |
lib/ansi2knr.1
0 → 100644
1 | .TH ANSI2KNR 1 "19 Jan 1996" | ||
2 | .SH NAME | ||
3 | ansi2knr \- convert ANSI C to Kernighan & Ritchie C | ||
4 | .SH SYNOPSIS | ||
5 | .I ansi2knr | ||
6 | [--varargs] input_file [output_file] | ||
7 | .SH DESCRIPTION | ||
8 | If no output_file is supplied, output goes to stdout. | ||
9 | .br | ||
10 | There are no error messages. | ||
11 | .sp | ||
12 | .I ansi2knr | ||
13 | recognizes function definitions by seeing a non-keyword identifier at the left | ||
14 | margin, followed by a left parenthesis, with a right parenthesis as the last | ||
15 | character on the line, and with a left brace as the first token on the | ||
16 | following line (ignoring possible intervening comments). It will recognize a | ||
17 | multi-line header provided that no intervening line ends with a left or right | ||
18 | brace or a semicolon. These algorithms ignore whitespace and comments, except | ||
19 | that the function name must be the first thing on the line. | ||
20 | .sp | ||
21 | The following constructs will confuse it: | ||
22 | .br | ||
23 | - Any other construct that starts at the left margin and follows the | ||
24 | above syntax (such as a macro or function call). | ||
25 | .br | ||
26 | - Some macros that tinker with the syntax of the function header. | ||
27 | .sp | ||
28 | The --varargs switch is obsolete, and is recognized only for | ||
29 | backwards compatibility. The present version of | ||
30 | .I ansi2knr | ||
31 | will always attempt to convert a ... argument to va_alist and va_dcl. | ||
32 | .SH AUTHOR | ||
33 | L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and | ||
34 | continues to maintain the current version; most of the code in the current | ||
35 | version is his work. ansi2knr also includes contributions by Francois | ||
36 | Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>. |
lib/ansi2knr.c
0 → 100644
1 | /* Copyright (C) 1989, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. */ | ||
2 | |||
3 | /*$Id$*/ | ||
4 | /* Convert ANSI C function definitions to K&R ("traditional C") syntax */ | ||
5 | |||
6 | /* | ||
7 | ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY | ||
8 | WARRANTY. No author or distributor accepts responsibility to anyone for the | ||
9 | consequences of using it or for whether it serves any particular purpose or | ||
10 | works at all, unless he says so in writing. Refer to the GNU General Public | ||
11 | License (the "GPL") for full details. | ||
12 | |||
13 | Everyone is granted permission to copy, modify and redistribute ansi2knr, | ||
14 | but only under the conditions described in the GPL. A copy of this license | ||
15 | is supposed to have been given to you along with ansi2knr so you can know | ||
16 | your rights and responsibilities. It should be in a file named COPYLEFT, | ||
17 | or, if there is no file named COPYLEFT, a file named COPYING. Among other | ||
18 | things, the copyright notice and this notice must be preserved on all | ||
19 | copies. | ||
20 | |||
21 | We explicitly state here what we believe is already implied by the GPL: if | ||
22 | the ansi2knr program is distributed as a separate set of sources and a | ||
23 | separate executable file which are aggregated on a storage medium together | ||
24 | with another program, this in itself does not bring the other program under | ||
25 | the GPL, nor does the mere fact that such a program or the procedures for | ||
26 | constructing it invoke the ansi2knr executable bring any other part of the | ||
27 | program under the GPL. | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * Usage: | ||
32 | ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]] | ||
33 | * --filename provides the file name for the #line directive in the output, | ||
34 | * overriding input_file (if present). | ||
35 | * If no input_file is supplied, input is read from stdin. | ||
36 | * If no output_file is supplied, output goes to stdout. | ||
37 | * There are no error messages. | ||
38 | * | ||
39 | * ansi2knr recognizes function definitions by seeing a non-keyword | ||
40 | * identifier at the left margin, followed by a left parenthesis, | ||
41 | * with a right parenthesis as the last character on the line, | ||
42 | * and with a left brace as the first token on the following line | ||
43 | * (ignoring possible intervening comments), except that a line | ||
44 | * consisting of only | ||
45 | * identifier1(identifier2) | ||
46 | * will not be considered a function definition unless identifier2 is | ||
47 | * the word "void", and a line consisting of | ||
48 | * identifier1(identifier2, <<arbitrary>>) | ||
49 | * will not be considered a function definition. | ||
50 | * ansi2knr will recognize a multi-line header provided | ||
51 | * that no intervening line ends with a left or right brace or a semicolon. | ||
52 | * These algorithms ignore whitespace and comments, except that | ||
53 | * the function name must be the first thing on the line. | ||
54 | * The following constructs will confuse it: | ||
55 | * - Any other construct that starts at the left margin and | ||
56 | * follows the above syntax (such as a macro or function call). | ||
57 | * - Some macros that tinker with the syntax of function headers. | ||
58 | */ | ||
59 | |||
60 | /* | ||
61 | * The original and principal author of ansi2knr is L. Peter Deutsch | ||
62 | * <ghost@aladdin.com>. Other authors are noted in the change history | ||
63 | * that follows (in reverse chronological order): | ||
64 | lpd 1999-04-12 added minor fixes from Pavel Roskin | ||
65 | <pavel_roskin@geocities.com> for clean compilation with | ||
66 | gcc -W -Wall | ||
67 | lpd 1999-03-22 added hack to recognize lines consisting of | ||
68 | identifier1(identifier2, xxx) as *not* being procedures | ||
69 | lpd 1999-02-03 made indentation of preprocessor commands consistent | ||
70 | lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an | ||
71 | endless loop; quoted strings within an argument list | ||
72 | confused the parser | ||
73 | lpd 1999-01-24 added a check for write errors on the output, | ||
74 | suggested by Jim Meyering <meyering@ascend.com> | ||
75 | lpd 1998-11-09 added further hack to recognize identifier(void) | ||
76 | as being a procedure | ||
77 | lpd 1998-10-23 added hack to recognize lines consisting of | ||
78 | identifier1(identifier2) as *not* being procedures | ||
79 | lpd 1997-12-08 made input_file optional; only closes input and/or | ||
80 | output file if not stdin or stdout respectively; prints | ||
81 | usage message on stderr rather than stdout; adds | ||
82 | --filename switch (changes suggested by | ||
83 | <ceder@lysator.liu.se>) | ||
84 | lpd 1996-01-21 added code to cope with not HAVE_CONFIG_H and with | ||
85 | compilers that don't understand void, as suggested by | ||
86 | Tom Lane | ||
87 | lpd 1996-01-15 changed to require that the first non-comment token | ||
88 | on the line following a function header be a left brace, | ||
89 | to reduce sensitivity to macros, as suggested by Tom Lane | ||
90 | <tgl@sss.pgh.pa.us> | ||
91 | lpd 1995-06-22 removed #ifndefs whose sole purpose was to define | ||
92 | undefined preprocessor symbols as 0; changed all #ifdefs | ||
93 | for configuration symbols to #ifs | ||
94 | lpd 1995-04-05 changed copyright notice to make it clear that | ||
95 | including ansi2knr in a program does not bring the entire | ||
96 | program under the GPL | ||
97 | lpd 1994-12-18 added conditionals for systems where ctype macros | ||
98 | don't handle 8-bit characters properly, suggested by | ||
99 | Francois Pinard <pinard@iro.umontreal.ca>; | ||
100 | removed --varargs switch (this is now the default) | ||
101 | lpd 1994-10-10 removed CONFIG_BROKETS conditional | ||
102 | lpd 1994-07-16 added some conditionals to help GNU `configure', | ||
103 | suggested by Francois Pinard <pinard@iro.umontreal.ca>; | ||
104 | properly erase prototype args in function parameters, | ||
105 | contributed by Jim Avera <jima@netcom.com>; | ||
106 | correct error in writeblanks (it shouldn't erase EOLs) | ||
107 | lpd 1989-xx-xx original version | ||
108 | */ | ||
109 | |||
110 | /* Most of the conditionals here are to make ansi2knr work with */ | ||
111 | /* or without the GNU configure machinery. */ | ||
112 | |||
113 | #if HAVE_CONFIG_H | ||
114 | # include <config.h> | ||
115 | #endif | ||
116 | |||
117 | #include <stdio.h> | ||
118 | #include <ctype.h> | ||
119 | |||
120 | #if HAVE_CONFIG_H | ||
121 | |||
122 | /* | ||
123 | For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h). | ||
124 | This will define HAVE_CONFIG_H and so, activate the following lines. | ||
125 | */ | ||
126 | |||
127 | # if STDC_HEADERS || HAVE_STRING_H | ||
128 | # include <string.h> | ||
129 | # else | ||
130 | # include <strings.h> | ||
131 | # endif | ||
132 | |||
133 | #else /* not HAVE_CONFIG_H */ | ||
134 | |||
135 | /* Otherwise do it the hard way */ | ||
136 | |||
137 | # ifdef BSD | ||
138 | # include <strings.h> | ||
139 | # else | ||
140 | # ifdef VMS | ||
141 | extern int strlen(), strncmp(); | ||
142 | # else | ||
143 | # include <string.h> | ||
144 | # endif | ||
145 | # endif | ||
146 | |||
147 | #endif /* not HAVE_CONFIG_H */ | ||
148 | |||
149 | #if STDC_HEADERS | ||
150 | # include <stdlib.h> | ||
151 | #else | ||
152 | /* | ||
153 | malloc and free should be declared in stdlib.h, | ||
154 | but if you've got a K&R compiler, they probably aren't. | ||
155 | */ | ||
156 | # ifdef MSDOS | ||
157 | # include <malloc.h> | ||
158 | # else | ||
159 | # ifdef VMS | ||
160 | extern char *malloc(); | ||
161 | extern void free(); | ||
162 | # else | ||
163 | extern char *malloc(); | ||
164 | extern int free(); | ||
165 | # endif | ||
166 | # endif | ||
167 | |||
168 | #endif | ||
169 | |||
170 | /* Define NULL (for *very* old compilers). */ | ||
171 | #ifndef NULL | ||
172 | # define NULL (0) | ||
173 | #endif | ||
174 | |||
175 | /* | ||
176 | * The ctype macros don't always handle 8-bit characters correctly. | ||
177 | * Compensate for this here. | ||
178 | */ | ||
179 | #ifdef isascii | ||
180 | # undef HAVE_ISASCII /* just in case */ | ||
181 | # define HAVE_ISASCII 1 | ||
182 | #else | ||
183 | #endif | ||
184 | #if STDC_HEADERS || !HAVE_ISASCII | ||
185 | # define is_ascii(c) 1 | ||
186 | #else | ||
187 | # define is_ascii(c) isascii(c) | ||
188 | #endif | ||
189 | |||
190 | #define is_space(c) (is_ascii(c) && isspace(c)) | ||
191 | #define is_alpha(c) (is_ascii(c) && isalpha(c)) | ||
192 | #define is_alnum(c) (is_ascii(c) && isalnum(c)) | ||
193 | |||
194 | /* Scanning macros */ | ||
195 | #define isidchar(ch) (is_alnum(ch) || (ch) == '_') | ||
196 | #define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_') | ||
197 | |||
198 | /* Forward references */ | ||
199 | char *skipspace(); | ||
200 | char *scanstring(); | ||
201 | int writeblanks(); | ||
202 | int test1(); | ||
203 | int convert1(); | ||
204 | |||
205 | /* The main program */ | ||
206 | int | ||
207 | main(argc, argv) | ||
208 | int argc; | ||
209 | char *argv[]; | ||
210 | { FILE *in = stdin; | ||
211 | FILE *out = stdout; | ||
212 | char *filename = 0; | ||
213 | char *program_name = argv[0]; | ||
214 | char *output_name = 0; | ||
215 | #define bufsize 5000 /* arbitrary size */ | ||
216 | char *buf; | ||
217 | char *line; | ||
218 | char *more; | ||
219 | char *usage = | ||
220 | "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n"; | ||
221 | /* | ||
222 | * In previous versions, ansi2knr recognized a --varargs switch. | ||
223 | * If this switch was supplied, ansi2knr would attempt to convert | ||
224 | * a ... argument to va_alist and va_dcl; if this switch was not | ||
225 | * supplied, ansi2knr would simply drop any such arguments. | ||
226 | * Now, ansi2knr always does this conversion, and we only | ||
227 | * check for this switch for backward compatibility. | ||
228 | */ | ||
229 | int convert_varargs = 1; | ||
230 | int output_error; | ||
231 | |||
232 | while ( argc > 1 && argv[1][0] == '-' ) { | ||
233 | if ( !strcmp(argv[1], "--varargs") ) { | ||
234 | convert_varargs = 1; | ||
235 | argc--; | ||
236 | argv++; | ||
237 | continue; | ||
238 | } | ||
239 | if ( !strcmp(argv[1], "--filename") && argc > 2 ) { | ||
240 | filename = argv[2]; | ||
241 | argc -= 2; | ||
242 | argv += 2; | ||
243 | continue; | ||
244 | } | ||
245 | fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name, | ||
246 | argv[1]); | ||
247 | fprintf(stderr, usage); | ||
248 | exit(1); | ||
249 | } | ||
250 | switch ( argc ) | ||
251 | { | ||
252 | default: | ||
253 | fprintf(stderr, usage); | ||
254 | exit(0); | ||
255 | case 3: | ||
256 | output_name = argv[2]; | ||
257 | out = fopen(output_name, "w"); | ||
258 | if ( out == NULL ) { | ||
259 | fprintf(stderr, "%s: Cannot open output file %s\n", | ||
260 | program_name, output_name); | ||
261 | exit(1); | ||
262 | } | ||
263 | /* falls through */ | ||
264 | case 2: | ||
265 | in = fopen(argv[1], "r"); | ||
266 | if ( in == NULL ) { | ||
267 | fprintf(stderr, "%s: Cannot open input file %s\n", | ||
268 | program_name, argv[1]); | ||
269 | exit(1); | ||
270 | } | ||
271 | if ( filename == 0 ) | ||
272 | filename = argv[1]; | ||
273 | /* falls through */ | ||
274 | case 1: | ||
275 | break; | ||
276 | } | ||
277 | if ( filename ) | ||
278 | fprintf(out, "#line 1 \"%s\"\n", filename); | ||
279 | buf = malloc(bufsize); | ||
280 | if ( buf == NULL ) | ||
281 | { | ||
282 | fprintf(stderr, "Unable to allocate read buffer!\n"); | ||
283 | exit(1); | ||
284 | } | ||
285 | line = buf; | ||
286 | while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) | ||
287 | { | ||
288 | test: line += strlen(line); | ||
289 | switch ( test1(buf) ) | ||
290 | { | ||
291 | case 2: /* a function header */ | ||
292 | convert1(buf, out, 1, convert_varargs); | ||
293 | break; | ||
294 | case 1: /* a function */ | ||
295 | /* Check for a { at the start of the next line. */ | ||
296 | more = ++line; | ||
297 | f: if ( line >= buf + (bufsize - 1) ) /* overflow check */ | ||
298 | goto wl; | ||
299 | if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL ) | ||
300 | goto wl; | ||
301 | switch ( *skipspace(more, 1) ) | ||
302 | { | ||
303 | case '{': | ||
304 | /* Definitely a function header. */ | ||
305 | convert1(buf, out, 0, convert_varargs); | ||
306 | fputs(more, out); | ||
307 | break; | ||
308 | case 0: | ||
309 | /* The next line was blank or a comment: */ | ||
310 | /* keep scanning for a non-comment. */ | ||
311 | line += strlen(line); | ||
312 | goto f; | ||
313 | default: | ||
314 | /* buf isn't a function header, but */ | ||
315 | /* more might be. */ | ||
316 | fputs(buf, out); | ||
317 | strcpy(buf, more); | ||
318 | line = buf; | ||
319 | goto test; | ||
320 | } | ||
321 | break; | ||
322 | case -1: /* maybe the start of a function */ | ||
323 | if ( line != buf + (bufsize - 1) ) /* overflow check */ | ||
324 | continue; | ||
325 | /* falls through */ | ||
326 | default: /* not a function */ | ||
327 | wl: fputs(buf, out); | ||
328 | break; | ||
329 | } | ||
330 | line = buf; | ||
331 | } | ||
332 | if ( line != buf ) | ||
333 | fputs(buf, out); | ||
334 | free(buf); | ||
335 | if ( output_name ) { | ||
336 | output_error = ferror(out); | ||
337 | output_error |= fclose(out); | ||
338 | } else { /* out == stdout */ | ||
339 | fflush(out); | ||
340 | output_error = ferror(out); | ||
341 | } | ||
342 | if ( output_error ) { | ||
343 | fprintf(stderr, "%s: error writing to %s\n", program_name, | ||
344 | (output_name ? output_name : "stdout")); | ||
345 | exit(1); | ||
346 | } | ||
347 | if ( in != stdin ) | ||
348 | fclose(in); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* Skip over whitespace and comments, in either direction. */ | ||
353 | char * | ||
354 | skipspace(p, dir) | ||
355 | register char *p; | ||
356 | register int dir; /* 1 for forward, -1 for backward */ | ||
357 | { for ( ; ; ) | ||
358 | { while ( is_space(*p) ) | ||
359 | p += dir; | ||
360 | if ( !(*p == '/' && p[dir] == '*') ) | ||
361 | break; | ||
362 | p += dir; p += dir; | ||
363 | while ( !(*p == '*' && p[dir] == '/') ) | ||
364 | { if ( *p == 0 ) | ||
365 | return p; /* multi-line comment?? */ | ||
366 | p += dir; | ||
367 | } | ||
368 | p += dir; p += dir; | ||
369 | } | ||
370 | return p; | ||
371 | } | ||
372 | |||
373 | /* Scan over a quoted string, in either direction. */ | ||
374 | char * | ||
375 | scanstring(p, dir) | ||
376 | register char *p; | ||
377 | register int dir; | ||
378 | { | ||
379 | for (p += dir; ; p += dir) | ||
380 | if (*p == '"' && p[-dir] != '\\') | ||
381 | return p + dir; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * Write blanks over part of a string. | ||
386 | * Don't overwrite end-of-line characters. | ||
387 | */ | ||
388 | int | ||
389 | writeblanks(start, end) | ||
390 | char *start; | ||
391 | char *end; | ||
392 | { char *p; | ||
393 | for ( p = start; p < end; p++ ) | ||
394 | if ( *p != '\r' && *p != '\n' ) | ||
395 | *p = ' '; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Test whether the string in buf is a function definition. | ||
401 | * The string may contain and/or end with a newline. | ||
402 | * Return as follows: | ||
403 | * 0 - definitely not a function definition; | ||
404 | * 1 - definitely a function definition; | ||
405 | * 2 - definitely a function prototype (NOT USED); | ||
406 | * -1 - may be the beginning of a function definition, | ||
407 | * append another line and look again. | ||
408 | * The reason we don't attempt to convert function prototypes is that | ||
409 | * Ghostscript's declaration-generating macros look too much like | ||
410 | * prototypes, and confuse the algorithms. | ||
411 | */ | ||
412 | int | ||
413 | test1(buf) | ||
414 | char *buf; | ||
415 | { register char *p = buf; | ||
416 | char *bend; | ||
417 | char *endfn; | ||
418 | int contin; | ||
419 | |||
420 | if ( !isidfirstchar(*p) ) | ||
421 | return 0; /* no name at left margin */ | ||
422 | bend = skipspace(buf + strlen(buf) - 1, -1); | ||
423 | switch ( *bend ) | ||
424 | { | ||
425 | case ';': contin = 0 /*2*/; break; | ||
426 | case ')': contin = 1; break; | ||
427 | case '{': return 0; /* not a function */ | ||
428 | case '}': return 0; /* not a function */ | ||
429 | default: contin = -1; | ||
430 | } | ||
431 | while ( isidchar(*p) ) | ||
432 | p++; | ||
433 | endfn = p; | ||
434 | p = skipspace(p, 1); | ||
435 | if ( *p++ != '(' ) | ||
436 | return 0; /* not a function */ | ||
437 | p = skipspace(p, 1); | ||
438 | if ( *p == ')' ) | ||
439 | return 0; /* no parameters */ | ||
440 | /* Check that the apparent function name isn't a keyword. */ | ||
441 | /* We only need to check for keywords that could be followed */ | ||
442 | /* by a left parenthesis (which, unfortunately, is most of them). */ | ||
443 | { static char *words[] = | ||
444 | { "asm", "auto", "case", "char", "const", "double", | ||
445 | "extern", "float", "for", "if", "int", "long", | ||
446 | "register", "return", "short", "signed", "sizeof", | ||
447 | "static", "switch", "typedef", "unsigned", | ||
448 | "void", "volatile", "while", 0 | ||
449 | }; | ||
450 | char **key = words; | ||
451 | char *kp; | ||
452 | unsigned len = endfn - buf; | ||
453 | |||
454 | while ( (kp = *key) != 0 ) | ||
455 | { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) | ||
456 | return 0; /* name is a keyword */ | ||
457 | key++; | ||
458 | } | ||
459 | } | ||
460 | { | ||
461 | char *id = p; | ||
462 | int len; | ||
463 | /* | ||
464 | * Check for identifier1(identifier2) and not | ||
465 | * identifier1(void), or identifier1(identifier2, xxxx). | ||
466 | */ | ||
467 | |||
468 | while ( isidchar(*p) ) | ||
469 | p++; | ||
470 | len = p - id; | ||
471 | p = skipspace(p, 1); | ||
472 | if (*p == ',' || | ||
473 | (*p == ')' && (len != 4 || strncmp(id, "void", 4))) | ||
474 | ) | ||
475 | return 0; /* not a function */ | ||
476 | } | ||
477 | /* | ||
478 | * If the last significant character was a ), we need to count | ||
479 | * parentheses, because it might be part of a formal parameter | ||
480 | * that is a procedure. | ||
481 | */ | ||
482 | if (contin > 0) { | ||
483 | int level = 0; | ||
484 | |||
485 | for (p = skipspace(buf, 1); *p; p = skipspace(p + 1, 1)) | ||
486 | level += (*p == '(' ? 1 : *p == ')' ? -1 : 0); | ||
487 | if (level > 0) | ||
488 | contin = -1; | ||
489 | } | ||
490 | return contin; | ||
491 | } | ||
492 | |||
493 | /* Convert a recognized function definition or header to K&R syntax. */ | ||
494 | int | ||
495 | convert1(buf, out, header, convert_varargs) | ||
496 | char *buf; | ||
497 | FILE *out; | ||
498 | int header; /* Boolean */ | ||
499 | int convert_varargs; /* Boolean */ | ||
500 | { char *endfn; | ||
501 | register char *p; | ||
502 | /* | ||
503 | * The breaks table contains pointers to the beginning and end | ||
504 | * of each argument. | ||
505 | */ | ||
506 | char **breaks; | ||
507 | unsigned num_breaks = 2; /* for testing */ | ||
508 | char **btop; | ||
509 | char **bp; | ||
510 | char **ap; | ||
511 | char *vararg = 0; | ||
512 | |||
513 | /* Pre-ANSI implementations don't agree on whether strchr */ | ||
514 | /* is called strchr or index, so we open-code it here. */ | ||
515 | for ( endfn = buf; *(endfn++) != '('; ) | ||
516 | ; | ||
517 | top: p = endfn; | ||
518 | breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); | ||
519 | if ( breaks == NULL ) | ||
520 | { /* Couldn't allocate break table, give up */ | ||
521 | fprintf(stderr, "Unable to allocate break table!\n"); | ||
522 | fputs(buf, out); | ||
523 | return -1; | ||
524 | } | ||
525 | btop = breaks + num_breaks * 2 - 2; | ||
526 | bp = breaks; | ||
527 | /* Parse the argument list */ | ||
528 | do | ||
529 | { int level = 0; | ||
530 | char *lp = NULL; | ||
531 | char *rp = NULL; | ||
532 | char *end = NULL; | ||
533 | |||
534 | if ( bp >= btop ) | ||
535 | { /* Filled up break table. */ | ||
536 | /* Allocate a bigger one and start over. */ | ||
537 | free((char *)breaks); | ||
538 | num_breaks <<= 1; | ||
539 | goto top; | ||
540 | } | ||
541 | *bp++ = p; | ||
542 | /* Find the end of the argument */ | ||
543 | for ( ; end == NULL; p++ ) | ||
544 | { switch(*p) | ||
545 | { | ||
546 | case ',': | ||
547 | if ( !level ) end = p; | ||
548 | break; | ||
549 | case '(': | ||
550 | if ( !level ) lp = p; | ||
551 | level++; | ||
552 | break; | ||
553 | case ')': | ||
554 | if ( --level < 0 ) end = p; | ||
555 | else rp = p; | ||
556 | break; | ||
557 | case '/': | ||
558 | if (p[1] == '*') | ||
559 | p = skipspace(p, 1) - 1; | ||
560 | break; | ||
561 | case '"': | ||
562 | p = scanstring(p, 1) - 1; | ||
563 | break; | ||
564 | default: | ||
565 | ; | ||
566 | } | ||
567 | } | ||
568 | /* Erase any embedded prototype parameters. */ | ||
569 | if ( lp && rp ) | ||
570 | writeblanks(lp + 1, rp); | ||
571 | p--; /* back up over terminator */ | ||
572 | /* Find the name being declared. */ | ||
573 | /* This is complicated because of procedure and */ | ||
574 | /* array modifiers. */ | ||
575 | for ( ; ; ) | ||
576 | { p = skipspace(p - 1, -1); | ||
577 | switch ( *p ) | ||
578 | { | ||
579 | case ']': /* skip array dimension(s) */ | ||
580 | case ')': /* skip procedure args OR name */ | ||
581 | { int level = 1; | ||
582 | while ( level ) | ||
583 | switch ( *--p ) | ||
584 | { | ||
585 | case ']': case ')': | ||
586 | level++; | ||
587 | break; | ||
588 | case '[': case '(': | ||
589 | level--; | ||
590 | break; | ||
591 | case '/': | ||
592 | if (p > buf && p[-1] == '*') | ||
593 | p = skipspace(p, -1) + 1; | ||
594 | break; | ||
595 | case '"': | ||
596 | p = scanstring(p, -1) + 1; | ||
597 | break; | ||
598 | default: ; | ||
599 | } | ||
600 | } | ||
601 | if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) | ||
602 | { /* We found the name being declared */ | ||
603 | while ( !isidfirstchar(*p) ) | ||
604 | p = skipspace(p, 1) + 1; | ||
605 | goto found; | ||
606 | } | ||
607 | break; | ||
608 | default: | ||
609 | goto found; | ||
610 | } | ||
611 | } | ||
612 | found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) | ||
613 | { if ( convert_varargs ) | ||
614 | { *bp++ = "va_alist"; | ||
615 | vararg = p-2; | ||
616 | } | ||
617 | else | ||
618 | { p++; | ||
619 | if ( bp == breaks + 1 ) /* sole argument */ | ||
620 | writeblanks(breaks[0], p); | ||
621 | else | ||
622 | writeblanks(bp[-1] - 1, p); | ||
623 | bp--; | ||
624 | } | ||
625 | } | ||
626 | else | ||
627 | { while ( isidchar(*p) ) p--; | ||
628 | *bp++ = p+1; | ||
629 | } | ||
630 | p = end; | ||
631 | } | ||
632 | while ( *p++ == ',' ); | ||
633 | *bp = p; | ||
634 | /* Make a special check for 'void' arglist */ | ||
635 | if ( bp == breaks+2 ) | ||
636 | { p = skipspace(breaks[0], 1); | ||
637 | if ( !strncmp(p, "void", 4) ) | ||
638 | { p = skipspace(p+4, 1); | ||
639 | if ( p == breaks[2] - 1 ) | ||
640 | { bp = breaks; /* yup, pretend arglist is empty */ | ||
641 | writeblanks(breaks[0], p + 1); | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | /* Put out the function name and left parenthesis. */ | ||
646 | p = buf; | ||
647 | while ( p != endfn ) putc(*p, out), p++; | ||
648 | /* Put out the declaration. */ | ||
649 | if ( header ) | ||
650 | { fputs(");", out); | ||
651 | for ( p = breaks[0]; *p; p++ ) | ||
652 | if ( *p == '\r' || *p == '\n' ) | ||
653 | putc(*p, out); | ||
654 | } | ||
655 | else | ||
656 | { for ( ap = breaks+1; ap < bp; ap += 2 ) | ||
657 | { p = *ap; | ||
658 | while ( isidchar(*p) ) | ||
659 | putc(*p, out), p++; | ||
660 | if ( ap < bp - 1 ) | ||
661 | fputs(", ", out); | ||
662 | } | ||
663 | fputs(") ", out); | ||
664 | /* Put out the argument declarations */ | ||
665 | for ( ap = breaks+2; ap <= bp; ap += 2 ) | ||
666 | (*ap)[-1] = ';'; | ||
667 | if ( vararg != 0 ) | ||
668 | { *vararg = 0; | ||
669 | fputs(breaks[0], out); /* any prior args */ | ||
670 | fputs("va_dcl", out); /* the final arg */ | ||
671 | fputs(bp[0], out); | ||
672 | } | ||
673 | else | ||
674 | fputs(breaks[0], out); | ||
675 | } | ||
676 | free((char *)breaks); | ||
677 | return 0; | ||
678 | } |
-
Please register or sign in to post a comment