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$");
48 static int func_entry(void);
49 static void hash_entry(void);
50 static void skip_string(int);
51 static int str_entry(int);
55 * read .c and .h files and call appropriate routines
60 int c; /* current character */
61 int level; /* brace level */
62 int token; /* if reading a token */
63 int t_def; /* if reading a typedef */
64 int t_level; /* typedef's brace level */
65 char *sp; /* buffer pointer */
66 char tok[MAXTOKEN]; /* token buffer */
68 lineftell = ftell(inf);
69 sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
70 while (GETC(!=, EOF)) {
73 * Here's where it DOESN'T handle: {
80 * puts("hello, world");
88 * if level goes below zero, try and fix
89 * it, even though we've already messed up
98 * the above 3 cases are similar in that they
99 * are special characters that also end tokens.
101 endtok: if (sp > tok) {
111 * We ignore quoted strings and character constants
120 * comments can be fun; note the state is unchanged after
121 * return, in case we found:
122 * "foo() XX comment XX { int bar; }"
125 if (GETC(==, '*') || c == '/') {
129 (void)ungetc(c, inf);
133 /* hash marks flag #define's. */
142 * if we have a current token, parenthesis on
143 * level zero indicates a function.
146 if (!level && token) {
152 * grab the line immediately, we may
153 * already be wrong, for example,
161 pfnote(tok, curline);
168 * semi-colons indicate the end of a typedef; if we find a
169 * typedef we search for the next semi-colon of the same
170 * level as the typedef. Ignoring "structs", they are
171 * tricky, since you can find:
173 * "typedef long time_t;"
174 * "typedef unsigned int u_int;"
175 * "typedef unsigned int u_int [10];"
177 * If looking at a typedef, we save a copy of the last token
178 * found. Then, when we find the ';' we take the current
179 * token if it starts with a valid token name, else we take
180 * the one we saved. There's probably some reasonable
181 * alternative to this...
184 if (t_def && level == t_level) {
195 * store characters until one that can't be part of a token
196 * comes along; check the current token against certain
200 /* ignore whitespace */
201 if (c == ' ' || c == '\t') {
203 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
207 (void)ungetc(c, inf);
210 storec: if (!intoken(c)) {
215 /* no typedefs inside typedefs */
217 !memcmp(tok, "typedef",8)) {
222 /* catch "typedef struct" */
223 if ((!t_def || t_level < level)
224 && (!memcmp(tok, "struct", 7)
225 || !memcmp(tok, "union", 6)
226 || !memcmp(tok, "enum", 5))) {
228 * get line immediately;
229 * may change before '{'
240 else if (sp != tok || begtoken(c)) {
241 if (sp == tok + sizeof tok - 1)
242 /* Too long -- truncate it */
258 * handle a function reference
263 int c; /* current character */
264 int level = 0; /* for matching '()' */
265 static char attribute[] = "__attribute__";
266 char maybe_attribute[sizeof attribute + 1],
270 * Find the end of the assumed function declaration.
271 * Note that ANSI C functions can have type definitions so keep
272 * track of the parentheses nesting level.
274 while (GETC(!=, EOF)) {
278 /* skip strings and character constants */
283 if (GETC(==, '*') || c == '/')
301 * we assume that the character after a function's right paren
302 * is a token character if it's a function and a non-token
303 * character if it's a declaration. Comments don't count...
305 for (anext = maybe_attribute;;) {
306 while (GETC(!=, EOF) && iswhite(c))
312 * Recognize the gnu __attribute__ extension, which would
313 * otherwise make the heuristic test DTWT
315 if (anext == maybe_attribute) {
322 if (anext - maybe_attribute
323 < (ptrdiff_t)(sizeof attribute - 1))
329 if (strcmp(maybe_attribute, attribute) == 0) {
330 (void)ungetc(c, inf);
336 if (intoken(c) || c == '{')
338 if (c == '/' && (GETC(==, '*') || c == '/'))
340 else { /* don't ever "read" '/' */
341 (void)ungetc(c, inf);
352 * handle a line starting with a '#'
357 int c; /* character read */
358 int curline; /* line started on */
359 char *sp; /* buffer pointer */
360 char tok[MAXTOKEN]; /* storage buffer */
362 /* ignore leading whitespace */
363 while (GETC(!=, EOF) && (c == ' ' || c == '\t'))
365 (void)ungetc(c, inf);
368 for (sp = tok;;) { /* get next token */
373 if (sp == tok + sizeof tok - 1)
374 /* Too long -- truncate it */
380 if (memcmp(tok, "define", 6)) /* only interested in #define's */
382 for (;;) { /* this doesn't handle "#define \n" */
388 for (sp = tok;;) { /* get next token */
389 if (sp == tok + sizeof tok - 1)
390 /* Too long -- truncate it */
397 * this is where it DOESN'T handle
404 if (dflag || c == '(') { /* only want macros */
406 pfnote(tok, curline);
408 skip: if (c == '\n') { /* get rid of rest of define */
410 if (*(sp - 1) != '\\')
413 (void)skip_key('\n');
418 * handle a struct, union or enum entry
421 str_entry(int c) /* c is current character */
423 int curline; /* line started on */
424 char *sp; /* buffer pointer */
425 char tok[LINE_MAX]; /* storage buffer */
431 if (c == '{') /* it was "struct {" */
433 for (sp = tok;;) { /* get next token */
434 if (sp == tok + sizeof tok - 1)
435 /* Too long -- truncate it */
445 case '{': /* it was "struct foo{" */
448 case '\n': /* it was "struct foo\n" */
451 default: /* probably "struct foo " */
452 while (GETC(!=, EOF))
456 (void)ungetc(c, inf);
461 pfnote(tok, curline);
470 skip_comment(int t) /* t is comment character */
472 int c; /* character read */
473 int star; /* '*' flag */
475 for (star = 0; GETC(!=, EOF);)
477 /* comments don't nest, nor can they be escaped. */
482 if (star && t == '*')
498 * skip to the end of a string or character constant.
506 for (skip = NO; GETC(!=, EOF); )
508 case '\\': /* a backslash escapes anything */
509 skip = !skip; /* we toggle in case it's "\\" */
515 if (c == key && !skip)
523 * skip to next char "key"
532 for (skip = retval = NO; GETC(!=, EOF);)
534 case '\\': /* a backslash escapes anything */
535 skip = !skip; /* we toggle in case it's "\\" */
537 case ';': /* special case for yacc; if one */
538 case '|': /* of these chars occurs, we may */
539 retval = YES; /* have moved out of the rule */
540 break; /* not used by C */
543 /* skip strings and character constants */
548 if (GETC(==, '*') || c == '/') {
552 (void)ungetc(c, inf);
560 if (c == key && !skip)