Category : Miscellaneous Language Source Code
Archive   : BAGTAG.ZIP
Filename : CTAGS.C

 
Output of file : CTAGS.C contained in archive : BAGTAG.ZIP
/****************************************************************************
*
* ctags.c 19Jun93
*
* Generate tags for subsequent use by Brief editor.
*
* Contains entries:
* main
* usage
* find_functions
* get_typedefs
* get_defines
* get_structs
* get_token
* print_defn_line
* not_c_keyword
*
* Usage: ctags [flags] file(s) [[flags] file(s) ...] [>ctags.tag]
*
* Flags (/ or - for flag character):
* -d Include defines (default); -!d excludes them
* -t Include typedefs (default); -!t excludes them
* -s Include structs (default); -!s excludes them
* -u Include unions (default); -!u excludes them
* -e Include enums (default); -!e excludes them
* - Signals end of flags
*
* This program will perform a simple parsing of one or more C source
* files and write a "tags" file to stdout. This file is then used in
* conjunction with tagging commands build into VI and available (via
* the ctags.cb macro) for Brief. The tags file will contain a line for
* each procedure in the source file. Each line has the form:
*
*
*
* The search criteria contains the entire source line containing the
* tag name to reduce the possibility of the search finding the
* wrong line.
*
* This has been compiled under Microsoft C V6.0a (and used to compile
* under Unix V on an AT&T 3B1). When using Microsoft C, link with
* setargv.obj to enable wild card expansion of command line arguments.
*
* To build: CL /AT ctags.c setargv.obj wilds.obj
* (wilds.obj replaces Microsoft's wild.c and does real reg-exp wildcard
* processing, including such things as "*d.*" and "e[a-f]*.[ch]")
*
* For debug build, CL /AS /Zi /Od /DDEBUG ctags.c setargv.obj wilds.obj
*
* Futures:
* >> Flags below were from the VI version; not implemented here
* -a append output to existing `tags' file.
* (Silly, since output goes to stdout -- but see below)
*
* -B generate backward (from the current position) searches
* -F generate forward searches (default)
* (Huh?)
*
* -w suppress warnings
* (What warnings?)
*
* -x produce a more human readable report on standard output
* (Including sorting?)
*
* >> Look for duplicates?
*
* >> How to organize a project's tag files? One big file or separate
* by directories? Beware of duplicate tags.
*
* >> If -a above is to make sense, we should make it
* -a (or -a )
* instead of re-directing output. This would also allow for
* -u (or -u )
* meaning update the output file (i.e., remove all tag lines for the
* input file before checking it for tags).
* (And maybe change to (or allow) -f to supplant stdout.)
*
* >> Allow for adding or suppressing specific tags.
*
* >> Produce tags for variables (definitions of statics and external
* vars in particular).
*
* >> Maybe use lex/yacc to do real parse of the program; might have to
* deal with such issues as pre-processor vs. final compiler scan;
* conditional compilation (#if family of statements); #includes;
* /D and /I parameters, INCLUDE environment var. But let's not go
* overboard.
*
* >> Sky Schulz's SKYTAGS allows for duplicates by popping up a window
* for user choice; but that only makes sense if all potential tag
* files are read (he assumes one big tag file for a project, stored
* centrally). If the one big file idea is adopted, save time by
* reading it and saving it.
*
* Copyright (c) 1992 B. Goldstein -- Pequod Software
*
* Change History:
* Date Who What
* ------- --- -------------
* 01/11/87 Paul Verket Initial release
* 02/01/87 Misc. minor enhancements.
* 04/22/87 Tag #defined names in addition to function names.
* --------
* 05/14/90 Michael Denio Modified to put the full path of the filename
* in the tag file
* --------
* 08/18/90 Morris Maynard Added cases to handle MSC dbl slash comments
* --------
* 07/14/92 Edward Diener Modified to correctly handle an absolute or
* relative file specification.
* Eliminated C reserved keywords as possible
* function names.
* Added a pre-processor definition, NODEFINE,
* that eliminates defined names being output.
* Added recognition of new style // comments.
* --------
* 21Oct92 BAG added code to print_defn_line to escape re chars in search
* pattern
* the following screws up:
* main F:\TMP\ctags.c ??
* but this works:
* main F:\TMP\ctags.c ??
* (can't just turn RE off, since it's needed for < and >)
* 22Oct92 BAG Changed generated pattern to use < and > for line brackets
* 25Oct92 BAG Don't die if can't open a file (might be a directory, etc.,
* especially since using setargv.obj)
* 26Oct92 BAG Merged in changes from E.D. above
* Changed his NODEFINE to a run-time control:
* -d: include #defines (default); -!d turns it off
* Allowed for #[ \t]@define with the "#" not in column 1
* (note that this will accept #defines preceeded by
* non-white-space on the line (in the real world, the
* pre-processor scan is done as a separate pass).
* 04Nov92 BAG line_start wasn't initialized, so if fn was on line 1, it
* came up with an empty tag line (... ?<>?)
* 05Nov92 BAG Added debug display of whole line
* 11Nov92 BAG Added handling of typedefs
* Dropped pretense of checking for balanced parens or braces
* 18Nov92 BAG Added handling of "[...]" in get_token, as T_SUBSCRIPT
* Improved typedef processing (skip first token, save word at
* first close-paren, etc.)
* 22Nov92 BAG Added handling of structs, unions, enums (including enum
* constants.
* 22Nov92 BAG Added handling of things embedded within braces; this
* required dropping everything below the level of function
* tags into subroutines.
* 22Nov92 BAG DebugBuffer seems to screw up file positioning; I think one
* can't mix fgets with fgetc's safely while doing fseeks and
* ftells.
* 22Nov92 BAG Re-worked setting of line_start, so it won't be done early
* (it was set before the final word token was processed; now
* it's processed exactly when the T_NL token is returned).
* 23Nov92 BAG Finishing "recursive" tagging
* 25Nov92 BAG Allow for grouped flags: e.g.: -!sue
* 19Jun93 BAG BUG: "struct foo bar;" screws up "parser"
* ditto for enum, union
*
****************************************************************************/
/* Definitions */

