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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
45 static int func_entry(void);
46 static void hash_entry(void);
47 static void skip_string(int);
48 static int str_entry(int);
52 * read .c and .h files and call appropriate routines
57 int c; /* current character */
58 int level; /* brace level */
59 int token; /* if reading a token */
60 int t_def; /* if reading a typedef */
61 int t_level; /* typedef's brace level */
62 char *sp; /* buffer pointer */
63 char tok[MAXTOKEN]; /* token buffer */
65 lineftell = ftell(inf);
66 sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
67 while (GETC(!=, EOF)) {
70 * Here's where it DOESN'T handle: {
77 * puts("hello, world");
85 * if level goes below zero, try and fix
86 * it, even though we've already messed up
95 * the above 3 cases are similar in that they
96 * are special characters that also end tokens.
98 endtok: if (sp > tok) {
108 * We ignore quoted strings and character constants
117 * comments can be fun; note the state is unchanged after
118 * return, in case we found:
119 * "foo() XX comment XX { int bar; }"
122 if (GETC(==, '*') || c == '/') {
126 (void)ungetc(c, inf);
130 /* hash marks flag #define's. */
139 * if we have a current token, parenthesis on
140 * level zero indicates a function.
143 if (!level && token) {
149 * grab the line immediately, we may
150 * already be wrong, for example,
158 pfnote(tok, curline);
165 * semi-colons indicate the end of a typedef; if we find a
166 * typedef we search for the next semi-colon of the same
167 * level as the typedef. Ignoring "structs", they are
168 * tricky, since you can find:
170 * "typedef long time_t;"
171 * "typedef unsigned int u_int;"
172 * "typedef unsigned int u_int [10];"
174 * If looking at a typedef, we save a copy of the last token
175 * found. Then, when we find the ';' we take the current
176 * token if it starts with a valid token name, else we take
177 * the one we saved. There's probably some reasonable
178 * alternative to this...
181 if (t_def && level == t_level) {
192 * store characters until one that can't be part of a token
193 * comes along; check the current token against certain
197 /* ignore whitespace */
198 if (c == ' ' || c == '\t') {
200 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
204 (void)ungetc(c, inf);
207 storec: if (!intoken(c)) {
212 /* no typedefs inside typedefs */
214 !memcmp(tok, "typedef",8)) {
219 /* catch "typedef struct" */
220 if ((!t_def || t_level < level)
221 && (!memcmp(tok, "struct", 7)
222 || !memcmp(tok, "union", 6)
223 || !memcmp(tok, "enum", 5))) {
225 * get line immediately;
226 * may change before '{'
237 else if (sp != tok || begtoken(c)) {
238 if (sp == tok + sizeof tok - 1)
239 /* Too long -- truncate it */
255 * handle a function reference
260 int c; /* current character */
261 int level = 0; /* for matching '()' */
264 * Find the end of the assumed function declaration.
265 * Note that ANSI C functions can have type definitions so keep
266 * track of the parentheses nesting level.
268 while (GETC(!=, EOF)) {
272 /* skip strings and character constants */
277 if (GETC(==, '*') || c == '/')
295 * we assume that the character after a function's right paren
296 * is a token character if it's a function and a non-token
297 * character if it's a declaration. Comments don't count...
300 while (GETC(!=, EOF) && iswhite(c))
303 if (intoken(c) || c == '{')
305 if (c == '/' && (GETC(==, '*') || c == '/'))
307 else { /* don't ever "read" '/' */
308 (void)ungetc(c, inf);
319 * handle a line starting with a '#'
324 int c; /* character read */
325 int curline; /* line started on */
326 char *sp; /* buffer pointer */
327 char tok[MAXTOKEN]; /* storage buffer */
329 /* ignore leading whitespace */
330 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
332 (void)ungetc(c, inf);
335 for (sp = tok;;) { /* get next token */
340 if (sp == tok + sizeof tok - 1)
341 /* Too long -- truncate it */
347 if (memcmp(tok, "define", 6)) /* only interested in #define's */
349 for (;;) { /* this doesn't handle "#define \n" */
355 for (sp = tok;;) { /* get next token */
356 if (sp == tok + sizeof tok - 1)
357 /* Too long -- truncate it */
364 * this is where it DOESN'T handle
371 if (dflag || c == '(') { /* only want macros */
373 pfnote(tok, curline);
375 skip: if (c == '\n') { /* get rid of rest of define */
377 if (*(sp - 1) != '\\')
380 (void)skip_key('\n');
385 * handle a struct, union or enum entry
388 str_entry(int c) /* c is current character */
390 int curline; /* line started on */
391 char *sp; /* buffer pointer */
392 char tok[LINE_MAX]; /* storage buffer */
398 if (c == '{') /* it was "struct {" */
400 for (sp = tok;;) { /* get next token */
401 if (sp == tok + sizeof tok - 1)
402 /* Too long -- truncate it */
412 case '{': /* it was "struct foo{" */
415 case '\n': /* it was "struct foo\n" */
418 default: /* probably "struct foo " */
419 while (GETC(!=, EOF))
423 (void)ungetc(c, inf);
428 pfnote(tok, curline);
437 skip_comment(int t) /* t is comment character */
439 int c; /* character read */
440 int star; /* '*' flag */
442 for (star = 0; GETC(!=, EOF);)
444 /* comments don't nest, nor can they be escaped. */
449 if (star && t == '*')
465 * skip to the end of a string or character constant.
473 for (skip = NO; GETC(!=, EOF); )
475 case '\\': /* a backslash escapes anything */
476 skip = !skip; /* we toggle in case it's "\\" */
482 if (c == key && !skip)
490 * skip to next char "key"
499 for (skip = retval = NO; GETC(!=, EOF);)
501 case '\\': /* a backslash escapes anything */
502 skip = !skip; /* we toggle in case it's "\\" */
504 case ';': /* special case for yacc; if one */
505 case '|': /* of these chars occurs, we may */
506 retval = YES; /* have moved out of the rule */
507 break; /* not used by C */
510 /* skip strings and character constants */
515 if (GETC(==, '*') || c == '/') {
519 (void)ungetc(c, inf);
527 if (c == key && !skip)