/** * Read a tag segment with sorting. * * @param[in] gtop #GTOP structure <br> * Output: @CODE{gtop->gtp_array} segment table <br> * Output: @CODE{gtop->gtp_count} segment table size <br> * Output: @CODE{gtop->gtp_index} segment table index (initial value = 0) <br> * Output: @CODE{gtop->cur_tagname} current tag name * * A segment is a set of tag records which have same tag name. <br> * This function read a segment from tag file, sort it and put it on segment table. <br> * This function can treat both of standard format and compact format. * * Sorting is done by three keys. * - 1st key: tag name * - 2nd key: file name * - 3rd key: line number * * Since all records in a segment have same tag name, you need not think about 1st key. */ void segment_read(GTOP *gtop) { const char *tagline, *fid, *path, *lineno; GTP *gtp; struct sh_entry *sh; /* * Save tag lines. */ gtop->cur_tagname[0] = '\0'; while ((tagline = dbop_next(gtop->dbop)) != NULL) { VIRTUAL_GRTAGS_GSYMS_PROCESSING(gtop); /* * get tag name and line number. * * tagline = <file id> <tag name> <line number> */ if (gtop->cur_tagname[0] == '\0') { strlimcpy(gtop->cur_tagname, gtop->dbop->lastkey, sizeof(gtop->cur_tagname)); } else if (strcmp(gtop->cur_tagname, gtop->dbop->lastkey) != 0) { /* * Dbop_next() wil read the same record again. */ dbop_unread(gtop->dbop); break; } gtp = varray_append(gtop->vb); gtp->tagline = pool_strdup(gtop->segment_pool, tagline, 0); gtp->tag = (const char *)gtop->cur_tagname; /* * convert fid into hashed path name to save memory. */ fid = (const char *)strmake(tagline, " "); path = gpath_fid2path(fid, NULL); if (path == NULL) die("gtags_first: path not found. (fid=%s)", fid); sh = strhash_assign(gtop->path_hash, path, 1); gtp->path = sh->name; lineno = seekto(gtp->tagline, SEEKTO_LINENO); if (lineno == NULL) die("illegal tag record.\n%s", tagline); gtp->lineno = atoi(lineno); } /* * Sort tag lines. */ gtop->gtp_array = varray_assign(gtop->vb, 0, 0); gtop->gtp_count = gtop->vb->length; gtop->gtp_index = 0; if (!(gtop->flags & GTOP_NOSORT)) qsort(gtop->gtp_array, gtop->gtp_count, sizeof(GTP), compare_tags); }
/** * 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)); }
/** * gfind_open: start iterator using GPATH. * * @param[in] dbpath dbpath * @param[in] local local prefix, * if NULL specified, it assumes "./"; * @param[in] target GPATH_SOURCE: only source file, * GPATH_OTHER: only other file, * GPATH_BOTH: source file + other file * @param[in] flags GPATH_NEARSORT * @return GFIND structure */ GFIND * gfind_open(const char *dbpath, const char *local, int target, int flags) { GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1); gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0); if (gfind->dbop == NULL) die("GPATH not found."); gfind->path = NULL; gfind->prefix = check_strdup(local ? local : "./"); gfind->first = 1; gfind->eod = 0; gfind->target = target; gfind->type = GPATH_SOURCE; gfind->flags = flags; gfind->path_array = NULL; gfind->version = dbop_getversion(gfind->dbop); if (gfind->version > support_version) die("GPATH seems new format. Please install the latest GLOBAL."); else if (gfind->version < support_version) die("GPATH seems older format. Please remake tag files."); /* * Nearness sort. * In fact, this timing of sort is not good for performance. * Reconsideration is needed later. */ if (gfind->flags & GPATH_NEARSORT) { const char *path = NULL; VARRAY *varray = varray_open(sizeof(char *), 100); POOL *pool = pool_open(); while ((path = gfind_read(gfind)) != NULL) { char **a = varray_append(varray); *a = pool_strdup(pool, path, 0); } if ((nearbase = get_nearbase_path()) == NULL) die("cannot get nearbase path."); qsort(varray_assign(varray, 0, 0), varray->length, sizeof(char *), compare_nearpath); gfind->path_array = varray; gfind->pool = pool; gfind->index = 0; } return gfind; }
/* * setup two internal tables for abbreviation. * * i) abbrev abbreviation string */ void abbrev_open(const char *abbrev) { int i, limit; struct abbrmap *ab; char *p; /* * abbrev string: "ddefine ttypedef" */ /* copy abbrev string to static area */ strlimcpy(abbrev_string, abbrev, sizeof(abbrev_string)); p = abbrev_string; /* initialize ab2name table */ limit = sizeof(ab2name) / sizeof(struct abbrmap); for (i = 0; i < limit; i++) { ab2name[i].c = 0; ab2name[i].name = NULL; } name2ab = varray_open(sizeof(struct abbrmap), 5); while (*p) { ab = (struct abbrmap *)varray_append(name2ab); ab->c = *p++; ab->name = p; for (; *p && *p != ' '; p++) ; if (*p == ' ') *p++ = '\0'; ab->length = strlen(ab->name); if (ab->c < 'a' || ab->c > 'z') die("Abbrev character must be a lower alphabetic character. (%s)", abbrev); i = ab->c - 'a'; ab2name[i].c = ab->c; ab2name[i].name = ab->name; ab2name[i].length = ab->length; } }
/** * anchor_load: load anchor table * * @param[in] path path name */ void anchor_load(const char *path) { int db, current_fid; /* Get fid of the path */ { const char *p = path2fid(path); if (p == NULL) die("anchor_load: internal error. file '%s' not found in GPATH.", path); current_fid = atoi(p); } FIRST = LAST = 0; end = CURRENT = NULL; if (vb == NULL) vb = varray_open(sizeof(struct anchor), 1000); else varray_reset(vb); for (db = GTAGS; db < GTAGLIM; db++) { XARGS *xp; char *ctags_xid; if ((xp = anchor_input[db]) == NULL) continue; /* * Read from input stream until it reaches end of file * or the line of another file appears. */ while ((ctags_xid = xargs_read(xp)) != NULL) { SPLIT ptable; struct anchor *a; int type, fid; const char *ctags_x = parse_xid(ctags_xid, NULL, &fid); /* * It is the following file. */ if (current_fid != fid) { xargs_unread(xp); break; } if (split(ctags_x, 4, &ptable) < 4) { recover(&ptable); die("too small number of parts in anchor_load().\n'%s'", ctags_x); } if (db == GTAGS) { char *p = ptable.part[PART_LINE].start; for (; *p && isspace((unsigned char)*p); p++) ; if (!*p) { recover(&ptable); die("The output of parser is illegal.\n%s", ctags_x); } /* * Function header is applied only to the anchor whoes type is 'D'. * (D: function, M: macro, T: type) */ type = 'T'; if (*p == '#') type = 'M'; else if (locatestring(p, "typedef", MATCH_AT_FIRST)) type = 'T'; else if ((p = locatestring(p, ptable.part[PART_TAG].start, MATCH_FIRST)) != NULL) { /* skip a tag and the following blanks */ p += strlen(ptable.part[PART_TAG].start); for (; *p && isspace((unsigned char)*p); p++) ; if (*p == '(') type = 'D'; } } else if (db == GRTAGS) type = 'R'; else type = 'Y'; /* allocate an entry */ a = varray_append(vb); a->lineno = atoi(ptable.part[PART_LNO].start); a->type = type; a->done = 0; settag(a, ptable.part[PART_TAG].start); recover(&ptable); } if (ctags_xid == NULL) { xargs_close(anchor_input[db]); anchor_input[db] = NULL; } } if (vb->length == 0) { table = NULL; } else { int i, used = vb->length; /* * Sort by lineno. */ table = varray_assign(vb, 0, 0); qsort(table, used, sizeof(struct anchor), cmp); /* * Setup some lineno. */ for (i = 0; i < used; i++) if (table[i].type == 'D') break; if (i < used) FIRST = table[i].lineno; for (i = used - 1; i >= 0; i--) if (table[i].type == 'D') break; if (i >= 0) LAST = table[i].lineno; } /* * Setup loop range. */ start = table; curp = NULL; end = &table[vb->length]; /* anchor_dump(stderr, 0);*/ }