Esempio n. 1
0
static void
load_notfunction(const char *filename)
{
	FILE *ip;
	STRBUF *sb = strbuf_open(0);
	STRBUF *ib = strbuf_open(0);
	char *p;
	int i;

	if ((ip = fopen(filename, "r")) == NULL)
		die("'%s' cannot read.", filename);
	for (tablesize = 0; (p = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL; tablesize++)
		strbuf_puts0(sb, p);
	fclose(ip);
	words = (struct words *)check_malloc(sizeof(struct words) * tablesize);
	/*
	 * Don't free *p.
	 */
	p = (char *)check_malloc(strbuf_getlen(sb) + 1);
	memcpy(p, strbuf_value(sb), strbuf_getlen(sb) + 1);
	for (i = 0; i < tablesize; i++) {
		words[i].name = p;
		p += strlen(p) + 1;
	}
	qsort(words, tablesize, sizeof(struct words), cmp);
	strbuf_close(sb);
	strbuf_close(ib);
}
Esempio n. 2
0
/*
 * getdefinitionURL: get URL includes specified definition.
 *
 *	i)	arg	definition name
 *	i)	htmldir HTML directory
 *	o)	URL	URL begin with 'file:'
 */
void
getdefinitionURL(const char *arg, const char *htmldir, STRBUF *URL)
{
	FILE *fp;
	char *p;
	SPLIT ptable;
	int status = -1;
	STRBUF *sb = strbuf_open(0);
	const char *path = makepath(htmldir, "MAP", NULL);

	if (!test("f", path))
		die("'%s' not found. Please invoke htags(1) with the --map-file option.", path);
	fp = fopen(path, "r");
	if (!fp)
		die("cannot open '%s'.", path);
	while ((p = strbuf_fgets(sb, fp, STRBUF_NOCRLF)) != NULL) {
		if (split(p, 2, &ptable) != 2)
			die("illegal format.");
		if (!strcmp(arg, ptable.part[0].start)) {
			status = 0;
			break;
		}
	}
	fclose(fp);
	if (status == -1)
		die("definition %s not found.", arg);
	strbuf_reset(URL);
	/*
	 * convert path into URL.
	 */
	makefileurl(makepath(htmldir, ptable.part[1].start, NULL), 0, URL);
	recover(&ptable);
	strbuf_close(sb);
}
Esempio n. 3
0
void
setenv_from_config(void)
{
	int i, lim = sizeof(envname) / sizeof(char *);
	STRBUF *sb = strbuf_open(0);

	for (i = 0; i < lim; i++) {
		if (getenv(envname[i]) == NULL) {
			strbuf_reset(sb);
			if (getconfs(envname[i], sb))
				set_env(envname[i], strbuf_value(sb));
			else if (getconfb(envname[i]))
				set_env(envname[i], "");
		}
	}
	/*
	 * For upper compatibility.
	 * htags_options is deprecated.
	 */
	if (getenv("HTAGS_OPTIONS") == NULL) {
		strbuf_reset(sb);
		if (getconfs("htags_options", sb))
			set_env("HTAGS_OPTIONS", strbuf_value(sb));
	}
	strbuf_close(sb);
}
Esempio n. 4
0
File: path.c Progetto: vmx/global
/**
 * makedirectories: make directories on the path like @XREF{mkdir,1} with the @OPTION{-p} option.
 *
 *	@param[in]	base	base directory
 *	@param[in]	rest	path from the base
 *	@param[in]	verbose 1: verbose mode, 0: not verbose mode
 *	@return		0: success <br>
 *			-1: base directory not found <br>
 *			-2: permission error <br>
 *			-3: cannot make directory
 */
int
makedirectories(const char *base, const char *rest, int verbose)
{
	STRBUF *sb;
	const char *p, *q;

	if (!test("d", base))
		return -1;
	if (!test("drw", base))
		return -2;
	sb = strbuf_open(0);
	strbuf_puts(sb, base);
	if (*rest == SEP)
		rest++;
	for (q = rest; *q;) {
		p = q;
		while (*q && *q != SEP)
			q++;
		strbuf_putc(sb, SEP);
		strbuf_nputs(sb, p, q - p);
		p = strbuf_value(sb);
		if (!test("d", p)) {
			if (verbose)
				fprintf(stderr, " Making directory '%s'.\n", p);
			if (mkdir(p, 0775) < 0) {
				strbuf_close(sb);
				return -3;
			}
		}
		if (*q == SEP)
			q++;
	}
	strbuf_close(sb);
	return 0;
}
Esempio n. 5
0
File: find.c Progetto: kosaki/gtags
/*
 * 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();
}
Esempio n. 6
0
FILE *rbm_fopen(const char *filename, const char *mode)
{
    STRBUF *sb;
    STRBUF *id = ht_getvoid(strbufv, filename, NULL, NULL);

    /* Only the "w" mode is currently supported */
    if (strcmp(mode, "w") == 0) {
        // Rprintf("rbm_fopen: opening file to write: %s\n", filename);
        sb = strbuf_create_empty(STRBUF_LEN);
        if (id != NULL) {
            Rprintf("rbm_fopen: warning: destroying previous STRBUF: %s\n", filename);
            strbuf_destroy(id);
        }
        ht_setvoid(strbufv, filename, sb);
    } else {
        // Rprintf("rbm_fopen: opening file to read: %s\n", filename);
        sb = id;
        if (sb != NULL) {
            if (sb->open) {
                Rprintf("rbm_fopen: error: file already open: %s\n", filename);
                sb = NULL;  // XXX Is this right?
            } else {
                strbuf_open(sb);
                strbuf_rewind(sb);
            }
        } else {
            // Rprintf("rbm_fopen: no such file: %s\n", filename);
            sb = NULL;
        }
    }

    return (FILE *) sb;
}
Esempio n. 7
0
/*
 * convert_open: open convert filter
 *
 *	i)	type	PATH_ABSOLUTE, PATH_RELATIVE, PATH_THROUGH
 *	i)	format	tag record format
 *	i)	root	root directory of source tree
 *	i)	cwd	current directory
 *	i)	dbpath	dbpath directory
 *	i)	op	output file
 */
CONVERT *
convert_open(int type, int format, const char *root, const char *cwd, const char *dbpath, FILE *op)
{
	CONVERT *cv = (CONVERT *)check_calloc(sizeof(CONVERT), 1);
	/*
	 * set base directory.
	 */
	cv->abspath = strbuf_open(MAXPATHLEN);
	strbuf_puts(cv->abspath, root);
	strbuf_unputc(cv->abspath, '/');
	cv->start_point = strbuf_getlen(cv->abspath);
	/*
	 * copy elements.
	 */
	if (strlen(cwd) > MAXPATHLEN)
		die("current directory name too long.");
	strlimcpy(cv->basedir, cwd, sizeof(cv->basedir));
	cv->type = type;
	cv->format = format;
	cv->op = op;
	/*
	 * open GPATH.
	 */
	if (gpath_open(dbpath, 0) < 0)
		die("GPATH not found.");
	return cv;
}
Esempio n. 8
0
/**
 * gtags_delete: delete records belong to set of fid.
 *
 *	@param[in]	gtop	#GTOP structure
 *	@param[in]	deleteset bit array of fid
 */
