]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.1 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * Copyright 1993 NeXT Computer, Inc. | |
26 | * All rights reserved. | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Standalone Interface Generator | |
31 | * | |
32 | * Input file format: a series of lines of the form: | |
33 | * | |
34 | * #<text> | |
35 | * or | |
36 | * <function declaration> <arg list> ; | |
37 | * | |
38 | * e.g.: | |
39 | * void *malloc(int len) len; | |
40 | * | |
41 | * Lines starting with '#' are passed through unchanged. | |
42 | * Lines starting with '/' are ignored. | |
43 | * | |
44 | * | |
45 | */ | |
46 | ||
47 | #import <stdio.h> | |
48 | #import <ctype.h> | |
49 | #import <string.h> | |
50 | #import <stdlib.h> | |
51 | #import <sys/param.h> | |
52 | ||
53 | #define MAXLINE 65535 | |
54 | typedef enum {NO=0, YES=1} BOOL; | |
55 | #define strdup(str) ((char *)strcpy(malloc(strlen(str)+1),str)) | |
56 | extern int getopt(); | |
57 | ||
58 | enum { | |
59 | none, | |
60 | external, | |
61 | internal, | |
62 | table, | |
63 | defs | |
64 | } which; | |
65 | char *osuffix[] = { | |
66 | "none", | |
67 | "_external.h", | |
68 | "_internal.h", | |
69 | "_table.c", | |
70 | "_defs.h" | |
71 | }; | |
72 | ||
73 | FILE *ofile; | |
74 | int lineNumber, outputNumber; | |
75 | char *moduleName; | |
76 | char *moduleNameCaps; | |
77 | ||
78 | char *stringToLower(char *string) | |
79 | { | |
80 | char *new = strdup(string); | |
81 | char *p = new; | |
82 | ||
83 | while (*p) | |
84 | *p = tolower(*p++); | |
85 | return new; | |
86 | } | |
87 | ||
88 | char *stringToUpper(char *string) | |
89 | { | |
90 | char *new = strdup(string); | |
91 | char *p = new; | |
92 | ||
93 | while (*p) | |
94 | *p = toupper(*p++); | |
95 | return new; | |
96 | } | |
97 | ||
98 | inline BOOL | |
99 | isIdentifier(char c) | |
100 | { | |
101 | if (isalnum(c) || c == '_') | |
102 | return YES; | |
103 | else | |
104 | return NO; | |
105 | } | |
106 | ||
107 | void | |
108 | outputLine(char *decl, char *function, char *args, char *arglist) | |
109 | { | |
110 | if (which == table) { | |
111 | static int struct_started; | |
112 | if (struct_started == 0) { | |
113 | fprintf(ofile, "unsigned long (*%s_functions[])() = {\n", | |
114 | moduleName); | |
115 | struct_started = 1; | |
116 | } | |
117 | fprintf(ofile, "(unsigned long (*)())_%s,\t\t/* %d */\n", function, outputNumber); | |
118 | } | |
119 | ||
120 | if (which == defs) { | |
121 | fprintf(ofile, "#define %s _%s\n",function,function); | |
122 | } | |
123 | ||
124 | if (which == internal) { | |
125 | fprintf(ofile, "extern %s _%s(%s);\n", decl, function, args); | |
126 | } | |
127 | ||
128 | if (which == external) { | |
129 | fprintf(ofile, "#define %s_%s_FN %d\n", | |
130 | moduleNameCaps, function, outputNumber); | |
131 | fprintf(ofile, | |
132 | "static inline %s %s ( %s ) {\n", decl, function, args); | |
133 | fprintf(ofile, | |
134 | "\treturn (%s)(*%s_FN[%d])(%s);\n", | |
135 | decl, moduleNameCaps, outputNumber, arglist); | |
136 | fprintf(ofile, "}\n"); | |
137 | } | |
138 | outputNumber++; | |
139 | } | |
140 | ||
141 | void | |
142 | parseLine(char *line) | |
143 | { | |
144 | char *paren, *parenEnd; | |
145 | char *ident, *identEnd; | |
146 | char *arglist, *arglistEnd; | |
147 | char *function; | |
148 | ||
149 | paren = strchr(line, '('); | |
150 | if (paren == NULL) | |
151 | goto syntax_error; | |
152 | for (identEnd = paren - 1; !isIdentifier(*identEnd); identEnd--) | |
153 | continue; | |
154 | for (ident = identEnd; isIdentifier(*ident); ident--) | |
155 | continue; | |
156 | ident++; | |
157 | *++identEnd = '\0'; | |
158 | paren++; | |
159 | parenEnd = strchr(paren, ')'); | |
160 | if (parenEnd == NULL) | |
161 | goto syntax_error; | |
162 | *parenEnd = '\0'; | |
163 | ||
164 | arglist = parenEnd + 1; | |
165 | while (isspace(*arglist)) | |
166 | arglist++; | |
167 | arglistEnd = strchr(arglist, ';'); | |
168 | if (arglistEnd == NULL) | |
169 | goto syntax_error; | |
170 | *arglistEnd = '\0'; | |
171 | ||
172 | function = strdup(ident); | |
173 | *ident = '\0'; | |
174 | outputLine(line, function, paren, arglist); | |
175 | free(function); | |
176 | return; | |
177 | ||
178 | syntax_error: | |
179 | fprintf(stderr, "Syntax error at line %d\n",lineNumber); | |
180 | return; | |
181 | } | |
182 | ||
183 | int | |
184 | getLineThru(FILE *file, char *linebuf, char stop, int len) | |
185 | { | |
186 | char *p = linebuf; | |
187 | int c, gotten; | |
188 | ||
189 | gotten = 0; | |
190 | while (((c = fgetc(file)) != EOF) && len) { | |
191 | *p++ = c; | |
192 | len--; | |
193 | gotten++; | |
194 | if (c == '\n') lineNumber++; | |
195 | if (c == stop) | |
196 | break; | |
197 | } | |
198 | *p = '\0'; | |
199 | return gotten; | |
200 | } | |
201 | ||
202 | int | |
203 | peekf(FILE *file) | |
204 | { | |
205 | int c = fgetc(file); | |
206 | ungetc(c, file); | |
207 | return c; | |
208 | } | |
209 | ||
210 | void | |
211 | skipWhitespace(FILE *file) | |
212 | { | |
213 | int c; | |
214 | ||
215 | while ((c = fgetc(file)) != EOF && isspace(c)) | |
216 | if (c == '\n') ++lineNumber; | |
217 | ungetc(c, file); | |
218 | } | |
219 | ||
220 | void | |
221 | parseFile(FILE *file) | |
222 | { | |
223 | char *line, c; | |
224 | int len, lineNumber; | |
225 | ||
226 | line = malloc(MAXLINE+1); | |
227 | lineNumber = 1; | |
228 | ||
229 | skipWhitespace(file); | |
230 | ||
231 | while (!feof(file)) { | |
232 | c = peekf(file); | |
233 | if (c == '#' || c == '/') { | |
234 | len = getLineThru(file, line, '\n', MAXLINE); | |
235 | if (c == '#') | |
236 | fprintf(ofile, line); | |
237 | } else { | |
238 | len = getLineThru(file, line, ';', MAXLINE); | |
239 | parseLine(line); | |
240 | } | |
241 | skipWhitespace(file); | |
242 | } | |
243 | free(line); | |
244 | } | |
245 | ||
246 | int | |
247 | main(int argc, char **argv) | |
248 | { | |
249 | extern char *optarg; | |
250 | extern int optind; | |
251 | FILE *file; | |
252 | int c, errflag = 0; | |
253 | char ofilename[MAXPATHLEN]; | |
254 | char *ifile, *odir = "."; | |
255 | ||
256 | while ((c = getopt(argc, argv, "d:n:")) != EOF) | |
257 | switch (c) { | |
258 | case 'd': | |
259 | odir = optarg; | |
260 | break; | |
261 | case 'n': | |
262 | moduleName = optarg; | |
263 | moduleNameCaps = stringToUpper(moduleName); | |
264 | break; | |
265 | default: | |
266 | errflag++; | |
267 | break; | |
268 | } | |
269 | ||
270 | ofile = stdout; | |
271 | if ((ifile = argv[optind]) != NULL) { | |
272 | file = fopen(argv[optind], "r"); | |
273 | if (file == NULL) { | |
274 | perror("open"); | |
275 | exit(1); | |
276 | } | |
277 | } else { | |
278 | fprintf(stderr,"No input file specified\n"); | |
279 | exit(2); | |
280 | } | |
281 | ||
282 | if (moduleName == NULL) { | |
283 | char *newName, *dot; | |
284 | int len; | |
285 | newName = strchr(ifile, '/'); | |
286 | if (newName == NULL) | |
287 | newName = ifile; | |
288 | dot = strchr(newName, '.'); | |
289 | if (dot == NULL) | |
290 | dot = &newName[strlen(newName)]; | |
291 | len = dot - newName; | |
292 | moduleName = (char *)malloc(len + 1); | |
293 | strncpy(moduleName, newName, len); | |
294 | moduleName[len] = '\0'; | |
295 | moduleNameCaps = stringToUpper(moduleName); | |
296 | } | |
297 | ||
298 | for (which = external; which <= defs; which++) { | |
299 | rewind(file); | |
300 | lineNumber = 1; | |
301 | outputNumber = 0; | |
302 | sprintf(ofilename, "%s/%s%s", odir, moduleName, osuffix[which]); | |
303 | ofile = fopen((const char *)ofilename, "w"); | |
304 | if (ofile == NULL) { | |
305 | fprintf(stderr,"error opening output file %s\n",ofilename); | |
306 | exit(3); | |
307 | } | |
308 | ||
309 | if (which == table) { | |
310 | fprintf(ofile, "#define %s_TABLE 1\n", moduleNameCaps); | |
311 | fprintf(ofile, "#import \"%s_internal.h\"\n",moduleName); | |
312 | } | |
313 | ||
314 | if (which == internal) { | |
315 | fprintf(ofile, "#define %s_INTERNAL 1\n", moduleNameCaps); | |
316 | } | |
317 | ||
318 | if (which == defs) { | |
319 | fprintf(ofile, "#define %s_DEFS 1\n", moduleNameCaps); | |
320 | } | |
321 | ||
322 | if (which == external) { | |
323 | fprintf(ofile, "#import \"memory.h\"\n"); | |
324 | fprintf(ofile, "#define %s_EXTERNAL 1\n", moduleNameCaps); | |
325 | fprintf(ofile, | |
326 | "#define %s_FN (*(unsigned long (***)())%s_TABLE_POINTER)\n\n", | |
327 | moduleNameCaps, moduleNameCaps); | |
328 | } | |
329 | parseFile(file); | |
330 | ||
331 | if (which == table) { | |
332 | fprintf(ofile, "};\n\n"); | |
333 | } | |
334 | } | |
335 | return 0; | |
336 | } |