Пример #1
0
/*
 * for debugging.
 */
void
abbrev_dump(void)
{
	struct abbrmap *ab;
	int i, limit = sizeof(ab2name) / sizeof(struct abbrmap);

	if (!name2ab) {
		fprintf(stderr, "name2ab is NULL.\n");
		return;
	}
	fprintf(stderr, "ab2name: %d entries\n", limit);
	for (i = 0; i < limit; i++) {
		if (ab2name[i].c != 0) {
			fprintf(stderr, "ab2name[%d].c    = %c\n", i, ab2name[i].c);
			fprintf(stderr, "ab2name[%d].name = %s\n", i, ab2name[i].name);
		}
	}
	ab = (struct abbrmap *)varray_assign(name2ab, 0, 0);
	limit = name2ab->length;
	fprintf(stderr, "name2ab: %d entries\n", limit);
	for (i = 0; i < limit; i++) {
		if (ab[i].c != 0) {
			fprintf(stderr, "name2ab[%d].c    = %c\n", i, ab[i].c);
			fprintf(stderr, "name2ab[%d].name = %s\n", i, ab[i].name);
		}
	}
}
Пример #2
0
/*
 * find_open: start iterator without GPATH.
 *
 *	i)	start	start directory
 *			If NULL, assumed '.' directory.
 */
void
find_open(const char *start)
{
	struct stack_entry *curp;
	assert(find_mode == 0);
	find_mode = FIND_OPEN;

	/*
	 * This is temporary measures. It doesn't decide how to become final.
	 */
	if (getenv("GTAGSALLOWBLANK"))
		allow_blank = 1;
	if (!start)
		start = "./";
	/*
	 * setup stack.
	 */
	stack = varray_open(sizeof(struct stack_entry), 50);
	current_entry = 0;
	curp = varray_assign(stack, current_entry, 1);
	strlimcpy(dir, start, sizeof(dir));
	curp->dirp = dir + strlen(dir);
	curp->sb = strbuf_open(0);
	if (getdirs(dir, curp->sb) < 0)
		die("cannot open '.' directory.");
	curp->start = curp->p = strbuf_value(curp->sb);
	curp->end   = curp->start + strbuf_getlen(curp->sb);

	/*
	 * prepare regular expressions.
	 */
	prepare_source();
	prepare_skip();
}
Пример #3
0
/**
 * Read a tag segment with sorting.
 *
 *	@param[in]	gtop	#GTOP structure <br>
 *		Output:	@CODE{gtop->gtp_array}		segment table <br>
 *		Output:	@CODE{gtop->gtp_count}		segment table size <br>
 *		Output:	@CODE{gtop->gtp_index}		segment table index (initial value = 0) <br>
 *		Output:	@CODE{gtop->cur_tagname}	current tag name
 *
 * A segment is a set of tag records which have same tag name. <br>
 * This function read a segment from tag file, sort it and put it on segment table. <br>
 * This function can treat both of standard format and compact format.
 *
 * Sorting is done by three keys.
 *	- 1st key: tag name
 *	- 2nd key: file name
 *	- 3rd key: line number
 *
 * Since all records in a segment have same tag name, you need not think about 1st key.
 */