void
gtags_delete(GTOP *gtop, IDSET *deleteset)
{
	const char *tagline;
	int fid;
	long id;

#ifdef USE_SQLITE3
	if (gtop->dbop->openflags & DBOP_SQLITE3) {
		STRBUF *where = strbuf_open(0);
		strbuf_puts(where, "(");
		for (id = idset_first(deleteset); id != END_OF_ID; id = idset_next(deleteset)) {
			strbuf_puts(where, "'");
			strbuf_putn(where, id);
			strbuf_puts(where, "',");
		}
		strbuf_unputc(where, ',');
		strbuf_puts(where, ")");
		dbop_delete(gtop->dbop, strbuf_value(where));
		strbuf_close(where);
	} else
#endif
	for (tagline = dbop_first(gtop->dbop, NULL, NULL, 0); tagline; tagline = dbop_next(gtop->dbop)) {
		/*
		 * Extract path from the tag line.
		 */
		fid = atoi(tagline);
		/*
		 * If the file id exists in the deleteset, delete the tagline.
		 */
		if (idset_contains(deleteset, fid))
			dbop_delete(gtop->dbop, NULL);
	}
}
Esempio n. 9
0
/**
 * load configuration variables.
 */
static void
configuration(void)
{
	STRBUF *sb = strbuf_open(0);

	/*
	 * Config variables.
	 */
	strbuf_reset(sb);
	if (!getconfs("datadir", sb))
		die("cannot get datadir directory name.");
	strlimcpy(datadir, strbuf_value(sb), sizeof(datadir));
	strbuf_reset(sb);
	if (!getconfs("localstatedir", sb))
		die("cannot get localstatedir directory name.");
	strlimcpy(localstatedir, strbuf_value(sb), sizeof(localstatedir));
	strbuf_reset(sb);
	if (getconfs("prolog_script", sb))
		prolog_script = check_strdup(strbuf_value(sb));
	strbuf_reset(sb);
	if (getconfs("epilog_script", sb))
		epilog_script = check_strdup(strbuf_value(sb));
	if (getconfb("colorize_warned_line"))
		colorize_warned_line = 1;
	strbuf_reset(sb);
	if (getconfs("include_file_suffixes", sb))
		include_file_suffixes = check_strdup(strbuf_value(sb));
	strbuf_reset(sb);
	if (getconfs("langmap", sb))
		langmap = check_strdup(strbuf_value(sb));
	strbuf_close(sb);
}
Esempio n. 10
0
/*
 * load_alias: load alias value.
 *
 * [$HOME/.gozillarc]
 * +-----------------------
 * |a:http://www.gnu.org
 * |f = file:/usr/share/xxx.html
 * |www	http://www.xxx.yyy/
 */
static void
load_alias(void)
{
	FILE *ip;
	STRBUF *sb = strbuf_open(0);
	char *p;
	int flag = STRBUF_NOCRLF;
	struct sh_entry *ent;

	sh = strhash_open(10);
	if (!(p = get_home_directory()))
		goto end;
	if (!test("r", makepath(p, gozillarc, NULL)))
#ifdef __DJGPP__
		if (!test("r", makepath(p, dos_gozillarc, NULL)))
#endif
			goto end;
	if (!(ip = fopen(makepath(p, gozillarc, NULL), "r")))
#ifdef __DJGPP__
		if (!(ip = fopen(makepath(p, dos_gozillarc, NULL), "r")))
#endif
			goto end;
	while ((p = strbuf_fgets(sb, ip, flag)) != NULL) {
		char *name, *value;

		flag &= ~STRBUF_APPEND;
		if (*p == '#')
			continue;
		if (strbuf_unputc(sb, '\\')) {
			flag |= STRBUF_APPEND;
			continue;
		}
		while (*p && isblank(*p))	/* skip spaces */
			p++;
		name = p;
		while (*p && isalnum(*p))	/* get name */
			p++;
		*p++ = 0;
		while (*p && isblank(*p))	/* skip spaces */
			p++;
		if (*p == '=' || *p == ':') {
			p++;
			while (*p && isblank(*p))/* skip spaces */
				p++;
		}
		value = p;
		while (*p && !isblank(*p))	/* get value */
			p++;
		*p = 0;
		ent = strhash_assign(sh, name, 1);
		if (ent->value)
			(void)free(ent->value);
		ent->value = check_strdup(value);
	}
	fclose(ip);
end:
	strbuf_close(sb);
}
Esempio n. 11
0
static void
replace_variables(STRBUF *sb)
{
	STRBUF *result = strbuf_open(0);
	STRBUF *word = strbuf_open(0);
	const char *p = strbuf_value(sb);

	/*
	 * Simple of detecting infinite loop.
	 */
	if (++recursive_call > 32)
		die("Seems to be a never-ending referring.");
	for (;;) {
		for (; *p; p++) {
			if (*p == '$')
				break;
			if (*p == '\\' && *(p + 1) != 0)
				p++;
			strbuf_putc(result, *p);
		}
		if (*p == 0)
			break;
		/*
		 * $<word> or ${<word>}
		 */
		if (*p == '$') {
			strbuf_reset(word);
			if (*++p == '{') {
				for (p++; *p && *p != '}'; p++)
					strbuf_putc(word, *p);;
				if (*p++ != '}')
					die("invalid variable.");
			} else {
				for (; *p && (isalnum(*p) || *p == '_'); p++)
					strbuf_putc(word, *p);
			}
			getconfs(strbuf_value(word), result);
		}
	}
	strbuf_reset(sb);
	strbuf_puts(sb, strbuf_value(result));
	strbuf_close(result);
	strbuf_close(word);
	recursive_call--;
}
Esempio n. 12
0
File: find.c Progetto: kosaki/gtags
/*
 * prepare_source: preparing regular expression.
 *
 *	i)	flags	flags for regcomp.
 *	go)	suff	regular expression for source files.
 */
static void
prepare_source(void)
{
	STRBUF *sb = strbuf_open(0);
	char *sufflist = NULL;
	int flags = REG_EXTENDED;

	/*
	 * load icase_path option.
	 */
	if (getconfb("icase_path"))
		flags |= REG_ICASE;
#if defined(_WIN32) || defined(__DJGPP__)
	flags |= REG_ICASE;
#endif
	strbuf_reset(sb);
	if (!getconfs("suffixes", sb))
		die("cannot get suffixes data.");
	sufflist = check_strdup(strbuf_value(sb));
	trim(sufflist);
	{
		const char *suffp;
		int retval;

		strbuf_reset(sb);
		strbuf_puts(sb, "\\.(");       /* ) */
		for (suffp = sufflist; suffp; ) {
			const char *p;

			for (p = suffp; *p && *p != ','; p++) {
				if (!isalnum((unsigned char)*p))
					strbuf_putc(sb, '\\');
				strbuf_putc(sb, *p);
			}
			if (!*p)
				break;
			assert(*p == ',');
			strbuf_putc(sb, '|');
			suffp = ++p;
		}
		strbuf_puts(sb, ")$");
		/*
		 * compile regular expression.
		 */
		retval = regcomp(suff, strbuf_value(sb), flags);
#ifdef DEBUG
		if (debug)
			fprintf(stderr, "find regex: %s\n", strbuf_value(sb));
#endif
		if (retval != 0)
			die("cannot compile regular expression.");
	}
	strbuf_close(sb);
	if (sufflist)
		free(sufflist);
}
Esempio n. 13
0
/**
 * usable: check if command is executable or not.
 *
 *	@param[in]	command
 *	@return		==NULL: not found. <br>
 *			!=NULL: absolute path of @a command.
 */
