/** * 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); } }
/** * gtags_put_using: put tag record with packing. * * @param[in] gtop descripter of #GTOP * @param[in] tag tag name * @param[in] lno line number * @param[in] fid file id * @param[in] img line image */ void gtags_put_using(GTOP *gtop, const char *tag, int lno, const char *fid, const char *img) { const char *key; if (gtop->format & GTAGS_COMPACT) { struct sh_entry *entry; /* * Register each record into the pool. * * Pool image: * * tagname lno * ------------------------------ * "funcA" | 1| 3| 7|23|11| 2|... * "funcB" |34| 2| 5|66| 3|... * ... */ entry = strhash_assign(gtop->path_hash, tag, 1); if (entry->value == NULL) entry->value = varray_open(sizeof(int), 100); *(int *)varray_append((VARRAY *)entry->value) = lno; return; } /* * 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(tag, ".", MATCH_LAST)) != NULL) key++; else if ((key = locatestring(tag, "::", MATCH_LAST)) != NULL) key += 2; else key = tag; } else { key = tag; } strbuf_reset(gtop->sb); strbuf_puts(gtop->sb, fid); strbuf_putc(gtop->sb, ' '); strbuf_puts(gtop->sb, (gtop->format & GTAGS_COMPNAME) ? compress(tag, key) : tag); strbuf_putc(gtop->sb, ' '); strbuf_putn(gtop->sb, lno); strbuf_putc(gtop->sb, ' '); strbuf_puts(gtop->sb, (gtop->format & GTAGS_COMPRESS) ? compress(img, key) : img); dbop_put(gtop->dbop, key, strbuf_value(gtop->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); } }
/** * 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; }
/* * compress source line. * * i) in source line * i) name replaced string * r) compressed string */ char * compress(const char *in, const char *name) { STATIC_STRBUF(sb); const char *p = in; int length = strlen(name); int spaces = 0; strbuf_clear(sb); while (*p) { if (*p == ' ') { spaces++; p++; continue; } if (spaces > 0) { if (spaces >= 10) { strbuf_putc(sb, '@'); strbuf_putc(sb, '{'); strbuf_putn(sb, spaces); strbuf_putc(sb, '}'); } else if (spaces > 3) { strbuf_putc(sb, '@'); strbuf_putn(sb, spaces); } else { strbuf_nputc(sb, ' ', spaces); } } spaces = 0; if (*p == '@') { strbuf_puts(sb, "@@"); p++; } else if (!strncmp(p, name, length)) { strbuf_puts(sb, "@n"); p += length; } else if (name2ab) { int i, limit = name2ab->length; struct abbrmap *ab = (struct abbrmap *)varray_assign(name2ab, 0, 0); for (i = 0; i < limit; i++) { if (!strncmp(p, ab[i].name, ab[i].length)) { strbuf_putc(sb, '@'); strbuf_putc(sb, ab[i].c); p += ab[i].length; break; } } if (i >= limit) { strbuf_putc(sb, *p); p++; } } else { strbuf_putc(sb, *p); p++; } } if (spaces > 0) { if (spaces < 4) { strbuf_nputc(sb, ' ', spaces); } else if (spaces < 10) { strbuf_putc(sb, '@'); strbuf_putn(sb, spaces); } else { strbuf_putc(sb, '@'); strbuf_putc(sb, '{'); strbuf_putn(sb, spaces); strbuf_putc(sb, '}'); } } return strbuf_value(sb); }