void
segment_read(GTOP *gtop)
{
	const char *tagline, *fid, *path, *lineno;
	GTP *gtp;
	struct sh_entry *sh;

	/*
	 * Save tag lines.
	 */
	gtop->cur_tagname[0] = '\0';
	while ((tagline = dbop_next(gtop->dbop)) != NULL) {
		VIRTUAL_GRTAGS_GSYMS_PROCESSING(gtop);
		/*
		 * get tag name and line number.
		 *
		 * tagline = <file id> <tag name> <line number>
		 */
		if (gtop->cur_tagname[0] == '\0') {
			strlimcpy(gtop->cur_tagname, gtop->dbop->lastkey, sizeof(gtop->cur_tagname));
		} else if (strcmp(gtop->cur_tagname, gtop->dbop->lastkey) != 0) {
			/*
			 * Dbop_next() wil read the same record again.
			 */
			dbop_unread(gtop->dbop);
			break;
		}
		gtp = varray_append(gtop->vb);
		gtp->tagline = pool_strdup(gtop->segment_pool, tagline, 0);
		gtp->tag = (const char *)gtop->cur_tagname;
		/*
		 * convert fid into hashed path name to save memory.
		 */
		fid = (const char *)strmake(tagline, " ");
		path = gpath_fid2path(fid, NULL);
		if (path == NULL)
			die("gtags_first: path not found. (fid=%s)", fid);
		sh = strhash_assign(gtop->path_hash, path, 1);
		gtp->path = sh->name;
		lineno = seekto(gtp->tagline, SEEKTO_LINENO);
		if (lineno == NULL)
			die("illegal tag record.\n%s", tagline);
		gtp->lineno = atoi(lineno);
	}
	/*
	 * Sort tag lines.
	 */
	gtop->gtp_array = varray_assign(gtop->vb, 0, 0);
	gtop->gtp_count = gtop->vb->length;
	gtop->gtp_index = 0;
	if (!(gtop->flags & GTOP_NOSORT))
		qsort(gtop->gtp_array, gtop->gtp_count, sizeof(GTP), compare_tags);
}
Пример #4
0
/**
 * gfind_open: start iterator using GPATH.
 *
 *	@param[in]	dbpath  dbpath
 *	@param[in]	local   local prefix,
 *			if NULL specified, it assumes "./";
 *	@param[in]      target  GPATH_SOURCE: only source file,
 *			GPATH_OTHER: only other file,
 *			GPATH_BOTH: source file + other file
 *	@param[in]	flags	GPATH_NEARSORT
 *	@return		GFIND structure
 */
GFIND *
gfind_open(const char *dbpath, const char *local, int target, int flags)
{
	GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1);

	gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0);
	if (gfind->dbop == NULL)
		die("GPATH not found.");
	gfind->path = NULL;
	gfind->prefix = check_strdup(local ? local : "./");
	gfind->first = 1;
	gfind->eod = 0;
	gfind->target = target;
	gfind->type = GPATH_SOURCE;
	gfind->flags = flags;
	gfind->path_array = NULL;
	gfind->version = dbop_getversion(gfind->dbop);
	if (gfind->version > support_version)
		die("GPATH seems new format. Please install the latest GLOBAL.");
	else if (gfind->version < support_version)
		die("GPATH seems older format. Please remake tag files."); 
	/*
	 * Nearness sort.
	 * In fact, this timing of sort is not good for performance.
	 * Reconsideration is needed later.
	 */
	if (gfind->flags & GPATH_NEARSORT) {
		const char *path = NULL;
		VARRAY *varray = varray_open(sizeof(char *), 100);
		POOL *pool = pool_open();
		while ((path = gfind_read(gfind)) != NULL) {
			char **a = varray_append(varray);
			*a = pool_strdup(pool, path, 0);
		}
		if ((nearbase = get_nearbase_path()) == NULL)
			die("cannot get nearbase path.");
		qsort(varray_assign(varray, 0, 0), varray->length, sizeof(char *), compare_nearpath);
		gfind->path_array = varray;
		gfind->pool = pool;
		gfind->index = 0;
	}
	return gfind;
}
Пример #5
0
/**
 * gfind_read: read path using GPATH.
 *
 *	@param[in]	gfind	GFIND structure
 *	@return		path
 */
const char *
gfind_read(GFIND *gfind)
{
	const char *flag;

	if (gfind->path_array) {
		char **a = NULL;
		if (gfind->index >= gfind->path_array->length)
			return NULL;
		a = varray_assign(gfind->path_array, gfind->index++, 0);
		return *a;
	}
	gfind->type = GPATH_SOURCE;
	if (gfind->eod)
		return NULL;
	for (;;) {
		if (gfind->first) {
			gfind->first = 0;
			gfind->path = dbop_first(gfind->dbop, gfind->prefix, NULL, DBOP_KEY | DBOP_PREFIX);
		} else {
			gfind->path = dbop_next(gfind->dbop);
		}
		if (gfind->path == NULL) {
			gfind->eod = 1;
			break;
		}
		/*
		 * if gfind->target == 0, return only source files.
		 * *flag == 'o' means 'other files' like README.
		 */
		flag = dbop_getflag(gfind->dbop);
		if (flag == NULL)
			flag = "";
		gfind->type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
		if (gfind->type & gfind->target)
			break;
	}
	return gfind->path;
}
Пример #6
0
/**
 * anchor_load: load anchor table
 *
 *	@param[in]	path	path name
 */
