⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ctags.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ctags.c *//* This is a reimplementation of the ctags(1) program.  It supports ANSI C, * and has heaps o' flags.  It is meant to be distributed with elvis. */#include <stdio.h>#include "config.h"#ifndef FALSE# define FALSE	0# define TRUE	1#endif#ifndef TAGS# define TAGS	"tags"#endif#ifndef REFS# define REFS	"refs"#endif#ifndef BLKSIZE# define BLKSIZE 1024#endif#include "ctype.c" /* yes, that really is the .c file, not the .h one. *//* -------------------------------------------------------------------------- *//* Some global variables *//* The following boolean variables are set according to command line flags */int	incl_static;	/* -s  include static tags */int	incl_types;	/* -t  include typedefs and structs */int	incl_vars;	/* -v  include variables */int	make_refs;	/* -r  generate a "refs" file */int	append_files;	/* -a  append to "tags" [and "refs"] files *//* The following are used for outputting to the "tags" and "refs" files */FILE	*tags;		/* used for writing to the "tags" file */FILE	*refs;		/* used for writing to the "refs" file *//* -------------------------------------------------------------------------- *//* These are used for reading a source file.  It keeps track of line numbers */char	*file_name;	/* name of the current file */FILE	*file_fp;	/* stream used for reading the file */long	file_lnum;	/* line number in the current file */long	file_seek;	/* fseek() offset to the start of current line */int	file_afternl;	/* boolean: was previous character a newline? */int	file_prevch;	/* a single character that was ungotten */int	file_header;	/* boolean: is the current file a header file? *//* This function opens a file, and resets the line counter.  If it fails, it * it will display an error message and leave the file_fp set to NULL. */void file_open(name)	char	*name;	/* name of file to be opened */{	/* if another file was already open, then close it */	if (file_fp)	{		fclose(file_fp);	}	/* try to open the file for reading.  The file must be opened in	 * "binary" mode because otherwise fseek() would misbehave under DOS.	 */#if MSDOS || TOS	file_fp = fopen(name, "rb");#else	file_fp = fopen(name, "r");#endif	if (!file_fp)	{		perror(name);	}	/* reset the name & line number */	file_name = name;	file_lnum = 0L;	file_seek = 0L;	file_afternl = TRUE;	/* determine whether this is a header file */	file_header = FALSE;	name += strlen(name) - 2;	if (name >= file_name && name[0] == '.' && (name[1] == 'h' || name[1] == 'H'))	{		file_header = TRUE;	}}/* This function reads a single character from the stream.  If the *previous* * character was a newline, then it also increments file_lnum and sets * file_offset. */int file_getc(){	int	ch;	/* if there is an ungotten character, then return it.  Don't do any	 * other processing on it, though, because we already did that the	 * first time it was read.	 */	if (file_prevch)	{		ch = file_prevch;		file_prevch = 0;		return ch;	}	/* if previous character was a newline, then we're starting a line */	if (file_afternl)	{		file_afternl = FALSE;		file_seek = ftell(file_fp);		file_lnum++;	}	/* Get a character.  If no file is open, then return EOF */	ch = (file_fp ? getc(file_fp) : EOF);	/* if it is a newline, then remember that fact */	if (ch == '\n')	{		file_afternl = TRUE;	}	/* return the character */	return ch;}/* This function ungets a character from the current source file */void file_ungetc(ch)	int	ch;	/* character to be ungotten */{	file_prevch = ch;}/* This function copies the current line out some other fp.  It has no effect * on the file_getc() function.  During copying, any '\' characters are doubled * and a leading '^' or trailing '$' is also quoted.  The newline character is * not copied. * * This is meant to be used when generating a tag line. */void file_copyline(seek, fp)	long	seek;	/* where the lines starts in the source file */	FILE	*fp;	/* the output stream to copy it to */{	long	oldseek;/* where the file's pointer was before we messed it up */	char	ch;	/* a single character from the file */	char	next;	/* the next character from this file */	/* go to the start of the line */	oldseek = ftell(file_fp);	fseek(file_fp, seek, 0);	/* if first character is '^', then emit \^ */	ch = getc(file_fp);	if (ch == '^')	{		putc('\\', fp);		putc('^', fp);		ch = getc(file_fp);	}	/* write everything up to, but not including, the newline */	while (ch != '\n')	{		/* preread the next character from this file */		next = getc(file_fp);		/* if character is '\', or a terminal '$', then quote it */		if (ch == '\\' || (ch == '$' && next == '\n'))		{			putc('\\', fp);		}		putc(ch, fp);		/* next character... */		ch = next;	}	/* seek back to the old position */	fseek(file_fp, oldseek, 0);}/* -------------------------------------------------------------------------- *//* This section handles preprocessor directives.  It strips out all of the * directives, and may emit a tag for #define directives. */int	cpp_afternl;	/* boolean: look for '#' character? */int	cpp_prevch;	/* an ungotten character, if any */int	cpp_refsok;	/* boolean: can we echo characters out to "refs"? *//* This function opens the file & resets variables */void cpp_open(name)	char	*name;	/* name of source file to be opened */{	/* use the lower-level file_open function to open the file */	file_open(name);	/* reset variables */	cpp_afternl = TRUE;	cpp_refsok = TRUE;}/* This function copies a character from the source file to the "refs" file */void cpp_echo(ch)	int	ch; /* the character to copy */{	static	wasnl;	/* echo non-EOF chars, unless not making "ref", or echo turned off */	if (ch != EOF && make_refs && cpp_refsok && !file_header)	{		/* try to avoid blank lines */		if (ch == '\n')		{			if (wasnl)			{				return;			}			wasnl = TRUE;		}		else		{			wasnl = FALSE;		}		/* add the character */		putc(ch, refs);	}}/* This function returns the next character which isn't part of a directive */int cpp_getc(){	static	int	ch;	/* the next input character */	char	*scan;	/* if we have an ungotten character, then return it */	if (cpp_prevch)	{		ch = cpp_prevch;		cpp_prevch = 0;		return ch;	}	/* Get a character from the file.  Return it if not special '#' */	ch = file_getc();	if (ch == '\n')	{		cpp_afternl = TRUE;		cpp_echo(ch);		return ch;	}	else if (ch != '#' || !cpp_afternl)	{		/* normal character.  Any non-whitespace should turn off afternl */		if (ch != ' ' && ch != '\t')		{			cpp_afternl = FALSE;		}		cpp_echo(ch);		return ch;	}	/* Yikes!  We found a directive */	/* see whether this is a #define line */	scan = " define ";	while (*scan)	{		if (*scan == ' ')		{			/* space character matches any whitespace */			do			{				ch = file_getc();			} while (ch == ' ' || ch == '\t');			file_ungetc(ch);		}		else		{			/* other characters should match exactly */			ch = file_getc();			if (ch != *scan)			{				file_ungetc(ch);				break;			}		}		scan++;	}	/* is this a #define line?  and should we generate a tag for it? */	if (!*scan && (file_header || incl_static))	{		/* if not a header, then this will be a static tag */		if (!file_header)		{			fputs(file_name, tags);			putc(':', tags);		}		/* output the tag name */		for (ch = file_getc(); isalnum(ch) || ch == '_'; ch = file_getc())		{			putc(ch, tags);		}		/* output a tab, the filename, another tab, and the line number */		fprintf(tags, "\t%s\t%ld\n", file_name, file_lnum);	}	/* skip to the end of the directive -- a newline that isn't preceded	 * by a '\' character.	 */	while (ch != EOF && ch != '\n')	{		if (ch == '\\')		{			ch = file_getc();		}		ch = file_getc();	}	/* return the newline that we found at the end of the directive */	cpp_echo(ch);	return ch;}/* This puts a character back into the input queue for the source file */cpp_ungetc(ch)	int	ch;	/* a character to be ungotten */{	cpp_prevch = ch;}/* -------------------------------------------------------------------------- *//* This is the lexical analyser.  It gets characters from the preprocessor, * and gives tokens to the parser.  Some special codes are... *   (deleted)  /*...* /	(comments) *   (deleted)	//...\n	(comments) *   (deleted)	(*	(parens used in complex declaration) *   (deleted)	[...]	(array subscript, when ... contains no ]) *   (deleted)	struct	(intro to structure declaration) *   BODY	{...}	('{' can occur anywhere, '}' only at BOW if ... has '{') *   ARGS	(...{	(args of function, not extern or forward) *   ARGS	(...);	(args of an extern/forward function declaration) *   COMMA	,	(separate declarations that have same scope) *   SEMICOLON	;	(separate declarations that have different scope) *   SEMICOLON  =...;	(initializer) *   TYPEDEF	typedef	(the "typedef" keyword) *   STATIC	static	(the "static" keyword) *   STATIC	private	(the "static" keyword) *   STATIC	PRIVATE	(the "static" keyword) *   NAME	[a-z]+	(really any valid name that isn't reserved word) *//* #define EOF -1 */#define DELETED	  0#define BODY	  1#define ARGS	  2#define COMMA	  3#define SEMICOLON 4#define TYPEDEF   5#define STATIC	  6#define EXTERN	  7#define NAME	  8char	lex_name[BLKSIZE];	/* the name of a "NAME" token */long	lex_seek;		/* start of line that contains lex_name */lex_gettoken(){	int	ch;		/* a character from the preprocessor */	int	next;		/* the next character */	int	token;		/* the token that we'll return */	int	i;	/* loop until we get a token that isn't "DELETED" */	do	{		/* get the next character */		ch = cpp_getc();		/* process the character */		switch (ch)		{		  case ',':			token = COMMA;			break;		  case ';':			token = SEMICOLON;			break;		  case '/':			/* get the next character */			ch = cpp_getc();			switch (ch)			{			  case '*':	/* start of C comment */				ch = cpp_getc();				next = cpp_getc();				while (next != EOF && (ch != '*' || next != '/'))				{					ch = next;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -