103 |
* |
* |
104 |
* Since we know the format version 3 is better than 1 in all aspect, |
* Since we know the format version 3 is better than 1 in all aspect, |
105 |
* the default format version will be changed into 3 in the future. |
* the default format version will be changed into 3 in the future. |
106 |
|
* |
107 |
|
* [Example of each format] |
108 |
|
* |
109 |
|
* [gtags/gtags.c] |
110 |
|
* +----------------------------- |
111 |
|
* 1|... |
112 |
|
* 2| * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 |
113 |
|
* ..... |
114 |
|
* 203|main(int argc, char **argv) |
115 |
|
* |{ |
116 |
|
* |
117 |
|
* (Standard format) |
118 |
|
* |
119 |
|
* 0 1 2 3 |
120 |
|
* ------------------------------------------------------------------ |
121 |
|
* main 203 ./gtags/gtags.c main(int argc, char **argv) |
122 |
|
* |
123 |
|
* (Pathindex format) |
124 |
|
* 0 1 2 3 |
125 |
|
* ---------------------------------------------------- |
126 |
|
* main 203 22 main(int argc, char **argv) |
127 |
|
* |
128 |
|
* (Compact format) |
129 |
|
* |
130 |
|
* 0 1 2 |
131 |
|
* ---------------------------------------------------- |
132 |
|
* main 22 203 |
133 |
*/ |
*/ |
134 |
static int support_version = 3; /* acceptable format version */ |
static int support_version = 3; /* acceptable format version */ |
135 |
static const char *tagslist[] = {"GPATH", "GTAGS", "GRTAGS", "GSYMS"}; |
static const char *tagslist[] = {"GPATH", "GTAGS", "GRTAGS", "GSYMS"}; |
185 |
/* |
/* |
186 |
* formatcheck: check format of tag command's output |
* formatcheck: check format of tag command's output |
187 |
* |
* |
188 |
* i) line input |
* i) ctags_x tag line (ctags -x format) |
189 |
* |
* |
190 |
* 0 1 2 3 |
* 0 1 2 3 |
191 |
* ---------------------------------------------------- |
* ---------------------------------------------------- |
194 |
void |
void |
195 |
formatcheck(const char *ctags_x) /* virtually const */ |
formatcheck(const char *ctags_x) /* virtually const */ |
196 |
{ |
{ |
|
int n; |
|
197 |
const char *p; |
const char *p; |
198 |
SPLIT ptable; |
SPLIT ptable; |
199 |
|
|
200 |
/* |
/* |
201 |
* Extract parts. |
* Extract parts. |
202 |
*/ |
*/ |
203 |
n = split((char *)ctags_x, 4, &ptable); |
split((char *)ctags_x, 4, &ptable); |
204 |
|
|
205 |
/* |
/* |
206 |
* line number |
* line number |
207 |
*/ |
*/ |
208 |
if (n < 4) { |
if (ptable.npart < 4) { |
209 |
recover(&ptable); |
recover(&ptable); |
210 |
die("too small number of parts.\n'%s'", ctags_x); |
die("too small number of parts.\n'%s'", ctags_x); |
211 |
} |
} |
622 |
void |
void |
623 |
gtags_delete(GTOP *gtop, IDSET *deleteset) |
gtags_delete(GTOP *gtop, IDSET *deleteset) |
624 |
{ |
{ |
625 |
const char *line, *p; |
const char *tagline, *s_fid; |
626 |
SPLIT ptable; |
SPLIT ptable; |
627 |
int fid, n; |
int fid; |
628 |
|
|
629 |
for (line = dbop_first(gtop->dbop, NULL, NULL, 0); line; line = dbop_next(gtop->dbop)) { |
for (tagline = dbop_first(gtop->dbop, NULL, NULL, 0); tagline; tagline = dbop_next(gtop->dbop)) { |
630 |
/* |
/* |
631 |
* Extract the path, and if needed, convert it into the file id. |
* Extract fid from the tag line. |
632 |
*/ |
*/ |
633 |
n = split((char *)line, 4, &ptable); |
split((char *)tagline, 4, &ptable); |
634 |
if (gtop->format & GTAGS_COMPACT) { |
if (gtop->format == GTAGS_STANDARD) { |
635 |
if (n != 3) |
if (ptable.npart < 4) { |
|
die("illegal compact format.\n"); |
|
|
p = ptable.part[1].start; |
|
|
} else { |
|
|
if (n < 4) { |
|
636 |
recover(&ptable); |
recover(&ptable); |
637 |
die("too small number of parts.\n'%s'", line); |
die("too small number of parts.\n'%s'", tagline); |
638 |
} |
} |
639 |
p = ptable.part[2].start; |
s_fid = gpath_path2fid(ptable.part[PART_PATH].start); |
640 |
} |
if (s_fid == NULL) |
|
if (!(gtop->format & GTAGS_PATHINDEX)) { |
|
|
p = gpath_path2fid(p); |
|
|
if (p == NULL) |
|
641 |
die("GPATH is corrupted."); |
die("GPATH is corrupted."); |
642 |
} |
} |
643 |
fid = atoi(p); |
else if (gtop->format == GTAGS_PATHINDEX) { |
644 |
|
if (ptable.npart < 4) { |
645 |
|
recover(&ptable); |
646 |
|
die("too small number of parts in pathindex format.\n'%s'", tagline); |
647 |
|
} |
648 |
|
s_fid = ptable.part[PART_FID_PIDX].start; |
649 |
|
} else { /* gtop->format & GTAGS_COMPACT */ |
650 |
|
if (ptable.npart != 3) { |
651 |
|
recover(&ptable); |
652 |
|
die("too small number of parts in compact format.\n'%s'", tagline); |
653 |
|
} |
654 |
|
s_fid = ptable.part[PART_FID_COMP].start; |
655 |
|
} |
656 |
|
fid = atoi(s_fid); |
657 |
recover(&ptable); |
recover(&ptable); |
658 |
/* |
/* |
659 |
* If the file id exists in the deleteset, delete the record. |
* If the file id exists in the deleteset, delete the tagline. |
660 |
*/ |
*/ |
661 |
if (idset_contains(deleteset, fid)) |
if (idset_contains(deleteset, fid)) |
662 |
dbop_delete(gtop->dbop, NULL); |
dbop_delete(gtop->dbop, NULL); |
683 |
int dbflags = 0; |
int dbflags = 0; |
684 |
char prefix[IDENTLEN+1]; |
char prefix[IDENTLEN+1]; |
685 |
regex_t *preg = ® |
regex_t *preg = ® |
686 |
const char *key, *p, *line; |
const char *key, *tagline; |
687 |
int regflags = 0; |
int regflags = 0; |
688 |
|
|
689 |
gtop->flags = flags; |
gtop->flags = flags; |
697 |
if (flags & GTOP_IGNORECASE) |
if (flags & GTOP_IGNORECASE) |
698 |
regflags |= REG_ICASE; |
regflags |= REG_ICASE; |
699 |
|
|
700 |
|
/* |
701 |
|
* Get key and compiled regular expression for dbop_xxxx(). |
702 |
|
*/ |
703 |
if (flags & GTOP_NOREGEX) { |
if (flags & GTOP_NOREGEX) { |
704 |
key = pattern; |
key = pattern; |
705 |
preg = NULL; |
preg = NULL; |
706 |
} else if (pattern == NULL || !strcmp(pattern, ".*")) { |
} else if (pattern == NULL || !strcmp(pattern, ".*")) { |
707 |
|
/* |
708 |
|
* Since the regular expression '.*' matches to any record, |
709 |
|
* we take sequential read method. |
710 |
|
*/ |
711 |
key = NULL; |
key = NULL; |
712 |
preg = NULL; |
preg = NULL; |
713 |
} else if (isregex(pattern) && regcomp(preg, pattern, regflags) == 0) { |
} else if (isregex(pattern) && regcomp(preg, pattern, regflags) == 0) { |
714 |
|
const char *p; |
715 |
|
|
716 |
|
/* |
717 |
|
* If the pattern include '^' + some non regular expression |
718 |
|
* characters like '^aaa[0-9]', we take prefix read method |
719 |
|
* with the non regular expression part as the prefix. |
720 |
|
*/ |
721 |
if (!(flags & GTOP_IGNORECASE) && *pattern == '^' && *(p = pattern + 1) && !isregexchar(*p)) { |
if (!(flags & GTOP_IGNORECASE) && *pattern == '^' && *(p = pattern + 1) && !isregexchar(*p)) { |
722 |
int i = 0; |
int i = 0; |
723 |
|
|
733 |
key = pattern; |
key = pattern; |
734 |
preg = NULL; |
preg = NULL; |
735 |
} |
} |
736 |
if ((line = dbop_first(gtop->dbop, key, preg, dbflags)) == NULL) |
tagline = dbop_first(gtop->dbop, key, preg, dbflags); |
737 |
return NULL; |
if (tagline) { |
738 |
if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY) |
if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY) |
739 |
return line; |
return tagline; |
740 |
if (gtop->format == GTAGS_PATHINDEX) |
else if (gtop->format == GTAGS_PATHINDEX) |
741 |
return unpack_pathindex(line); |
return unpack_pathindex(tagline); |
742 |
/* |
else { /* Compact format */ |
743 |
* Compact format. |
gtop->line = (char *)tagline; |
744 |
*/ |
gtop->opened = 0; |
745 |
gtop->line = (char *)line; /* gtop->line = $0 */ |
return genrecord(gtop); |
746 |
gtop->opened = 0; |
} |
747 |
return genrecord(gtop); |
} |
748 |
|
return NULL; |
749 |
} |
} |
750 |
/* |
/* |
751 |
* gtags_next: return followed record |
* gtags_next: return followed record |
757 |
const char * |
const char * |
758 |
gtags_next(GTOP *gtop) |
gtags_next(GTOP *gtop) |
759 |
{ |
{ |
760 |
const char *line; |
const char *tagline; |
761 |
/* |
/* |
762 |
* If it is standard format or only key. |
* If it is standard format or only key. |
763 |
* Just return it. |
* Just return it. |
764 |
*/ |
*/ |
765 |
if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY) |
if (gtop->format == GTAGS_STANDARD || gtop->flags & GTOP_KEY) { |
766 |
return dbop_next(gtop->dbop); |
return dbop_next(gtop->dbop); |
767 |
|
} |
768 |
/* |
/* |
769 |
* Pathindex format. |
* Pathindex format. |
770 |
*/ |
*/ |
771 |
if (gtop->format == GTAGS_PATHINDEX) { |
else if (gtop->format == GTAGS_PATHINDEX) { |
772 |
line = dbop_next(gtop->dbop); |
tagline = dbop_next(gtop->dbop); |
773 |
if (line == NULL) |
return (tagline == NULL) ? NULL : unpack_pathindex(tagline); |
|
return NULL; |
|
|
return unpack_pathindex(line); |
|
774 |
} |
} |
775 |
/* |
/* |
776 |
* gtop->format & GTAGS_COMPACT |
* gtop->format & GTAGS_COMPACT |
777 |
*/ |
*/ |
778 |
if ((line = genrecord(gtop)) != NULL) |
else { |
779 |
return line; |
const char *ctags_x; |
780 |
/* |
|
781 |
* read next record. |
/* |
782 |
*/ |
* If some unpacked record exists then return one of them |
783 |
if ((line = dbop_next(gtop->dbop)) == NULL) |
* else read the next tag line. |
784 |
return line; |
*/ |
785 |
gtop->line = (char *)line; /* gtop->line = $0 */ |
if ((ctags_x = genrecord(gtop)) != NULL) |
786 |
gtop->opened = 0; |
return ctags_x; |
787 |
return genrecord(gtop); |
if ((tagline = dbop_next(gtop->dbop)) == NULL) |
788 |
|
return NULL; |
789 |
|
gtop->line = (char *)tagline; /* gtop->line = $0 */ |
790 |
|
gtop->opened = 0; |
791 |
|
return genrecord(gtop); |
792 |
|
} |
793 |
} |
} |
794 |
/* |
/* |
795 |
* gtags_close: close tag file |
* gtags_close: close tag file |
816 |
/* |
/* |
817 |
* unpack_pathindex: convert pathindex format into standard format. |
* unpack_pathindex: convert pathindex format into standard format. |
818 |
* |
* |
819 |
* i) line tag line |
* i) tagline tag line (pathindex format) |
820 |
*/ |
*/ |
821 |
static const char * |
static const char * |
822 |
unpack_pathindex(const char *line) /* virtually const */ |
unpack_pathindex(const char *tagline) /* virtually const */ |
823 |
{ |
{ |
824 |
STATIC_STRBUF(output); |
STATIC_STRBUF(output); |
825 |
SPLIT ptable; |
SPLIT ptable; |
|
int n; |
|
826 |
const char *path; |
const char *path; |
827 |
|
|
828 |
n = split((char *)line, 4, &ptable); |
split((char *)tagline, 4, &ptable); |
829 |
if (n < 4) { |
if (ptable.npart < 4) { |
830 |
recover(&ptable); |
recover(&ptable); |
831 |
die("illegal tag format.'%s'\n", line); |
die("illegal tag format.'%s'\n", tagline); |
832 |
} |
} |
833 |
/* |
/* |
834 |
* extract path and convert into file number. |
* extract file id and convert into path name. |
835 |
*/ |
*/ |
836 |
path = gpath_fid2path(ptable.part[2].start); |
path = gpath_fid2path(ptable.part[PART_FID_PIDX].start); |
837 |
if (path == NULL) |
if (path == NULL) |
838 |
die("GPATH is corrupted.(fid '%s' not found)", ptable.part[2].start); |
die("GPATH is corrupted.(fid '%s' not found)", ptable.part[PART_FID_PIDX].start); |
839 |
recover(&ptable); |
recover(&ptable); |
840 |
/* |
/* |
841 |
* copy line with converting. |
* copy line with converting fid into path name. |
842 |
*/ |
*/ |
843 |
strbuf_clear(output); |
strbuf_clear(output); |
844 |
strbuf_nputs(output, line, ptable.part[2].start - line); |
strbuf_nputs(output, tagline, ptable.part[PART_FID_PIDX].start - tagline); |
845 |
strbuf_puts(output, path); |
strbuf_puts(output, path); |
846 |
strbuf_puts(output, ptable.part[2].end); |
strbuf_puts(output, ptable.part[PART_FID_PIDX].end); |
847 |
|
|
848 |
return strbuf_value(output); |
return strbuf_value(output); |
849 |
} |
} |
856 |
static const char * |
static const char * |
857 |
genrecord(GTOP *gtop) |
genrecord(GTOP *gtop) |
858 |
{ |
{ |
|
SPLIT ptable; |
|
|
static char output[MAXBUFLEN+1]; |
|
|
char path[MAXPATHLEN+1]; |
|
|
static char buf[1]; |
|
|
const char *buffer = buf; |
|
859 |
const char *lnop; |
const char *lnop; |
|
int tagline; |
|
860 |
|
|
861 |
if (!gtop->opened) { |
if (!gtop->opened) { |
862 |
int n; |
SPLIT ptable; |
863 |
const char *p; |
const char *fid, *path; |
864 |
|
|
865 |
gtop->opened = 1; |
gtop->opened = 1; |
866 |
n = split(gtop->line, 3, &ptable); |
split(gtop->line, 3, &ptable); |
867 |
if (n != 3) { |
if (ptable.npart != 3) { |
868 |
recover(&ptable); |
recover(&ptable); |
869 |
die("illegal compact format. '%s'\n", gtop->line); |
die("illegal compact format. '%s'\n", gtop->line); |
870 |
} |
} |
871 |
/* |
/* Tag name */ |
872 |
* gtop->tag = part[0] |
strlimcpy(gtop->tag, ptable.part[PART_TAG].start, sizeof(gtop->tag)); |
|
*/ |
|
|
strlimcpy(gtop->tag, ptable.part[0].start, sizeof(gtop->tag)); |
|
873 |
|
|
874 |
/* |
/* Path name */ |
875 |
* gtop->path = part[1] |
fid = ptable.part[PART_FID_COMP].start; |
876 |
*/ |
if ((path = gpath_fid2path(fid)) == NULL) |
877 |
p = ptable.part[1].start; |
die("GPATH is corrupted.('%s' not found)", fid); |
878 |
if (gtop->format & GTAGS_PATHINDEX) { |
strlimcpy(gtop->path, path, sizeof(gtop->path)); |
|
const char *q; |
|
|
if ((q = gpath_fid2path(p)) == NULL) |
|
|
die("GPATH is corrupted.('%s' not found)", p); |
|
|
p = q; |
|
|
} |
|
|
strlimcpy(gtop->path, p, sizeof(gtop->path)); |
|
879 |
|
|
880 |
|
/* line number list */ |
881 |
|
gtop->lnop = ptable.part[PART_LNO_COMP].start; |
882 |
/* |
/* |
883 |
* gtop->lnop = part[2] |
* Open source file. |
884 |
*/ |
*/ |
|
gtop->lnop = ptable.part[2].start; |
|
|
|
|
|
if (gtop->root) |
|
|
snprintf(path, sizeof(path), |
|
|
"%s/%s", gtop->root, >op->path[2]); |
|
|
else |
|
|
snprintf(path, sizeof(path), "%s", >op->path[2]); |
|
885 |
if (!(gtop->flags & GTOP_NOSOURCE)) { |
if (!(gtop->flags & GTOP_NOSOURCE)) { |
886 |
if ((gtop->fp = fopen(path, "r")) != NULL) |
char path[MAXPATHLEN+1]; |
887 |
gtop->lno = 0; |
|
888 |
|
if (gtop->root) |
889 |
|
snprintf(path, sizeof(path), |
890 |
|
"%s/%s", gtop->root, >op->path[2]); |
891 |
|
else |
892 |
|
snprintf(path, sizeof(path), "%s", >op->path[2]); |
893 |
|
gtop->fp = fopen(path, "r"); |
894 |
|
gtop->lno = 0; |
895 |
} |
} |
896 |
recover(&ptable); |
recover(&ptable); |
897 |
} |
} |
898 |
|
|
899 |
lnop = gtop->lnop; |
lnop = gtop->lnop; |
900 |
if (*lnop >= '0' && *lnop <= '9') { |
if (*lnop >= '0' && *lnop <= '9') { |
901 |
|
const char *src = ""; |
902 |
|
static char output[MAXBUFLEN+1]; |
903 |
|
int lno; |
904 |
|
|
905 |
/* get line number */ |
/* get line number */ |
906 |
for (tagline = 0; *lnop >= '0' && *lnop <= '9'; lnop++) |
for (lno = 0; *lnop >= '0' && *lnop <= '9'; lnop++) |
907 |
tagline = tagline * 10 + *lnop - '0'; |
lno = lno * 10 + *lnop - '0'; |
908 |
if (*lnop == ',') |
if (*lnop == ',') |
909 |
lnop++; |
lnop++; |
910 |
gtop->lnop = lnop; |
gtop->lnop = lnop; |
911 |
if (gtop->fp) { |
if (gtop->fp) { |
912 |
if (gtop->lno == tagline) |
/* |
913 |
|
* If it is duplicate line, return the previous line. |
914 |
|
*/ |
915 |
|
if (gtop->lno == lno) |
916 |
return output; |
return output; |
917 |
while (gtop->lno < tagline) { |
while (gtop->lno < lno) { |
918 |
if (!(buffer = strbuf_fgets(gtop->ib, gtop->fp, STRBUF_NOCRLF))) |
if (!(src = strbuf_fgets(gtop->ib, gtop->fp, STRBUF_NOCRLF))) |
919 |
die("unexpected end of file. '%s'", gtop->path); |
die("unexpected end of file. '%s'", gtop->path); |
920 |
strbuf_trim(gtop->ib); |
strbuf_trim(gtop->ib); |
921 |
gtop->lno++; |
gtop->lno++; |
922 |
} |
} |
923 |
} |
} |
924 |
snprintf(output, sizeof(output), "%-16s %4d %-16s %s", |
snprintf(output, sizeof(output), "%-16s %4d %-16s %s", |
925 |
gtop->tag, tagline, gtop->path, buffer); |
gtop->tag, lno, gtop->path, src); |
926 |
return output; |
return output; |
927 |
|
} else { |
928 |
|
if (gtop->opened && gtop->fp != NULL) { |
929 |
|
gtop->opened = 0; |
930 |
|
fclose(gtop->fp); |
931 |
|
gtop->fp = NULL; |
932 |
|
} |
933 |
|
return NULL; |
934 |
} |
} |
|
if (gtop->opened && gtop->fp != NULL) { |
|
|
gtop->opened = 0; |
|
|
fclose(gtop->fp); |
|
|
gtop->fp = NULL; |
|
|
} |
|
|
return NULL; |
|
935 |
} |
} |