char *
usable(const char *command)
{
	STRBUF *sb;
	char *p;
	const char *dir;
	static char path[MAXPATHLEN];

#if defined(_WIN32) || defined(__DJGPP__)
	int i, lim = sizeof(suffix)/sizeof(char *);
#endif

	if (isabspath(command) || locatestring(command, "./", MATCH_AT_FIRST)
		|| locatestring(command, "../", MATCH_AT_FIRST)) {
		if (test("fx", command)) {
			strlimcpy(path, command, sizeof(path));
			return path;
		}
		return NULL;
	}
	/*
	 * If found in BINDIR then use it.
	 */
	if (test("fx", makepath(BINDIR, command, NULL))) {
		strlimcpy(path, makepath(BINDIR, command, NULL), sizeof(path));
		return path;
	}
	/*
	 * Locate the command for each path in PATH.
	 */
	*path = 0;
	/* Don't use fixed length buffer for environment variable
	 * because it brings buffer overflow. */
	sb = strbuf_open(0);
	strbuf_puts(sb, getenv("PATH"));
	p = strbuf_value(sb);
	while (p) {
		dir = p;
		if ((p = locatestring(p, PATHSEP, MATCH_FIRST)) != NULL)
			*p++ = 0;
		if (test("fx", makepath(dir, command, NULL))) {
			strlimcpy(path, makepath(dir, command, NULL), sizeof(path));
			goto finish;
		}
#if defined(_WIN32) || defined(__DJGPP__)
		for (i = 0; i < lim; i++)
			if (test("f", makepath(dir, command, suffix[i]))) {
				strlimcpy(path, makepath(dir, command, suffix[i]), sizeof(path));
				goto finish;
			}
#endif
	}
finish:
	strbuf_close(sb);
	return *path ? path : NULL;
}
Esempio n. 14
0
/**
 * dbop_close: close db
 * 
 *	@param[in]	dbop	dbop descripter
 */
void
dbop_close(DBOP *dbop)
{
	DB *db = dbop->db;

	/*
	 * Load sorted tag records and write them to the tag file.
	 */
	if (dbop->sortout != NULL) {
		STRBUF *sb = strbuf_open(256);
		char *p;

		/*
		 * End of the former stage of sorted writing.
		 * fclose() and sortout = NULL is important.
		 *
		 * fclose(): enables reading from sortin descriptor.
		 * sortout = NULL: makes the following dbop_put write to the tag file directly.
		 */
		fclose(dbop->sortout);
		dbop->sortout = NULL;
		/*
		 * The last stage of sorted writing.
		 */
		while (strbuf_fgets(sb, dbop->sortin, STRBUF_NOCRLF)) {
			for (p = strbuf_value(sb); *p && *p != SORT_SEP; p++)
				;
			if (!*p)
				die("unexpected end of record.");
			*p++ = '\0';
			dbop_put(dbop, strbuf_value(sb), p);
		}
		fclose(dbop->sortin);
		strbuf_close(sb);
		terminate_sort_process(dbop);
	}
#ifdef USE_SQLITE3
	if (dbop->openflags & DBOP_SQLITE3) {
		dbop3_close(dbop);
		return;
	}
#endif
#ifdef USE_DB185_COMPAT
	(void)db->close(db);
#else
	/*
	 * If dbname = NULL, omit writing to the disk in __bt_close().
	 */
	(void)db->close(db, dbop->dbname[0] == '\0' ? 1 : 0);
#endif
	if (dbop->dbname[0] != '\0') {
		if (dbop->perm && chmod(dbop->dbname, dbop->perm) < 0)
			die("chmod(2) failed.");
	}
	(void)free(dbop);
}
Esempio n. 15
0
/**
 * xargs_open_with_file: open xargs stream using file
 *
 *	@param[in]	command	command skeleton.
 *	@param[in]	max_args 0: no limit, \>0: max argument
 *	@param[in]	ip	file pointer
 *	@return		xargs structure
 *
 * The @CODE{'\%s'} in the command skeleton is replaced with given arguments. <br>
 * If @CODE{'\%s'} doesn't exist, the arguments is appended to the tail of the
 * skeleton.
 */
XARGS *
xargs_open_with_file(const char *command, int max_args, FILE *ip)
{
	XARGS *xp = xargs_open_generic(command, max_args);

	xp->type = XARGS_FILE;
	xp->ip = ip;
	xp->path = strbuf_open(0);
	xp->fptr = 0;
	return xp;
}
Esempio n. 16
0
/**
 * Load file.
 */
void
loadfile(const char *file, STRBUF *result)
{
	STRBUF *sb = strbuf_open(0);
	FILE *ip = fopen(file, "r");
	if (!ip)
		die("file '%s' not found.", file);
	while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL)
		strbuf_puts_nl(result, strbuf_value(sb));
	fclose(ip);
	strbuf_close(sb);
}
Esempio n. 17
0
/*
 * tagsearch: execute tag search
 *
 *	i)	pattern		search pattern
 *	i)	cwd		current directory
 *	i)	root		root of source tree
 *	i)	dbpath		database directory
 *	i)	db		GTAGS,GRTAGS,GSYMS
 */
void
tagsearch(const char *pattern, const char *cwd, const char *root, const char *dbpath, int db)
{
	int count, total = 0;
	char libdbpath[MAXPATHLEN];

	/*
	 * search in current source tree.
	 */
	count = search(pattern, root, cwd, dbpath, db);
	total += count;
	/*
	 * search in library path.
	 */
	if (db == GTAGS && getenv("GTAGSLIBPATH") && (count == 0 || Tflag) && !lflag) {
		STRBUF *sb = strbuf_open(0);
		char *libdir, *nextp = NULL;

		strbuf_puts(sb, getenv("GTAGSLIBPATH"));
		/*
		 * search for each tree in the library path.
		 */
		for (libdir = strbuf_value(sb); libdir; libdir = nextp) {
			if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL)
				*nextp++ = 0;
			if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0))
				continue;
			if (!strcmp(dbpath, libdbpath))
				continue;
			if (!test("f", makepath(libdbpath, dbname(db), NULL)))
				continue;
			/*
			 * search again
			 */
			count = search(pattern, libdir, cwd, libdbpath, db);
			total += count;
			if (count > 0 && !Tflag) {
				/* for verbose message */
				dbpath = libdbpath;
				break;
			}
		}
		strbuf_close(sb);
	}
	if (vflag) {
		print_count(total);
		if (!Tflag)
			fprintf(stderr, " (using '%s')", makepath(dbpath, dbname(db), NULL));
		fputs(".\n", stderr);
	}
}
Esempio n. 18
0
/**
 * makedirectories: make directories on the path like @XREF{mkdir,1} with the @OPTION{-p} option.
 *
 *	@param[in]	base	base directory
 *	@param[in]	rest	path from the base
 *	@param[in]	verbose 1: verbose mode, 0: not verbose mode
 *	@return		0: success <br>
 *			-1: base directory not found <br>
 *			-2: permission error <br>
 *			-3: cannot make directory
 */
