40 |
|
|
41 |
#include "char.h" |
#include "char.h" |
42 |
#include "conf.h" |
#include "conf.h" |
|
#include "gparam.h" |
|
43 |
#include "dbop.h" |
#include "dbop.h" |
44 |
#include "die.h" |
#include "die.h" |
45 |
|
#include "gparam.h" |
46 |
#include "gtagsop.h" |
#include "gtagsop.h" |
47 |
#include "locatestring.h" |
#include "locatestring.h" |
48 |
#include "makepath.h" |
#include "makepath.h" |
50 |
#include "gpathop.h" |
#include "gpathop.h" |
51 |
#include "split.h" |
#include "split.h" |
52 |
#include "strbuf.h" |
#include "strbuf.h" |
53 |
|
#include "strhash.h" |
54 |
#include "strlimcpy.h" |
#include "strlimcpy.h" |
55 |
#include "strmake.h" |
#include "strmake.h" |
56 |
|
#include "varray.h" |
57 |
|
|
58 |
#define HASHBUCKETS 256 |
#define HASHBUCKETS 256 |
59 |
|
|
|
static unsigned int hashpjw(const char *); |
|
60 |
static int compare_lno(const void *, const void *); |
static int compare_lno(const void *, const void *); |
61 |
static void gtop_flush_htab(GTOP *); |
static void flush_pool(GTOP *); |
62 |
static const char *unpack_pathindex(const char *); |
static const char *unpack_pathindex(const char *); |
63 |
static const char *genrecord(GTOP *); |
static const char *genrecord(GTOP *); |
64 |
static regex_t reg; |
static regex_t reg; |
322 |
gtop->ib = strbuf_open(MAXBUFLEN); |
gtop->ib = strbuf_open(MAXBUFLEN); |
323 |
else { |
else { |
324 |
gtop->sb = strbuf_open(0); |
gtop->sb = strbuf_open(0); |
325 |
gtop->htab = calloc(sizeof(struct gtop_compact_entry *), HASHBUCKETS); |
gtop->pool = strhash_open(HASHBUCKETS, NULL); |
|
if (gtop->htab == NULL) |
|
|
die("short of memory."); |
|
326 |
} |
} |
327 |
} else if (gtop->format == GTAGS_PATHINDEX && gtop->mode != GTAGS_READ) |
} else if (gtop->format == GTAGS_PATHINDEX && gtop->mode != GTAGS_READ) |
328 |
gtop->sb = strbuf_open(0); |
gtop->sb = strbuf_open(0); |
341 |
void |
void |
342 |
gtags_put(GTOP *gtop, const char *tag, const char *ctags_x) /* virtually const */ |
gtags_put(GTOP *gtop, const char *tag, const char *ctags_x) /* virtually const */ |
343 |
{ |
{ |
344 |
const char *tagname; |
/* |
345 |
SPLIT ptable; |
* Standard format. |
346 |
struct gtop_compact_entry *entry, **prev; |
*/ |
|
int *lno; |
|
|
|
|
347 |
if (gtop->format == GTAGS_STANDARD) { |
if (gtop->format == GTAGS_STANDARD) { |
348 |
/* entab(ctags_x); */ |
/* entab(ctags_x); */ |
349 |
dbop_put(gtop->dbop, tag, ctags_x); |
dbop_put(gtop->dbop, tag, ctags_x); |
|
return; |
|
350 |
} |
} |
351 |
if (gtop->format == GTAGS_PATHINDEX) { |
/* |
352 |
|
* Only pathindex format. (not compact format) |
353 |
|
*/ |
354 |
|
else if (gtop->format == GTAGS_PATHINDEX) { |
355 |
char *p = locatestring(ctags_x, "./", MATCH_FIRST); |
char *p = locatestring(ctags_x, "./", MATCH_FIRST); |
356 |
const char *fid, *path; |
const char *fid, *path; |
357 |
int savec; |
int savec; |
373 |
strbuf_puts(gtop->sb, fid); |
strbuf_puts(gtop->sb, fid); |
374 |
strbuf_puts(gtop->sb, p); |
strbuf_puts(gtop->sb, p); |
375 |
dbop_put(gtop->dbop, tag, strbuf_value(gtop->sb)); |
dbop_put(gtop->dbop, tag, strbuf_value(gtop->sb)); |
|
return; |
|
376 |
} |
} |
377 |
/* |
/* |
378 |
* gtop->format & GTAGS_COMPACT |
* Compact format. (gtop->format & GTAGS_COMPACT) |
379 |
*/ |
*/ |
380 |
if (split((char *)ctags_x, 4, &ptable) != 4) { |
else { |
381 |
recover(&ptable); |
SPLIT ptable; |
382 |
die("illegal tag format.\n'%s'", ctags_x); |
struct sh_entry *entry; |
383 |
} |
VARRAY *vb; |
384 |
tagname = ptable.part[PART_TAG].start; |
int *lno; |
|
/* |
|
|
* Register each record into the hash table. |
|
|
* Duplicated records will be combined. |
|
|
*/ |
|
|
if (gtop->prev_path[0] && strcmp(gtop->prev_path, ptable.part[PART_PATH].start)) |
|
|
gtop_flush_htab(gtop); |
|
|
strlimcpy(gtop->prev_path, ptable.part[PART_PATH].start, sizeof(gtop->prev_path)); |
|
|
for (prev = gtop->htab + hashpjw(tagname) % HASHBUCKETS; |
|
|
(entry = *prev) != NULL; |
|
|
prev = &entry->next) { |
|
|
if (strcmp(entry->tag, tagname) == 0) |
|
|
break; |
|
|
} |
|
|
if (entry == NULL) { |
|
|
entry = malloc(offsetof(struct gtop_compact_entry, tag) + strlen(tagname) + 1); |
|
|
if (entry == NULL) |
|
|
die("short of memory."); |
|
|
entry->next = NULL; |
|
|
entry->vb = varray_open(sizeof(int), 100); |
|
|
strcpy(entry->tag, tagname); |
|
|
*prev = entry; |
|
|
} |
|
|
lno = varray_append(entry->vb); |
|
|
*lno = atoi(ptable.part[PART_LNO].start); |
|
|
recover(&ptable); |
|
|
} |
|
|
/* |
|
|
* hashpjw: calculate hash value for given string. |
|
|
* |
|
|
* i) string |
|
|
* r) hash value |
|
|
*/ |
|
|
static unsigned int |
|
|
hashpjw(const char *s) |
|
|
{ |
|
|
unsigned int h, g; |
|
385 |
|
|
386 |
h = strlen(s); |
if (split((char *)ctags_x, 4, &ptable) != 4) { |
387 |
while (*s != '\0') { |
recover(&ptable); |
388 |
h <<= 4; |
die("illegal tag format.\n'%s'", ctags_x); |
389 |
h += (unsigned char)*s++; |
} |
390 |
g = h & 0xf0000000; |
/* |
391 |
if (g != 0) |
* Flush the pool when path is changed. |
392 |
h = h ^ (g >> 24) ^ g; |
* Line numbers in the pool will be sorted and duplicated |
393 |
|
* records will be combined. |
394 |
|
* |
395 |
|
* pool "funcA" | 1| 3| 7|23|11| 2|... |
396 |
|
* v |
397 |
|
* output funcA 33 1,2,3,7,11,23... |
398 |
|
*/ |
399 |
|
if (gtop->prev_path[0] && strcmp(gtop->prev_path, ptable.part[PART_PATH].start)) { |
400 |
|
flush_pool(gtop); |
401 |
|
strhash_reset(gtop->pool); |
402 |
|
} |
403 |
|
strlimcpy(gtop->prev_path, ptable.part[PART_PATH].start, sizeof(gtop->prev_path)); |
404 |
|
/* |
405 |
|
* Register each record into the pool. |
406 |
|
* |
407 |
|
* Pool image: |
408 |
|
* |
409 |
|
* tagname lno |
410 |
|
* ------------------------------ |
411 |
|
* "funcA" | 1| 3| 7|23|11| 2|... |
412 |
|
* "funcB" |34| 2| 5|66| 3|... |
413 |
|
* ... |
414 |
|
*/ |
415 |
|
entry = strhash_assign(gtop->pool, ptable.part[PART_TAG].start, 1); |
416 |
|
if (entry->value == NULL) |
417 |
|
entry->value = vb = varray_open(sizeof(int), 100); |
418 |
|
else |
419 |
|
vb = (VARRAY *)entry->value; |
420 |
|
lno = varray_append(vb); |
421 |
|
*lno = atoi(ptable.part[PART_LNO].start); |
422 |
|
recover(&ptable); |
423 |
} |
} |
|
|
|
|
return h; |
|
424 |
} |
} |
425 |
/* |
/* |
426 |
* compare_lno: compare function for sorting line number. |
* compare_lno: compare function for sorting line number. |
431 |
return *(const int *)s1 - *(const int *)s2; |
return *(const int *)s1 - *(const int *)s2; |
432 |
} |
} |
433 |
/* |
/* |
434 |
* gtop_flush_htab: register each record into the tag database and delete from the hash table. |
* flush_pool: flush the pool and write is as compact format. |
435 |
* |
* |
436 |
* i) gtop descripter of GTOP |
* i) gtop descripter of GTOP |
437 |
*/ |
*/ |
438 |
static void |
static void |
439 |
gtop_flush_htab(GTOP *gtop) |
flush_pool(GTOP *gtop) |
440 |
{ |
{ |
441 |
const char *path, *key; |
struct sh_entry *entry; |
442 |
struct gtop_compact_entry *entry, *next; |
const char *path = gtop->prev_path; |
|
int *lno_array; |
|
|
int i, j, savelen; |
|
443 |
|
|
|
path = gtop->prev_path; |
|
444 |
if (gtop->format & GTAGS_PATHINDEX) { |
if (gtop->format & GTAGS_PATHINDEX) { |
445 |
path = gpath_path2fid(gtop->prev_path); |
path = gpath_path2fid(gtop->prev_path); |
446 |
if (path == NULL) |
if (path == NULL) |
447 |
die("GPATH is corrupted.('%s' not found)", gtop->prev_path); |
die("GPATH is corrupted.('%s' not found)", gtop->prev_path); |
448 |
} |
} |
449 |
|
/* |
450 |
|
* Write records as compact format and free line number table |
451 |
|
* for each entry in the pool. |
452 |
|
*/ |
453 |
|
for (entry = strhash_first(gtop->pool); entry; entry = strhash_next(gtop->pool)) { |
454 |
|
VARRAY *vb = (VARRAY *)entry->value; |
455 |
|
int *lno_array = varray_assign(vb, 0, 0); |
456 |
|
const char *key = entry->name; |
457 |
|
|
458 |
for (i = 0; i < HASHBUCKETS; i++) { |
/* |
459 |
for (entry = gtop->htab[i]; entry != NULL; entry = next) { |
* extract method when class method definition. |
460 |
/* |
* |
461 |
* extract method when class method definition. |
* Ex: Class::method(...) |
462 |
* |
* |
463 |
* Ex: Class::method(...) |
* key = 'method' |
464 |
* |
* data = 'Class::method 103 ./class.cpp ...' |
465 |
* key = 'method' |
*/ |
466 |
* data = 'Class::method 103 ./class.cpp ...' |
if (gtop->flags & GTAGS_EXTRACTMETHOD) { |
467 |
*/ |
if ((key = locatestring(entry->name, ".", MATCH_LAST)) != NULL) |
468 |
key = entry->tag; |
key++; |
469 |
if (gtop->flags & GTAGS_EXTRACTMETHOD) { |
else if ((key = locatestring(entry->name, "::", MATCH_LAST)) != NULL) |
470 |
if ((key = locatestring(entry->tag, ".", MATCH_LAST)) != NULL) |
key += 2; |
471 |
key++; |
else |
472 |
else if ((key = locatestring(entry->tag, "::", MATCH_LAST)) != NULL) |
key = entry->name; |
473 |
key += 2; |
} |
474 |
else |
/* Sort line number table */ |
475 |
key = entry->tag; |
qsort(lno_array, vb->length, sizeof(int), compare_lno); |
476 |
} |
|
477 |
lno_array = varray_assign(entry->vb, 0, 0); |
strbuf_reset(gtop->sb); |
478 |
qsort(lno_array, entry->vb->length, sizeof(int), compare_lno); |
strbuf_puts(gtop->sb, entry->name); |
479 |
strbuf_reset(gtop->sb); |
strbuf_putc(gtop->sb, ' '); |
480 |
strbuf_puts(gtop->sb, entry->tag); |
strbuf_puts(gtop->sb, path); |
481 |
strbuf_putc(gtop->sb, ' '); |
strbuf_putc(gtop->sb, ' '); |
482 |
strbuf_puts(gtop->sb, path); |
{ |
483 |
strbuf_putc(gtop->sb, ' '); |
int savelen = strbuf_getlen(gtop->sb); |
484 |
savelen = strbuf_getlen(gtop->sb); |
int last = 0; /* line 0 doesn't exist */ |
485 |
for (j = 0; j < entry->vb->length; j++) { |
int i; |
486 |
if ((gtop->flags & GTAGS_UNIQUE) && j > 0 |
|
487 |
&& lno_array[j - 1] == lno_array[j]) |
for (i = 0; i < vb->length; i++) { |
488 |
|
int n = lno_array[i]; |
489 |
|
|
490 |
|
if ((gtop->flags & GTAGS_UNIQUE) && n == last) |
491 |
continue; |
continue; |
492 |
if (strbuf_getlen(gtop->sb) > savelen) |
if (strbuf_getlen(gtop->sb) > savelen) |
493 |
strbuf_putc(gtop->sb, ','); |
strbuf_putc(gtop->sb, ','); |
494 |
strbuf_putn(gtop->sb, lno_array[j]); |
strbuf_putn(gtop->sb, n); |
495 |
if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) { |
if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) { |
496 |
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
497 |
strbuf_setlen(gtop->sb, savelen); |
strbuf_setlen(gtop->sb, savelen); |
498 |
} |
} |
499 |
|
last = n; |
500 |
} |
} |
501 |
if (strbuf_getlen(gtop->sb) > savelen) |
if (strbuf_getlen(gtop->sb) > savelen) |
502 |
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
|
varray_close(entry->vb); |
|
|
next = entry->next; |
|
|
free(entry); |
|
503 |
} |
} |
504 |
gtop->htab[i] = NULL; |
/* Free line number table */ |
505 |
|
varray_close(vb); |
506 |
} |
} |
507 |
} |
} |
508 |
/* |
/* |
751 |
void |
void |
752 |
gtags_close(GTOP *gtop) |
gtags_close(GTOP *gtop) |
753 |
{ |
{ |
754 |
if (gtop->htab) { |
if (gtop->pool) { |
755 |
if (gtop->prev_path[0]) |
if (gtop->prev_path[0]) |
756 |
gtop_flush_htab(gtop); |
flush_pool(gtop); |
757 |
free(gtop->htab); |
strhash_close(gtop->pool); |
758 |
} |
} |
759 |
if (gtop->sb) |
if (gtop->sb) |
760 |
strbuf_close(gtop->sb); |
strbuf_close(gtop->sb); |