386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / ansi2knr.c
CommitLineData
528b75e1
WJ
1/* Copyright (C) 1989, 1991 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* ansi2knr.c */
21/* Convert ANSI function declarations to K&R syntax */
22#include <stdio.h>
23#include <ctype.h>
24#include "string_.h"
25#include "malloc_.h"
26
27/* Usage:
28 ansi2knr input_file output_file
29 * If no output_file is supplied, output goes to stdout.
30 * There are no error messages.
31 *
32 * ansi2knr recognizes functions by seeing a non-keyword identifier
33 * at the left margin, followed by a left parenthesis,
34 * with a right parenthesis as the last character on the line.
35 * It will recognize a multi-line header if the last character
36 * on each line but the last is a left parenthesis or comma.
37 * These algorithms ignore whitespace and comments, except that
38 * the function name must be the first thing on the line.
39 * The following constructs will confuse it:
40 - Any other construct that starts at the left margin and
41 follows the above syntax (such as a macro or function call).
42 - Macros that tinker with the syntax of the function header.
43 */
44
45/* Scanning macros */
46#define isidchar(ch) (isalnum(ch) || (ch) == '_')
47#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_')
48
49main(argc, argv)
50 int argc;
51 char *argv[];
52{ FILE *in, *out;
53#define bufsize 500 /* arbitrary size */
54 char buf[bufsize];
55 char *line;
56 switch ( argc )
57 {
58 default:
59 printf("Usage: ansi2knr input_file [output_file]\n");
60 exit(0);
61 case 2:
62 out = stdout; break;
63 case 3:
64 out = fopen(argv[2], "w");
65 if ( out == NULL )
66 { fprintf(stderr, "Cannot open %s\n", argv[2]);
67 exit(1);
68 }
69 }
70 in = fopen(argv[1], "r");
71 if ( in == NULL )
72 { fprintf(stderr, "Cannot open %s\n", argv[1]);
73 exit(1);
74 }
75 fprintf(out, "#line 1 \"%s\"\n", argv[1]);
76 line = buf;
77 while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
78 { switch ( test1(buf) )
79 {
80 case 1: /* a function */
81 convert1(buf, out);
82 break;
83 case -1: /* maybe the start of a function */
84 line = buf + strlen(buf);
85 continue;
86 default: /* not a function */
87 fputs(buf, out);
88 break;
89 }
90 line = buf;
91 }
92 if ( line != buf ) fputs(buf, out);
93 fclose(out);
94 fclose(in);
95 return 0;
96}
97
98/* Skip over space and comments, in either direction. */
99char *
100skipspace(p, dir)
101 register char *p;
102 register int dir; /* 1 for forward, -1 for backward */
103{ for ( ; ; )
104 { while ( isspace(*p) ) p += dir;
105 if ( !(*p == '/' && p[dir] == '*') ) break;
106 p += dir; p += dir;
107 while ( !(*p == '*' && p[dir] == '/') )
108 { if ( *p == 0 ) return p; /* multi-line comment?? */
109 p += dir;
110 }
111 p += dir; p += dir;
112 }
113 return p;
114}
115
116/*
117 * Write blanks over part of a string.
118 */
119void
120writeblanks(start, end)
121 char *start;
122 char *end;
123{ char *p;
124 for ( p = start; p < end; p++ ) *p = ' ';
125}
126
127/*
128 * Test whether the string in buf is a function definition.
129 * The string may contain and/or end with a newline.
130 * Return as follows:
131 * 0 - definitely not a function definition;
132 * 1 - definitely a function definition;
133 * -1 - may be the beginning of a function definition,
134 * append another line and look again.
135 */
136test1(buf)
137 char *buf;
138{ register char *p = buf;
139 char *bend;
140 char *endfn;
141 int contin;
142 if ( !isidfirstchar(*p) )
143 return 0; /* no name at left margin */
144 bend = skipspace(buf + strlen(buf) - 1, -1);
145 switch ( *bend )
146 {
147 case ')': contin = 1; break;
148 case '(':
149 case ',': contin = -1; break;
150 default: return 0; /* not a function */
151 }
152 while ( isidchar(*p) ) p++;
153 endfn = p;
154 p = skipspace(p, 1);
155 if ( *p++ != '(' )
156 return 0; /* not a function */
157 p = skipspace(p, 1);
158 if ( *p == ')' )
159 return 0; /* no parameters */
160 /* Check that the apparent function name isn't a keyword. */
161 /* We only need to check for keywords that could be followed */
162 /* by a left parenthesis (which, unfortunately, is most of them). */
163 { static char *words[] =
164 { "asm", "auto", "case", "char", "const", "double",
165 "extern", "float", "for", "if", "int", "long",
166 "register", "return", "short", "signed", "sizeof",
167 "static", "switch", "typedef", "unsigned",
168 "void", "volatile", "while", 0
169 };
170 char **key = words;
171 char *kp;
172 int len = endfn - buf;
173 while ( (kp = *key) != 0 )
174 { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
175 return 0; /* name is a keyword */
176 key++;
177 }
178 }
179 return contin;
180}
181
182convert1(buf, out)
183 char *buf;
184 FILE *out;
185{ char *endfn = strchr(buf, '(') + 1;
186 register char *p;
187 char **breaks;
188 unsigned num_breaks = 2; /* for testing */
189 char **btop;
190 char **bp;
191 char **ap;
192top: p = endfn;
193 breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
194 if ( breaks == 0 )
195 { /* Couldn't allocate break table, give up */
196 fprintf(stderr, "Unable to allocate break table!\n");
197 fputs(buf, out);
198 return -1;
199 }
200 btop = breaks + num_breaks * 2 - 2;
201 bp = breaks;
202 /* Parse the argument list */
203 do
204 { int level = 0;
205 char *end = NULL;
206 if ( bp >= btop )
207 { /* Filled up break table. */
208 /* Allocate a bigger one and start over. */
209 free((char *)breaks);
210 num_breaks <<= 1;
211 goto top;
212 }
213 *bp++ = p;
214 /* Find the end of the argument */
215 for ( ; end == NULL; p++ )
216 { switch(*p)
217 {
218 case ',': if ( !level ) end = p; break;
219 case '(': level++; break;
220 case ')': if ( --level < 0 ) end = p; break;
221 case '/': p = skipspace(p, 1) - 1; break;
222 default: ;
223 }
224 }
225 p--; /* back up over terminator */
226 /* Find the name being declared. */
227 /* This is complicated because of procedure and */
228 /* array modifiers. */
229 for ( ; ; )
230 { p = skipspace(p - 1, -1);
231 switch ( *p )
232 {
233 case ']': /* skip array dimension(s) */
234 case ')': /* skip procedure args OR name */
235 { int level = 1;
236 while ( level )
237 switch ( *--p )
238 {
239 case ']': case ')': level++; break;
240 case '[': case '(': level--; break;
241 case '/': p = skipspace(p, -1) + 1; break;
242 default: ;
243 }
244 }
245 if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
246 { /* We found the name being declared */
247 while ( !isidfirstchar(*p) )
248 p = skipspace(p, 1) + 1;
249 goto found;
250 }
251 break;
252 default: goto found;
253 }
254 }
255found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
256 { p++;
257 if ( bp == breaks + 1 ) /* sole argument */
258 writeblanks(breaks[0], p);
259 else
260 writeblanks(bp[-1] - 1, p);
261 bp--;
262 }
263 else
264 { while ( isidchar(*p) ) p--;
265 *bp++ = p+1;
266 }
267 p = end;
268 }
269 while ( *p++ == ',' );
270 *bp = p;
271 /* Make a special check for 'void' arglist */
272 if ( bp == breaks+2 )
273 { p = skipspace(breaks[0], 1);
274 if ( !strncmp(p, "void", 4) )
275 { p = skipspace(p+4, 1);
276 if ( p == breaks[2] - 1 )
277 { bp = breaks; /* yup, pretend arglist is empty */
278 writeblanks(breaks[0], p + 1);
279 }
280 }
281 }
282 /* Put out the function name */
283 p = buf;
284 while ( p != endfn ) putc(*p, out), p++;
285 /* Put out the declaration */
286 for ( ap = breaks+1; ap < bp; ap += 2 )
287 { p = *ap;
288 while ( isidchar(*p) ) putc(*p, out), p++;
289 if ( ap < bp - 1 ) fputs(", ", out);
290 }
291 fputs(") ", out);
292 /* Put out the argument declarations */
293 for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';';
294 fputs(breaks[0], out);
295 free((char *)breaks);
296 return 0;
297}