int
makedirectories(const char *base, const char *rest, int verbose)
{
	STRBUF *sb;
	const char *p, *q;

	if (!test("d", base))
		return -1;
	if (!test("drw", base))
		return -2;
	sb = strbuf_open(0);
	strbuf_puts(sb, base);
	if (*rest == SEP)
		rest++;
	for (q = rest; *q;) {
		p = q;
		while (*q && *q != SEP)
			q++;
		strbuf_putc(sb, SEP);
		strbuf_nputs(sb, p, q - p);
		p = strbuf_value(sb);
		if (!test("d", p)) {
			if (verbose)
				fprintf(stderr, " Making directory '%s'.\n", p);
#if defined(_WIN32) && !defined(__CYGWIN__)
			if (mkdir(p) < 0) {
#else
			if (mkdir(p, 0775) < 0) {
#endif /* WIN32 */
				strbuf_close(sb);
				return -3;
			}
		}
		if (*q == SEP)
			q++;
	}
	strbuf_close(sb);
	return 0;
}
/**
 * trimpath: trim path name
 */
const char *
trimpath(const char *path)
{
	if (*path == '.' && *(path + 1) == '/')
		path += 2;
	return path;
}
Esempio n. 19
0
/**
 * load configuration variables.
 */
static void
configuration()
{
    STRBUF *sb = strbuf_open(0);

    if (getconfb("extractmethod"))
        extractmethod = 1;
    strbuf_reset(sb);
    if (getconfs("langmap", sb))
        langmap = check_strdup(strbuf_value(sb));
    strbuf_reset(sb);
    if (getconfs("gtags_parser", sb))
        gtags_parser = check_strdup(strbuf_value(sb));
    strbuf_close(sb);
}
Esempio n. 20
0
/**
 * opentoken:
 *
 *	@param[in]	file
 */
int
opentoken(const char *file)
{
	/*
	 * b flag is needed for WIN32 environment. Almost unix ignore it.
	 */
	if ((ip = fopen(file, "rb")) == NULL)
		return 0;
	ib = strbuf_open(MAXBUFLEN);
	strlimcpy(curfile, file, sizeof(curfile));
	sp = cp = lp = NULL; ptok[0] = '\0'; lineno = 0;
	crflag = cmode = cppmode = ymode = 0;
	continued_line = 0;
	return 1;
}
Esempio n. 21
0
/**
 * completion_idutils: print completion list of specified @a prefix
 *
 *	@param[in]	dbpath	dbpath directory
 *	@param[in]	root	root directory
 *	@param[in]	prefix	prefix of primary key
 */
void
completion_idutils(const char *dbpath, const char *root, const char *prefix)
{
	FILE *ip;
	STRBUF *sb = strbuf_open(0);
	const char *lid = usable("lid");
	char *line, *p;

	if (prefix && *prefix == 0)	/* In the case global -c '' */
		prefix = NULL;
	/*
	 * make lid command line.
	 * Invoke lid with the --result=grep option to generate grep format.
	 */
	if (!lid)
		die("lid(idutils) not found.");
	strbuf_puts(sb, lid);
	strbuf_sprintf(sb, " --file=%s/ID", quote_shell(dbpath));
	strbuf_puts(sb, " --key=token");
	if (iflag)
		strbuf_puts(sb, " --ignore-case");
	if (prefix) {
		strbuf_putc(sb, ' ');
		strbuf_putc(sb, '"');
		strbuf_putc(sb, '^');
		strbuf_puts(sb, prefix);
		strbuf_putc(sb, '"');
	}
	if (debug)
		fprintf(stderr, "completion_idutils: %s\n", strbuf_value(sb));
	if (chdir(root) < 0)
		die("cannot move to '%s' directory.", root);
	if (!(ip = popen(strbuf_value(sb), "r")))
		die("cannot execute '%s'.", strbuf_value(sb));
	while ((line = strbuf_fgets(sb, ip, STRBUF_NOCRLF)) != NULL) {
		for (p = line; *p && *p != ' '; p++)
			;
		if (*p == '\0') {
			warning("Invalid line: %s", line);
			continue;
		}
		*p = '\0';
		puts(line);
	}
	if (pclose(ip) != 0)
		die("terminated abnormally (errno = %d).", errno);
	strbuf_close(sb);
}
Esempio n. 22
0
/*
 * getURL: get URL of the specified file.
 *
 *	i)	file	file name
 *	i)	htmldir HTML directory
 *	o)	URL	URL begin with 'file:'
 */
void
getURL(const char *file, const char *htmldir, STRBUF *URL)
{
	char *p;
	char buf[MAXPATHLEN];
	STRBUF *sb = strbuf_open(0);

	if (!test("f", file) && !test("d", file))
		die("file '%s' not found.", file);
	p = normalize(file, get_root_with_slash(), cwd, buf, sizeof(buf));
	if (p != NULL && convertpath(dbpath, htmldir, p, sb) == 0)
		makefileurl(strbuf_value(sb), linenumber, URL);
	else
		makefileurl(realpath(file, buf), 0, URL);
	strbuf_close(sb);
}
Esempio n. 23
0
/**
 * set_env: put environment variable.
 *
 *	@param[in]	var	environment variable
 *	@param[in]	val	value
 *
 * Machine independent version of @XREF{setenv,3}.
 */
void
set_env(const char *var, const char *val)
{
/*
 * sparc-sun-solaris2.6 doesn't have setenv(3).
 */
#ifdef HAVE_PUTENV
	STRBUF *sb = strbuf_open(0);

	strbuf_sprintf(sb, "%s=%s", var, val);
	putenv(strbuf_value(sb));
	/* Don't free memory. putenv(3) require it. */
#else
	setenv(var, val, 1);
#endif
}
Esempio n. 24
0
/*
 * printconf: print configuration data.
 *
 *	i)	name	label of config data
 *	r)		exit code
 */
int
printconf(const char *name)
{
	int num;
	int exist = 1;

	if (getconfn(name, &num))
		fprintf(stdout, "%d\n", num);
	else if (getconfb(name))
		fprintf(stdout, "1\n");
	else {
		STRBUF *sb = strbuf_open(0);
		if (getconfs(name, sb))
			fprintf(stdout, "%s\n", strbuf_value(sb));
		else
			exist = 0;
		strbuf_close(sb);
	}
	return exist;
}
Esempio n. 25
0
/**
 * xargs_open_generic: allocate generic part of xargs structure.
 *
 *	@param[in]	command	command line except for the arguments.
 *	@param[in]	max_args 0: no limit, \>0: max argument
 *	@return		xargs structure	
 */
static XARGS *
xargs_open_generic(const char *command, int max_args)
{
	XARGS *xp;

	xp  = check_calloc(sizeof(XARGS), 1);
	xp->command = check_strdup(command);
	xp->type = 0;
	xp->pipe = NULL;
	xp->result = strbuf_open(0);
	xp->end_of_arg = 0;
	xp->unread = 0;
	xp->max_args = max_args;
	xp->seqno = 0;
	xp->skip_assembly = 0;
	/*
	 * Procedure to display verbose message.
	 * proc(path, seqno, skip)
	 */
	xp->verbose = NULL;
	/*
	 * By default, the error status returned by pclose() is not ignored,
	 * because global(1) doesn't return error code when the target
	 * was not found.
	 * Some commands like grep(1) return error code when the target
	 * was not found. If you would like to use such command, set the
	 * flag to 1.
	 */
	xp->ignore_error = 0;
	/*
	 * By default, we doesn't put the path to GPATH.
	 * This option is prepared for createtags() and updatetags().
	 */
	xp->put_gpath = 0;
	/*
	 * By default, we don't cut off the blanks at the tail of the line.
	 */
	xp->trim_line = 0;

	return xp;
}
Esempio n. 26
0
/**
 * completion: print completion list of specified @a prefix
 *
 *	@param[in]	dbpath	dbpath directory
 *	@param[in]	root	root directory
 *	@param[in]	prefix	prefix of primary key
 *	@param[in]	db	#GTAGS,#GRTAGS,#GSYMS
 */
void
completion(const char *dbpath, const char *root, const char *prefix, int db)
{
	int count, total = 0;
	char libdbpath[MAXPATHLEN];

	if (prefix && *prefix == 0)	/* In the case global -c '' */
		prefix = NULL;
	count = completion_tags(dbpath, root, prefix, db);
	/*
	 * search in library path.
	 */
	if (db == GTAGS && getenv("GTAGSLIBPATH") && (count == 0 || Tflag) && !Sflag) {
		STRBUF *sb = strbuf_open(0);
		char *libdir, *nextp = NULL;

		strbuf_puts(sb, getenv("GTAGSLIBPATH"));
		/*
		* search for each tree in the library path.
		*/
		for (libdir = strbuf_value(sb); libdir; libdir = nextp) {
			if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL)
				*nextp++ = 0;
			if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0))
				continue;
			if (!strcmp(dbpath, libdbpath))
				continue;
			if (!test("f", makepath(libdbpath, dbname(db), NULL)))
				continue;
			/*
			 * search again
			 */
			count = completion_tags(libdbpath, libdir, prefix, db);
			total += count;
			if (count > 0 && !Tflag)
				break;
		}
		strbuf_close(sb);
	}
	/* return total; */
}
Esempio n. 27
0
/**
 * includelabel: procedure for tc= (or include=)
 *
 *	@param[in]	fp	file pointer
 *	@param[out]	sb	string buffer
 *	@param[in]	label	record label
 *	@param[in]	level	nest level for check
 *
 * This function may call itself (recursive)
 */