#pragma comment (user,"Source file "__FILE__" modified on "__TIMESTAMP__)
#pragma comment (user,"Compiled on "__DATE__" "__TIME__)
#pragma comment (compiler)

#include
#include
#include
#include
#include

typedef enum
{ T_WORD, T_COMMA, T_SEMI,
T_PREPROCESS, T_TYPEDEF, T_STRUCT, T_UNION, T_ENUM,
T_OPENPAREN, T_CLOSEPAREN, T_OPENBRACE, T_CLOSEBRACE, T_NL,
T_SUBSCRIPT,
T_EOF
} TOKEN;

// Command line flag(s)
static int WantDefines = 1;
static int WantTypedefs = 1;
static int WantStructs = 1;
static int WantUnions = 1;
static int WantEnums = 1;
static int EndFlags = 0;

// Built-in limits
#define MAX_TAGSIZE 132

// Here instead of as args
static FILE *in_file;
static char full_path[_MAX_PATH];
static char word[MAX_TAGSIZE];
static long line_start;

// Prototypes
void main (int argc, char *argv[]);
static void usage (void);
static void find_functions (char *filename);
static void get_typedefs (void);
static void get_defines (void);
static void get_structs (TOKEN t);
static TOKEN get_token (void);
static void print_defn_line (long defnstart);
static int not_c_keyword (char *s);

/***************************************************************************/

/****************************************************************************
*
* main 22Nov92
*
* Scan arg list for flags and file names.
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
* 22Nov92 BAG Changed scanning method; added s, u, e flags
*
****************************************************************************/

void main (int argc, char *argv[])

