diff options
Diffstat (limited to 'doc/tools/src2html1.4a/Ctags/C.c')
-rw-r--r-- | doc/tools/src2html1.4a/Ctags/C.c | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/doc/tools/src2html1.4a/Ctags/C.c b/doc/tools/src2html1.4a/Ctags/C.c new file mode 100644 index 0000000000..f091fcedad --- /dev/null +++ b/doc/tools/src2html1.4a/Ctags/C.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 1987 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)C.c 5.5 (Berkeley) 2/26/91"; +#endif /* not lint */ + +#include <stdio.h> +#include <string.h> +#include "ctags.h" + +static int func_entry(), str_entry(); +static void hash_entry(); + +/* + * c_entries -- + * read .c and .h files and call appropriate routines + */ +c_entries() +{ + extern int tflag; /* -t: create tags for typedefs */ + register int c, /* current character */ + level; /* brace level */ + register char *sp; /* buffer pointer */ + int token, /* if reading a token */ + t_def, /* if reading a typedef */ + t_level; /* typedef's brace level */ + char tok[MAXTOKEN]; /* token buffer */ + int st; /* Symbol type */ + int rparen; /* State of last rparen */ + + lineftell = ftell(inf); + sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1; + rparen=0; + while (GETC(!=,EOF)) { + rparen--; + switch ((char)c) { + /* + * Here's where it DOESN'T handle: + * foo(a) + * { + * #ifdef notdef + * } + * #endif + * if (a) + * puts("hello, world"); + * } + */ + case '{': + ++level; + goto endtok; + case '}': + /* + * if level goes below zero, try and fix + * it, even though we've already messed up + */ + if (--level < 0) + level = 0; + goto endtok; + + case '\n': + SETLINE; + /* + * the above 3 cases are similar in that they + * are special characters that also end tokens. + */ +endtok: if (sp > tok) { + *sp = EOS; + token = YES; + sp = tok; + } + else + token = NO; + continue; + + /* we ignore quoted strings and comments in their entirety */ + case '"': + case '\'': + (void)skip_key(c); + break; + /* We ignore everything between [] */ + case '[': + (void)skip_key(']'); + goto storec; + + /* + * comments can be fun; note the state is unchanged after + * return, in case we found: + * "foo() XX comment XX { int bar; }" + */ + case '/': + if (GETC(==,'*')) { + skip_comment(); + continue; + } + (void)ungetc(c,inf); + c = '/'; + goto storec; + + /* hash marks flag #define's. */ + case '#': + if (sp == tok) { + hash_entry(); + break; + } + goto storec; + + /* + * if we have a current token, parenthesis on + * level zero indicates a function. + */ + case '(': + if (!level && token) { + int curline; + + if (sp != tok) + *sp = EOS; + /* + * grab the line immediately, we may + * already be wrong, for example, + * foo\n + * (arg1, + */ + getline(); + curline = lineno; + if (func_entry()) { + ++level; + pfnote(tok,curline,SY_FUN); + } else rparen=2; + break; + } + goto storec; + + /* + * semi-colons indicate the end of a typedef; if we find a + * typedef we search for the next semi-colon of the same + * level as the typedef. Ignoring "structs", they are + * tricky, since you can find: + * + * "typedef long time_t;" + * "typedef unsigned int u_int;" + * "typedef unsigned int u_int [10];" + * + * If looking at a typedef, we save a copy of the last token + * found. Then, when we find the ';' we take the current + * token if it starts with a valid token name, else we take + * the one we saved. There's probably some reasonable + * alternative to this... + */ + case ';': + if (t_def && level == t_level) { + t_def = NO; + getline(); + if (sp != tok) + *sp = EOS; + pfnote(tok,lineno,SY_TYP); + break; + } + /* + * Catch global variables by the fact that they end in ; or , + * and they are at level zero. + */ + case ',': + if (sp != tok) *sp = EOS; + if (level==0 && rparen!=1) { + pfnote(tok,lineno,SY_VAR); + break; + } + goto storec; + + /* + * store characters until one that can't be part of a token + * comes along; check the current token against certain + * reserved words. + */ + default: +storec: if (!intoken(c)) { + if (sp == tok) + break; + *sp = EOS; + if (tflag) { + /* no typedefs inside typedefs */ + if (!t_def && !bcmp(tok,"typedef",8)) { + t_def = YES; + t_level = level; + break; + } + /* catch "typedef struct" */ + if ((!t_def || t_level < level) + && (!bcmp(tok,"struct",7) + || !bcmp(tok,"union",6) + || !bcmp(tok,"enum",5))) { + /* Get type of symbol */ + st=0; + switch (*tok) { + case 's' : st= SY_STR; break; + case 'u' : st= SY_UNI; break; + case 'e' : st= SY_ENU; break; + } + /* + * get line immediately; + * may change before '{' + */ + getline(); + if (str_entry(c,st)) + ++level; + break; + } + } + sp = tok; + } + else if (sp != tok || begtoken(c)) { + *sp++ = c; + token = YES; + } + continue; + } + sp = tok; + token = NO; + } +} + +/* + * func_entry -- + * handle a function reference + */ +static +func_entry() +{ + register int c; /* current character */ + + /* + * we assume that the character after a function's right paren + * is a token character if it's a function and a non-token + * character if it's a declaration. Comments don't count... + */ + (void)skip_key((int)')'); + for (;;) { + while (GETC(!=,EOF) && iswhite(c)) + if (c == (int)'\n') + SETLINE; + if (intoken(c) || c == (int)'{') + break; + if (c == (int)'/' && GETC(==,'*')) + skip_comment(); + else { /* don't ever "read" '/' */ + (void)ungetc(c,inf); + return(NO); + } + } + if (c != (int)'{') + (void)skip_key((int)'{'); + return(YES); +} + +/* + * hash_entry -- + * handle a line starting with a '#' + */ +static void +hash_entry() +{ + extern int dflag; /* -d: non-macro defines */ + register int c, /* character read */ + curline; /* line started on */ + register char *sp; /* buffer pointer */ + char tok[MAXTOKEN]; /* storage buffer */ + + curline = lineno; + for (sp = tok;;) { /* get next token */ + if (GETC(==,EOF)) + return; + if (iswhite(c)) + break; + *sp++ = c; + } + *sp = EOS; + if (bcmp(tok,"define",6)) /* only interested in #define's */ + goto skip; + for (;;) { /* this doesn't handle "#define \n" */ + if (GETC(==,EOF)) + return; + if (!iswhite(c)) + break; + } + for (sp = tok;;) { /* get next token */ + *sp++ = c; + if (GETC(==,EOF)) + return; + /* + * this is where it DOESN'T handle + * "#define \n" + */ + if (!intoken(c)) + break; + } + *sp = EOS; + if (dflag || c == (int)'(') { /* only want macros */ + getline(); + if (c == (int)'(') pfnote(tok,curline,SY_MAC); + else pfnote(tok,curline,SY_DEF); + } +skip: if (c == (int)'\n') { /* get rid of rest of define */ + SETLINE + if (*(sp - 1) != '\\') + return; + } + (void)skip_key((int)'\n'); +} + +/* + * str_entry -- + * handle a struct, union or enum entry + */ +static +str_entry(c,st) + register int c; /* current character */ + int st; /* type of symbol */ +{ + register char *sp; /* buffer pointer */ + int curline; /* line started on */ + char tok[BUFSIZ]; /* storage buffer */ + + curline = lineno; + while (iswhite(c)) + if (GETC(==,EOF)) + return(NO); + if (c == (int)'{') /* it was "struct {" */ + return(YES); + for (sp = tok;;) { /* get next token */ + *sp++ = c; + if (GETC(==,EOF)) + return(NO); + if (!intoken(c)) + break; + } + switch ((char)c) { + case '{': /* it was "struct foo{" */ + --sp; + break; + case '\n': /* it was "struct foo\n" */ + SETLINE; + /*FALLTHROUGH*/ + default: /* probably "struct foo " */ + while (GETC(!=,EOF)) + if (!iswhite(c)) + break; + if (c != (int)'{') { + (void)ungetc(c, inf); + return(NO); + } + } + *sp = EOS; + pfnote(tok,curline,st); + return(YES); +} + +/* + * skip_comment -- + * skip over comment + */ +skip_comment() +{ + register int c, /* character read */ + star; /* '*' flag */ + + for (star = 0;GETC(!=,EOF);) + switch((char)c) { + /* comments don't nest, nor can they be escaped. */ + case '*': + star = YES; + break; + case '/': + if (star) + return; + break; + case '\n': + SETLINE; + /*FALLTHROUGH*/ + default: + star = NO; + } +} + +/* + * skip_key -- + * skip to next char "key" + */ +skip_key(key) + register int key; +{ + register int c, + skip, + retval; + + for (skip = retval = NO;GETC(!=,EOF);) + switch((char)c) { + case '\\': /* a backslash escapes anything */ + skip = !skip; /* we toggle in case it's "\\" */ + break; + case ';': /* special case for yacc; if one */ + case '|': /* of these chars occurs, we may */ + retval = YES; /* have moved out of the rule */ + break; /* not used by C */ + case '\n': + SETLINE; + /*FALLTHROUGH*/ + default: + if (c == key && !skip) + return(retval); + skip = NO; + } + return(retval); +} |