void
anchor_load(const char *path)
{
	int db, current_fid;

	/* Get fid of the path */
	{
		const char *p = path2fid(path);
		if (p == NULL)
			die("anchor_load: internal error. file '%s' not found in GPATH.", path);
		current_fid = atoi(p);
	}
	FIRST = LAST = 0;
	end = CURRENT = NULL;

	if (vb == NULL)
		vb = varray_open(sizeof(struct anchor), 1000);
	else
		varray_reset(vb);

	for (db = GTAGS; db < GTAGLIM; db++) {
		XARGS *xp;
		char *ctags_xid;

		if ((xp = anchor_input[db]) == NULL)
			continue;
		/*
		 * Read from input stream until it reaches end of file
		 * or the line of another file appears.
		 */
		while ((ctags_xid = xargs_read(xp)) != NULL) {
			SPLIT ptable;
			struct anchor *a;
			int type, fid;
			const char *ctags_x = parse_xid(ctags_xid, NULL, &fid);

			/*
			 * It is the following file.
			 */
			if (current_fid != fid) {
				xargs_unread(xp);
				break;
			}
			if (split(ctags_x, 4, &ptable) < 4) {
				recover(&ptable);
				die("too small number of parts in anchor_load().\n'%s'", ctags_x);
			}
			if (db == GTAGS) {
				char *p = ptable.part[PART_LINE].start;

				for (; *p && isspace((unsigned char)*p); p++)
					;
				if (!*p) {
					recover(&ptable);
					die("The output of parser is illegal.\n%s", ctags_x);
				}
				/*
				 * Function header is applied only to the anchor whoes type is 'D'.
				 * (D: function, M: macro, T: type)
				 */
				type = 'T';
				if (*p == '#')
					type = 'M';
				else if (locatestring(p, "typedef", MATCH_AT_FIRST))
					type = 'T';
				else if ((p = locatestring(p, ptable.part[PART_TAG].start, MATCH_FIRST)) != NULL) {
					/* skip a tag and the following blanks */
					p += strlen(ptable.part[PART_TAG].start);
					for (; *p && isspace((unsigned char)*p); p++)
						;
					if (*p == '(')
						type = 'D';
				}
			}  else if (db == GRTAGS)
				type = 'R';
			else
				type = 'Y';
			/* allocate an entry */
			a = varray_append(vb);
			a->lineno = atoi(ptable.part[PART_LNO].start);
			a->type = type;
			a->done = 0;
			settag(a, ptable.part[PART_TAG].start);
			recover(&ptable);
		}
		if (ctags_xid == NULL) {
			xargs_close(anchor_input[db]);
			anchor_input[db] = NULL;
		}
	}
	if (vb->length == 0) {
		table = NULL;
	} else {
		int i, used = vb->length;
		/*
		 * Sort by lineno.
		 */
		table = varray_assign(vb, 0, 0);
		qsort(table, used, sizeof(struct anchor), cmp); 
		/*
		 * Setup some lineno.
		 */
		for (i = 0; i < used; i++)
			if (table[i].type == 'D')
				break;
		if (i < used)
			FIRST = table[i].lineno;
		for (i = used - 1; i >= 0; i--)
			if (table[i].type == 'D')
				break;
		if (i >= 0)
			LAST = table[i].lineno;
	}
	/*
	 * Setup loop range.
	 */
	start = table;
	curp = NULL;
	end = &table[vb->length];
	/* anchor_dump(stderr, 0);*/
}
Пример #7
0
/**
 * flush_pool: flush the pool and write is as compact format.
 *
 *	@param[in]	gtop	descripter of #GTOP
 *	@param[in]	s_fid
 */