static void
includelabel(FILE *fp, STRBUF *sb, const char *label, int level)
{
	const char *savep, *p, *q;
	char *file;

	if (++level > allowed_nest_level)
		die("nested include= (or tc=) over flow.");
	/*
	 * Label can include a '@' and a following path name.
	 * Label: <label>[@<path>]
	 */
	if ((file = locatestring(label, "@", MATCH_FIRST)) != NULL) {
		*file++ = '\0';
		if ((p = makepath_with_tilde(file)) == NULL)
			die("config file must be absolute path. (%s)", file);
		fp = fopen(p, "r");
		if (fp == NULL)
			die("cannot open config file. (%s)", p);
	}
	if (!(savep = p = readrecord(fp, label)))
		die("label '%s' not found.", label);
	while ((q = locatestring(p, ":include=", MATCH_FIRST)) || (q = locatestring(p, ":tc=", MATCH_FIRST))) {
		STRBUF *inc = strbuf_open(0);

		strbuf_nputs(sb, p, q - p);
		q = locatestring(q, "=", MATCH_FIRST) + 1;
		for (; *q && *q != ':'; q++)
			strbuf_putc(inc, *q);
		includelabel(fp, sb, strbuf_value(inc), level);
		p = q;
		strbuf_close(inc);
	}
	strbuf_puts(sb, p);
	free((void *)savep);
	if (file)
		fclose(fp);
}
Esempio n. 28
0
/**
 * includelabel: procedure for @CODE{tc=} (or @CODE{include=})
 *
 *	@param[out]	sb	string buffer
 *	@param[in]	label	record label
 *	@param[in]	level	nest level for check
 */
static void
includelabel(STRBUF *sb, const char *label, int	level)
{
	const char *savep, *p, *q;

	if (++level > allowed_nest_level)
		die("nested include= (or tc=) over flow.");
	if (!(savep = p = readrecord(label)))
		die("label '%s' not found.", label);
	while ((q = locatestring(p, ":include=", MATCH_FIRST)) || (q = locatestring(p, ":tc=", MATCH_FIRST))) {
		STRBUF *inc = strbuf_open(0);

		strbuf_nputs(sb, p, q - p);
		q = locatestring(q, "=", MATCH_FIRST) + 1;
		for (; *q && *q != ':'; q++)
			strbuf_putc(inc, *q);
		includelabel(sb, strbuf_value(inc), level);
		p = q;
		strbuf_close(inc);
	}
	strbuf_puts(sb, p);
	free((void *)savep);
}
Esempio n. 29
0
/*
 * makedefineindex: make definition index (including alphabetic index)
 *
 *	@param[in]	file		definition index file
 *	@param[in]	total		definitions total
 *	@param[out]	defines		@defines
 *	Globals used (input):
 *		tag cache	  XXX: should this be global output, not input?
 */
