2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1987, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
47 static int func_entry(void);
48 static void hash_entry(void);
49 static void skip_string(int);
50 static int str_entry(int);
54 * read .c and .h files and call appropriate routines
59 int c; /* current character */
60 int level; /* brace level */
61 int token; /* if reading a token */
62 int t_def; /* if reading a typedef */
63 int t_level; /* typedef's brace level */
64 char *sp; /* buffer pointer */
65 char tok[MAXTOKEN]; /* token buffer */
67 lineftell = ftell(inf);
68 sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
69 while (GETC(!=, EOF)) {
72 * Here's where it DOESN'T handle: {
79 * puts("hello, world");
87 * if level goes below zero, try and fix
88 * it, even though we've already messed up
97 * the above 3 cases are similar in that they
98 * are special characters that also end tokens.
100 endtok: if (sp > tok) {
110 * We ignore quoted strings and character constants
119 * comments can be fun; note the state is unchanged after
120 * return, in case we found:
121 * "foo() XX comment XX { int bar; }"
124 if (GETC(==, '*') || c == '/') {
128 (void)ungetc(c, inf);
132 /* hash marks flag #define's. */
141 * if we have a current token, parenthesis on
142 * level zero indicates a function.
145 if (!level && token) {
151 * grab the line immediately, we may
152 * already be wrong, for example,
160 pfnote(tok, curline);
167 * semi-colons indicate the end of a typedef; if we find a
168 * typedef we search for the next semi-colon of the same
169 * level as the typedef. Ignoring "structs", they are
170 * tricky, since you can find:
172 * "typedef long time_t;"
173 * "typedef unsigned int u_int;"
174 * "typedef unsigned int u_int [10];"
176 * If looking at a typedef, we save a copy of the last token
177 * found. Then, when we find the ';' we take the current
178 * token if it starts with a valid token name, else we take
179 * the one we saved. There's probably some reasonable
180 * alternative to this...
183 if (t_def && level == t_level) {
194 * store characters until one that can't be part of a token
195 * comes along; check the current token against certain
199 /* ignore whitespace */
200 if (c == ' ' || c == '\t') {
202 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
206 (void)ungetc(c, inf);
209 storec: if (!intoken(c)) {
214 /* no typedefs inside typedefs */
216 !memcmp(tok, "typedef",8)) {
221 /* catch "typedef struct" */
222 if ((!t_def || t_level < level)
223 && (!memcmp(tok, "struct", 7)
224 || !memcmp(tok, "union", 6)
225 || !memcmp(tok, "enum", 5))) {
227 * get line immediately;
228 * may change before '{'
239 else if (sp != tok || begtoken(c)) {
240 if (sp == tok + sizeof tok - 1)
241 /* Too long -- truncate it */
257 * handle a function reference
262 int c; /* current character */
263 int level = 0; /* for matching '()' */
266 * Find the end of the assumed function declaration.
267 * Note that ANSI C functions can have type definitions so keep
268 * track of the parentheses nesting level.
270 while (GETC(!=, EOF)) {
274 /* skip strings and character constants */
279 if (GETC(==, '*') || c == '/')
297 * we assume that the character after a function's right paren
298 * is a token character if it's a function and a non-token
299 * character if it's a declaration. Comments don't count...
302 while (GETC(!=, EOF) && iswhite(c))
305 if (intoken(c) || c == '{')
307 if (c == '/' && (GETC(==, '*') || c == '/'))
309 else { /* don't ever "read" '/' */
310 (void)ungetc(c, inf);
321 * handle a line starting with a '#'
326 int c; /* character read */
327 int curline; /* line started on */
328 char *sp; /* buffer pointer */
329 char tok[MAXTOKEN]; /* storage buffer */
331 /* ignore leading whitespace */
332 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
334 (void)ungetc(c, inf);
337 for (sp = tok;;) { /* get next token */
342 if (sp == tok + sizeof tok - 1)
343 /* Too long -- truncate it */
349 if (memcmp(tok, "define", 6)) /* only interested in #define's */
351 for (;;) { /* this doesn't handle "#define \n" */
357 for (sp = tok;;) { /* get next token */
358 if (sp == tok + sizeof tok - 1)
359 /* Too long -- truncate it */
366 * this is where it DOESN'T handle
373 if (dflag || c == '(') { /* only want macros */
375 pfnote(tok, curline);
377 skip: if (c == '\n') { /* get rid of rest of define */
379 if (*(sp - 1) != '\\')
382 (void)skip_key('\n');
387 * handle a struct, union or enum entry
390 str_entry(int c) /* c is current character */
392 int curline; /* line started on */
393 char *sp; /* buffer pointer */
394 char tok[LINE_MAX]; /* storage buffer */
400 if (c == '{') /* it was "struct {" */
402 for (sp = tok;;) { /* get next token */
403 if (sp == tok + sizeof tok - 1)
404 /* Too long -- truncate it */
414 case '{': /* it was "struct foo{" */
417 case '\n': /* it was "struct foo\n" */
420 default: /* probably "struct foo " */
421 while (GETC(!=, EOF))
425 (void)ungetc(c, inf);
430 pfnote(tok, curline);
439 skip_comment(int t) /* t is comment character */
441 int c; /* character read */
442 int star; /* '*' flag */
444 for (star = 0; GETC(!=, EOF);)
446 /* comments don't nest, nor can they be escaped. */
451 if (star && t == '*')
467 * skip to the end of a string or character constant.
475 for (skip = NO; GETC(!=, EOF); )
477 case '\\': /* a backslash escapes anything */
478 skip = !skip; /* we toggle in case it's "\\" */
484 if (c == key && !skip)
492 * skip to next char "key"
501 for (skip = retval = NO; GETC(!=, EOF);)
503 case '\\': /* a backslash escapes anything */
504 skip = !skip; /* we toggle in case it's "\\" */
506 case ';': /* special case for yacc; if one */
507 case '|': /* of these chars occurs, we may */
508 retval = YES; /* have moved out of the rule */
509 break; /* not used by C */
512 /* skip strings and character constants */
517 if (GETC(==, '*') || c == '/') {
521 (void)ungetc(c, inf);
529 if (c == key && !skip)