{ int argi;
int setting;
char *argp;

if (argc < 2)
usage (); // (it exits)

/* Cycle through each argument on the command line. */

for (argi = 1; argi < argc; argi++)
{ if (! EndFlags &&
(strcmp (argv[argi], "-") == 0 || strcmp (argv[argi], "/") == 0))
{ EndFlags = 1;
continue;
}

if (argv[argi][0] == '-' && ! EndFlags
|| argv[argi][0] == '/')
{ EndFlags = 0;
setting = 1; // default is On

for (argp = &argv[argi][1]; *argp; argp++)
{ if (*argp == '!')
{ setting = 0;
continue;
}

switch (*argp)
{ case 'd':
case 'D':
WantDefines = setting;
break;

case 't':
case 'T':
WantTypedefs = setting;
break;

case 's':
case 'S':
WantStructs = setting;
break;

case 'u':
case 'U':
WantUnions = setting;
break;

case 'e':
case 'E':
WantEnums = setting;
break;

default:
usage ();
}
}

continue;
}

in_file = fopen (argv[argi], "rt");
if (in_file == NULL)
{ perror (argv[argi]);
continue; // Probably it was a directory
}
find_functions (argv[argi]);
fclose (in_file);
}

exit (0);
}

/****************************************************************************
*
* usage 25Nov92
*
* Usage note and exit.
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
* 25Nov92 BAG Explain about switch chars
*
****************************************************************************/

static void usage (void)

{ fprintf (stderr,
"\nUsage: CTAGS [flags] file(s) [[flags] file(s) ...] [>ctags.tag]\n");
fprintf (stderr, " flags (signalled by - or /):\n");
fprintf (stderr, " -d: include defines\n");
fprintf (stderr, " -t: include typedefs\n");
fprintf (stderr, " -s: include structs\n");
fprintf (stderr, " -u: include unions\n");
fprintf (stderr, " -e: include enums\n");
fprintf (stderr, " ! turns off any following flags in the group\n\n");
fprintf (stderr, " -: no more flags (until next /x flag)\n\n");
fprintf (stderr, " Default flags: all on: -dtsue\n");

exit (1);
}

/****************************************************************************
*
* find_functions 19Jun93
*
* Top level scan:
* Looks for function tags here
* Calls appropriate subroutine if it encounters another level to tag
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
* 22Nov92 BAG Broke it up into subroutines so can get tags within {}
* 24Nov92 BAG Look for other tag types within function body
* 19Jun93 BAG "struct foo xxx;" bug fix
*
****************************************************************************/

static void find_functions (char *filename)