int
makedefineindex(const char *file, int total, STRBUF *defines)
{
	int count = 0;
	int alpha_count = 0;
	FILEOP *fileop_MAP = NULL, *fileop_DEFINES, *fileop_ALPHA = NULL;
	FILE *MAP = NULL;
	FILE *DEFINES, *STDOUT, *TAGS, *ALPHA = NULL;
	STRBUF *sb = strbuf_open(0);
	STRBUF *url = strbuf_open(0);
	/* Index link */
	const char *target = (Fflag) ? "mains" : "_top";
	const char *indexlink;
	const char *index_string = "Index Page";
	char command[1024], buf[1024], alpha[32], alpha_f[32], *_;

	if (!aflag && !Fflag)
		indexlink = "mains";
	else if (Fflag)
		indexlink = "../defines";
	else
		indexlink = "../mains";

	if (map_file) {
		fileop_MAP = open_output_file(makepath(distpath, "MAP", NULL), 0);
		MAP = get_descripter(fileop_MAP);
	}
	fileop_DEFINES = open_output_file(makepath(distpath, file, NULL), 0);
	DEFINES = get_descripter(fileop_DEFINES);
	fputs_nl(gen_page_begin(title_define_index, TOPDIR), DEFINES);
	fputs_nl(body_begin, DEFINES);
	fputs(header_begin, DEFINES);
	if (Fflag)
		fputs(gen_href_begin(NULL, "defines", normal_suffix, NULL), DEFINES);
	fputs(title_define_index, DEFINES);
	if (Fflag)
		fputs(gen_href_end(), DEFINES);
	fputs_nl(header_end, DEFINES);
	if (!aflag && !Fflag) {
		fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), DEFINES);
		if (Iflag)
			fputs(gen_image(CURRENT, back_icon, ".."), DEFINES);
		else
			fputs("[..]", DEFINES);
		fputs_nl(gen_href_end(), DEFINES);
	}
	if (!aflag) {
		if (!no_order_list)
			fputs_nl(list_begin, DEFINES);
	}
	/*
	 * map DEFINES to STDOUT.
	 */
	STDOUT = DEFINES;
	snprintf(command, sizeof(command), PQUOTE "%s -c" PQUOTE, quote_shell(global_path));
	if ((TAGS = popen(command, "r")) == NULL)
		die("cannot execute '%s'.", command);
	alpha[0] = '\0';
	while ((_ = strbuf_fgets(sb, TAGS, STRBUF_NOCRLF)) != NULL) {
		const char *tag, *line;
		char guide[1024], url_for_map[1024];

		count++;
		tag = _;
		message(" [%d/%d] adding %s", count, total, tag);
		if (aflag && (alpha[0] == '\0' || !locatestring(tag, alpha, MATCH_AT_FIRST))) {
			const char *msg = (alpha_count == 1) ? "definition" : "definitions";
			int c;

			if (alpha[0]) {
				char tmp[128];
				snprintf(tmp, sizeof(tmp), "%d %s", alpha_count, msg);
				strbuf_puts(defines, gen_href_begin_with_title("defines", alpha_f, HTML, NULL, tmp));
				strbuf_sprintf(defines, "[%s]", alpha);
				strbuf_puts_nl(defines, gen_href_end());
				alpha_count = 0;
				if (!no_order_list)
					fputs_nl(list_end, ALPHA);
				else
					fputs_nl(br, ALPHA);
				fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
				if (Iflag)
					fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
				else
					fputs("[..]", ALPHA);
				fputs_nl(gen_href_end(), ALPHA);
				fputs_nl(body_end, ALPHA);
				fputs_nl(gen_page_end(), ALPHA);
				close_file(fileop_ALPHA);
				html_count++;
			}
			/*
			 * setup index char (for example, 'a' of '[a]').
			 * alpha is used for display.
			 * alpha_f is used for part of path.
			 */
			c = (unsigned char)*tag;
			if (c > 127) {
				int i2 = *(tag + 1) & 0xff;
				/*
				 * for multi-byte(EUC) code.
				 */
				alpha[0] = *tag;
				alpha[1] = *(tag + 1);
				alpha[2] = '\0';
				snprintf(alpha_f, sizeof(alpha_f), "%03d%03d", c, i2);
			} else if (isalpha(c) || c == '_') {
				alpha[0] = *tag;
				alpha[1] = '\0';
				/*
				 * for CD9660 or FAT file system
				 */
				if (islower(c)) {
					alpha_f[0] = 'l';
					alpha_f[1] = *tag;
					alpha_f[2] = '\0';
				} else {
					alpha_f[0] = *tag;
					alpha_f[1] = '\0';
				}
			} else {
				alpha[0] = *tag;
				alpha[1] = '\0';
				snprintf(alpha_f, sizeof(alpha_f), "%03d", c);
			}
			snprintf(buf, sizeof(buf), "%s/defines/%s.%s", distpath, alpha_f, HTML);
			fileop_ALPHA = open_output_file(buf, 0);
			ALPHA = get_descripter(fileop_ALPHA);
			snprintf(buf, sizeof(buf), "[%s]", alpha);
			fputs_nl(gen_page_begin(buf, SUBDIR), ALPHA);
			fputs_nl(body_begin, ALPHA);
			fprintf(ALPHA, "%s[%s]%s\n", header_begin, alpha, header_end);
			fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
			if (Iflag)
				fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
			else
				fputs("[..]", ALPHA);
			fputs_nl(gen_href_end(), ALPHA);
			if (!no_order_list)
				fputs_nl(list_begin, ALPHA);
			else
				fprintf(ALPHA, "%s%s\n", br, br);
			STDOUT = ALPHA;
		}
		alpha_count++;
		/*
		 * generating url for function definition.
	 	 */
		line = cache_get(GTAGS, tag);
		strbuf_reset(url);

		if (line == NULL)
			die("internal error in makedefineindex()."); 
		/*
		 * About the format of 'line', please see the head comment of cache.c.
		 */
		if (*line == ' ') {
			const char *fid = line + 1;
			const char *enumber = nextstring(fid);

			snprintf(url_for_map, sizeof(url_for_map), "%s/%s.%s",
				DEFS, fid, HTML);
			if (dynamic) {
				if (*action != '/' && aflag)
					strbuf_puts(url, "../");
				strbuf_puts(url, action);
				strbuf_sprintf(url, "?pattern=%s%stype=definitions", tag, quote_amp);
			} else {
				if (aflag)
					strbuf_puts(url, "../");
				strbuf_sprintf(url, "%s/%s.%s", DEFS, fid, HTML);
			}
			snprintf(guide, sizeof(guide), "Multiple defined in %s places.", enumber);
		} else {
			const char *lno = line;
			const char *fid = nextstring(line);
			const char *path = gpath_fid2path(fid, NULL);

			path += 2;		/* remove './' */
			snprintf(url_for_map, sizeof(url_for_map), "%s/%s.%s#L%s",
				SRCS, fid, HTML, lno);
			if (aflag)
				strbuf_puts(url, "../");
			strbuf_sprintf(url, "%s/%s.%s#L%s", SRCS, fid, HTML, lno);
			snprintf(guide, sizeof(guide), "Defined at %s in %s.", lno, path);
		}
		if (!no_order_list)
			fputs(item_begin, STDOUT);
		fputs(gen_href_begin_with_title_target(NULL, strbuf_value(url), NULL, NULL, guide, target), STDOUT);
		fputs(tag, STDOUT);
		fputs(gen_href_end(), STDOUT);
		if (!no_order_list)
			fputs(item_end, STDOUT);
		else
			fputs(br, STDOUT);
		fputc('\n', STDOUT);
		if (map_file)
			fprintf(MAP, "%s\t%s\n", tag, url_for_map);
	}
	if (pclose(TAGS) != 0)
		die("terminated abnormally '%s' (errno = %d).", command, errno);
	if (aflag && alpha[0]) {
		char tmp[128];
		const char *msg = (alpha_count == 1) ? "definition" : "definitions";

		snprintf(tmp, sizeof(tmp), "%d %s", alpha_count, msg);
		strbuf_puts(defines, gen_href_begin_with_title("defines", alpha_f, HTML, NULL, tmp));
		strbuf_sprintf(defines, "[%s]", alpha);
		strbuf_puts_nl(defines, gen_href_end());
		if (!no_order_list)
			fputs_nl(list_end, ALPHA);
		else
			fputs_nl(br, ALPHA);
		fputs(gen_href_begin_with_title(NULL, indexlink, normal_suffix, NULL, index_string), ALPHA);
		if (Iflag)
			fputs(gen_image(PARENT, back_icon, ".."), ALPHA);
		else
			fputs("[..]", ALPHA);
		fputs_nl(gen_href_end(), ALPHA);
		fputs_nl(body_end, ALPHA);
		fputs_nl(gen_page_end(), ALPHA);
		close_file(fileop_ALPHA);
		html_count++;

		fputs(strbuf_value(defines), DEFINES);
	}
	if (!no_order_list && !aflag)
		fputs_nl(list_end, DEFINES);
	if (!aflag && !Fflag) {
		fputs(gen_href_begin_with_title(NULL, "mains", normal_suffix, NULL, index_string), DEFINES);
		if (Iflag)
			fputs(gen_image(CURRENT, back_icon, ".."), DEFINES);
		else
			fputs("[..]", DEFINES);
		fputs_nl(gen_href_end(), DEFINES);
	}
	fputs_nl(body_end, DEFINES);
	fputs_nl(gen_page_end(), DEFINES);
	close_file(fileop_DEFINES);
	html_count++;
	if (map_file)
		close_file(fileop_MAP);
	strbuf_close(sb);
	strbuf_close(url);
	return count;
}
Esempio n. 30
0
/**
 *	@param[in]	param	source file
 *	@param[in]	type	#TYPE_C, #TYPE_YACC, #TYPE_LEX
 */