static void
flush_pool(GTOP *gtop, const char *s_fid)
{
	struct sh_entry *entry;
	int header_offset;
	int i, last;

	if (s_fid == NULL && (s_fid = gpath_path2fid(gtop->cur_path, NULL)) == NULL)
		die("GPATH is corrupted.('%s' not found)", gtop->cur_path);
	/*
	 * Write records as compact format and free line number table
	 * for each entry in the pool.
	 */
	for (entry = strhash_first(gtop->path_hash); entry; entry = strhash_next(gtop->path_hash)) {
		VARRAY *vb = (VARRAY *)entry->value;
		int *lno_array = varray_assign(vb, 0, 0);
		const char *key = entry->name;

		/*
		 * extract method when class method definition.
		 *
		 * Ex: Class::method(...)
		 *
		 * key	= 'method'
		 * data = 'Class::method  103 ./class.cpp ...'
		 */
		if (gtop->flags & GTAGS_EXTRACTMETHOD) {
			if ((key = locatestring(entry->name, ".", MATCH_LAST)) != NULL)
				key++;
			else if ((key = locatestring(entry->name, "::", MATCH_LAST)) != NULL)
				key += 2;
			else
				key = entry->name;
		}
		/* Sort line number table */
		qsort(lno_array, vb->length, sizeof(int), compare_lineno); 

		strbuf_reset(gtop->sb);
		strbuf_puts(gtop->sb, s_fid);
		strbuf_putc(gtop->sb, ' ');
		if (gtop->format & GTAGS_COMPNAME) {
			strbuf_puts(gtop->sb, compress(entry->name, key));
		} else {
			strbuf_puts(gtop->sb, entry->name);
		}
		strbuf_putc(gtop->sb, ' ');
		header_offset = strbuf_getlen(gtop->sb);
		/*
		 * If GTAGS_COMPLINE flag is set, each line number is expressed as the
		 * difference from the previous line number except for the head.
		 * GTAGS_COMPLINE is set by default in format version 5.
		 */
		if (gtop->format & GTAGS_COMPLINE) {
			int cont = 0;

			last = 0;			/* line 0 doesn't exist */
			for (i = 0; i < vb->length; i++) {
				int n = lno_array[i];

				if (n == last)
					continue;
				if (last > 0 && n == last + 1) {
					if (!cont) {
						/*
						 * Don't use range expression at the head.
						 */
						if (strbuf_getlen(gtop->sb) == header_offset)
							strbuf_putn(gtop->sb, n);
						else
							cont = last;
					}
				} else {
					/*
					 * Range expression. ex: 10-2 means 10 11 12
					 */
					if (cont) {
						strbuf_putc(gtop->sb, '-');
						strbuf_putn(gtop->sb, last - cont);
						cont = 0;
					}
					if (strbuf_getlen(gtop->sb) > header_offset) {
						strbuf_putc(gtop->sb, ',');
						strbuf_putn(gtop->sb, n - last);
					} else {
						strbuf_putn(gtop->sb, n);
					}
					if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) {
						dbop_put(gtop->dbop, key, strbuf_value(gtop->sb));
						strbuf_setlen(gtop->sb, header_offset);
					}
				}
				last = n;
			}
			if (cont) {
				strbuf_putc(gtop->sb, '-');
				strbuf_putn(gtop->sb, last - cont);
			}
		} else {
			/*
			 * This code is to support older format (version 4).
			 */
			last = 0;			/* line 0 doesn't exist */
			for (i = 0; i < vb->length; i++) {
				int n = lno_array[i];

				if (n == last)
					continue;
				if (strbuf_getlen(gtop->sb) > header_offset)
					strbuf_putc(gtop->sb, ',');
				strbuf_putn(gtop->sb, n);
				if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) {
					dbop_put(gtop->dbop, key, strbuf_value(gtop->sb));
					strbuf_setlen(gtop->sb, header_offset);
				}
				last = n;
			}
		}
		if (strbuf_getlen(gtop->sb) > header_offset) {
			dbop_put(gtop->dbop, key, strbuf_value(gtop->sb));
		}
		/* Free line number table */
		varray_close(vb);
	}
}
Пример #8
0
/*
 * compress source line.
 *
 *	i)	in	source line
 *	i)	name	replaced string
 *	r)		compressed string
 */