{ TOKEN curr_token;

enum
{ NEUTRAL,
NAME, INPAREN, FN_NAME, INBRACE
} state = NEUTRAL;

char function[MAX_TAGSIZE];

int paren_cnt = 0,
brace_cnt = 0;

long fn_start;

// Get full path name of file; report it
if (_fullpath (full_path, filename, sizeof(full_path)-1) == NULL)
strcpy (full_path, filename); // Can't happen: file's already open
fprintf (stderr, "Tagging file %s\n", full_path);


// Initialize
line_start = ftell (in_file);
fn_start = line_start; // (Not really needed, but shuts LINT up)


// Process the file ...

while ((curr_token = get_token ()) != T_EOF)
{ switch ((int) state)
{ // STARTING OUTSIDE ---------------------------------------------

/* The "home" state. If a "word" is found, assume that it is
a procedure name. If the word is "typedef", scan for the
new type. If T_PREPROCESS, look for #define names and
toss the rest of the line since macro definitions look
like procedures. If an open brace is found, start gobbling
up the text contained within the braces. Keep a brace count
to handle nested braces. */

case NEUTRAL:
switch ((int)curr_token)
{ case T_WORD:
state = NAME;
// Note that the parens may start on the next line,
// so store the offset now
fn_start = line_start;
continue;

case T_PREPROCESS:
get_defines ();
continue;

case T_TYPEDEF:
get_typedefs ();
continue;

case T_STRUCT:
case T_UNION:
case T_ENUM:
get_structs (curr_token);
continue;

case T_OPENBRACE:
state = INBRACE;
brace_cnt = 1;
continue;

default:
continue;
}


// FUNCTION TAG -------------------------------------------------

/* All subsequent "word"s will be assumed to be the real
function name until an open paren is found. If something
other than a word or paren is found, then this wasn't
a function name after all. */

// Ah, but! the word might have been "static" or "_FAR_" and
// we really can't just skip all words up to the one before
// the open paren, for we may have hit "struct" or its sisters

case NAME:
switch ((int)curr_token)
{ case T_WORD:
fn_start = line_start;
continue;

case T_STRUCT:
case T_UNION:
case T_ENUM:
get_structs (curr_token);
continue;

case T_NL:
continue;

case T_OPENPAREN:
state = INPAREN;
strcpy (function, word);
paren_cnt = 1;
continue;

default:
state = NEUTRAL;
continue;
}

/* Eat up all the stuff within parens until the close paren
is found. Keep a counter to handle nested parens. */

case INPAREN:
switch ((int)curr_token)
{ case T_OPENPAREN:
paren_cnt++;
continue;

case T_CLOSEPAREN:
if (--paren_cnt == 0)
state = FN_NAME;
continue;

default:
continue;
}

/* If a comma or a semicolon is found, then this was a false
alarm. If an opening brace or another word is found, then
we found a procedure definition. */

case FN_NAME:
switch ((int)curr_token)
{ case T_COMMA:
case T_SEMI:
state = NEUTRAL;
continue;

case T_NL:
continue;

case T_OPENBRACE:
state = INBRACE;
brace_cnt = 1;
if (not_c_keyword (function))
{ printf ("%s", function);
print_defn_line (fn_start);
}
continue;

default:
state = NEUTRAL;
if (not_c_keyword (function))
{ printf ("%s", function);
print_defn_line (fn_start);
}
continue;
}

// Loop through function body until the closing brace is found.
// Here is where to alter things to find defines,
// typedefs, etc., within functions.

case INBRACE:
switch ((int)curr_token)
{ case T_OPENBRACE:
brace_cnt++;
continue;

case T_PREPROCESS:
get_defines ();
continue;

case T_TYPEDEF:
get_typedefs ();
continue;

case T_STRUCT:
case T_UNION:
case T_ENUM:
get_structs (curr_token);
continue;

case T_CLOSEBRACE:
if (--brace_cnt == 0)
state = NEUTRAL;
continue;

default:
continue;
}

default:
continue;
}
}

return;
}

/****************************************************************************
*
* get_typedefs 24Nov92
*
* Scan for typedefs
*
* Skip all subsequent words and anything in () or {}, until
* we get a word followed by a comma or a semi-colon; such
* words are typedef tags. We want to save the line with the
* tag, since it will be a more distinctive search pattern
* than the "typedef" line itself.
*
* This logic won't handle
* typedef void (_cdecl *PHANDLER)(void);
* so try skipping the first token ("void") and
* if there hasn't been a word at the first close-paren,
* use the current word (which should get "PHANDLER").
*
* Change History:
* Date Who What
* ------- --- -------------
* 22Nov92 BAG First draft
* 24Nov92 BAG Look for other tag types within the body of the typedef {}'s
*
****************************************************************************/

void get_typedefs (void)

