27 |
#include <stdio.h> |
#include <stdio.h> |
28 |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
29 |
#include <stdlib.h> |
#include <stdlib.h> |
30 |
|
#include <stddef.h> |
31 |
#endif |
#endif |
32 |
#ifdef HAVE_STRING_H |
#ifdef HAVE_STRING_H |
33 |
#include <string.h> |
#include <string.h> |
54 |
#include "strmake.h" |
#include "strmake.h" |
55 |
#include "tab.h" |
#include "tab.h" |
56 |
|
|
57 |
|
#define HASHBUCKETS 256 |
58 |
|
|
59 |
|
static unsigned int hashpjw(const char *); |
60 |
|
static int compare_lno(const void *, const void *); |
61 |
|
static void gtop_flush_htab(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; |
330 |
strlimcpy(gtop->root, root, sizeof(gtop->root)); |
strlimcpy(gtop->root, root, sizeof(gtop->root)); |
331 |
if (gtop->mode == GTAGS_READ) |
if (gtop->mode == GTAGS_READ) |
332 |
gtop->ib = strbuf_open(MAXBUFLEN); |
gtop->ib = strbuf_open(MAXBUFLEN); |
333 |
else |
else { |
334 |
gtop->sb = strbuf_open(0); |
gtop->sb = strbuf_open(0); |
335 |
|
gtop->htab = calloc(sizeof(struct gtop_compact_entry *), HASHBUCKETS); |
336 |
|
if (gtop->htab == NULL) |
337 |
|
die("short of memory."); |
338 |
|
} |
339 |
} else if (gtop->format == GTAGS_PATHINDEX && gtop->mode != GTAGS_READ) |
} else if (gtop->format == GTAGS_PATHINDEX && gtop->mode != GTAGS_READ) |
340 |
gtop->sb = strbuf_open(0); |
gtop->sb = strbuf_open(0); |
341 |
return gtop; |
return gtop; |
356 |
const char *tag; |
const char *tag; |
357 |
const char *record; /* virtually const */ |
const char *record; /* virtually const */ |
358 |
{ |
{ |
359 |
const char *line, *path, *fid; |
const char *line, *path; |
360 |
SPLIT ptable; |
SPLIT ptable; |
361 |
|
struct gtop_compact_entry *entry, **prev; |
362 |
|
int *lno; |
363 |
|
|
364 |
if (gtop->format == GTAGS_STANDARD) { |
if (gtop->format == GTAGS_STANDARD) { |
365 |
/* entab(record); */ |
/* entab(record); */ |
368 |
} |
} |
369 |
if (gtop->format == GTAGS_PATHINDEX) { |
if (gtop->format == GTAGS_PATHINDEX) { |
370 |
char *p = locatestring(record, "./", MATCH_FIRST); |
char *p = locatestring(record, "./", MATCH_FIRST); |
371 |
|
const char *fid; |
372 |
int savec; |
int savec; |
373 |
|
|
374 |
if (p == NULL) |
if (p == NULL) |
400 |
line = ptable.part[1].start; |
line = ptable.part[1].start; |
401 |
path = ptable.part[2].start; |
path = ptable.part[2].start; |
402 |
/* |
/* |
403 |
* First time, it occurs, because 'prev_tag' and 'prev_path' are NULL. |
* Register each record into the hash table. |
404 |
|
* Duplicated records will be combined. |
405 |
*/ |
*/ |
406 |
if (strcmp(gtop->prev_tag, tag) || strcmp(gtop->prev_path, path)) { |
if (gtop->prev_path[0] && strcmp(gtop->prev_path, path)) |
407 |
if (gtop->prev_tag[0]) { |
gtop_flush_htab(gtop); |
408 |
dbop_put(gtop->dbop, gtop->prev_tag, strbuf_value(gtop->sb)); |
strlimcpy(gtop->prev_path, path, sizeof(gtop->prev_path)); |
409 |
} |
for (prev = gtop->htab + hashpjw(record) % HASHBUCKETS; |
410 |
strlimcpy(gtop->prev_tag, tag, sizeof(gtop->prev_tag)); |
(entry = *prev) != NULL; |
411 |
strlimcpy(gtop->prev_path, path, sizeof(gtop->prev_path)); |
prev = &entry->next) { |
412 |
/* |
if (strcmp(entry->tag, record) == 0) |
413 |
* Start creating new record. |
break; |
414 |
*/ |
} |
415 |
strbuf_reset(gtop->sb); |
if (entry == NULL) { |
416 |
strbuf_puts(gtop->sb, strmake(record, " \t")); |
entry = malloc(offsetof(struct gtop_compact_entry, tag) + strlen(record) + 1); |
417 |
strbuf_putc(gtop->sb, ' '); |
if (entry == NULL) |
418 |
if (gtop->format & GTAGS_PATHINDEX) { |
die("short of memory."); |
419 |
fid = gpath_path2fid(path); |
entry->next = NULL; |
420 |
if (fid == NULL) |
entry->vb = varray_open(sizeof(int), 100); |
421 |
die("GPATH is corrupted.('%s' not found)", path); |
strcpy(entry->tag, record); |
422 |
path = fid; |
*prev = entry; |
|
} |
|
|
strbuf_puts(gtop->sb, path); |
|
|
strbuf_putc(gtop->sb, ' '); |
|
|
strbuf_puts(gtop->sb, line); |
|
|
} else { |
|
|
strbuf_putc(gtop->sb, ','); |
|
|
strbuf_puts(gtop->sb, line); |
|
|
if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) |
|
|
gtop->prev_path[0] = '\0'; |
|
423 |
} |
} |
424 |
|
lno = varray_append(entry->vb); |
425 |
|
*lno = atoi(line); |
426 |
recover(&ptable); |
recover(&ptable); |
427 |
} |
} |
428 |
/* |
/* |
429 |
|
* hashpjw: calculate hash value for given string. |
430 |
|
* |
431 |
|
* i) string |
432 |
|
* r) hash value |
433 |
|
*/ |
434 |
|
static unsigned int |
435 |
|
hashpjw(s) |
436 |
|
const char *s; |
437 |
|
{ |
438 |
|
unsigned int h, g; |
439 |
|
|
440 |
|
h = strlen(s); |
441 |
|
while (*s != '\0') { |
442 |
|
h <<= 4; |
443 |
|
h += (unsigned char)*s++; |
444 |
|
g = h & 0xf0000000; |
445 |
|
if (g != 0) |
446 |
|
h = h ^ (g >> 24) ^ g; |
447 |
|
} |
448 |
|
|
449 |
|
return h; |
450 |
|
} |
451 |
|
/* |
452 |
|
* compare_lno: compare function for sorting line number. |
453 |
|
*/ |
454 |
|
static int |
455 |
|
compare_lno(s1, s2) |
456 |
|
const void *s1; |
457 |
|
const void *s2; |
458 |
|
{ |
459 |
|
return *(const int *)s1 - *(const int *)s2; |
460 |
|
} |
461 |
|
/* |
462 |
|
* gtop_flush_htab: register each record into the tag database and delete from the hash table. |
463 |
|
* |
464 |
|
* i) gtop descripter of GTOP |
465 |
|
*/ |
466 |
|
static void |
467 |
|
gtop_flush_htab(gtop) |
468 |
|
GTOP *gtop; |
469 |
|
{ |
470 |
|
const char *path, *key; |
471 |
|
struct gtop_compact_entry *entry, *next; |
472 |
|
int *lno_array; |
473 |
|
int i, j, savelen; |
474 |
|
|
475 |
|
path = gtop->prev_path; |
476 |
|
if (gtop->format & GTAGS_PATHINDEX) { |
477 |
|
path = gpath_path2fid(gtop->prev_path); |
478 |
|
if (path == NULL) |
479 |
|
die("GPATH is corrupted.('%s' not found)", gtop->prev_path); |
480 |
|
} |
481 |
|
|
482 |
|
for (i = 0; i < HASHBUCKETS; i++) { |
483 |
|
for (entry = gtop->htab[i]; entry != NULL; entry = next) { |
484 |
|
/* |
485 |
|
* extract method when class method definition. |
486 |
|
* |
487 |
|
* Ex: Class::method(...) |
488 |
|
* |
489 |
|
* key = 'method' |
490 |
|
* data = 'Class::method 103 ./class.cpp ...' |
491 |
|
*/ |
492 |
|
key = entry->tag; |
493 |
|
if (gtop->flags & GTAGS_EXTRACTMETHOD) { |
494 |
|
if ((key = locatestring(entry->tag, ".", MATCH_LAST)) != NULL) |
495 |
|
key++; |
496 |
|
else if ((key = locatestring(entry->tag, "::", MATCH_LAST)) != NULL) |
497 |
|
key += 2; |
498 |
|
else |
499 |
|
key = entry->tag; |
500 |
|
} |
501 |
|
lno_array = varray_assign(entry->vb, 0, 0); |
502 |
|
qsort(lno_array, entry->vb->length, sizeof(int), compare_lno); |
503 |
|
strbuf_reset(gtop->sb); |
504 |
|
strbuf_puts(gtop->sb, entry->tag); |
505 |
|
strbuf_putc(gtop->sb, ' '); |
506 |
|
strbuf_puts(gtop->sb, path); |
507 |
|
strbuf_putc(gtop->sb, ' '); |
508 |
|
savelen = strbuf_getlen(gtop->sb); |
509 |
|
for (j = 0; j < entry->vb->length; j++) { |
510 |
|
if ((gtop->flags & GTAGS_UNIQUE) && j > 0 |
511 |
|
&& lno_array[j - 1] == lno_array[j]) |
512 |
|
continue; |
513 |
|
if (strbuf_getlen(gtop->sb) > savelen) |
514 |
|
strbuf_putc(gtop->sb, ','); |
515 |
|
strbuf_putn(gtop->sb, lno_array[j]); |
516 |
|
if (strbuf_getlen(gtop->sb) > DBOP_PAGESIZE / 4) { |
517 |
|
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
518 |
|
strbuf_setlen(gtop->sb, savelen); |
519 |
|
} |
520 |
|
} |
521 |
|
if (strbuf_getlen(gtop->sb) > savelen) |
522 |
|
dbop_put(gtop->dbop, key, strbuf_value(gtop->sb)); |
523 |
|
varray_close(entry->vb); |
524 |
|
next = entry->next; |
525 |
|
free(entry); |
526 |
|
} |
527 |
|
gtop->htab[i] = NULL; |
528 |
|
} |
529 |
|
} |
530 |
|
/* |
531 |
* gtags_add: add tags belonging to the path list into tag file. |
* gtags_add: add tags belonging to the path list into tag file. |
532 |
* |
* |
533 |
* i) gtop descripter of GTOP |
* i) gtop descripter of GTOP |
547 |
STRBUF *sb = strbuf_open(0); |
STRBUF *sb = strbuf_open(0); |
548 |
STRBUF *ib = strbuf_open(MAXBUFLEN); |
STRBUF *ib = strbuf_open(MAXBUFLEN); |
549 |
const char *path, *end; |
const char *path, *end; |
550 |
|
int path_num; |
551 |
|
|
552 |
|
gtop->flags = flags; |
553 |
/* |
/* |
554 |
* add path index if not yet. |
* add path index if not yet. |
555 |
*/ |
*/ |
556 |
path = strbuf_value(path_list); |
path = strbuf_value(path_list); |
557 |
end = path + strbuf_getlen(path_list); |
end = path + strbuf_getlen(path_list); |
558 |
|
path_num = 0; |
559 |
while (path < end) { |
while (path < end) { |
560 |
gpath_put(path); |
gpath_put(path); |
561 |
|
path_num++; |
562 |
path += strlen(path) + 1; |
path += strlen(path) + 1; |
563 |
} |
} |
564 |
/* |
/* |
568 |
/* |
/* |
569 |
* Compact format. |
* Compact format. |
570 |
*/ |
*/ |
571 |
if (gtop->format & GTAGS_COMPACT) { |
if ((gtop->format & GTAGS_COMPACT) != 0 |
572 |
strbuf_puts(sb, "| gnusort -k3,3 -k 1,1 -k 2,2n"); |
&& locatestring(comline, "gtags-parser", MATCH_FIRST) == NULL |
573 |
if (flags & GTAGS_UNIQUE) |
&& path_num > 1) |
574 |
strbuf_puts(sb, " -u"); |
strbuf_puts(sb, "| gnusort -k3,3"); |
|
} |
|
575 |
#ifdef DEBUG |
#ifdef DEBUG |
576 |
if (flags & GTAGS_DEBUG) |
if (flags & GTAGS_DEBUG) |
577 |
fprintf(stderr, "gtags_add() executing '%s'\n", strbuf_value(sb)); |
fprintf(stderr, "gtags_add() executing '%s'\n", strbuf_value(sb)); |
774 |
gtags_close(gtop) |
gtags_close(gtop) |
775 |
GTOP *gtop; |
GTOP *gtop; |
776 |
{ |
{ |
777 |
if (gtop->format & GTAGS_PATHINDEX || gtop->mode != GTAGS_READ) |
if (gtop->htab) { |
778 |
gpath_close(); |
if (gtop->prev_path[0]) |
779 |
if (gtop->sb && gtop->prev_tag[0]) |
gtop_flush_htab(gtop); |
780 |
dbop_put(gtop->dbop, gtop->prev_tag, strbuf_value(gtop->sb)); |
free(gtop->htab); |
781 |
|
} |
782 |
if (gtop->sb) |
if (gtop->sb) |
783 |
strbuf_close(gtop->sb); |
strbuf_close(gtop->sb); |
784 |
if (gtop->ib) |
if (gtop->ib) |
785 |
strbuf_close(gtop->ib); |
strbuf_close(gtop->ib); |
786 |
|
if (gtop->format & GTAGS_PATHINDEX || gtop->mode != GTAGS_READ) |
787 |
|
gpath_close(); |
788 |
dbop_close(gtop->dbop); |
dbop_close(gtop->dbop); |
789 |
free(gtop); |
free(gtop); |
790 |
} |
} |