char *
compress(const char *in, const char *name)
{
	STATIC_STRBUF(sb);
	const char *p = in;
	int length = strlen(name);
	int spaces = 0;

	strbuf_clear(sb);
	while (*p) {
		if (*p == ' ') {
			spaces++;
			p++;
			continue;
		}
		if (spaces > 0) {
			if (spaces >= 10) {
				strbuf_putc(sb, '@');
				strbuf_putc(sb, '{');
				strbuf_putn(sb, spaces);
				strbuf_putc(sb, '}');
			} else if (spaces > 3) {
				strbuf_putc(sb, '@');
				strbuf_putn(sb, spaces);
			} else {
				strbuf_nputc(sb, ' ', spaces);
			}
		}
		spaces = 0;
		if (*p == '@') {
			strbuf_puts(sb, "@@");
			p++;
		} else if (!strncmp(p, name, length)) {
			strbuf_puts(sb, "@n");
			p += length;
		} else if (name2ab) {
			int i, limit = name2ab->length;
			struct abbrmap *ab = (struct abbrmap *)varray_assign(name2ab, 0, 0);

			for (i = 0; i < limit; i++) {
				if (!strncmp(p, ab[i].name, ab[i].length)) {
					strbuf_putc(sb, '@');
					strbuf_putc(sb, ab[i].c);
					p += ab[i].length;
					break;
				}
			}
			if (i >= limit) {
				strbuf_putc(sb, *p);
				p++;
			}
		} else {
			strbuf_putc(sb, *p);
			p++;
		}
	}
	if (spaces > 0) {
		if (spaces < 4) {
			strbuf_nputc(sb, ' ', spaces);
		} else if (spaces < 10) {
			strbuf_putc(sb, '@');
			strbuf_putn(sb, spaces);
		} else {
			strbuf_putc(sb, '@');
			strbuf_putc(sb, '{');
			strbuf_putn(sb, spaces);
			strbuf_putc(sb, '}');
		}
	}
	return strbuf_value(sb);
}
Пример #9
0
/*
 * find_read_traverse: read path without GPATH.
 *
 *	r)		path
 */
char *
find_read_traverse(void)
{
	static char val[MAXPATHLEN];
	char path[MAXPATHLEN];
	struct stack_entry *curp = varray_assign(stack, current_entry, 1);

	for (;;) {
		while (curp->p < curp->end) {
			char type = *(curp->p);
			const char *unit = curp->p + 1;

			curp->p += strlen(curp->p) + 1;

			/*
			 * Skip files described in the skip list.
			 */
				/* makepath() returns unsafe module local area. */
			strlimcpy(path, makepath(dir, unit, NULL), sizeof(path));
			if (type == 'd')
				strcat(path, "/");
			if (skipthisfile(path))
				continue;
			if (type == 'f') {
				/*
				 * Skip the following:
				 * o directory
				 * o file which does not exist
				 * o dead symbolic link
				 */
				if (!test("f", path)) {
					if (test("d", path))
						warning("'%s' is a directory. (Ignored)", path);
					else
						warning("'%s' not found. (Ignored)", path);
					continue;
				}
				/*
				 * GLOBAL cannot treat path which includes blanks.
				 * It will be improved in the future.
				 */
				if (!allow_blank && locatestring(path, " ", MATCH_FIRST)) {
					warning("'%s' ignored, because it includes blank.", &path[2]);
					continue;
				}
				/*
				 * A blank at the head of path means
				 * other than source file.
				 */
				if (regexec(suff, path, 0, 0, 0) == 0) {
					/* source file */
					strlimcpy(val, path, sizeof(val));
				} else {
					/* other file like 'Makefile' */
					val[0] = ' ';
					strlimcpy(&val[1], path, sizeof(val) - 1);
				}
				val[sizeof(val) - 1] = '\0';
				return val;
			}
			if (type == 'd') {
				STRBUF *sb = strbuf_open(0);
				char *dirp = curp->dirp;

				strcat(dirp, unit);
				strcat(dirp, "/");
				if (getdirs(dir, sb) < 0) {
					warning("cannot open directory '%s'. (Ignored)", dir);
					strbuf_close(sb);
					*(curp->dirp) = 0;
					continue;
				}
				/*
				 * Push stack.
				 */
				curp = varray_assign(stack, ++current_entry, 1);
				curp->dirp = dirp + strlen(dirp);
				curp->sb = sb;
				curp->start = curp->p = strbuf_value(sb);
				curp->end   = curp->start + strbuf_getlen(sb);
			}
		}
		strbuf_close(curp->sb);
		curp->sb = NULL;
		if (current_entry == 0)
			break;
		/*
		 * Pop stack.
		 */
		curp = varray_assign(stack, --current_entry, 0);
		*(curp->dirp) = 0;
	}
	find_eof = 1;
	return NULL;
}
Пример #10
0
/**
 * varray_append: append varray entry.
 *
 *	@param[in]	vb	#VARRAY structure
 *	@return		pointer of the entry
 *
 * This procedure @EMPH{doesn't} operate the contents of the array.
 */
void *
varray_append(VARRAY *vb)
{
	return varray_assign(vb, vb->length, 1);
}