static void
C_family(const struct parser_param *param, int type)
{
	int c, cc;
	int savelevel;
	int startmacro, startsharp;
	const char *interested = "{}=;";
	STRBUF *sb = strbuf_open(0);
	/*
	 * yacc file format is like the following.
	 *
	 * declarations
	 * %%
	 * rules
	 * %%
	 * programs
	 *
	 */
	int yaccstatus = (type == TYPE_YACC) ? DECLARATIONS : PROGRAMS;
	int inC = (type == TYPE_YACC) ? 0 : 1;	/* 1 while C source */

	level = piflevel = externclevel = 0;
	savelevel = -1;
	startmacro = startsharp = 0;

	if (!opentoken(param->file))
		die("'%s' cannot open.", param->file);
	cmode = 1;			/* allow token like '#xxx' */
	crflag = 1;			/* require '\n' as a token */
	if (type == TYPE_YACC)
		ymode = 1;		/* allow token like '%xxx' */

	while ((cc = nexttoken(interested, c_reserved_word)) != EOF) {
		switch (cc) {
		case SYMBOL:		/* symbol	*/
			if (inC && peekc(0) == '('/* ) */) {
				if (param->isnotfunction(token)) {
					PUT(PARSER_REF_SYM, token, lineno, sp);
				} else if (level > 0 || startmacro) {
					PUT(PARSER_REF_SYM, token, lineno, sp);
				} else if (level == 0 && !startmacro && !startsharp) {
					char arg1[MAXTOKEN], savetok[MAXTOKEN], *saveline;
					int savelineno = lineno;

					strlimcpy(savetok, token, sizeof(savetok));
					strbuf_reset(sb);
					strbuf_puts(sb, sp);
					saveline = strbuf_value(sb);
					arg1[0] = '\0';
					/*
					 * Guile function entry using guile-snarf is like follows:
					 *
					 * SCM_DEFINE (scm_list, "list", 0, 0, 1, 
					 *           (SCM objs),
					 *            "Return a list containing OBJS, the arguments to `list'.")
					 * #define FUNC_NAME s_scm_list
					 * {
					 *   return objs;
					 * }
					 * #undef FUNC_NAME
					 *
					 * We should assume the first argument as a function name instead of 'SCM_DEFINE'.
					 */
					if (function_definition(param, arg1)) {
						if (!strcmp(savetok, "SCM_DEFINE") && *arg1)
							strlimcpy(savetok, arg1, sizeof(savetok));
						PUT(PARSER_DEF, savetok, savelineno, saveline);
					} else {
						PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
					}
				}
			} else {
				PUT(PARSER_REF_SYM, token, lineno, sp);
			}
			break;
		case '{':  /* } */
			DBG_PRINT(level, "{"); /* } */
			if (yaccstatus == RULES && level == 0)
				inC = 1;
			++level;
			if ((param->flags & PARSER_BEGIN_BLOCK) && atfirst) {
				if ((param->flags & PARSER_WARNING) && level != 1)
					warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
				level = 1;
			}
			break;
			/* { */
		case '}':
			if (--level < 0) {
				if (externclevel > 0)
					externclevel--;
				else if (param->flags & PARSER_WARNING)
					warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
				level = 0;
			}
			if ((param->flags & PARSER_END_BLOCK) && atfirst) {
				if ((param->flags & PARSER_WARNING) && level != 0) /* { */
					warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile);
				level = 0;
			}
			if (yaccstatus == RULES && level == 0)
				inC = 0;
			/* { */
			DBG_PRINT(level, "}");
			break;
		case '\n':
			if (startmacro && level != savelevel) {
				if (param->flags & PARSER_WARNING)
					warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile);
				level = savelevel;
			}
			startmacro = startsharp = 0;
			break;
		case YACC_SEP:		/* %% */
			if (level != 0) {
				if (param->flags & PARSER_WARNING)
					warning("forced level 0 block end by '%%' [+%d %s].", lineno, curfile);
				level = 0;
			}
			if (yaccstatus == DECLARATIONS) {
				PUT(PARSER_DEF, "yyparse", lineno, sp);
				yaccstatus = RULES;
			} else if (yaccstatus == RULES)
				yaccstatus = PROGRAMS;
			inC = (yaccstatus == PROGRAMS) ? 1 : 0;
			break;
		case YACC_BEGIN:	/* %{ */
			if (level != 0) {
				if (param->flags & PARSER_WARNING)
					warning("forced level 0 block end by '%%{' [+%d %s].", lineno, curfile);
				level = 0;
			}
			if (inC == 1 && (param->flags & PARSER_WARNING))
				warning("'%%{' appeared in C mode. [+%d %s].", lineno, curfile);
			inC = 1;
			break;
		case YACC_END:		/* %} */
			if (level != 0) {
				if (param->flags & PARSER_WARNING)
					warning("forced level 0 block end by '%%}' [+%d %s].", lineno, curfile);
				level = 0;
			}
			if (inC == 0 && (param->flags & PARSER_WARNING))
				warning("'%%}' appeared in Yacc mode. [+%d %s].", lineno, curfile);
			inC = 0;
			break;
		case YACC_UNION:	/* %union {...} */
			if (yaccstatus == DECLARATIONS)
				PUT(PARSER_DEF, "YYSTYPE", lineno, sp);
			break;
		/*
		 * #xxx
		 */
		case SHARP_DEFINE:
		case SHARP_UNDEF:
			startmacro = 1;
			savelevel = level;
			if ((c = nexttoken(interested, c_reserved_word)) != SYMBOL) {
				pushbacktoken();
				break;
			}
			if (peekc(1) == '('/* ) */) {
				PUT(PARSER_DEF, token, lineno, sp);
				while ((c = nexttoken("()", c_reserved_word)) != EOF && c != '\n' && c != /* ( */ ')')
					if (c == SYMBOL)
						PUT(PARSER_REF_SYM, token, lineno, sp);
				if (c == '\n')
					pushbacktoken();
			} else {
				PUT(PARSER_DEF, token, lineno, sp);
			}
			break;
		case SHARP_IMPORT:
		case SHARP_INCLUDE:
		case SHARP_INCLUDE_NEXT:
		case SHARP_ERROR:
		case SHARP_LINE:
		case SHARP_PRAGMA:
		case SHARP_WARNING:
		case SHARP_IDENT:
		case SHARP_SCCS:
			while ((c = nexttoken(interested, c_reserved_word)) != EOF && c != '\n')
				;
			break;
		case SHARP_IFDEF:
		case SHARP_IFNDEF:
		case SHARP_IF:
		case SHARP_ELIF:
		case SHARP_ELSE:
		case SHARP_ENDIF:
			condition_macro(param, cc);
			break;
		case SHARP_SHARP:		/* ## */
			(void)nexttoken(interested, c_reserved_word);
			break;
		case C_EXTERN: /* for 'extern "C"/"C++"' */
			if (peekc(0) != '"') /* " */
				continue; /* If does not start with '"', continue. */
			while ((c = nexttoken(interested, c_reserved_word)) == '\n')
				;
			/*
			 * 'extern "C"/"C++"' block is a kind of namespace block.
			 * (It doesn't have any influence on level.)
			 */
			if (c == '{') /* } */
				externclevel++;
			else
				pushbacktoken();
			break;
		case C_STRUCT:
		case C_ENUM:
		case C_UNION:
			while ((c = nexttoken(interested, c_reserved_word)) == C___ATTRIBUTE__)
				process_attribute(param);
			if (c == SYMBOL) {
				if (peekc(0) == '{') /* } */ {
					PUT(PARSER_DEF, token, lineno, sp);
				} else {
					PUT(PARSER_REF_SYM, token, lineno, sp);
				}
				c = nexttoken(interested, c_reserved_word);
			}
			if (c == '{' /* } */ && cc == C_ENUM) {
				enumerator_list(param);
			} else {
				pushbacktoken();
			}
			break;
		/* control statement check */
		case C_BREAK:
		case C_CASE:
		case C_CONTINUE:
		case C_DEFAULT:
		case C_DO:
		case C_ELSE:
		case C_FOR:
		case C_GOTO:
		case C_IF:
		case C_RETURN:
		case C_SWITCH:
		case C_WHILE:
			if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
				warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
			break;
		case C_TYPEDEF:
			{
				/*
				 * This parser is too complex to maintain.
				 * We should rewrite the whole.
				 */
				char savetok[MAXTOKEN];
				int savelineno = 0;
				int typedef_savelevel = level;

				savetok[0] = 0;

				/* skip type qualifiers */
				do {
					c = nexttoken("{}(),;", c_reserved_word);
				} while (IS_TYPE_QUALIFIER(c) || c == '\n');

				if ((param->flags & PARSER_WARNING) && c == EOF) {
					warning("unexpected eof. [+%d %s]", lineno, curfile);
					break;
				} else if (c == C_ENUM || c == C_STRUCT || c == C_UNION) {
					char *interest_enum = "{},;";
					int c_ = c;

					while ((c = nexttoken(interest_enum, c_reserved_word)) == C___ATTRIBUTE__)
						process_attribute(param);
					/* read tag name if exist */
					if (c == SYMBOL) {
						if (peekc(0) == '{') /* } */ {
							PUT(PARSER_DEF, token, lineno, sp);
						} else {
							PUT(PARSER_REF_SYM, token, lineno, sp);
						}
						c = nexttoken(interest_enum, c_reserved_word);
					}
				
					if (c_ == C_ENUM) {
						if (c == '{') /* } */
							c = enumerator_list(param);
						else
							pushbacktoken();
					} else {
						for (; c != EOF; c = nexttoken(interest_enum, c_reserved_word)) {
							switch (c) {
							case SHARP_IFDEF:
							case SHARP_IFNDEF:
							case SHARP_IF:
							case SHARP_ELIF:
							case SHARP_ELSE:
							case SHARP_ENDIF:
								condition_macro(param, c);
								continue;
							default:
								break;
							}
							if (c == ';' && level == typedef_savelevel) {
								if (savetok[0])
									PUT(PARSER_DEF, savetok, savelineno, sp);
								break;
							} else if (c == '{')
								level++;
							else if (c == '}') {
								if (--level == typedef_savelevel)
									break;
							} else if (c == SYMBOL) {
								PUT(PARSER_REF_SYM, token, lineno, sp);
								/* save lastest token */
								strlimcpy(savetok, token, sizeof(savetok));
								savelineno = lineno;
							}
						}
						if (c == ';')
							break;
					}
					if ((param->flags & PARSER_WARNING) && c == EOF) {
						warning("unexpected eof. [+%d %s]", lineno, curfile);
						break;
					}
				} else if (c == SYMBOL) {
					PUT(PARSER_REF_SYM, token, lineno, sp);
				}
				savetok[0] = 0;
				while ((c = nexttoken("(),;", c_reserved_word)) != EOF) {
					switch (c) {
					case SHARP_IFDEF:
					case SHARP_IFNDEF:
					case SHARP_IF:
					case SHARP_ELIF:
					case SHARP_ELSE:
					case SHARP_ENDIF:
						condition_macro(param, c);
						continue;
					default:
						break;
					}
					if (c == '(')
						level++;
					else if (c == ')')
						level--;
					else if (c == SYMBOL) {
						if (level > typedef_savelevel) {
							PUT(PARSER_REF_SYM, token, lineno, sp);
						} else {
							/* put latest token if any */
							if (savetok[0]) {
								PUT(PARSER_REF_SYM, savetok, savelineno, sp);
							}
							/* save lastest token */
							strlimcpy(savetok, token, sizeof(savetok));
							savelineno = lineno;
						}
					} else if (c == ',' || c == ';') {
						if (savetok[0]) {
							PUT(PARSER_DEF, savetok, lineno, sp);
							savetok[0] = 0;
						}
					}
					if (level == typedef_savelevel && c == ';')
						break;
				}
				if (param->flags & PARSER_WARNING) {
					if (c == EOF)
						warning("unexpected eof. [+%d %s]", lineno, curfile);
					else if (level != typedef_savelevel)
						warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
				}
			}
			break;
		case C___ATTRIBUTE__:
			process_attribute(param);
			break;
		default:
			break;
		}
	}
	strbuf_close(sb);
	if (param->flags & PARSER_WARNING) {
		if (level != 0)
			warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
		if (piflevel != 0)
			warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
	}
	closetoken();
}