{ TOKEN curr_token;

enum
{ TYPEDEF0, TYPEDEF, TYPEDEFINPAREN, TYPEDEFINBRACE
} state = TYPEDEF0;

char typedeftag[MAX_TAGSIZE];

int paren_cnt = 0,
brace_cnt = 0;

long typedef_start;

typedeftag[0] = '\0';
word[0] = '\0';

// The typedef last line is the desired search line, but we'll
// store the current line offset here to start with
typedef_start = line_start;

while ((curr_token = get_token ()) != T_EOF)
{ switch (state)
{ case TYPEDEF0:
state = TYPEDEF;
switch ((int)curr_token)
{ case T_STRUCT:
case T_UNION:
case T_ENUM:
get_structs (curr_token);
continue;

default:
continue;
}

case TYPEDEF:
switch ((int)curr_token)
{ case T_WORD:
strcpy (typedeftag, word);
typedef_start = line_start;
continue;

case T_NL:
continue;

case T_OPENPAREN:
state = TYPEDEFINPAREN;
paren_cnt = 1;
continue;

case T_OPENBRACE:
state = TYPEDEFINBRACE;
brace_cnt = 1;
continue;

case T_COMMA:
case T_SEMI:
if (WantTypedefs && *typedeftag)
{ // have to check because of typedef void (*FOO)(int x);
if (not_c_keyword (typedeftag))
{ printf ("%s", typedeftag);
print_defn_line (typedef_start);
}
}
if (curr_token == T_SEMI)
return;
continue;

default:
continue;
}

case TYPEDEFINPAREN:
switch ((int)curr_token)
{ case T_OPENPAREN:
paren_cnt++;
continue;

case T_CLOSEPAREN:
if (--paren_cnt == 0)
{ state = TYPEDEF;
if (*typedeftag == '\0')
strcpy (typedeftag, word);
}
continue;

default:
continue;
}

// This section is what scans through typedef structs, so
// here is where to alter things to find defines, structs,
// unions, enums (typedefs are illegal)

case TYPEDEFINBRACE:
switch ((int)curr_token)
{ case T_OPENBRACE:
brace_cnt++;
continue;

case T_PREPROCESS:
get_defines ();
continue;

case T_STRUCT:
case T_UNION:
case T_ENUM:
get_structs (curr_token);
continue;

case T_CLOSEBRACE:
if (--brace_cnt == 0)
state = TYPEDEF;
continue;

default:
continue;
}

}
}

return;
}

/****************************************************************************
*
* get_defines 22Nov92
*
* Scan for defines
*
* Change History:
* Date Who What
* ------- --- -------------
* 22Nov92 BAG First draft
*
****************************************************************************/

void get_defines (void)

{ TOKEN curr_token;


enum
{ CHECK_DEFINE, RECORD_DEFINE, PREPROCESSOR
} state = CHECK_DEFINE;

long define_start;

define_start = line_start;

while ((curr_token = get_token ()) != T_EOF && curr_token != T_NL)
{ switch (state)
{ case CHECK_DEFINE:
switch ((int)curr_token)
{ case T_WORD:
if (strcmp (word, "define") == 0)
state = RECORD_DEFINE;
else
state = PREPROCESSOR;
continue;
default:
state = PREPROCESSOR;
continue;
}

/* Record the defined name in the same way as function names */

case RECORD_DEFINE:
if (WantDefines)
{ printf ("%s", word);
print_defn_line (define_start);
}
state = PREPROCESSOR; /* toss the rest */
continue;

/* Handle the preprocessor line until a new-line is found.
The tokenizer tosses escaped new lines. */

case PREPROCESSOR:
continue; // skip everything to new line (better not hit eof)

default:
continue;
}
}

return;
}

/****************************************************************************
*
* get_structs 19Jun93
*
* Scan for structs, unions, enums (and enum constants)
*
* Change History:
* Date Who What
* ------- --- -------------
* 22Nov92 BAG First draft
* 24Nov92 BAG Look for tags within the body of this item
* 24Nov92 BAG Process enum constants
* 19Jun93 BAG BUG: "struct foo xxx;" with no {} screwed up
*
****************************************************************************/

void get_structs (TOKEN token)

