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); }
/* * 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); }
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); }
/** * 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; }
/* * 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(); }
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; }
/* * 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; }
/** * 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); } }
/** * 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); }
/* * 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); }
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--; }
/* * 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); }
/** * 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; }
/** * 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); }
/** * 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; }
/** * 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); }
/* * 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); } }
/** * 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; }
/** * 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); }
/** * 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; }
/** * 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); }
/* * 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); }
/** * 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 }
/* * 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; }
/** * 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; }
/** * 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; */ }
/** * 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); }
/** * 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); }
/* * 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; }
/** * @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(); }