source: trunk/minix/commands/simple/proto.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 14.3 KB
Line 
1/* proto - Generate ANSI C prototypes. Author: Eric R. Smith */
2
3/* Program to extract function declarations from C source code
4 * Written by Eric R. Smith and placed in the public domain
5 * Thanks are due to Jwahar R. Bammi for fixing several bugs
6 * And providing the Unix makefiles.
7 */
8#define EXIT_SUCCESS 0
9#define EXIT_FAILURE 1
10
11#include <string.h>
12#include <ctype.h>
13#include <stdlib.h>
14#include <stdio.h>
15
16#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_' ))
17#define ABORTED ( (Word *) -1 )
18#define MAXPARAM 20 /* max. number of parameters to a function */
19
20typedef struct word {
21 struct word *next;
22 char string[1];
23} Word;
24
25int inquote = 0; /* in a quote? */
26int newline_seen = 1; /* are we at the start of a line */
27long linenum = 1L; /* line number in current file */
28long endline = 0L; /* the last line before the { of a f'n */
29long symline = 0L; /* Line that symbol was on, set by getsym() */
30int dostatic = 0; /* do static functions? */
31int donum = 0; /* print line numbers? */
32int dohead = 1; /* do file headers? */
33int docond = 1; /* conditionalize for non-ANSI compilers? */
34int dodiff = 0; /* Output a diff file to prototype original */
35int doold = 0; /* do old style: P() */
36int glastc = ' '; /* last char. seen by getsym() */
37Word *endlist; /* Parentheses after the parameters */
38char *progname; /* name of program (for error messages) */
39
40
41_PROTOTYPE(Word * word_alloc, (char *s));
42_PROTOTYPE(void word_free, (Word * w));
43_PROTOTYPE(int List_len, (Word * w));
44_PROTOTYPE(Word * word_append, (Word * w1, Word * w2));
45_PROTOTYPE(int foundin, (Word * w1, Word * w2));
46_PROTOTYPE(void addword, (Word * w, char *s));
47_PROTOTYPE(void printlist, (Word * p));
48_PROTOTYPE(Word * typelist, (Word * p));
49_PROTOTYPE(void typefixhack, (Word * w));
50_PROTOTYPE(int ngetc, (FILE * f));
51_PROTOTYPE(int fnextch, (FILE * f));
52_PROTOTYPE(int nextch, (FILE * f));
53_PROTOTYPE(int getsym, (char *buf, FILE * f));
54_PROTOTYPE(int skipit, (char *buf, FILE * f));
55_PROTOTYPE(Word * getparamlist, (FILE * f));
56_PROTOTYPE(void emit, (Word * wlist, Word * plist, long startline));
57_PROTOTYPE(void getdecl, (FILE * f));
58_PROTOTYPE(int main, (int argc, char **argv));
59_PROTOTYPE(void Usage, (void));
60
61/* Routines for manipulating lists of words. */
62
63Word *word_alloc(s)
64char *s;
65{
66 Word *w;
67
68 w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
69 if (w == NULL) {
70 fprintf(stderr, "%s: out of memory\n", progname);
71 exit(1);
72 }
73 (void) strcpy(w->string, s);
74 w->next = NULL;
75 return w;
76}
77
78void word_free(w)
79Word *w;
80{
81 Word *oldw;
82 while (w) {
83 oldw = w;
84 w = w->next;
85 free((char *) oldw);
86 }
87}
88
89/* Return the length of a list; empty words are not counted */
90int List_len(w)
91Word *w;
92{
93 int count = 0;
94
95 while (w) {
96 if (*w->string) count++;
97 w = w->next;
98 }
99 return count;
100}
101
102/* Append two lists, and return the result */
103Word *word_append(w1, w2)
104Word *w1, *w2;
105{
106 Word *r, *w;
107
108 r = w = word_alloc("");
109
110 while (w1) {
111 w->next = word_alloc(w1->string);
112 w = w->next;
113 w1 = w1->next;
114 }
115 while (w2) {
116 w->next = word_alloc(w2->string);
117 w = w->next;
118 w2 = w2->next;
119 }
120
121 return r;
122}
123
124/* See if the last entry in w2 is in w1 */
125int foundin(w1, w2)
126Word *w1, *w2;
127{
128 while (w2->next) w2 = w2->next;
129
130 while (w1) {
131 if (!strcmp(w1->string, w2->string)) return 1;
132 w1 = w1->next;
133 }
134 return 0;
135}
136
137/* Add the string s to the given list of words */
138void addword(w, s)
139Word *w;
140char *s;
141{
142 while (w->next) w = w->next;
143 w->next = word_alloc(s);
144}
145
146/* Printlist: print out a list */
147void printlist(p)
148Word *p;
149{
150 Word *w;
151 int i = 0;
152
153 for (w = p; w; w = w->next) {
154 printf("%s", w->string);
155 if (ISCSYM(w->string[0]) && i > 0
156 && w->next && w->next->string[0] != ',') printf(" ");
157 i++;
158 }
159}
160
161/* Given a list representing a type and a variable name, extract just
162 * the base type, e.g. "struct word *x" would yield "struct word".
163 * Similarly, "unsigned char x[]" would yield "unsigned char".
164 */
165Word *typelist(p)
166Word *p;
167{
168 Word *w, *r, *last;
169
170 last = r = w = word_alloc("");
171 while (p && p->next) {
172 if (p->string[0] == '[') {
173 word_free(w);
174 last->next = NULL;
175 break;
176 }
177 if (p->string[0] && !ISCSYM(p->string[0])) break;
178 w->next = word_alloc(p->string);
179 last = w;
180 w = w->next;
181 p = p->next;
182 }
183 return r;
184}
185
186/* Typefixhack: promote formal parameters of type "char", "unsigned char",
187 * "short", or "unsigned short" to "int".
188 */
189void typefixhack(w)
190Word *w;
191{
192 Word *oldw = 0;
193
194 while (w) {
195 if (*w->string) {
196 if ((!strcmp(w->string, "char") ||
197 !strcmp(w->string, "short"))
198 && (List_len(w->next) < 2)) {
199 if (oldw && !strcmp(oldw->string, "unsigned")) {
200 oldw->next = w->next;
201 free((char *) w);
202 w = oldw;
203 }
204 (void) strcpy(w->string, "int");
205 }
206 }
207 w = w->next;
208 }
209}
210
211/* Read a character: if it's a newline, increment the line count */
212int ngetc(f)
213FILE *f;
214{
215 int c;
216
217 c = getc(f);
218 if (c == '\n') linenum++;
219
220 return c;
221}
222
223/* Read the next character from the file. If the character is '\' then
224 * read and skip the next character. Any comment sequence is converted
225 * to a blank.
226 */
227int fnextch(f)
228FILE *f;
229{
230 int c, lastc, incomment;
231
232 c = ngetc(f);
233 while (c == '\\') {
234 c = ngetc(f); /* skip a character */
235 c = ngetc(f);
236 }
237 if (c == '/' && !inquote) {
238 c = ngetc(f);
239 if (c == '*') {
240 incomment = 1;
241 c = ' ';
242 while (incomment) {
243 lastc = c;
244 c = ngetc(f);
245 if (lastc == '*' && c == '/')
246 incomment = 0;
247 else if (c < 0)
248 return c;
249 }
250 return fnextch(f);
251 } else {
252 if (c == '\n') linenum--;
253 (void) ungetc(c, f);
254 return '/';
255 }
256 }
257 return c;
258}
259
260
261/* Get the next "interesting" character. Comments are skipped, and strings
262 * are converted to "0". Also, if a line starts with "#" it is skipped.
263 */
264int nextch(f)
265FILE *f;
266{
267 int c;
268
269 c = fnextch(f);
270 if (newline_seen && c == '#') {
271 do {
272 c = fnextch(f);
273 } while (c >= 0 && c != '\n');
274 if (c < 0) return c;
275 }
276 newline_seen = (c == '\n');
277
278 if (c == '\'' || c == '\"') {
279 inquote = c;
280 while ((c = fnextch(f)) >= 0) {
281 if (c == inquote) {
282 inquote = 0;
283 return '0';
284 }
285 }
286 }
287 return c;
288}
289
290/* Get the next symbol from the file, skipping blanks.
291 * Return 0 if OK, -1 for EOF.
292 * Also collapses everything between { and }
293 */
294int getsym(buf, f)
295char *buf;
296FILE *f;
297{
298 register int c;
299 int inbrack = 0;
300
301 c = glastc;
302 while ((c > 0) && isspace(c)) c = nextch(f);
303 if (c < 0) return -1;
304 if (c == '{') {
305 inbrack = 1;
306 endline = linenum;
307 while (inbrack) {
308 c = nextch(f);
309 if (c < 0) {
310 glastc = c;
311 return c;
312 }
313 if (c == '{')
314 inbrack++;
315 else if (c == '}')
316 inbrack--;
317 }
318 (void) strcpy(buf, "{}");
319 glastc = nextch(f);
320 return 0;
321 }
322 if (!ISCSYM(c)) {
323 *buf++ = c;
324 glastc = nextch(f);
325 if (c == '(' && glastc == '*') { /* Look for a 'f'n pointer */
326 *buf++ = glastc;
327 glastc = nextch(f);
328 }
329 *buf = 0;
330 return 0;
331 }
332 symline = linenum;
333 while (ISCSYM(c)) {
334 *buf++ = c;
335 c = nextch(f);
336 }
337 *buf = 0;
338 glastc = c;
339 return 0;
340}
341
342
343/* Skipit: skip until a ";" or the end of a function declaration is seen */
344int skipit(buf, f)
345char *buf;
346FILE *f;
347{
348 int i;
349
350 do {
351 i = getsym(buf, f);
352 if (i < 0) return i;
353 } while (*buf != ';' && *buf != '{');
354
355 return 0;
356}
357
358/* Get a parameter list; when this is called the next symbol in line
359 * should be the first thing in the list.
360 */
361Word *getparamlist(f)
362FILE *f;
363{
364 static Word *pname[MAXPARAM]; /* parameter names */
365 Word *tlist, /* type name */
366 *plist; /* temporary */
367 int np = 0; /* number of parameters */
368 int typed[MAXPARAM]; /* parameter has been given a type */
369 int tlistdone; /* finished finding the type name */
370 int sawsomething;
371 int i;
372 int inparen = 0;
373 char buf[80];
374
375 for (i = 0; i < MAXPARAM; i++) typed[i] = 0;
376
377 plist = word_alloc("");
378 endlist = word_alloc("");
379
380 /* First, get the stuff inside brackets (if anything) */
381
382 sawsomething = 0; /* gets set nonzero when we see an arg */
383 for (;;) {
384 if (getsym(buf, f) < 0) return(NULL);
385 if (*buf == ')' && (--inparen < 0)) {
386 if (sawsomething) { /* if we've seen an arg */
387 pname[np] = plist;
388 plist = word_alloc("");
389 np++;
390 }
391 break;
392 }
393 if (*buf == ';') { /* something weird */
394 return ABORTED;
395 }
396 sawsomething = 1; /* there's something in the arg. list */
397 if (*buf == ',' && inparen == 0) {
398 pname[np] = plist;
399 plist = word_alloc("");
400 np++;
401 } else {
402 addword(plist, buf);
403 if (*buf == '(') inparen++;
404 }
405 }
406
407 /* Next, get the declarations after the function header */
408 inparen = 0;
409 tlist = word_alloc("");
410 plist = word_alloc("");
411 tlistdone = 0;
412 sawsomething = 0;
413 for (;;) {
414 if (getsym(buf, f) < 0) return(NULL);
415
416 /* Handle parentheses, which should indicate func pointer rtn values */
417 if (*buf == '(') {
418 addword(endlist, buf);
419 addword(endlist, " void ");
420 inparen++;
421 } else if (*buf == ')') {
422 if (symline == linenum) {
423 addword(endlist, buf);
424 addword(endlist, buf);
425 }
426 inparen--;
427 } else if (*buf == ',' && !inparen) {
428 /* Handle a list like "int x,y,z" */
429 if (!sawsomething) return(NULL);
430 for (i = 0; i < np; i++) {
431 if (!typed[i] && foundin(plist, pname[i])) {
432 typed[i] = 1;
433 word_free(pname[i]);
434 pname[i] = word_append(tlist, plist);
435 /* Promote types */
436 typefixhack(pname[i]);
437 break;
438 }
439 }
440 if (!tlistdone) {
441 tlist = typelist(plist);
442 tlistdone = 1;
443 }
444 word_free(plist);
445 plist = word_alloc("");
446 } else if (*buf == ';') {
447 /* Handle the end of a list */
448 if (!sawsomething) return ABORTED;
449 for (i = 0; i < np; i++) {
450 if (!typed[i] && foundin(plist, pname[i])) {
451 typed[i] = 1;
452 word_free(pname[i]);
453 pname[i] = word_append(tlist, plist);
454 typefixhack(pname[i]);
455 break;
456 }
457 }
458 tlistdone = 0;
459 word_free(tlist);
460 word_free(plist);
461 tlist = word_alloc("");
462 plist = word_alloc("");
463 } else if (!strcmp(buf, "{}"))
464 break; /* Handle the beginning of the function */
465 /* Otherwise, throw word into list (except for "register") */
466 else if (strcmp(buf, "register")) {
467 sawsomething = 1;
468 addword(plist, buf);
469 if (*buf == '(') inparen++;
470 if (*buf == ')') inparen--;
471 }
472 }
473
474 /* Now take the info we have and build a prototype list */
475
476 /* Empty parameter list means "void" */
477 if (np == 0) return word_alloc("void");
478
479 plist = tlist = word_alloc("");
480 for (i = 0; i < np; i++) {
481
482 /* If no type provided, make it an "int" */
483 if (!(pname[i]->next) ||
484 (!(pname[i]->next->next)&&strcmp(pname[i]->next->string,"void"))) {
485 addword(tlist, "int");
486 }
487 while (tlist->next) tlist = tlist->next;
488 tlist->next = pname[i];
489 if (i < np - 1) addword(tlist, ", ");
490 }
491 return plist;
492}
493
494/* Emit a function declaration. The attributes and name of the function
495 * are in wlist; the parameters are in plist.
496 */
497void emit(wlist, plist, startline)
498Word *wlist, *plist;
499long startline;
500{
501 Word *w;
502 int count = 0;
503
504 if (doold == 0) printf("_PROTOTYPE( ");
505 if (dodiff) {
506 printf("%lda%ld,%ld\n", startline - 1, startline, startline +2);
507 printf("> #ifdef __STDC__\n> ");
508 }
509 if (donum) printf("/*%8ld */ ", startline);
510 for (w = wlist; w; w = w->next) {
511 if (w->string[0]) count++;
512 }
513 if (count < 2) printf("int ");
514 printlist(wlist);
515 if (docond) {
516 if (doold)
517 printf(" P((");
518 else
519 printf(", (");
520 } else {
521 printf("(");
522 }
523
524 printlist(plist);
525 printlist(endlist);
526
527 if (docond) {
528 if (doold)
529 printf("))");
530 else
531 printf(") )");
532 } else {
533 printf(")");
534 }
535
536 if (!dodiff)
537 printf(";\n");
538 else
539 printf("\n");
540
541 if (dodiff) {
542 printf("> #else\n");
543 printf("%lda%ld\n", endline - 1, endline);
544 printf("> #endif\n");
545 }
546}
547
548/* Get all the function declarations */
549void getdecl(f)
550FILE *f;
551{
552 Word *plist, *wlist = NULL;
553 char buf[80];
554 int sawsomething;
555 long startline = 0L; /* line where declaration started */
556 int oktoprint;
557
558again: /* SHAME SHAME */
559 word_free(wlist);
560 wlist = word_alloc("");
561 sawsomething = 0;
562 oktoprint = 1;
563
564 for (;;) {
565 if (getsym(buf, f) < 0) return;
566
567 /* Guess when a declaration is not an external function definition */
568 if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
569 !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
570 !strcmp(buf, "extern")) {
571 (void) skipit(buf, f);
572 goto again;
573 }
574 if (!dostatic && !strcmp(buf, "static")) oktoprint = 0;
575
576 /* For the benefit of compilers that allow "inline" declarations */
577 if (!strcmp(buf, "inline") && !sawsomething) continue;
578 if (!strcmp(buf, ";")) goto again;
579
580 /* A left parenthesis *might* indicate a function definition */
581 if (!strcmp(buf, "(")) {
582 if (!sawsomething || !(plist = getparamlist(f))) {
583 (void) skipit(buf, f);
584 goto again;
585 }
586 if (plist == ABORTED) goto again;
587
588 /* It seems to have been what we wanted */
589 if (oktoprint) emit(wlist, plist, startline);
590 word_free(plist);
591 goto again;
592 }
593 addword(wlist, buf);
594 if (!sawsomething) startline = symline;
595 sawsomething = 1;
596 }
597}
598
599int main(argc, argv)
600int argc;
601char **argv;
602{
603 FILE *f, *g;
604 char *t;
605 char newname[40];
606
607 progname = argv[0];
608 argv++;
609 argc--;
610 g = stdout;
611
612 while (*argv && **argv == '-') {
613 t = *argv++;
614 --argc;
615 t++;
616 while (*t) {
617 if (*t == 's')
618 dostatic = 1;
619 else if (*t == 'n')
620 donum = 1;
621 else if (*t == 'p')
622 docond = 0;
623 else if (*t == 'P')
624 doold =1;
625 else if (*t == 'd') {
626 dodiff = 1;
627 doold = 1;
628 docond = 0;
629 donum = 0;
630 dostatic = 1;
631 } else
632 Usage();
633 t++;
634 }
635 }
636
637 if (docond && doold) {
638 printf("#ifdef __STDC__\n");
639 printf("# define P(args)\targs\n");
640 printf("#else\n");
641 printf("# define P(args)\t()\n");
642 printf("#endif\n\n");
643 }
644 if (argc == 0)
645 getdecl(stdin);
646 else
647 while (argc > 0 && *argv) {
648 if (!(f = fopen(*argv, "r"))) {
649 perror(*argv);
650 exit(EXIT_FAILURE);
651 }
652#if 0
653 if (dodiff) {
654 (void) sprintf(newname, "%sdif", *argv);
655 (void) fclose(g);
656 if (!(g = fopen(newname, "w"))) {
657 perror(newname);
658 exit(EXIT_FAILURE);
659 }
660 }
661#endif
662 if (doold && dohead && !dodiff) printf("\n/* %s */\n", *argv);
663 linenum = 1;
664 newline_seen = 1;
665 glastc = ' ';
666 getdecl(f);
667 argc--;
668 argv++;
669 (void) fclose(f);
670 }
671 if (docond && doold) printf("\n#undef P\n"); /* clean up namespace */
672 (void) fclose(g);
673 return(EXIT_SUCCESS);
674}
675
676
677void Usage()
678{
679 fputs("Usage: ", stderr);
680 fputs(progname, stderr);
681 fputs(" [-d][-n][-p][-s] [files ...]\n", stderr);
682 fputs(" -P: use P() style instead of _PROTOTYPE\n", stderr);
683 fputs(" -d: produce a diff file to prototype original source\n", stderr);
684 fputs(" -n: put line numbers of declarations as comments\n", stderr);
685 fputs(" -p: don't make header files readable by K&R compilers\n", stderr);
686 fputs(" -s: include declarations for static functions\n", stderr);
687 exit(EXIT_FAILURE);
688}
Note: See TracBrowser for help on using the repository browser.