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
33 * @(#)C.c 8.4 (Berkeley) 4/2/94
34 * $FreeBSD: src/usr.bin/ctags/C.c,v 1.3.2.2 2002/07/30 00:55:07 tjr Exp $
35 * $DragonFly: src/usr.bin/ctags/C.c,v 1.2 2003/06/17 04:29:25 dillon Exp $
44 static int func_entry(void);
45 static void hash_entry(void);
46 static void skip_string(int);
47 static int str_entry(int);
51 * read .c and .h files and call appropriate routines
56 int c
; /* current character */
57 int level
; /* brace level */
58 int token
; /* if reading a token */
59 int t_def
; /* if reading a typedef */
60 int t_level
; /* typedef's brace level */
61 char *sp
; /* buffer pointer */
62 char tok
[MAXTOKEN
]; /* token buffer */
64 lineftell
= ftell(inf
);
65 sp
= tok
; token
= t_def
= NO
; t_level
= -1; level
= 0; lineno
= 1;
66 while (GETC(!=, EOF
)) {
69 * Here's where it DOESN'T handle: {
76 * puts("hello, world");
84 * if level goes below zero, try and fix
85 * it, even though we've already messed up
94 * the above 3 cases are similar in that they
95 * are special characters that also end tokens.
97 endtok
: if (sp
> tok
) {
107 * We ignore quoted strings and character constants
112 (void)skip_string(c
);
116 * comments can be fun; note the state is unchanged after
117 * return, in case we found:
118 * "foo() XX comment XX { int bar; }"
121 if (GETC(==, '*') || c
== '/') {
125 (void)ungetc(c
, inf
);
129 /* hash marks flag #define's. */
138 * if we have a current token, parenthesis on
139 * level zero indicates a function.
142 if (!level
&& token
) {
148 * grab the line immediately, we may
149 * already be wrong, for example,
157 pfnote(tok
, curline
);
164 * semi-colons indicate the end of a typedef; if we find a
165 * typedef we search for the next semi-colon of the same
166 * level as the typedef. Ignoring "structs", they are
167 * tricky, since you can find:
169 * "typedef long time_t;"
170 * "typedef unsigned int u_int;"
171 * "typedef unsigned int u_int [10];"
173 * If looking at a typedef, we save a copy of the last token
174 * found. Then, when we find the ';' we take the current
175 * token if it starts with a valid token name, else we take
176 * the one we saved. There's probably some reasonable
177 * alternative to this...
180 if (t_def
&& level
== t_level
) {
191 * store characters until one that can't be part of a token
192 * comes along; check the current token against certain
196 /* ignore whitespace */
197 if (c
== ' ' || c
== '\t') {
199 while (GETC(!=, EOF
) && (c
== ' ' || c
== '\t'))
203 (void)ungetc(c
, inf
);
206 storec
: if (!intoken(c
)) {
211 /* no typedefs inside typedefs */
213 !memcmp(tok
, "typedef",8)) {
218 /* catch "typedef struct" */
219 if ((!t_def
|| t_level
< level
)
220 && (!memcmp(tok
, "struct", 7)
221 || !memcmp(tok
, "union", 6)
222 || !memcmp(tok
, "enum", 5))) {
224 * get line immediately;
225 * may change before '{'
236 else if (sp
!= tok
|| begtoken(c
)) {
237 if (sp
== tok
+ sizeof tok
- 1)
238 /* Too long -- truncate it */
254 * handle a function reference
259 int c
; /* current character */
260 int level
= 0; /* for matching '()' */
263 * Find the end of the assumed function declaration.
264 * Note that ANSI C functions can have type definitions so keep
265 * track of the parentheses nesting level.
267 while (GETC(!=, EOF
)) {
271 /* skip strings and character constants */
276 if (GETC(==, '*') || c
== '/')
294 * we assume that the character after a function's right paren
295 * is a token character if it's a function and a non-token
296 * character if it's a declaration. Comments don't count...
299 while (GETC(!=, EOF
) && iswhite(c
))
302 if (intoken(c
) || c
== '{')
304 if (c
== '/' && (GETC(==, '*') || c
== '/'))
306 else { /* don't ever "read" '/' */
307 (void)ungetc(c
, inf
);
318 * handle a line starting with a '#'
323 int c
; /* character read */
324 int curline
; /* line started on */
325 char *sp
; /* buffer pointer */
326 char tok
[MAXTOKEN
]; /* storage buffer */
328 /* ignore leading whitespace */
329 while (GETC(!=, EOF
) && (c
== ' ' || c
== '\t'))
331 (void)ungetc(c
, inf
);
334 for (sp
= tok
;;) { /* get next token */
339 if (sp
== tok
+ sizeof tok
- 1)
340 /* Too long -- truncate it */
346 if (memcmp(tok
, "define", 6)) /* only interested in #define's */
348 for (;;) { /* this doesn't handle "#define \n" */
354 for (sp
= tok
;;) { /* get next token */
355 if (sp
== tok
+ sizeof tok
- 1)
356 /* Too long -- truncate it */
363 * this is where it DOESN'T handle
370 if (dflag
|| c
== '(') { /* only want macros */
372 pfnote(tok
, curline
);
374 skip
: if (c
== '\n') { /* get rid of rest of define */
376 if (*(sp
- 1) != '\\')
379 (void)skip_key('\n');
384 * handle a struct, union or enum entry
387 str_entry(int c
) /* c is current character */
389 int curline
; /* line started on */
390 char *sp
; /* buffer pointer */
391 char tok
[LINE_MAX
]; /* storage buffer */
397 if (c
== '{') /* it was "struct {" */
399 for (sp
= tok
;;) { /* get next token */
400 if (sp
== tok
+ sizeof tok
- 1)
401 /* Too long -- truncate it */
411 case '{': /* it was "struct foo{" */
414 case '\n': /* it was "struct foo\n" */
417 default: /* probably "struct foo " */
418 while (GETC(!=, EOF
))
422 (void)ungetc(c
, inf
);
427 pfnote(tok
, curline
);
436 skip_comment(int t
) /* t is comment character */
438 int c
; /* character read */
439 int star
; /* '*' flag */
441 for (star
= 0; GETC(!=, EOF
);)
443 /* comments don't nest, nor can they be escaped. */
448 if (star
&& t
== '*')
464 * skip to the end of a string or character constant.
472 for (skip
= NO
; GETC(!=, EOF
); )
474 case '\\': /* a backslash escapes anything */
475 skip
= !skip
; /* we toggle in case it's "\\" */
481 if (c
== key
&& !skip
)
489 * skip to next char "key"
498 for (skip
= retval
= NO
; GETC(!=, EOF
);)
500 case '\\': /* a backslash escapes anything */
501 skip
= !skip
; /* we toggle in case it's "\\" */
503 case ';': /* special case for yacc; if one */
504 case '|': /* of these chars occurs, we may */
505 retval
= YES
; /* have moved out of the rule */
506 break; /* not used by C */
509 /* skip strings and character constants */
514 if (GETC(==, '*') || c
== '/') {
518 (void)ungetc(c
, inf
);
526 if (c
== key
&& !skip
)