2 * Copyright (c) 1987, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
49 static int func_entry(void);
50 static void hash_entry(void);
51 static void skip_string(int);
52 static int str_entry(int);
56 * read .c and .h files and call appropriate routines
61 int c; /* current character */
62 int level; /* brace level */
63 int token; /* if reading a token */
64 int t_def; /* if reading a typedef */
65 int t_level; /* typedef's brace level */
66 char *sp; /* buffer pointer */
67 char tok[MAXTOKEN]; /* token buffer */
69 lineftell = ftell(inf);
70 sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
71 while (GETC(!=, EOF)) {
74 * Here's where it DOESN'T handle: {
81 * puts("hello, world");
89 * if level goes below zero, try and fix
90 * it, even though we've already messed up
99 * the above 3 cases are similar in that they
100 * are special characters that also end tokens.
102 endtok: if (sp > tok) {
112 * We ignore quoted strings and character constants
121 * comments can be fun; note the state is unchanged after
122 * return, in case we found:
123 * "foo() XX comment XX { int bar; }"
126 if (GETC(==, '*') || c == '/') {
130 (void)ungetc(c, inf);
134 /* hash marks flag #define's. */
143 * if we have a current token, parenthesis on
144 * level zero indicates a function.
147 if (!level && token) {
153 * grab the line immediately, we may
154 * already be wrong, for example,
162 pfnote(tok, curline);
169 * semi-colons indicate the end of a typedef; if we find a
170 * typedef we search for the next semi-colon of the same
171 * level as the typedef. Ignoring "structs", they are
172 * tricky, since you can find:
174 * "typedef long time_t;"
175 * "typedef unsigned int u_int;"
176 * "typedef unsigned int u_int [10];"
178 * If looking at a typedef, we save a copy of the last token
179 * found. Then, when we find the ';' we take the current
180 * token if it starts with a valid token name, else we take
181 * the one we saved. There's probably some reasonable
182 * alternative to this...
185 if (t_def && level == t_level) {
196 * store characters until one that can't be part of a token
197 * comes along; check the current token against certain
201 /* ignore whitespace */
202 if (c == ' ' || c == '\t') {
204 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
208 (void)ungetc(c, inf);
211 storec: if (!intoken(c)) {
216 /* no typedefs inside typedefs */
218 !memcmp(tok, "typedef",8)) {
223 /* catch "typedef struct" */
224 if ((!t_def || t_level < level)
225 && (!memcmp(tok, "struct", 7)
226 || !memcmp(tok, "union", 6)
227 || !memcmp(tok, "enum", 5))) {
229 * get line immediately;
230 * may change before '{'
241 else if (sp != tok || begtoken(c)) {
242 if (sp == tok + sizeof tok - 1)
243 /* Too long -- truncate it */
259 * handle a function reference
264 int c; /* current character */
265 int level = 0; /* for matching '()' */
268 * Find the end of the assumed function declaration.
269 * Note that ANSI C functions can have type definitions so keep
270 * track of the parentheses nesting level.
272 while (GETC(!=, EOF)) {
276 /* skip strings and character constants */
281 if (GETC(==, '*') || c == '/')
299 * we assume that the character after a function's right paren
300 * is a token character if it's a function and a non-token
301 * character if it's a declaration. Comments don't count...
304 while (GETC(!=, EOF) && iswhite(c))
307 if (intoken(c) || c == '{')
309 if (c == '/' && (GETC(==, '*') || c == '/'))
311 else { /* don't ever "read" '/' */
312 (void)ungetc(c, inf);
323 * handle a line starting with a '#'
328 int c; /* character read */
329 int curline; /* line started on */
330 char *sp; /* buffer pointer */
331 char tok[MAXTOKEN]; /* storage buffer */
333 /* ignore leading whitespace */
334 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
336 (void)ungetc(c, inf);
339 for (sp = tok;;) { /* get next token */
344 if (sp == tok + sizeof tok - 1)
345 /* Too long -- truncate it */
351 if (memcmp(tok, "define", 6)) /* only interested in #define's */
353 for (;;) { /* this doesn't handle "#define \n" */
359 for (sp = tok;;) { /* get next token */
360 if (sp == tok + sizeof tok - 1)
361 /* Too long -- truncate it */
368 * this is where it DOESN'T handle
375 if (dflag || c == '(') { /* only want macros */
377 pfnote(tok, curline);
379 skip: if (c == '\n') { /* get rid of rest of define */
381 if (*(sp - 1) != '\\')
384 (void)skip_key('\n');
389 * handle a struct, union or enum entry
392 str_entry(int c) /* c is current character */
394 int curline; /* line started on */
395 char *sp; /* buffer pointer */
396 char tok[LINE_MAX]; /* storage buffer */
402 if (c == '{') /* it was "struct {" */
404 for (sp = tok;;) { /* get next token */
405 if (sp == tok + sizeof tok - 1)
406 /* Too long -- truncate it */
416 case '{': /* it was "struct foo{" */
419 case '\n': /* it was "struct foo\n" */
422 default: /* probably "struct foo " */
423 while (GETC(!=, EOF))
427 (void)ungetc(c, inf);
432 pfnote(tok, curline);
441 skip_comment(int t) /* t is comment character */
443 int c; /* character read */
444 int star; /* '*' flag */
446 for (star = 0; GETC(!=, EOF);)
448 /* comments don't nest, nor can they be escaped. */
453 if (star && t == '*')
469 * skip to the end of a string or character constant.
477 for (skip = NO; GETC(!=, EOF); )
479 case '\\': /* a backslash escapes anything */
480 skip = !skip; /* we toggle in case it's "\\" */
486 if (c == key && !skip)
494 * skip to next char "key"
503 for (skip = retval = NO; GETC(!=, EOF);)
505 case '\\': /* a backslash escapes anything */
506 skip = !skip; /* we toggle in case it's "\\" */
508 case ';': /* special case for yacc; if one */
509 case '|': /* of these chars occurs, we may */
510 retval = YES; /* have moved out of the rule */
511 break; /* not used by C */
514 /* skip strings and character constants */
519 if (GETC(==, '*') || c == '/') {
523 (void)ungetc(c, inf);
531 if (c == key && !skip)