static strbuf inline _overrun_quote(strbuf sb, char quote, const char *suffix) { if (strbuf_overrun(sb)) { strbuf_trunc(sb, -strlen(suffix) - 1); strbuf_putc(sb, quote); strbuf_puts(sb, suffix); } return sb; }
void logArgv(int level, struct __sourceloc where, const char *label, int argc, const char *const *argv) { if (_log_prepare(level, where)) { if (label) { strbuf_puts(&logbuf, label); strbuf_putc(&logbuf, ' '); } int i; for (i = 0; i < argc; ++i) { if (i) strbuf_putc(&logbuf, ' '); if (argv[i]) strbuf_toprint_quoted(&logbuf, "\"\"", argv[i]); else strbuf_puts(&logbuf, "NULL"); } _log_finish(level); } }
/** * append @CODE{'/'} after the path name * * @param[in] path path name * @return appended path name * * @note Doesn't check if ends with a @CODE{'/'} already. * * @par Examples: * @code * appendslash("a") => "a/" * @endcode */ static const char * appendslash(const char *path) { STATIC_STRBUF(sb); strbuf_clear(sb); strbuf_puts(sb, path); strbuf_putc(sb, '/'); return strbuf_value(sb); }
/* * makefileurl: make url which start with 'file:'. * * i) path path name (absolute) * i) line !=0: line number * o) url URL * * makefileurl('/dir/a.html', 10) => 'file:///dir/a.html#L10' * * (Windows32 environment) * makefileurl('c:/dir/a.html', 10) => 'file://c|/dir/a.html#L10' */ void makefileurl(const char *path, int line, STRBUF *url) { strbuf_puts(url, "file://"); #if _WIN32 || __DJGPP__ /* * copy drive name. (c: -> c|) */ if (isalpha(*path) && *(path+1) == ':') { strbuf_putc(url, *path); strbuf_putc(url, '|'); path += 2; } #endif strbuf_puts(url, path); if (line) { strbuf_puts(url, "#L"); strbuf_putn(url, line); } }
/** * print file name. * * @param[in] level 0,1,2... * @param[in] path path of the file */ static const char * print_file_name(int level, const char *path) { STATIC_STRBUF(sb); char *target = (Fflag) ? "mains" : "_top"; int size = filesize(path); char tips[80]; message(" [%d] adding %s", ++src_count, removedotslash(path)); /* * We assume the file which has one of the following suffixes * as a candidate of include file. * * C: .h * C++: .hxx, .hpp, .H, .hh * PHP: .inc.php */ if (regexec(&is_include_file, path, 0, 0, 0) == 0) put_inc(lastpart(path), path, src_count); strbuf_clear(sb); if (table_flist) strbuf_puts(sb, fitem_begin); else if (!no_order_list) strbuf_puts(sb, item_begin); if (size > 1) snprintf(tips, sizeof(tips), "%s bytes", insert_comma(size)); else snprintf(tips, sizeof(tips), "%s byte", insert_comma(size)); strbuf_puts(sb, gen_href_begin_with_title_target(level == 0 ? SRCS: upperdir(SRCS), path2fid(path), HTML, NULL, tips, target)); if (Iflag) { const char *lang, *suffix, *text_icon; if ((suffix = locatestring(path, ".", MATCH_LAST)) != NULL && (lang = decide_lang(suffix)) != NULL && (strcmp(lang, "c") == 0 || strcmp(lang, "cpp") == 0 || strcmp(lang, "yacc") == 0)) text_icon = c_icon; else text_icon = file_icon; strbuf_puts(sb, gen_image(level == 0 ? CURRENT : PARENT, text_icon, removedotslash(path))); strbuf_puts(sb, quote_space); } strbuf_puts(sb, full_path ? removedotslash(path) : lastpart(path)); strbuf_puts(sb, gen_href_end()); if (table_flist) strbuf_puts(sb, fitem_end); else if (!no_order_list) strbuf_puts(sb, item_end); else strbuf_puts(sb, br); strbuf_putc(sb, '\n'); return (const char *)strbuf_value(sb); }
strbuf strbuf_append_poll_events(strbuf sb, short events) { static struct { short flags; const char *name; } symbols[] = { { POLLIN, "IN" }, { POLLPRI, "PRI" }, { POLLOUT, "OUT" }, { POLLERR, "ERR" }, { POLLHUP, "HUP" }, { POLLNVAL, "NVAL" }, { POLLRDNORM, "RDNORM" }, { POLLRDBAND, "RDBAND" }, #ifdef POLLWRNORM { POLLWRNORM, "WRNORM" }, #endif #ifdef POLLWRBAND { POLLWRBAND, "WRBAND" }, #endif #ifdef POLLMSG { POLLMSG, "MSG" }, #endif #ifdef POLLREMOVE { POLLREMOVE, "REMOVE" }, #endif #ifdef POLLRDHUP { POLLRDHUP, "RDHUP" }, #endif { 0, NULL } }, *sp; int n = 0; for (sp = symbols; sp->name; ++sp) { if (events & sp->flags) { if (n) strbuf_putc(sb, '|'); strbuf_puts(sb, sp->name); ++n; } } if (!n) strbuf_putc(sb, '0'); return sb; }
/* * convertpath: convert source file into hypertext path. * * i) dbpath dbpath * i) htmldir HTML directory made by htags(1) * i) path source file path * o) sb string buffer * r) 0: normal, -1: error */ int convertpath(const char *dbpath, const char *htmldir, const char *path, STRBUF *sb) { static const char *suffix[] = {".html", ".htm"}; static const char *gz = ".gz"; int i, lim = sizeof(suffix)/sizeof(char *); const char *p; strbuf_reset(sb); strbuf_puts(sb, htmldir); strbuf_puts(sb, "/S/"); /* * new style. */ if (gpath_open(dbpath, 0) == 0) { int tag1 = strbuf_getlen(sb); p = gpath_path2fid(path, NULL); if (p == NULL) { gpath_close(); return -1; } gpath_close(); strbuf_puts(sb, p); for (i = 0; i < lim; i++) { int tag2 = strbuf_getlen(sb); strbuf_puts(sb, suffix[i]); if (test("f", strbuf_value(sb))) return 0; strbuf_puts(sb, gz); if (test("f", strbuf_value(sb))) return 0; strbuf_setlen(sb, tag2); } strbuf_setlen(sb, tag1); } /* * old style. */ for (p = path + 1; *p; p++) strbuf_putc(sb, (*p == '/') ? ' ' : *p); for (i = 0; i < lim; i++) { int tag = strbuf_getlen(sb); strbuf_puts(sb, suffix[i]); if (test("f", strbuf_value(sb))) return 0; strbuf_puts(sb, gz); if (test("f", strbuf_value(sb))) return 0; strbuf_setlen(sb, tag); } return -1; }
/* * decode_path: decode encoded path name. * * i) path encoded path name * r) decoded path name */ char * decode_path(const unsigned char *path) { STATIC_STRBUF(sb); const unsigned char *p; if (strchr((const char *)path, '%') == NULL) return (char *)path; strbuf_clear(sb); for (p = path; *p; p++) { if (*p == '%') { unsigned char c1, c2; c1 = *++p; c2 = *++p; if (outofrange(c1) || outofrange(c2)) die("decode_path: unexpected character. (%%%c%c)", c1, c2); strbuf_putc(sb, h2int(c1) * 16 + h2int(c2)); } else strbuf_putc(sb, *p); } return strbuf_value(sb); }
/* * Update tag files. */ static void update(void) { STATIC_STRBUF(command); strbuf_clear(command); strbuf_sprintf(command, "%s -u", global_path); if (vflag) { strbuf_putc(command, 'v'); fprintf(stderr, "gscope: %s\n", strbuf_value(command)); } system(strbuf_value(command)); }
/** * 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; }
/** * strtrim: make string from original string with deleting blanks. * * @param[in] p original string. * @param[in] flag TRIM_HEAD: from only head, * TRIM_TAIL: from only tail, * TRIM_BOTH: from head and tail, * TRIM_ALL: from all * @param[out] len length of result string, * if len == NULL then nothing returned. * @return result string * * Usage: * strtrim(" # define ", TRIM_HEAD, NULL) => "# define " * strtrim(" # define ", TRIM_TAIL, NULL) => " # define" * strtrim(" # define ", TRIM_BOTH, NULL) => "# define" * strtrim(" # define ", TRIM_ALL, NULL) => "#define" * * [Note] The result string area is function local. So, following call * to this function may destroy the area. */ const char * strtrim(const char *p, int flag, int *len) { STATIC_STRBUF(sb); int cut_off = -1; strbuf_clear(sb); /* * Delete blanks of the head. */ if (flag != TRIM_TAIL) SKIP_BLANKS(p); /* * Copy string. */ for (; *p; p++) { if (isspace(*p)) { if (flag != TRIM_ALL) { if (cut_off == -1 && flag != TRIM_HEAD) cut_off = strbuf_getlen(sb); strbuf_putc(sb,*p); } } else { strbuf_putc(sb,*p); cut_off = -1; } } /* * Delete blanks of the tail. */ if (cut_off != -1) strbuf_setlen(sb, cut_off); if (len) *len = strbuf_getlen(sb); return strbuf_value(sb); }
// Convert an inline list to HTML. Returns 0 on success, and sets result. static void inlines_to_plain_html(strbuf *html, node_inl* ils) { node_inl* children; bool visit_children; render_stack* rstack = NULL; while(ils != NULL) { visit_children = false; switch(ils->tag) { case INL_STRING: case INL_CODE: case INL_RAW_HTML: escape_html(html, ils->content.literal.data, ils->content.literal.len); break; case INL_LINEBREAK: case INL_SOFTBREAK: strbuf_putc(html, '\n'); break; case INL_LINK: case INL_IMAGE: children = ils->content.linkable.label; visit_children = true; rstack = push_inline(rstack, ils->next, ""); break; case INL_STRONG: case INL_EMPH: children = ils->content.inlines; visit_children = true; rstack = push_inline(rstack, ils->next, ""); break; } if (visit_children) { ils = children; } else { ils = ils->next; } while (ils == NULL && rstack != NULL) { strbuf_puts(html, rstack->literal); ils = rstack->next_sibling.inl; rstack = pop_render_stack(rstack); } } free_render_stack(rstack); }
/** * strmake: make string from original string with limit character. * * @param[in] p original string. * @param[in] lim limitter * @return result string * * Usage: * strmake("aaa:bbb", ":/=") => "aaa" * * [Note] The result string area is function local. So, following call * to this function may destroy the area. */ const char * strmake(const char *p, const char *lim) { STATIC_STRBUF(sb); const char *c; strbuf_clear(sb); for (; *p; p++) { for (c = lim; *c; c++) if (*p == *c) goto end; strbuf_putc(sb,*p); } end: return strbuf_value(sb); }
static inline strbuf _toprint(strbuf sb, char c) { if (c == '\0') strbuf_puts(sb, "\\0"); else if (c == '\n') strbuf_puts(sb, "\\n"); else if (c == '\r') strbuf_puts(sb, "\\r"); else if (c == '\t') strbuf_puts(sb, "\\t"); else if (c == '\\') strbuf_puts(sb, "\\\\"); else if (c >= ' ' && c <= '~') strbuf_putc(sb, c); else strbuf_sprintf(sb, "\\x%02x", c); return sb; }
/** * Check and fix an attribute's value; convert all @c ' (single quote) characters * into @CODE{\&\#39;} within it. */ static const char * fix_attr_value(const char *value) { STATIC_STRBUF(sb); char c; const char *cptr; strbuf_clear(sb); cptr = value; while((c = *cptr) != '\0') { if(c == ATTR_DELIM) strbuf_puts(sb, "'"); else strbuf_putc(sb, c); ++cptr; } return strbuf_value(sb); }
static int single_select_callback(void *v, int argc, char **argv, char **colname) { STATIC_STRBUF(sb); DBOP *dbop = (DBOP *)v; if (argc > 0) { strbuf_clear(sb); strbuf_puts(sb, argv[0]); dbop->lastsize = strbuf_getlen(sb); if (argv[1]) { strbuf_putc(sb, '\0'); strbuf_puts(sb, argv[1]); } dbop->lastdat = strbuf_value(sb); dbop->lastflag = argv[1] ? dbop->lastdat + dbop->lastsize + 1 : NULL; } else { dbop->lastdat = NULL; dbop->lastflag = NULL; dbop->lastsize = 0; } return SQLITE_OK; }
/** * 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); }
static void _log_prefix(_log_iterator *it, int level) { if (it->config == &config_file) { if (strbuf_is_empty(&_log_file_strbuf)) strbuf_init(&_log_file_strbuf, _log_file_buf, sizeof _log_file_buf); else if (strbuf_len(&_log_file_strbuf)) strbuf_putc(&_log_file_strbuf, '\n'); it->xpf = XPRINTF_STRBUF(&_log_file_strbuf); _log_prefix_level(it, level); } #ifdef ANDROID else if (it->config == &config.log.android) { strbuf_init(&_android_strbuf, _log_android_buf, sizeof _log_android_buf); it->xpf = XPRINTF_STRBUF(&_android_strbuf); } #endif // ANDROID else if (it->config == &config.log.console) { it->xpf = XPRINTF_STDIO(logfile_stderr); _log_prefix_level(it, level); } else abort(); if (it->config->show_pid) xprintf(it->xpf, "[%5u] ", getpid()); if (it->config->show_time) { if (it->tv.tv_sec == 0) { xputs("NOTIME______ ", it->xpf); } else { char buf[50]; if (strftime(buf, sizeof buf, "%T", &it->tm) == 0) xputs("EMPTYTIME___ ", it->xpf); else xprintf(it->xpf, "%s.%03u ", buf, (unsigned int)it->tv.tv_usec / 1000); } } }
/** * quote for shell. * * Examples: * aaa => 'aaa' * a'a => 'a'\''aa' */ const char * quote_shell(const char *s) { STATIC_STRBUF(sb); strbuf_clear(sb); strbuf_putc(sb, SHELL_QUOTE); #if defined(__DJGPP__) || (defined(_WIN32) && !defined(__CYGWIN__)) strbuf_puts(sb, s); #else for (; *s; s++) { if (*s == SHELL_QUOTE) { strbuf_putc(sb, SHELL_QUOTE); strbuf_putc(sb, '\\'); strbuf_putc(sb, SHELL_QUOTE); strbuf_putc(sb, SHELL_QUOTE); } else strbuf_putc(sb, *s); } #endif strbuf_putc(sb, SHELL_QUOTE); return strbuf_value(sb); }
/** * Generate anchor begin tag (@CODE{\<a href='dir/file.suffix\#key'\>}). * (complete format) * * @param[in] dir directory * @param[in] file file * @param[in] suffix suffix (file extension e.g. @CODE{'.txt'}). A @CODE{'.'} (dot) will be added. * @param[in] key key * @param[in] title @CODE{title='xxx'} attribute; if @VAR{NULL}, doesn't add it. * @param[in] target @CODE{target='xxx'} attribute; if @VAR{NULL}, doesn't add it. * @return generated anchor tag * * @note @a dir, @a file, @a suffix, @a key, @a target and @a title may be @VAR{NULL}. * @note Single quote (@CODE{'}) characters are used with the attribute values. */ const char * gen_href_begin_with_title_target(const char *dir, const char *file, const char *suffix, const char *key, const char *title, const char *target) { STATIC_STRBUF(sb); strbuf_clear(sb); /* * Construct URL. * href='dir/file.suffix#key' */ strbuf_puts(sb, "<a href='"); if (file) { if (dir) { strbuf_puts(sb, dir); strbuf_putc(sb, '/'); } strbuf_puts(sb, file); if (suffix) { strbuf_putc(sb, '.'); strbuf_puts(sb, suffix); } } if (key) { strbuf_putc(sb, '#'); /* * If the key starts with a digit, it assumed line number. * XHTML 1.1 profibits number as an anchor. */ if (isdigit(*key)) strbuf_putc(sb, 'L'); strbuf_puts(sb, key); } strbuf_putc(sb, '\''); if (Fflag && target) strbuf_sprintf(sb, " target='%s'", fix_attr_value(target)); if (title) strbuf_sprintf(sb, " title='%s'", fix_attr_value(title)); strbuf_putc(sb, '>'); return strbuf_value(sb); }
/** * flush_pool: flush the pool and write is as compact format. * * @param[in] gtop descripter of #GTOP * @param[in] s_fid */ static void flush_pool(GTOP *gtop, const char *s_fid) { struct sh_entry *entry; int header_offset; int i, last; if (s_fid == NULL && (s_fid = gpath_path2fid(gtop->cur_path, NULL)) == NULL) die("GPATH is corrupted.('%s' not found)", gtop->cur_path); /* * Write records as compact format and free line number table * for each entry in the pool. */ for (entry = strhash_first(gtop->path_hash); entry; entry = strhash_next(gtop->path_hash)) { VARRAY *vb = (VARRAY *)entry->value; int *lno_array = varray_assign(vb, 0, 0); const char *key = entry->name; /* * extract method when class method definition. * * Ex: Class::method(...) * * key = 'method' * data = 'Class::method 103 ./class.cpp ...' */ if (gtop->flags & GTAGS_EXTRACTMETHOD) { if ((key = locatestring(entry->name, ".", MATCH_LAST)) != NULL) key++; else if ((key = locatestring(entry->name, "::", MATCH_LAST)) != NULL) key += 2; else key = entry->name; } /* Sort line number table */ qsort(lno_array, vb->length, sizeof(int), compare_lineno); strbuf_reset(gtop->sb); strbuf_puts(gtop->sb, s_fid); strbuf_putc(gtop->sb, ' '); if (gtop->format & GTAGS_COMPNAME) { strbuf_puts(gtop->sb, compress(entry->name, key)); } else { strbuf_puts(gtop->sb, entry->name); } strbuf_putc(gtop->sb, ' '); header_offset = strbuf_getlen(gtop->sb); /* * If GTAGS_COMPLINE flag is set, each line number is expressed as the * difference from the previous line number except for the head. * GTAGS_COMPLINE is set by default in format version 5. */ if (gtop->format & GTAGS_COMPLINE) { int cont = 0; last = 0; /* line 0 doesn't exist */ for (i = 0; i < vb->length; i++) { int n = lno_array[i]; if (n == last) continue; if (last > 0 && n == last + 1) { if (!cont) { /* * Don't use range expression at the head. */ if (strbuf_getlen(gtop->sb) == header_offset) strbuf_putn(gtop->sb, n); else cont = last; } } else { /* * Range expression. ex: 10-2 means 10 11 12 */ if (cont) { strbuf_putc(gtop->sb, '-'); strbuf_putn(gtop->sb, last - cont); cont = 0; } if (strbuf_getlen(gtop->sb) > header_offset) { strbuf_putc(gtop->sb, ','); strbuf_putn(gtop->sb, n - last); } else { strbuf_putn(gtop->sb, n); } if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) { dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); strbuf_setlen(gtop->sb, header_offset); } } last = n; } if (cont) { strbuf_putc(gtop->sb, '-'); strbuf_putn(gtop->sb, last - cont); } } else { /* * This code is to support older format (version 4). */ last = 0; /* line 0 doesn't exist */ for (i = 0; i < vb->length; i++) { int n = lno_array[i]; if (n == last) continue; if (strbuf_getlen(gtop->sb) > header_offset) strbuf_putc(gtop->sb, ','); strbuf_putn(gtop->sb, n); if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) { dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); strbuf_setlen(gtop->sb, header_offset); } last = n; } } if (strbuf_getlen(gtop->sb) > header_offset) { dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); } /* Free line number table */ varray_close(vb); } }
/* * 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); }
/** * getconfs: get property string * * @param[in] name property name * @param[out] result string buffer (if not NULL) * @return 1: found, 0: not found */ int getconfs(const char *name, STRBUF *result) { STRBUF *sb = NULL; const char *p; char buf[MAXPROPLEN]; int all = 0; int exist = 0; int bufsize; if (!opened) die("configuration file not opened."); /* 'path' is reserved name for the current path of configuration file */ if (!strcmp(name, "path")) { if (config_path && result) strbuf_puts(result, config_path); return 1; } sb = strbuf_open(0); if (!strcmp(name, "skip") || !strcmp(name, "gtags_parser") || !strcmp(name, "langmap")) all = 1; snprintf(buf, sizeof(buf), ":%s=", name); bufsize = strlen(buf); p = confline; while ((p = locatestring(p, buf, MATCH_FIRST)) != NULL) { if (exist && sb) strbuf_putc(sb, ','); exist = 1; for (p += bufsize; *p; p++) { if (*p == ':') break; if (*p == '\\' && *(p + 1) == ':') /* quoted character */ p++; if (sb) strbuf_putc(sb, *p); } if (!all) break; } /* * If 'bindir' and 'datadir' are not defined then * return system configuration value. */ if (!exist) { if (!strcmp(name, "bindir")) { if (sb) strbuf_puts(sb, BINDIR); exist = 1; } else if (!strcmp(name, "datadir")) { #if defined(_WIN32) && !defined(__CYGWIN__) /* * Test if this directory exists, and if not, take the * directory relative to the binary. */ if (test("d", DATADIR)) { if (sb) strbuf_puts(sb, DATADIR); } else { char path[MAX_PATH], *name, *p; GetModuleFileName(NULL, path, MAX_PATH); for (p = name = path; *p; ++p) { if (*p == '\\') { *p = '/'; name = p+1; } } strcpy(name, "../share"); if (sb) strbuf_puts(sb, path); } #else if (sb) strbuf_puts(sb, DATADIR); #endif exist = 1; } else if (!strcmp(name, "libdir")) { if (sb) strbuf_puts(sb, LIBDIR); exist = 1; } else if (!strcmp(name, "localstatedir")) { if (sb) strbuf_puts(sb, LOCALSTATEDIR); exist = 1; } else if (!strcmp(name, "sysconfdir")) { if (sb) strbuf_puts(sb, SYSCONFDIR); exist = 1; } } replace_variables(sb); if (result) strbuf_puts(result, !strcmp(name, "langmap") ? trim_langmap(strbuf_value(sb)) : strbuf_value(sb)); strbuf_close(sb); return exist; }
/** * openconf: load configuration file. * * @param[in] rootdir Project root directory * * Globals used (output): * confline: specified entry */ void openconf(const char *rootdir) { STRBUF *sb; if (opened) return; opened = 1; /* * if config file not found then return default value. */ if (!(config_path = configpath(rootdir))) confline = check_strdup(""); /* * if it is not an absolute path then assumed config value itself. */ else if (!isabspath(config_path)) { confline = check_strdup(config_path); if (!locatestring(confline, ":", MATCH_FIRST)) die("GTAGSCONF must be absolute path name."); } /* * else load value from config file. */ else { if (test("d", config_path)) die("config file '%s' is a directory.", config_path); if (!test("f", config_path)) die("config file '%s' not found.", config_path); if (!test("r", config_path)) die("config file '%s' is not readable.", config_path); if ((config_label = getenv("GTAGSLABEL")) == NULL) config_label = "default"; if (!(fp = fopen(config_path, "r"))) die("cannot open '%s'.", config_path); ib = strbuf_open(MAXBUFLEN); sb = strbuf_open(0); includelabel(fp, sb, config_label, 0); confline = check_strdup(strbuf_value(sb)); strbuf_close(ib); strbuf_close(sb); fclose(fp); } /* * make up required variables. */ sb = strbuf_open(0); strbuf_puts(sb, confline); strbuf_unputc(sb, ':'); if (!getconfs("langmap", NULL)) { strbuf_puts(sb, ":langmap="); strbuf_puts(sb, quote_chars(DEFAULTLANGMAP, ':')); } if (!getconfs("skip", NULL)) { strbuf_puts(sb, ":skip="); strbuf_puts(sb, DEFAULTSKIP); } strbuf_unputc(sb, ':'); strbuf_putc(sb, ':'); confline = check_strdup(strbuf_value(sb)); strbuf_close(sb); trim(confline); return; }
int rbm_putc(int c, FILE *stream) { return strbuf_putc((STRBUF *) stream, c); }
/** * makecommonpart: make a common part for "mains.html" and "index.html" * * @param[in] title * @param[in] defines * @param[in] files * @return index common part */ static char * makecommonpart(const char *title, const char *defines, const char *files) { FILE *ip; STRBUF *sb = strbuf_open(0); STRBUF *ib = strbuf_open(0); char buf[MAXFILLEN]; const char *tips = "Go to the GLOBAL project page."; const char *_, *item; strbuf_puts(sb, title_begin); strbuf_puts(sb, title); strbuf_puts_nl(sb, title_end); strbuf_puts_nl(sb, poweredby_begin); strbuf_sprintf(sb, "Last updated %s%s\n", now(), br); if (Iflag) { snprintf(buf, sizeof(buf), "Powered by GLOBAL-%s.", get_version()); strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips,"_top")); strbuf_puts(sb, gen_image(CURRENT, "pglobe", buf)); strbuf_puts(sb, gen_href_end()); strbuf_puts(sb, br); } else { strbuf_sprintf(sb, "Powered by %sGLOBAL-%s%s.%s\n", gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips, "_top"), get_version(), gen_href_end(), br); } strbuf_puts_nl(sb, poweredby_end); strbuf_puts_nl(sb, hr); /* * Print items according to the value of variable 'item_order'. */ for (item = item_order; *item; item++) { switch (*item) { case 'c': if (caution) { strbuf_puts_nl(sb, caution_begin); strbuf_sprintf(sb, "<font size='+2' color='red'>CAUTION</font>%s\n", br); strbuf_sprintf(sb, "This hypertext consists of %d files.\n", html_count); strbuf_puts_nl(sb, "Please don't download the whole hypertext using a hypertext copy tool."); strbuf_puts_nl(sb, "Our network cannot afford such traffic."); strbuf_puts_nl(sb, "Instead, you can generate the same thing in your computer using"); strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, NULL, "_top")); strbuf_puts(sb, "GLOBAL source code tag system"); strbuf_puts_nl(sb, gen_href_end()); strbuf_puts_nl(sb, "Thank you."); strbuf_puts_nl(sb, caution_end); strbuf_sprintf(sb, "\n%s\n", hr); } break; case 's': if (fflag) { strbuf_puts(sb, makesearchpart(NULL)); strbuf_puts_nl(sb, hr); } break; case 't': if (call_file || callee_file) { strbuf_puts(sb, header_begin); if (call_file) { strbuf_puts(sb, gen_href_begin(NULL, "call", normal_suffix, NULL)); strbuf_puts(sb, title_call_tree); strbuf_puts(sb, gen_href_end()); } if (call_file && callee_file) strbuf_puts(sb, " / "); if (callee_file) { strbuf_puts(sb, gen_href_begin(NULL, "callee", normal_suffix, NULL)); strbuf_puts(sb, title_callee_tree); strbuf_puts(sb, gen_href_end()); } strbuf_puts_nl(sb, header_end); strbuf_puts_nl(sb, hr); } break; case 'm': strbuf_sprintf(sb, "%sMAINS%s\n", header_begin, header_end); snprintf(buf, sizeof(buf), PQUOTE "%s --result=ctags-xid --encode-path=\" \t\" --nofilter=path %s" PQUOTE, quote_shell(global_path), main_func); ip = popen(buf, "r"); if (!ip) die("cannot execute '%s'.", buf); strbuf_puts_nl(sb, gen_list_begin()); while ((_ = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) { char fid[MAXFIDLEN]; const char *ctags_x = parse_xid(_, fid, NULL); strbuf_puts_nl(sb, gen_list_body(SRCS, ctags_x, fid)); } strbuf_puts_nl(sb, gen_list_end()); if (pclose(ip) != 0) die("terminated abnormally '%s' (errno = %d).", buf, errno); strbuf_puts_nl(sb, hr); break; case 'd': if (aflag && !Fflag) { strbuf_puts(sb, header_begin); strbuf_puts(sb, title_define_index); strbuf_puts_nl(sb, header_end); strbuf_puts(sb, defines); } else { strbuf_puts(sb, header_begin); strbuf_puts(sb, gen_href_begin(NULL, "defines", normal_suffix, NULL)); strbuf_puts(sb, title_define_index); strbuf_puts(sb, gen_href_end()); strbuf_puts_nl(sb, header_end); } strbuf_puts_nl(sb, hr); break; case 'f': if (Fflag) { strbuf_puts(sb, header_begin); strbuf_puts(sb, gen_href_begin(NULL, "files", normal_suffix, NULL)); strbuf_puts(sb, title_file_index); strbuf_puts(sb, gen_href_end()); strbuf_puts_nl(sb, header_end); } else { strbuf_puts(sb, header_begin); strbuf_puts(sb, title_file_index); strbuf_puts_nl(sb, header_end); if (tree_view) { strbuf_puts_nl(sb, tree_control); strbuf_puts_nl(sb, tree_loading); if (tree_view_type) { strbuf_sprintf(sb, tree_begin_using, tree_view_type); strbuf_putc(sb, '\n'); } else { strbuf_puts_nl(sb, tree_begin); } } else if (table_flist) strbuf_puts_nl(sb, flist_begin); else if (!no_order_list) strbuf_puts_nl(sb, list_begin); strbuf_puts(sb, files); if (tree_view) strbuf_puts_nl(sb, tree_end); else if (table_flist) strbuf_puts_nl(sb, flist_end); else if (!no_order_list) strbuf_puts_nl(sb, list_end); else strbuf_puts_nl(sb, br); } strbuf_puts_nl(sb, hr); break; default: warning("unknown item '%c'. (Ignored)", *item); break; } } strbuf_close(ib); return strbuf_value(sb); /* doesn't close string buffer */ }
int main(int argc, char **argv) { const char *av = NULL; int func_total, file_total; char arg_dbpath[MAXPATHLEN]; const char *index = NULL; int optchar; int option_index = 0; STATISTICS_TIME *tim; arg_dbpath[0] = 0; basic_check(); /* * Setup GTAGSCONF and GTAGSLABEL environment variable * according to the --gtagsconf and --gtagslabel option. */ preparse_options(argc, argv); /* * Load configuration values. */ if (!vgetcwd(cwdpath, sizeof(cwdpath))) die("cannot get current directory."); openconf(cwdpath); configuration(); /* * setup_langmap() is needed to use decide_lang(). */ setup_langmap(langmap); save_environment(argc, argv); /* * insert htags_options at the head of argv. */ setenv_from_config(); { char *env = getenv("HTAGS_OPTIONS"); if (env && *env) argv = prepend_options(&argc, argv, env); } while ((optchar = getopt_long(argc, argv, "acd:DfFghIm:nNoqst:Tvwx", long_options, &option_index)) != EOF) { switch (optchar) { case 0: /* already flags set */ break; case OPT_AUTO_COMPLETION: auto_completion = 1; if (optarg) { if (atoi(optarg) > 0) auto_completion_limit = optarg; else die("The option value of --auto-completion must be numeric."); } break; case OPT_CFLOW: call_file = optarg; break; case OPT_CALL_TREE: call_file = optarg; break; case OPT_CALLEE_TREE: callee_file = optarg; break; case OPT_CVSWEB: cvsweb_url = optarg; break; case OPT_CVSWEB_CVSROOT: cvsweb_cvsroot = optarg; break; case OPT_GTAGSCONF: case OPT_GTAGSLABEL: /* These options are already parsed in preparse_options() */ break; case OPT_INSERT_FOOTER: insert_footer = optarg; break; case OPT_INSERT_HEADER: insert_header = optarg; break; case OPT_HTML_HEADER: { STATIC_STRBUF(sb); if (!test("r", optarg)) die("file '%s' not found.", optarg); strbuf_clear(sb); loadfile(optarg, sb); html_header = strbuf_value(sb); } break; case OPT_ITEM_ORDER: item_order = optarg; break; case OPT_TABS: if (atoi(optarg) > 0) tabs = atoi(optarg); else die("--tabs option requires numeric value."); break; case OPT_NCOL: if (atoi(optarg) > 0) ncol = atoi(optarg); else die("--ncol option requires numeric value."); break; case OPT_TREE_VIEW: tree_view = 1; if (optarg) tree_view_type = optarg; break; case 'a': aflag++; break; case 'd': strlimcpy(arg_dbpath, optarg, sizeof(arg_dbpath)); break; case 'D': dynamic = 1; break; case 'f': fflag++; break; case 'F': Fflag++; break; case 'g': gflag++; break; case 'h': definition_header = AFTER_HEADER; if (optarg) { if (!strcmp(optarg, "before")) definition_header = BEFORE_HEADER; else if (!strcmp(optarg, "right")) definition_header = RIGHT_HEADER; else if (!strcmp(optarg, "after")) definition_header = AFTER_HEADER; else die("The option value of --func-header must be one of 'before', 'right' and 'after'."); } break; case 'I': Iflag++; break; case 'm': main_func = optarg; break; case 'n': nflag++; if (optarg) { if (atoi(optarg) > 0) ncol = atoi(optarg); else die("The option value of --line-number must be numeric."); } break; case 'o': other_files = 1; break; case 's': symbol = 1; break; case 'T': table_flist = 1; if (optarg) { if (atoi(optarg) > 0) flist_fields = atoi(optarg); else die("The option value of the --table-flist must be numeric."); } break; case 't': title = optarg; break; case 'q': qflag++; setquiet(); break; case 'v': vflag++; setverbose(); break; case 'w': wflag++; break; default: usage(); break; } } /* * Leaving everything to htags. * Htags selects popular options for you. */ if (suggest2) suggest = 1; if (suggest) { int gtags_not_found = 0; char dbpath[MAXPATHLEN]; aflag = Iflag = nflag = vflag = 1; setverbose(); definition_header = AFTER_HEADER; other_files = symbol = show_position = table_flist = fixed_guide = 1; if (arg_dbpath[0]) { if (!test("f", makepath(arg_dbpath, dbname(GTAGS), NULL))) gtags_not_found = 1; } else if (gtagsexist(".", dbpath, sizeof(dbpath), 0) == 0) { gtags_not_found = 1; } if (gtags_not_found) gflag = 1; } if (suggest2) { Fflag = 1; /* uses frame */ fflag = dynamic = 1; /* needs a HTTP server */ auto_completion = tree_view = 1; /* needs javascript */ } if (call_file && !test("fr", call_file)) die("cflow file not found. '%s'", call_file); if (callee_file && !test("fr", callee_file)) die("cflow file not found. '%s'", callee_file); if (insert_header && !test("fr", insert_header)) die("page header file '%s' not found.", insert_header); if (insert_footer && !test("fr", insert_footer)) die("page footer file '%s' not found.", insert_footer); if (!fflag) auto_completion = 0; argc -= optind; argv += optind; if (!av) av = (argc > 0) ? *argv : NULL; if (debug) setdebug(); settabs(tabs); /* setup tab skip */ if (qflag) { setquiet(); vflag = 0; } if (show_version) version(av, vflag); if (show_help) help(); /* * Invokes gtags beforehand. */ if (gflag) { STRBUF *sb = strbuf_open(0); strbuf_puts(sb, gtags_path); if (vflag) strbuf_puts(sb, " -v"); if (wflag) strbuf_puts(sb, " -w"); if (suggest2 && enable_idutils && usable("mkid")) strbuf_puts(sb, " -I"); if (arg_dbpath[0]) { strbuf_putc(sb, ' '); strbuf_puts(sb, arg_dbpath); } if (system(strbuf_value(sb))) die("cannot execute gtags(1) command."); strbuf_close(sb); } /* * get dbpath. */ if (arg_dbpath[0]) { strlimcpy(dbpath, arg_dbpath, sizeof(dbpath)); } else { int status = setupdbpath(0); if (status < 0) die_with_code(-status, "%s", gtags_dbpath_error); strlimcpy(dbpath, get_dbpath(), sizeof(dbpath)); } if (!title) { char *p = strrchr(cwdpath, sep); title = p ? p + 1 : cwdpath; } if (cvsweb_url && test("d", "CVS")) use_cvs_module = 1; /* * decide directory in which we make hypertext. */ if (av) { char realpath[MAXPATHLEN]; if (!test("dw", av)) die("'%s' is not writable directory.", av); if (chdir(av) < 0) die("directory '%s' not found.", av); if (!vgetcwd(realpath, sizeof(realpath))) die("cannot get current directory"); if (chdir(cwdpath) < 0) die("cannot return to original directory."); snprintf(distpath, sizeof(distpath), "%s/HTML", realpath); } else { snprintf(distpath, sizeof(distpath), "%s/HTML", cwdpath); } /* * Existence check of tag files. */ { int i; const char *path; GTOP *gtop; for (i = GPATH; i < GTAGLIM; i++) { path = makepath(dbpath, dbname(i), NULL); gtags_exist[i] = test("fr", path); } /* * Real GRTAGS includes virtual GSYMS. */ gtags_exist[GSYMS] = symbol ? 1 : 0; if (!gtags_exist[GPATH] || !gtags_exist[GTAGS] || !gtags_exist[GRTAGS]) die("GPATH, GTAGS and/or GRTAGS not found. Please reexecute htags with the -g option."); /* * version check. * Do nothing, but the version of tag file will be checked. */ gtop = gtags_open(dbpath, cwdpath, GTAGS, GTAGS_READ, 0); gtags_close(gtop); /* * Check whether GRTAGS is empty. */ gtop = gtags_open(dbpath, cwdpath, GRTAGS, GTAGS_READ, 0); if (gtags_first(gtop, NULL, 0) == NULL) grtags_is_empty = 1; gtags_close(gtop); } /* * make dbpath absolute. */ { char buf[MAXPATHLEN]; if (realpath(dbpath, buf) == NULL) die("cannot get realpath of dbpath."); strlimcpy(dbpath, buf, sizeof(dbpath)); } /* * The older version (4.8.7 or former) of GPATH doesn't have files * other than source file. The oflag requires new version of GPATH. */ if (other_files) { GFIND *gp = gfind_open(dbpath, NULL, 0, 0); if (gp->version < 2) die("GPATH is old format. Please remake it by invoking gtags(1)."); gfind_close(gp); } /* * for global(1) and gtags(1). */ set_env("GTAGSROOT", cwdpath); set_env("GTAGSDBPATH", dbpath); set_env("GTAGSLIBPATH", ""); /*------------------------------------------------------------------ * MAKE FILES *------------------------------------------------------------------ * HTML/cgi-bin/global.cgi ... CGI program (1) * HTML/cgi-bin/ghtml.cgi ... unzip script (1) * HTML/.htaccess ... skeleton of .htaccess (1) * HTML/help.html ... help file (2) * HTML/R/ ... references (3) * HTML/D/ ... definitions (3) * HTML/search.html ... search index (4) * HTML/defines.html ... definitions index (5) * HTML/defines/ ... definitions index (5) * HTML/files/ ... file index (6) * HTML/index.html ... index file (7) * HTML/mains.html ... main index (8) * HTML/null.html ... main null html (8) * HTML/S/ ... source files (9) * HTML/I/ ... include file index (9) * HTML/rebuild.sh ... rebuild script (10) * HTML/style.css ... style sheet (11) *------------------------------------------------------------------ */ /* for clean up */ signal_setup(); sethandler(clean); HTML = normal_suffix; message("[%s] Htags started", now()); init_statistics(); /* * (#) check if GTAGS, GRTAGS is the latest. */ if (get_dbpath()) message(" Using %s/GTAGS.", get_dbpath()); if (grtags_is_empty) message(" GRTAGS is empty."); if (gpath_open(dbpath, 0) < 0) die("GPATH not found."); if (!w32) { /* UNDER CONSTRUCTION */ } if (auto_completion || tree_view) { STATIC_STRBUF(sb); strbuf_clear(sb); strbuf_puts_nl(sb, "<script type='text/javascript' src='js/jquery.js'></script>"); if (auto_completion) loadfile(makepath(datadir, "gtags/jscode_suggest", NULL), sb); if (tree_view) loadfile(makepath(datadir, "gtags/jscode_treeview", NULL), sb); jscode = strbuf_value(sb); } /* * (0) make directories */ message("[%s] (0) making directories ...", now()); if (!test("d", distpath)) if (mkdir(distpath, 0777) < 0) die("cannot make directory '%s'.", distpath); make_directory_in_distpath("files"); make_directory_in_distpath("defines"); make_directory_in_distpath(SRCS); make_directory_in_distpath(INCS); make_directory_in_distpath(INCREFS); if (!dynamic) { make_directory_in_distpath(DEFS); make_directory_in_distpath(REFS); if (symbol) make_directory_in_distpath(SYMS); } if (fflag || dynamic) make_directory_in_distpath("cgi-bin"); if (Iflag) make_directory_in_distpath("icons"); if (auto_completion || tree_view) make_directory_in_distpath("js"); /* * (1) make CGI program */ if (fflag || dynamic) { char cgidir[MAXPATHLEN]; snprintf(cgidir, sizeof(cgidir), "%s/cgi-bin", distpath); message("[%s] (1) making CGI program ...", now()); if (fflag || dynamic) makeprogram(cgidir, "global.cgi", 0755); if (auto_completion) makeprogram(cgidir, "completion.cgi", 0755); makehtaccess(cgidir, ".htaccess", 0644); } else { message("[%s] (1) making CGI program ...(skipped)", now()); } if (av) { const char *path = makepath(distpath, "GTAGSROOT", NULL); FILE *op = fopen(path, "w"); if (op == NULL) die("cannot make file '%s'.", path); fputs(cwdpath, op); fputc('\n', op); fclose(op); } /* * (2) make help file */ message("[%s] (2) making help.html ...", now()); makehelp("help.html"); /* * (#) load GPATH */ load_gpath(dbpath); /* * (3) make function entries (D/ and R/) * MAKING TAG CACHE */ message("[%s] (3) making tag lists ...", now()); cache_open(); tim = statistics_time_start("Time of making tag lists"); func_total = makedupindex(); statistics_time_end(tim); message("Total %d functions.", func_total); /* * (4) search index. (search.html) */ if (Fflag && fflag) { message("[%s] (4) making search index ...", now()); makesearchindex("search.html"); } { STRBUF *defines = strbuf_open(0); STRBUF *files = strbuf_open(0); /* * (5) make definition index (defines.html and defines/) * PRODUCE @defines */ message("[%s] (5) making definition index ...", now()); tim = statistics_time_start("Time of making definition index"); func_total = makedefineindex("defines.html", func_total, defines); statistics_time_end(tim); message("Total %d functions.", func_total); /* * (6) make file index (files.html and files/) * PRODUCE @files, %includes */ message("[%s] (6) making file index ...", now()); init_inc(); tim = statistics_time_start("Time of making file index"); file_total = makefileindex("files.html", files); statistics_time_end(tim); message("Total %d files.", file_total); html_count += file_total; /* * (7) make call tree using cflow(1)'s output (cflow.html) */ if (call_file || callee_file) { message("[%s] (7) making cflow index ...", now()); tim = statistics_time_start("Time of making cflow index"); if (call_file) if (makecflowindex("call.html", call_file) < 0) call_file = NULL; if (callee_file) if (makecflowindex("callee.html", callee_file) < 0) callee_file = NULL; statistics_time_end(tim); } /* * [#] make include file index. */ message("[%s] (#) making include file index ...", now()); tim = statistics_time_start("Time of making include file index"); makeincludeindex(); statistics_time_end(tim); /* * [#] make a common part for mains.html and index.html * USING @defines @files */ message("[%s] (#) making a common part ...", now()); index = makecommonpart(title, strbuf_value(defines), strbuf_value(files)); strbuf_close(defines); strbuf_close(files); } /* * (7)make index file (index.html) */ message("[%s] (7) making index file ...", now()); makeindex("index.html", title, index); /* * (8) make main index (mains.html) */ message("[%s] (8) making main index ...", now()); makemainindex("mains.html", index); /* * (9) make HTML files (SRCS/) * USING TAG CACHE, %includes and anchor database. */ message("[%s] (9) making hypertext from source code ...", now()); tim = statistics_time_start("Time of making hypertext"); makehtml(file_total); statistics_time_end(tim); /* * (10) rebuild script. (rebuild.sh) * * Don't grant execute permission to rebuild script. */ makerebuild("rebuild.sh"); if (chmod(makepath(distpath, "rebuild.sh", NULL), 0640) < 0) die("cannot chmod rebuild script."); /* * (11) style sheet file (style.css) */ if (enable_xhtml) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/style.css", datadir); snprintf(dist, sizeof(dist), "%s/style.css", distpath); copyfile(src, dist); } if (auto_completion || tree_view) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/jquery", datadir); snprintf(dist, sizeof(dist), "%s/js", distpath); copydirectory(src, dist); snprintf(src, sizeof(src), "%s/gtags/jquery/images", datadir); snprintf(dist, sizeof(dist), "%s/js/images", distpath); copydirectory(src, dist); } message("[%s] Done.", now()); if (vflag && (fflag || dynamic || auto_completion)) { message("\n[Information]\n"); message(" o Htags was invoked with the -f, -c, -D or --auto-completion option. You should"); message(" start http server so that cgi-bin/*.cgi is executed as a CGI script."); message("\n If you are using Apache, 'HTML/.htaccess' might be helpful for you.\n"); message(" Good luck!\n"); } if (Iflag) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/icons", datadir); snprintf(dist, sizeof(dist), "%s/icons", distpath); copydirectory(src, dist); } gpath_close(); /* * Print statistics information. */ print_statistics(statistics); clean(); return 0; }
/** * save_environment: save configuration data and arguments. */ static void save_environment(int argc, char *const *argv) { char command[MAXFILLEN]; STRBUF *sb = strbuf_open(0); STRBUF *save_c = strbuf_open(0); STRBUF *save_a = strbuf_open(0); int i; const char *p; FILE *ip; /* * save config values. */ snprintf(command, sizeof(command), PQUOTE "%s --config" PQUOTE, quote_shell(gtags_path)); if ((ip = popen(command, "r")) == NULL) die("cannot execute '%s'.", command); while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL) { for (p = strbuf_value(sb); *p; p++) { if (*p == '\'') { strbuf_putc(save_c, '\''); strbuf_putc(save_c, '"'); strbuf_putc(save_c, '\''); strbuf_putc(save_c, '"'); strbuf_putc(save_c, '\''); } else strbuf_putc(save_c, *p); } } if (pclose(ip) != 0) die("terminated abnormally '%s' (errno = %d).", command, errno); strbuf_close(sb); save_config = strbuf_value(save_c); /* doesn't close string buffer for save config. */ /* strbuf_close(save_c); */ /* * save arguments. */ { char *opt_gtagsconf = "--gtagsconf"; for (i = 1; i < argc; i++) { char *blank; /* * skip --gtagsconf because it is already read * as config value. */ if ((p = locatestring(argv[i], opt_gtagsconf, MATCH_AT_FIRST))) { if (*p == '\0') i++; continue; } blank = locatestring(argv[i], " ", MATCH_FIRST); strbuf_putc(save_a, ' '); if (blank) strbuf_putc(save_a, '\''); strbuf_puts(save_a, argv[i]); if (blank) strbuf_putc(save_a, '\''); } } save_argv = strbuf_value(save_a); /* doesn't close string buffer for save arguments. */ /* strbuf_close(save_a); */ }