/** * 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); }
/* * normalize: normalize path name * * i) path path name * i) root root of project (must be end with a '/') * i) cwd current directory * o) result normalized path name * i) size size of the result * r) ==NULL: error * !=NULL: result */ char * normalize(const char *path, const char *root, const char *cwd, char *result, const int size) { char *p, abs[MAXPATHLEN]; if (normalize_pathname(path, result, size) == NULL) goto toolong; if (isabspath(path)) { if (strlen(result) > MAXPATHLEN) goto toolong; strcpy(abs, result); } else { if (rel2abs(result, cwd, abs, sizeof(abs)) == NULL) goto toolong; } /* * Remove the root part of path and insert './'. * rootdir /a/b/ * path /a/b/c/d.c -> c/d.c -> ./c/d.c */ p = locatestring(abs, root, MATCH_AT_FIRST); if (p == NULL) return NULL; strlimcpy(result, "./", size); strlimcpy(result + 2, p, size - 2); return result; toolong: die("path name is too long."); }
/** * 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; }
/* * 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(); }
/* * 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; }
/* * locate_HTMLdir: locate HTML directory made by htags(1). * * r) HTML directory */ static const char * locate_HTMLdir(void) { static char htmldir[MAXPATHLEN]; if (test("d", makepath(dbpath, "HTML", NULL))) strlimcpy(htmldir, makepath(dbpath, "HTML", NULL), sizeof(htmldir)); else if (test("d", makepath(root, "HTML", NULL))) strlimcpy(htmldir, makepath(root, "HTML", NULL), sizeof(htmldir)); else if (test("d", makepath(root, "html/HTML", NULL))) /* Doxygen makes HTML in doxygen's html directory. */ strlimcpy(htmldir, makepath(root, "html/HTML", NULL), sizeof(htmldir)); else return NULL; if (vflag) fprintf(stdout, "HTML directory '%s'.\n", htmldir); return (const char *)htmldir; }
/* * Get global(1)'s path. */ static void get_global_path(void) { const char *p; if (!(p = usable("global"))) die("global command required but not found."); strlimcpy(global_path, p, sizeof(global_path)); }
/* * find_open_filelist: find_open like interface for handling output of find(1). * * i) filename file including list of file names. * When "-" is specified, read from standard input. * i) root root directory of source tree */ void find_open_filelist(const char *filename, const char *root) { assert(find_mode == 0); find_mode = FILELIST_OPEN; /* * This is temporary measures. It doesn't decide how to become final. */ if (getenv("GTAGSALLOWBLANK")) allow_blank = 1; if (!strcmp(filename, "-")) { /* * If the filename is '-', copy standard input onto * temporary file to be able to read repeatedly. */ if (temp == NULL) { char buf[MAXPATHLEN]; temp = tmpfile(); while (fgets(buf, sizeof(buf), stdin) != NULL) fputs(buf, temp); } rewind(temp); ip = temp; } else { ip = fopen(filename, "r"); if (ip == NULL) die("cannot open '%s'.", filename); } /* * rootdir always ends with '/'. */ if (!strcmp(root+ROOT, "/")) strlimcpy(rootdir, root, sizeof(rootdir)); else snprintf(rootdir, sizeof(rootdir), "%s/", root); strlimcpy(cwddir, root, sizeof(cwddir)); /* * prepare regular expressions. */ prepare_skip(); prepare_source(); }
/** * save path infomation */ void save_current_path(const char *path) { char *startp, *p; strlimcpy(current_path, path, sizeof(current_path)); /* Extract directory name and file name from path */ strlimcpy(current_dir, path, sizeof(current_path)); startp = current_dir; p = startp + strlen(current_dir); while (p > startp) { if (*--p == '/') { *p = '\0'; strlimcpy(current_file, p + 1, sizeof(current_file)); return; } } /* It seems that the path doesn't include '/' */ strlimcpy(current_file, path, sizeof(current_file)); }
/** * is_defined_in_GTAGS: whether or not the name is defined in #GTAGS. * * @param[in] gtop * @param[in] name tag name * @return 0: not defined, 1: defined * * @note It is assumed that the input stream is sorted by the tag name. */ static int is_defined_in_GTAGS(GTOP *gtop, const char *name) { static char prev_name[MAXTOKEN+1]; static int prev_result; if (!strcmp(name, prev_name)) return prev_result; strlimcpy(prev_name, name, sizeof(prev_name)); return prev_result = dbop_get(gtop->gtags, prev_name) ? 1 : 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); }
/** * dbop_next: get next record. * * @param[in] dbop dbop descripter * @return data or NULL * * [Note] dbop_next() always skip meta records. */ const char * dbop_next(DBOP *dbop) { DB *db = dbop->db; int flags = dbop->ioflags; DBT key, dat; int status; if (dbop->unread) { dbop->unread = 0; return dbop->lastdat; } #ifdef USE_SQLITE3 if (dbop->openflags & DBOP_SQLITE3) return dbop3_next(dbop); #endif while ((status = (*db->seq)(db, &key, &dat, R_NEXT)) == RET_SUCCESS) { dbop->readcount++; assert(dat.data != NULL); /* skip meta records */ if (!(dbop->openflags & DBOP_RAW)) { if (flags & DBOP_KEY && ismeta(key.data)) continue; else if (ismeta(dat.data)) continue; } if (flags & DBOP_KEY) { if (!strcmp(dbop->prev, (char *)key.data)) continue; if (strlen((char *)key.data) > MAXKEYLEN) die("primary key too long."); strlimcpy(dbop->prev, (char *)key.data, sizeof(dbop->prev)); } dbop->lastdat = (char *)dat.data; dbop->lastsize = dat.size; dbop->lastkey = (char *)key.data; dbop->lastkeysize = key.size; if (flags & DBOP_PREFIX) { if (strncmp((char *)key.data, dbop->key, dbop->keylen)) return NULL; } else if (dbop->keylen) { if (strcmp((char *)key.data, dbop->key)) return NULL; } if (dbop->preg && regexec(dbop->preg, (char *)key.data, 0, 0, 0) != 0) continue; return (flags & DBOP_KEY) ? (char *)key.data : (char *)dat.data; } if (status == RET_ERROR) die("dbop_next failed."); return NULL; }
/** * basic check. */ static void basic_check(void) { const char *p; /* * COMMAND EXISTENCE CHECK */ if (!(p = usable("gtags"))) die("gtags command required but not found."); strlimcpy(gtags_path, p, sizeof(gtags_path)); if (!(p = usable("global"))) die("global command required but not found."); strlimcpy(global_path, p, sizeof(global_path)); /* * Temporary directory. */ if ((p = getenv("TMPDIR")) == NULL) p = getenv("TMP"); if (p != NULL && test("d", p)) tmpdir = p; }
/** * get the current directory */ char * vgetcwd(char *buf, size_t size) { char *p; if (getenv("GTAGSLOGICALPATH")) { if ((p = getenv("PWD")) != NULL) { strlimcpy(buf, p, size); return buf; } } if (getcwd(buf, size) != NULL) return buf; return NULL; }
/** * @details * normalize: normalize path name * * @param[in] path path name * @param[in] root root of project (@STRONG{must be end with a '/'}) * @param[in] cwd current directory * @param[out] result normalized path name * @param[in] size size of the @a result * @return ==NULL: error <br> * !=NULL: @a result * * @note Calls die() if the result path name is too long (#MAXPATHLEN). */ char * normalize(const char *path, const char *root, const char *cwd, char *result, const int size) { char *p, abs[MAXPATHLEN]; if (normalize_pathname(path, result, size) == NULL) goto toolong; if (isabspath(path)) { if (strlen(result) > MAXPATHLEN) goto toolong; strcpy(abs, result); } else { if (rel2abs(result, cwd, abs, sizeof(abs)) == NULL) goto toolong; } /* * Remove the root part of path and insert './'. * rootdir /a/b/ * path /a/b/c/d.c -> c/d.c -> ./c/d.c */ p = locatestring(abs, root, MATCH_AT_FIRST); if (p == NULL) { p = locatestring(root, abs, MATCH_AT_FIRST); /* * abs == /usr/src should be considered to be equal to root == /usr/src/. */ if (p && !strcmp(p, "/")) result[0] = '\0'; else return NULL; } strlimcpy(result, "./", size); strlimcpy(result + 2, p, size - 2); return result; toolong: die("path name is too long."); }
/** * dbop_getoption: get option */ const char * dbop_getoption(DBOP *dbop, const char *key) { static char buf[1024]; const char *p; if ((p = dbop_get(dbop, key)) == NULL) return NULL; if (dbop->lastsize < strlen(key)) die("invalid format (dbop_getoption)."); for (p += strlen(key); *p && isspace((unsigned char)*p); p++) ; strlimcpy(buf, p, sizeof(buf)); return buf; }
/** * 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; }
/** * literal_comple: compile literal for search. * * @param[in] pat literal string * * Literal string is treated as is. */ void literal_comple(const char *pat) { /* * convert spaces into %FF format. */ encode(encoded_pattern, sizeof(encoded_pattern), pat); strlimcpy(pattern, pat, sizeof(pattern)); /* * construct a goto table. */ cgotofn(pattern); /* * construct fail links. */ cfail(); }
/** * get_prefix: get as long prefix of the pattern as possible. * * @param[in] pattern * @param[in] flags for gtags_first() * @return prefix for search */ static char * get_prefix(const char *pattern, int flags) { static char buffer[IDENTLEN]; char *prefix = buffer; if (pattern == NULL || pattern[0] == 0) { prefix = NULL; } else if (!isregex(pattern)) { if (flags & GTOP_IGNORECASE) { buffer[0] = toupper(*pattern); buffer[1] = 0; } else { prefix = NULL; } } else if (*pattern == '^') { int save = 0; char *p = (char *)(pattern + 1); char *q = locatestring(p, ".*$", MATCH_AT_LAST); if (!q) q = locatestring(pattern, "$", MATCH_AT_LAST); if (!q) q = locatestring(pattern, ".*", MATCH_AT_LAST); if (q) { save = *q; *q = 0; } if (*p == 0 || isregex(p)) { prefix = NULL; } else { if (flags & GTOP_IGNORECASE) { prefix[0] = toupper(*p); prefix[1] = 0; } else strlimcpy(buffer, p, sizeof(buffer)); } if (save) *q = save; } return prefix; }
/** * realpath: get the complete path */ char * realpath(const char *in_path, char *out_path) { #ifdef __DJGPP__ /* * I don't use _fixpath or _truename in LFN because neither guarantee * a complete long name. This is mainly DOS's fault, since the cwd can * be a mixture of long and short components. */ if (_USE_LFN) { strlimcpy(out_path, in_path, MAXPATHLEN); canonpath(out_path); } else _fixpath(in_path, out_path); #else _fullpath(out_path, in_path, MAXPATHLEN); canonpath(out_path); #endif return out_path; }
/** * make directory in the dist (distpath) directory. * * @param[in] name name of directory to create. * * Creates a file called "index.html" in the new directory. * * mkdir() creates the directory in mode 0775, if doesn't exist. */ static void make_directory_in_distpath(const char *name) { char path[MAXPATHLEN]; FILE *op; strlimcpy(path, makepath(distpath, name, NULL), sizeof(path)); if (!test("d", path)) if (mkdir(path, 0775)) die("cannot make directory '%s'.", path); /* * Not to publish the directory list. */ op = fopen(makepath(path, "index.html", NULL), "w"); if (op == NULL) die("cannot make file '%s'.", makepath(path, "index.html", NULL)); fputs(html_begin, op); fputs(html_end, op); fputc('\n', op); fclose(op); }
/* * setup two internal tables for abbreviation. * * i) abbrev abbreviation string */ void abbrev_open(const char *abbrev) { int i, limit; struct abbrmap *ab; char *p; /* * abbrev string: "ddefine ttypedef" */ /* copy abbrev string to static area */ strlimcpy(abbrev_string, abbrev, sizeof(abbrev_string)); p = abbrev_string; /* initialize ab2name table */ limit = sizeof(ab2name) / sizeof(struct abbrmap); for (i = 0; i < limit; i++) { ab2name[i].c = 0; ab2name[i].name = NULL; } name2ab = varray_open(sizeof(struct abbrmap), 5); while (*p) { ab = (struct abbrmap *)varray_append(name2ab); ab->c = *p++; ab->name = p; for (; *p && *p != ' '; p++) ; if (*p == ' ') *p++ = '\0'; ab->length = strlen(ab->name); if (ab->c < 'a' || ab->c > 'z') die("Abbrev character must be a lower alphabetic character. (%s)", abbrev); i = ab->c - 'a'; ab2name[i].c = ab->c; ab2name[i].name = ab->name; ab2name[i].length = ab->length; } }
/* * now: current date and time * * r) date and time */ const char * now(void) { static char buf[128]; #ifdef HAVE_STRFTIME time_t tval; if (time(&tval) == -1) die("cannot get current time."); (void)strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Z %Y", localtime(&tval)); #else FILE *ip; strlimcpy(buf, "unknown time", sizeof(buf)); if ((ip = popen("date", "r")) != NULL) { if (fgets(buf, sizeof(buf), ip)) buf[strlen(buf) - 1] = 0; pclose(ip); } #endif return buf; }
/** * @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(); }
/** * function_definition: return if function definition or not. * * @param param * @param[out] arg1 the first argument * @return target type */ static int function_definition(const struct parser_param *param, char arg1[MAXTOKEN]) { int c; int brace_level, isdefine; int accept_arg1 = 0; brace_level = isdefine = 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 == '('/* ) */) brace_level++; else if (c == /* ( */')') { if (--brace_level == 0) break; } /* pick up symbol */ if (c == SYMBOL) { if (accept_arg1 == 0) { accept_arg1 = 1; strlimcpy(arg1, token, MAXTOKEN); } PUT(PARSER_REF_SYM, token, lineno, sp); } } if (c == EOF) return 0; brace_level = 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; case C___ATTRIBUTE__: process_attribute(param); continue; default: break; } if (c == '('/* ) */ || c == '[') brace_level++; else if (c == /* ( */')' || c == ']') brace_level--; else if (brace_level == 0 && ((c == SYMBOL && strcmp(token, "__THROW")) || IS_RESERVED_WORD(c))) isdefine = 1; else if (c == ';' || c == ',') { if (!isdefine) break; } else if (c == '{' /* } */) { pushbacktoken(); return 1; } else if (c == /* { */'}') break; else if (c == '=') break; /* pick up symbol */ if (c == SYMBOL) PUT(PARSER_REF_SYM, token, lineno, sp); } return 0; }
/** * gtags_open: open global tag. * * @param[in] dbpath dbpath directory * @param[in] root root directory (needed when compact format) * @param[in] db #GTAGS, #GRTAGS, #GSYMS * @param[in] mode #GTAGS_READ: read only <br> * #GTAGS_CREATE: create tag <br> * #GTAGS_MODIFY: modify tag * @param[in] flags #GTAGS_COMPACT: compact format * @return #GTOP structure * * @note when error occurred, @NAME{gtags_open()} doesn't return. */ GTOP * gtags_open(const char *dbpath, const char *root, int db, int mode, int flags) { GTOP *gtop; char tagfile[MAXPATHLEN]; int dbmode; gtop = (GTOP *)check_calloc(sizeof(GTOP), 1); gtop->db = db; gtop->mode = mode; gtop->openflags = flags; /* * Open tag file allowing duplicate records. */ switch (gtop->mode) { case GTAGS_READ: dbmode = 0; break; case GTAGS_CREATE: dbmode = 1; break; case GTAGS_MODIFY: dbmode = 2; break; default: assert(0); } /* * GRTAGS and GSYMS are virtual tag file. They are included in a real GRTAGS file. * In fact, GSYMS doesn't exist now. * * GRTAGS: tags which belongs to GRTAGS, and are defined in GTAGS. * GSYMS: tags which belongs to GRTAGS, and is not defined in GTAGS. */ strlimcpy(tagfile, makepath(dbpath, dbname(db == GSYMS ? GRTAGS : db), NULL), sizeof(tagfile)); gtop->dbop = dbop_open(tagfile, dbmode, 0644, DBOP_DUP|DBOP_SORTED_WRITE); if (gtop->dbop == NULL) { if (dbmode == 1) die("cannot make %s.", dbname(db)); die("%s not found.", dbname(db)); } if (gtop->mode == GTAGS_READ && db != GTAGS) { const char *gtags = makepath(dbpath, dbname(GTAGS), NULL); int format_version; gtop->gtags = dbop_open(gtags, 0, 0, 0); if (gtop->gtags == NULL) die("GTAGS not found."); format_version = dbop_getversion(gtop->dbop); if (format_version > upper_bound_version) die("%s seems new format. Please install the latest GLOBAL.", gtags); else if (format_version < lower_bound_version) die("%s seems older format. Please remake tag files.", gtags); } if (gtop->mode == GTAGS_CREATE) { /* * Decide format. */ gtop->format = 0; gtop->format_version = new_format_version; /* * GRTAGS and GSYSM always use compact format. * GTAGS uses compact format only when the -c option specified. */ if (gtop->db == GRTAGS || gtop->db == GSYMS || gtop->openflags & GTAGS_COMPACT) { gtop->format |= GTAGS_COMPACT; gtop->format |= GTAGS_COMPLINE; } else { /* standard format */ gtop->format |= GTAGS_COMPRESS; } gtop->format |= GTAGS_COMPNAME; if (gtop->format & GTAGS_COMPACT) dbop_putoption(gtop->dbop, COMPACTKEY, NULL); if (gtop->format & GTAGS_COMPRESS) { dbop_putoption(gtop->dbop, COMPRESSKEY, DEFAULT_ABBREVIATION); abbrev_open(DEFAULT_ABBREVIATION); } if (gtop->format & GTAGS_COMPLINE) dbop_putoption(gtop->dbop, COMPLINEKEY, NULL); if (gtop->format & GTAGS_COMPNAME) dbop_putoption(gtop->dbop, COMPNAMEKEY, NULL); dbop_putversion(gtop->dbop, gtop->format_version); } 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; /* * check format version. */ gtop->format_version = dbop_getversion(gtop->dbop); if (gtop->format_version > upper_bound_version) die("%s seems new format. Please install the latest GLOBAL.", tagfile); else if (gtop->format_version < lower_bound_version) die("%s seems older format. Please remake tag files.", tagfile); gtop->format = 0; if (dbop_getoption(gtop->dbop, COMPACTKEY) != NULL) gtop->format |= GTAGS_COMPACT; if ((p = dbop_getoption(gtop->dbop, COMPRESSKEY)) != NULL) { abbrev_open(p); gtop->format |= GTAGS_COMPRESS; } if (dbop_getoption(gtop->dbop, COMPLINEKEY) != NULL) gtop->format |= GTAGS_COMPLINE; if (dbop_getoption(gtop->dbop, COMPNAMEKEY) != NULL) gtop->format |= GTAGS_COMPNAME; } if (gpath_open(dbpath, dbmode) < 0) { if (dbmode == 1) die("cannot create GPATH."); else die("GPATH not found."); } if (gtop->mode != GTAGS_READ) gtop->sb = strbuf_open(0); /* This buffer is used for working area. */ /* * 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->path_hash = strhash_open(HASHBUCKETS); } return gtop; }
/* * Make duplicate object index. * * If referred tag is only one, direct link which points the tag is generated. * Else if two or more tag exists, indirect link which points the tag list * is generated. */ int makedupindex(void) { STRBUF *sb = strbuf_open(0); STRBUF *tmp = strbuf_open(0); STRBUF *command = strbuf_open(0); int definition_count = 0; char srcdir[MAXPATHLEN]; int db; FILEOP *fileop = NULL; FILE *op = NULL; FILE *ip = NULL; snprintf(srcdir, sizeof(srcdir), "../%s", SRCS); for (db = GTAGS; db < GTAGLIM; db++) { const char *kind = kinds[db]; const char *option = options[db]; int writing = 0; int count = 0; int entry_count = 0; const char *ctags_xid, *ctags_x; char tag[IDENTLEN], prev[IDENTLEN], first_line[MAXBUFLEN]; if (gtags_exist[db] == 0) continue; prev[0] = 0; first_line[0] = 0; /* * construct command line. */ strbuf_reset(command); strbuf_sprintf(command, "%s -x%s --result=ctags-xid --encode-path=\" \t\" --nofilter=path", quote_shell(global_path), option); /* * Optimization when the --dynamic option is specified. */ if (dynamic) { strbuf_puts(command, " --nosource"); if (db != GSYMS) strbuf_puts(command, " --nofilter=sort"); } strbuf_puts(command, " \".*\""); if ((ip = popen(strbuf_value(command), "r")) == NULL) die("cannot execute command '%s'.", strbuf_value(command)); while ((ctags_xid = strbuf_fgets(sb, ip, STRBUF_NOCRLF)) != NULL) { char fid[MAXFIDLEN]; ctags_x = parse_xid(ctags_xid, fid, NULL); /* tag name */ (void)strcpy_withterm(tag, ctags_x, sizeof(tag), ' '); if (strcmp(prev, tag)) { count++; if (vflag) fprintf(stderr, " [%d] adding %s %s\n", count, kind, tag); if (writing) { if (!dynamic) { fputs_nl(gen_list_end(), op); fputs_nl(body_end, op); fputs_nl(gen_page_end(), op); close_file(fileop); html_count++; } writing = 0; /* * cache record: " <fid>\0<entry number>\0" */ strbuf_reset(tmp); strbuf_putc(tmp, ' '); strbuf_putn(tmp, count - 1); strbuf_putc(tmp, '\0'); strbuf_putn(tmp, entry_count); cache_put(db, prev, strbuf_value(tmp), strbuf_getlen(tmp) + 1); } /* single entry */ if (first_line[0]) { char fid[MAXFIDLEN]; const char *ctags_x = parse_xid(first_line, fid, NULL); const char *lno = nextelement(ctags_x); strbuf_reset(tmp); strbuf_puts_withterm(tmp, lno, ' '); strbuf_putc(tmp, '\0'); strbuf_puts(tmp, fid); cache_put(db, prev, strbuf_value(tmp), strbuf_getlen(tmp) + 1); } /* * Chop the tail of the line. It is not important. * strlimcpy(first_line, ctags_x, sizeof(first_line)); */ strncpy(first_line, ctags_xid, sizeof(first_line)); first_line[sizeof(first_line) - 1] = '\0'; strlimcpy(prev, tag, sizeof(prev)); entry_count = 0; } else { /* duplicate entry */ if (first_line[0]) { char fid[MAXFIDLEN]; const char *ctags_x = parse_xid(first_line, fid, NULL); if (!dynamic) { char path[MAXPATHLEN]; snprintf(path, sizeof(path), "%s/%s/%d.%s", distpath, dirs[db], count, HTML); fileop = open_output_file(path, cflag); op = get_descripter(fileop); fputs_nl(gen_page_begin(tag, SUBDIR), op); fputs_nl(body_begin, op); fputs_nl(gen_list_begin(), op); fputs_nl(gen_list_body(srcdir, ctags_x, fid), op); } writing = 1; entry_count++; first_line[0] = 0; } if (!dynamic) { fputs_nl(gen_list_body(srcdir, ctags_x, fid), op); } entry_count++; } } if (db == GTAGS) definition_count = count; if (pclose(ip) != 0) die("'%s' failed.", strbuf_value(command)); if (writing) { if (!dynamic) { fputs_nl(gen_list_end(), op); fputs_nl(body_end, op); fputs_nl(gen_page_end(), op); close_file(fileop); html_count++; } /* * cache record: " <fid>\0<entry number>\0" */ strbuf_reset(tmp); strbuf_putc(tmp, ' '); strbuf_putn(tmp, count); strbuf_putc(tmp, '\0'); strbuf_putn(tmp, entry_count); cache_put(db, prev, strbuf_value(tmp), strbuf_getlen(tmp) + 1); } if (first_line[0]) { char fid[MAXFIDLEN]; const char *ctags_x = parse_xid(first_line, fid, NULL); const char *lno = nextelement(ctags_x); strbuf_reset(tmp); strbuf_puts_withterm(tmp, lno, ' '); strbuf_putc(tmp, '\0'); strbuf_puts(tmp, fid); cache_put(db, prev, strbuf_value(tmp), strbuf_getlen(tmp) + 1); } } strbuf_close(sb); strbuf_close(tmp); strbuf_close(command); return definition_count; }
/** * Generate list body. * * @NAME{ctags_x} with the @CODE{--encode-path=\" \\t\"} */ const char * gen_list_body(const char *srcdir, const char *ctags_x, const char *fid) /* virtually const */ { STATIC_STRBUF(sb); char path[MAXPATHLEN]; const char *p; SPLIT ptable; strbuf_clear(sb); if (split((char *)ctags_x, 4, &ptable) < 4) { recover(&ptable); die("too small number of parts in list_body().\n'%s'", ctags_x); } strlimcpy(path, decode_path(ptable.part[PART_PATH].start + 2), sizeof(path)); if (fid == NULL) fid = path2fid(path); if (table_list) { strbuf_puts(sb, current_row_begin); if (enable_xhtml) { strbuf_puts(sb, "<td class='tag'>"); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); strbuf_sprintf(sb, "</td><td class='line'>%s</td><td class='file'>%s</td><td class='code'>", ptable.part[PART_LNO].start, path); } else { strbuf_puts(sb, "<td nowrap='nowrap'>"); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); strbuf_sprintf(sb, "</td><td nowrap='nowrap' align='right'>%s</td>" "<td nowrap='nowrap' align='left'>%s</td><td nowrap='nowrap'>", ptable.part[PART_LNO].start, path); } for (p = ptable.part[PART_LINE].start; *p; p++) { unsigned char c = *p; if (c == '&') strbuf_puts(sb, quote_amp); else if (c == '<') strbuf_puts(sb, quote_little); else if (c == '>') strbuf_puts(sb, quote_great); else if (c == ' ') strbuf_puts(sb, quote_space); else if (c == '\t') { strbuf_puts(sb, quote_space); strbuf_puts(sb, quote_space); } else strbuf_putc(sb, c); } strbuf_puts(sb, "</td>"); strbuf_puts(sb, current_row_end); recover(&ptable); } else { /* print tag name with anchor */ strbuf_puts(sb, current_line_begin); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); recover(&ptable); /* print line number */ for (p = ptable.part[PART_TAG].end; p < ptable.part[PART_PATH].start; p++) strbuf_putc(sb, *p); /* print file name */ strbuf_puts(sb, path); /* print the rest */ for (p = ptable.part[PART_PATH].end; *p; p++) { unsigned char c = *p; if (c == '&') strbuf_puts(sb, quote_amp); else if (c == '<') strbuf_puts(sb, quote_little); else if (c == '>') strbuf_puts(sb, quote_great); else strbuf_putc(sb, c); } strbuf_puts(sb, current_line_end); } return strbuf_value(sb); }
int nexttoken(const char *interested, int (*reserved)(const char *, int)) { int c; char *p; int sharp = 0; int percent = 0; /* check push back buffer */ if (ptok[0]) { strlimcpy(token, ptok, sizeof(token)); ptok[0] = '\0'; return lasttok; } for (;;) { /* skip spaces */ if (!crflag) while ((c = nextchar()) != EOF && isspace(c)) ; else while ((c = nextchar()) != EOF && isspace(c) && c != '\n') ; if (c == EOF || c == '\n') break; if (c == '"' || c == '\'') { /* quoted string */ int quote = c; while ((c = nextchar()) != EOF) { if (c == quote) break; if (quote == '\'' && c == '\n') break; if (c == '\\' && (c = nextchar()) == EOF) break; } } else if (c == '/') { /* comment */ if ((c = nextchar()) == '/') { while ((c = nextchar()) != EOF) if (c == '\n') { pushbackchar(); break; } } else if (c == '*') { while ((c = nextchar()) != EOF) { if (c == '*') { if ((c = nextchar()) == '/') break; pushbackchar(); } } } else pushbackchar(); } else if (c == '\\') { if (nextchar() == '\n') continued_line = 1; } else if (isdigit(c)) { /* digit */ while ((c = nextchar()) != EOF && (c == '.' || isalnum(c))) ; pushbackchar(); } else if (c == '#' && cmode) { /* recognize '##' as a token if it is reserved word. */ if (peekc(1) == '#') { p = token; *p++ = c; *p++ = nextchar(); *p = 0; if (reserved && (c = (*reserved)(token, tlen)) == 0) break; } else if (!continued_line && atfirst_exceptspace()) { sharp = 1; continue; } } else if (c == ':' && cppmode) { if (peekc(1) == ':') { p = token; *p++ = c; *p++ = nextchar(); *p = 0; if (reserved && (c = (*reserved)(token, tlen)) == 0) break; } } else if (c == '%' && ymode) { /* recognize '%%' as a token if it is reserved word. */ if (atfirst) { p = token; *p++ = c; if ((c = peekc(1)) == '%' || c == '{' || c == '}') { *p++ = nextchar(); *p = 0; if (reserved && (c = (*reserved)(token, tlen)) != 0) break; } else if (!isspace(c)) { percent = 1; continue; } } } else if (c & 0x80 || isalpha(c) || c == '_') {/* symbol */ p = token; if (sharp) { sharp = 0; *p++ = '#'; } else if (percent) { percent = 0; *p++ = '%'; } else if (c == 'L') { int tmp = peekc(1); if (tmp == '\"' || tmp == '\'') continue; } for (*p++ = c; (c = nextchar()) != EOF && (c & 0x80 || isalnum(c) || c == '_');) { if (tlen < sizeof(token)) *p++ = c; } if (tlen == sizeof(token)) { warning("symbol name is too long. (Ignored)[+%d %s]", lineno, curfile); continue; } *p = 0; if (c != EOF) pushbackchar(); /* convert token string into token number */ c = SYMBOL; if (reserved) c = (*reserved)(token, tlen); break; } else { /* special char */ if (interested == NULL || strchr(interested, c)) break; /* otherwise ignore it */ } sharp = percent = 0; } return lasttok = c; }
/** * pushbacktoken: push back token * * following nexttoken() return same token again. */ void pushbacktoken(void) { strlimcpy(ptok, token, sizeof(ptok)); }