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

📄 gtagsop.c

📁 代码检索工具GLOBAL源码。可用来浏览分析LINUX源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005 *	Tama Communications Corporation * * This file is part of GNU GLOBAL. * * GNU GLOBAL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GNU GLOBAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <assert.h>#include <ctype.h>#include <stdio.h>#ifdef STDC_HEADERS#include <stdlib.h>#include <stddef.h>#endif#ifdef HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "char.h"#include "conf.h"#include "gparam.h"#include "dbop.h"#include "die.h"#include "gtagsop.h"#include "locatestring.h"#include "makepath.h"#include "path.h"#include "gpathop.h"#include "split.h"#include "strbuf.h"#include "strlimcpy.h"#include "strmake.h"#define HASHBUCKETS	256static unsigned int hashpjw(const char *);static int compare_lno(const void *, const void *);static void gtop_flush_htab(GTOP *);static const char *unpack_pathindex(const char *);static const char *genrecord(GTOP *);static regex_t reg;/* * The concept of format version. * * Since GLOBAL's tag files are machine independent, they can be distributed * apart from GLOBAL itself. For example, if some network file system available, * client may execute global using server's tag files. In this case, both * GLOBAL are not necessarily the same version. So, we should assume that * older version of GLOBAL might access the tag files which generated * by new GLOBAL. To deal in such case, we decided to buried a version number * to both global(1) and tag files. The conclete procedure is like follows: * * 1. Gtags(1) bury the version number in tag files. * 2. Global(1) pick up the version number from a tag file. If the number *    is larger than its acceptable version number then global give up work *    any more and display error message. * 3. If version number is not found then it assumes version 1. * * [History of format version] * * GLOBAL-1.0 - 1.8	no idea about format version. * GLOBAL-1.9 - 2.24 	understand format version. *			support format version 1 (default). *			if (format version > 1) then print error message. * GLOBAL-3.0 - 4.5	support format version 1 and 2. *			if (format version > 2) then print error message. * GLOBAL-4.5.1 -	support format version 1, 2 and 3. *			if (format version > 3) then print error message. * format version 1 (default): *	original format. * format version 2 (gtags -c): *	compact format + pathindex format * format version 3 (gtags -cc): *	only pathindex format (undocumented) * * About GTAGS and GRTAGS, the default format is still version 1. * Since if version number is not found then it assumes version 1, we * don't bury format version in tag files currently. * * Since we know the format version 3 is better than 1 in all aspect, * the default format version will be changed into 3 in the future. */static int support_version = 3;	/* acceptable format version   */static const char *tagslist[] = {"GPATH", "GTAGS", "GRTAGS", "GSYMS"};/* * dbname: return db name * *	i)	db	0: GPATH, 1: GTAGS, 2: GRTAGS, 3: GSYMS *	r)		dbname */const char *dbname(db)	int db;{	assert(db >= 0 && db < GTAGLIM);	return tagslist[db];}/* * makecommand: make command line to make global tag file * *	i)	comline	skeleton command line *	i)	path_list	\0 separated list of path names *	o)	sb	command line * * command skeleton is like this: *	'gtags-parser -r %s' * following skeleton is allowed too. *	'gtags-parser -r' */voidmakecommand(comline, path_list, sb)	const char *comline;	STRBUF *path_list;	STRBUF *sb;{	const char *p = locatestring(comline, "%s", MATCH_FIRST);	const char *path, *end;	if (p) {		strbuf_nputs(sb, comline, p - comline);	} else {		strbuf_puts(sb, comline);		strbuf_putc(sb, ' ');	}	path = strbuf_value(path_list);	end = path + strbuf_getlen(path_list);	while (path < end) {		strbuf_puts(sb, path);		path += strlen(path) + 1;		if (path < end)			strbuf_putc(sb, ' ');	}	if (p)		strbuf_puts(sb, p + 2);}/* * formatcheck: check format of tag command's output * *	i)	line	input * * 0                 1  2              3 * ---------------------------------------------------- * func              83 ./func.c       func() */voidformatcheck(line)	const char *line;		/* virtually const */{	int n;	const char *p;	SPLIT ptable;	/*	 * Extract parts.	 */	n = split((char *)line, 4, &ptable);	/*	 * line number	 */	if (n < 4) {		recover(&ptable);		die("too small number of parts.\n'%s'", line);	}	for (p = ptable.part[1].start; *p; p++) {		if (!isdigit((unsigned char)*p)) {			recover(&ptable);			die("line number includes other than digit.\n'%s'", line);		}	}	/*	 * path name	 */	p = ptable.part[2].start;	if (!(*p == '.' && *(p + 1) == '/' && *(p + 2))) {		recover(&ptable);		die("path name must start with './'.\n'%s'", line);	}	recover(&ptable);}/* * gtags_open: open global tag. * *	i)	dbpath	dbpath directory *	i)	root	root directory (needed when compact format) *	i)	db	GTAGS, GRTAGS, GSYMS *	i)	mode	GTAGS_READ: read only *			GTAGS_CREATE: create tag *			GTAGS_MODIFY: modify tag *	i)	flags	GTAGS_COMPACT *			GTAGS_PATHINDEX *	r)		GTOP structure * * when error occurred, gtagopen doesn't return. * GTAGS_PATHINDEX needs GTAGS_COMPACT. */GTOP *gtags_open(dbpath, root, db, mode, flags)	const char *dbpath;	const char *root;	int db;	int mode;	int flags;{	GTOP *gtop;	int dbmode = 0;	if ((gtop = (GTOP *)calloc(sizeof(GTOP), 1)) == NULL)		die("short of memory.");	gtop->db = db;	gtop->mode = mode;	gtop->openflags = flags;	switch (gtop->mode) {	case GTAGS_READ:		dbmode = 0;		break;	case GTAGS_CREATE:		dbmode = 1;		break;	case GTAGS_MODIFY:		dbmode = 2;		break;	default:		assert(0);	}	/*	 * allow duplicate records.	 */	gtop->dbop = dbop_open(makepath(dbpath, dbname(db), NULL), dbmode, 0644, DBOP_DUP);	if (gtop->dbop == NULL) {		if (dbmode == 1)			die("cannot make %s.", dbname(db));		die("%s not found.", dbname(db));	}	/*	 * decide format version.	 */	gtop->format_version = 1;	gtop->format = GTAGS_STANDARD;	/*	 * This is a special case. GSYMS had compact format even if	 * format version 1.	 */	if (db == GSYMS)		gtop->format |= GTAGS_COMPACT;	if (gtop->mode == GTAGS_CREATE) {		if (flags & GTAGS_COMPACT) {			gtop->format |= GTAGS_COMPACT;			dbop_put(gtop->dbop, COMPACTKEY, COMPACTKEY);		}		if (flags & GTAGS_PATHINDEX) {			gtop->format |= GTAGS_PATHINDEX;			dbop_put(gtop->dbop, PATHINDEXKEY, PATHINDEXKEY);		}		if (gtop->format & (GTAGS_COMPACT|GTAGS_PATHINDEX)) {			char buf[80];			if (gtop->format == GTAGS_PATHINDEX)				gtop->format_version = 3;			else				gtop->format_version = 2;			snprintf(buf, sizeof(buf),				"%s %d", VERSIONKEY, gtop->format_version);			dbop_put(gtop->dbop, VERSIONKEY, buf);		}	} else {		/*		 * recognize format version of GTAGS. 'format version record'		 * is saved as a META record in GTAGS and GRTAGS.		 * if 'format version record' is not found, it's assumed		 * version 1.		 */		const char *p;		if ((p = dbop_get(gtop->dbop, VERSIONKEY)) != NULL) {			for (p += strlen(VERSIONKEY); *p && isspace((unsigned char)*p); p++)				;			gtop->format_version = atoi(p);		}		if (gtop->format_version > support_version)			die("GTAGS seems new format. Please install the latest GLOBAL.");		if (gtop->format_version > 1) {			if (dbop_get(gtop->dbop, COMPACTKEY) != NULL)				gtop->format |= GTAGS_COMPACT;			if (dbop_get(gtop->dbop, PATHINDEXKEY) != NULL)				gtop->format |= GTAGS_PATHINDEX;		}	}	if (gtop->format & GTAGS_PATHINDEX || gtop->mode != GTAGS_READ) {		if (gpath_open(dbpath, dbmode) < 0) {			if (dbmode == 1)				die("cannot create GPATH.");			else				die("GPATH not found.");		}	}	/*	 * Stuff for compact format.	 */	if (gtop->format & GTAGS_COMPACT) {		assert(root != NULL);		strlimcpy(gtop->root, root, sizeof(gtop->root));		if (gtop->mode == GTAGS_READ)			gtop->ib = strbuf_open(MAXBUFLEN);		else {			gtop->sb = strbuf_open(0);			gtop->htab = calloc(sizeof(struct gtop_compact_entry *), HASHBUCKETS);			if (gtop->htab == NULL)				die("short of memory.");		}	} else if (gtop->format == GTAGS_PATHINDEX && gtop->mode != GTAGS_READ)		gtop->sb = strbuf_open(0);	return gtop;}/* * gtags_put: put tag record with packing. * *	i)	gtop	descripter of GTOP *	i)	tag	tag name *	i)	record	ctags -x image * * NOTE: If format is GTAGS_COMPACT or GTAGS_PATHINDEX *       then this function is destructive. */voidgtags_put(gtop, tag, record)	GTOP *gtop;	const char *tag;	const char *record;		/* virtually const */{	const char *line, *path;	SPLIT ptable;	struct gtop_compact_entry *entry, **prev;	int *lno;	if (gtop->format == GTAGS_STANDARD) {		/* entab(record); */		dbop_put(gtop->dbop, tag, record);		return;	}	if (gtop->format == GTAGS_PATHINDEX) {		char *p = locatestring(record, "./", MATCH_FIRST);		const char *fid;		int savec;		if (p == NULL)			die("path name not found.");		path = p;		p += 2;		while (*p && !isspace((unsigned char)*p))			p++;		savec = *p;		*p = '\0';		fid = gpath_path2fid(path);		if (fid == NULL)			die("GPATH is corrupted.('%s' not found)", path);		*p = savec;		strbuf_reset(gtop->sb);		strbuf_nputs(gtop->sb, record, path - record);		strbuf_puts(gtop->sb, fid);		strbuf_puts(gtop->sb, p);		dbop_put(gtop->dbop, tag, strbuf_value(gtop->sb));		return;	}	/*	 * gtop->format & GTAGS_COMPACT	 */	if (split((char *)record, 4, &ptable) != 4) {		recover(&ptable);		die("illegal tag format.\n'%s'", record);	}	line = ptable.part[1].start;	path = ptable.part[2].start;	/*	 * Register each record into the hash table.	 * Duplicated records will be combined.	 */	if (gtop->prev_path[0] && strcmp(gtop->prev_path, path))		gtop_flush_htab(gtop);	strlimcpy(gtop->prev_path, path, sizeof(gtop->prev_path));	for (prev = gtop->htab + hashpjw(record) % HASHBUCKETS;	     (entry = *prev) != NULL;	     prev = &entry->next) {		if (strcmp(entry->tag, record) == 0)			break;	}	if (entry == NULL) {		entry = malloc(offsetof(struct gtop_compact_entry, tag) + strlen(record) + 1);		if (entry == NULL)			die("short of memory.");		entry->next = NULL;		entry->vb = varray_open(sizeof(int), 100);		strcpy(entry->tag, record);		*prev = entry;	}	lno = varray_append(entry->vb);	*lno = atoi(line);	recover(&ptable);}/* * hashpjw: calculate hash value for given string. * *	i)	string *	r)	hash value */static unsigned inthashpjw(s)	const char *s;{	unsigned int h, g;	h = strlen(s);	while (*s != '\0') {		h <<= 4;		h += (unsigned char)*s++;		g = h & 0xf0000000;		if (g != 0)			h = h ^ (g >> 24) ^ g;	}	return h;}/* * compare_lno: compare function for sorting line number. */static intcompare_lno(s1, s2)	const void *s1;	const void *s2;{	return *(const int *)s1 - *(const int *)s2;}/* * gtop_flush_htab: register each record into the tag database and delete from the hash table. * *	i)	gtop	descripter of GTOP */

⌨️ 快捷键说明

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