{ TOKEN curr_token;

enum
{ STRUCT0, STRUCT1, INBRACE, GOTENUMCONST, GOTTAG
} state = STRUCT0;

int brace_cnt = 0;

long struct_start;

struct_start = line_start;

while ((curr_token = get_token ()) != T_EOF)
{ switch (state)
{ case STRUCT0:
switch ((int)curr_token)
{ case T_WORD: // if there's a word after "struct", take it
struct_start = line_start; // Remember this line
state = GOTTAG;
continue;

case T_NL:
continue;

case T_OPENBRACE:
brace_cnt = 1;
state = INBRACE;
continue;

default:
state = STRUCT1;
continue;
}

case GOTTAG: // Got tag; is it followed by word or '{'?
switch ((int)curr_token)
{ case T_NL:
continue;

case T_OPENBRACE: // It really is a definition
if (WantStructs || WantUnions || WantEnums)
{ printf ("%s", word);
print_defn_line (struct_start);
}
brace_cnt = 1;
state = INBRACE;
continue;

default: // it's just "struct foo xxx;"; skip it
state = STRUCT1;
continue;
}

case STRUCT1: // no tag: skip everything except braces, ';'
switch ((int)curr_token)
{ case T_OPENBRACE:
brace_cnt = 1;
state = INBRACE;
continue;

case T_SEMI:
return;

default:
continue;
}

/* Here is where we would look for enum constants and also
for nested structs, unions, enums, and for that matter
embedded defines, structs, etc. (not typedefs). */

case INBRACE:
switch ((int)curr_token)
{ case T_OPENBRACE:
brace_cnt++;
continue;

case T_PREPROCESS:
get_defines ();
continue;

case T_STRUCT:
case T_UNION:
case T_ENUM:
if (token != T_ENUM)
get_structs (curr_token);
continue;

case T_CLOSEBRACE:
if (--brace_cnt == 0)
return;
continue;

// look for enum constants within the braces
// Note that if these are one to a line, the search
// pattern will hardly be unique
case T_WORD:
if (token == T_ENUM)
{ struct_start = line_start;
if (WantEnums)
{ printf ("%s", word);
print_defn_line (struct_start);
}
state = GOTENUMCONST;
}
continue;

default:
continue;
}

// We only get here from INBRACE in an ENUM

case GOTENUMCONST: // skip everything to a comma or }
switch ((int)curr_token)
{ case T_COMMA:
state = INBRACE; // go back to brace scanning
continue;

case T_CLOSEBRACE: // this ends the enum, so get out
return;

default:
continue;
}

default:
continue;
}
}

return;
}

/****************************************************************************
*
* get_token 23Nov92
*
* Break up input file into tokens. Take care with characters inside
* quotes and comments that might cause trouble.
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
*
****************************************************************************/

static TOKEN get_token (void)

{ enum
{ NEUTRAL, INQUOTE, INSQUOTE, INWORD, INCOMMENT, INDSLASH, INSUBSCRIPT
} state = NEUTRAL;
int c, c2;
char *w;

w = word;

while ((c = getc (in_file)) != EOF)
{ switch ((int) state)
{ /* The "home" state. Quoted strings and comments are
stripped. Words consisting of letters, digits and
the underscore are gathered. */

case NEUTRAL:
switch (c)
{ case '(':
return (T_OPENPAREN);

case ')':
return (T_CLOSEPAREN);

case '#':
// Note that most compilers require the "#" to be the first
// non-white-space character on a line; some require it to
// be the first character on the line; I don't care so much
return (T_PREPROCESS);

case '\n': // get start of what will be the next line
line_start = ftell (in_file);
return (T_NL);

case '"':
state = INQUOTE;
continue;

case '\'':
state = INSQUOTE;
continue;

case '{':
return (T_OPENBRACE);

case '}':
return (T_CLOSEBRACE);

case '/': /* start of comment? */
if ((c2 = getc (in_file)) == '*')
{ state = INCOMMENT;
continue;
}
else if (c2 == '/') /* double slash comment? */
{ state = INDSLASH;
continue;
}
else
{ (void)ungetc (c2, in_file);
continue;
}

case ';':
return (T_SEMI);

case ',':
return (T_COMMA);

case '\\': /* toss the escape */
(void)getc (in_file); // ignore char
continue;

case '[':
state = INSUBSCRIPT;
continue;

default:
if (isalnum (c) || c == '_')
{ state = INWORD;
//@@@ could check for overflow of MAX_TAGSIZE
*w++ = (char) c;
}
continue;
}


/* Stay in these states, tossing characters, until the
closing marker. */

case INCOMMENT:
switch (c)
{ case '*': /* end of comment? */
if ((c2 = getc (in_file)) == '/')
state = NEUTRAL;
else
(void)ungetc (c2, in_file);
continue;
default:
continue;
}

case INDSLASH:
switch (c)
{ case '\n': /* end of //-comment? */
state = NEUTRAL;
(void)ungetc (c, in_file); // let top of loop see newline
continue;
default:
continue;
}

case INQUOTE:
switch (c)
{ case '"':
state = NEUTRAL;
continue;
case '\\': /* toss the escape */
(void)getc (in_file); // ignore char
continue;
default:
continue;
}

case INSQUOTE:
switch (c)
{ case '\'':
state = NEUTRAL;
continue;
case '\\': /* toss the escape */
(void)getc (in_file); // ignore char
continue;
default:
continue;
}

case INSUBSCRIPT:
//@@@ could check for overflow of MAX_TAGSIZE
if (c == ']')
{ *w = '\0';
return (T_SUBSCRIPT);
}
else
{ *w++ = (char)c;
continue;
}


/* Gather up the word. */

case INWORD:
//@@@ could check for overflow of MAX_TAGSIZE
if (isalnum (c) || c == '_')
{ *w++ = (char)c;
continue;
}
else
{ (void)ungetc (c, in_file);
*w = '\0';
if (strcmp (word, "typedef") == 0)
return (T_TYPEDEF);
else if (strcmp (word, "struct") == 0)
return (T_STRUCT);
else if (strcmp (word, "union") == 0)
return (T_UNION);
else if (strcmp (word, "enum") == 0)
return (T_ENUM);
else
return (T_WORD);
}

default:
continue;
}
}

return (T_EOF);
}

/****************************************************************************
*
* print_defn_line 22Nov92
*
* Use the previously stored ftell() of the start of line to
* dump the source line.
*
* Escape any Regular Expression characters for Brief search
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
*
****************************************************************************/

static void print_defn_line (long defn_start)

{ long current_position;
int c;

current_position = ftell (in_file);
fseek (in_file, defn_start, SEEK_SET);

printf (" %s ?<", full_path);
while ((c = getc (in_file)) != EOF && c != '\n')
{ // if RE-char, have to escape it
if (strchr ("?*@+\\|%${}[]<>", c) != NULL)
putchar ('\\');
putchar (c);
}
printf (">?\n");

fseek (in_file, current_position, SEEK_SET);

return;
}

/****************************************************************************
*
* not_c_keyword 22Nov92
*
* Check for C keywords (shouldn't find these looking like functions
* outside of procedure bodies, but why not check?)
*
* If this is actually useful, should be expandable (like GNU indent or
* lint) to contain user-defined keywords.
*
* Change History:
* Date Who What
* ------- --- -------------
* 21Oct92 BAG Adopted
*
****************************************************************************/

static int not_c_keyword (char *s)

{ static char *CKeywords[] =
{ "auto",
"break",
"case",
"char",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"goto",
"if",
"int",
"long",
"register",
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"typedef",
"union",
"unsigned",
"void",
"volatile",
"while",
NULL
};
int i;

for (i = 0; CKeywords[i] != NULL; ++i)
if (strcmp (s, CKeywords[i]) == 0)
{ fprintf (stderr,
" Found C keyword %s outside of procedures\n", s);
return (0);
}

return (1);
}

/************************ end of ctags.c file ******************************/


  3 Responses to “Category : Miscellaneous Language Source Code
Archive   : BAGTAG.ZIP
Filename : CTAGS.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/