33 |
#include "global.h" |
#include "global.h" |
34 |
#include "anchor.h" |
#include "anchor.h" |
35 |
#include "htags.h" |
#include "htags.h" |
36 |
|
#include "xargs.h" |
37 |
|
|
38 |
struct anchor_input { |
static XARGS *anchor_input[GTAGLIM]; |
|
STRBUF *command; |
|
|
FILE *ip; |
|
|
STRBUF *ib; |
|
|
char *ctags_x; |
|
|
SPLIT ptable; |
|
|
}; |
|
|
|
|
|
static struct anchor_input anchor_input[GTAGLIM]; |
|
39 |
static struct anchor *table; |
static struct anchor *table; |
40 |
static VARRAY *vb; |
static VARRAY *vb; |
41 |
|
|
60 |
/* |
/* |
61 |
* anchor_prepare: setup input stream. |
* anchor_prepare: setup input stream. |
62 |
* |
* |
63 |
* i) path_list \0 separated list of paths |
* i) anchor_stream file pointer of path list |
|
* |
|
64 |
*/ |
*/ |
65 |
void |
void |
66 |
anchor_prepare(STRBUF *path_list) |
anchor_prepare(FILE *anchor_stream) |
67 |
{ |
{ |
68 |
/* |
/* |
69 |
* Option table: |
* Option table: |
70 |
* We use blank string instead of null string not to change the length. |
* We use blank string as null option instead of null string("") |
71 |
|
* not to change the command length. This length influences |
72 |
|
* the number of arguments in the xargs processing. |
73 |
*/ |
*/ |
74 |
char *options[] = {NULL, " ", "r", "s"}; |
char *options[] = {NULL, " ", "r", "s"}; |
75 |
|
char comline[MAXFILLEN]; |
76 |
int db; |
int db; |
|
struct anchor_input *input; |
|
77 |
|
|
78 |
for (db = GTAGS; db < GTAGLIM; db++) { |
for (db = GTAGS; db < GTAGLIM; db++) { |
|
char comline[MAXFILLEN]; |
|
|
|
|
79 |
if (!symbol && db == GSYMS) |
if (!symbol && db == GSYMS) |
80 |
continue; |
continue; |
81 |
/* |
/* |
|
* Setup input stream. |
|
|
* |
|
82 |
* Htags(1) should not use gtags-parser(1) directly; |
* Htags(1) should not use gtags-parser(1) directly; |
83 |
* it should use global(1) with the -f option instead. |
* it should use global(1) with the -f option instead. |
84 |
* Because gtags-parser is part of the implementation of |
* Because gtags-parser is part of the implementation of |
86 |
* program which uses global(1). If htags depends on |
* program which uses global(1). If htags depends on |
87 |
* gtags-parser, it will become difficult to change the |
* gtags-parser, it will become difficult to change the |
88 |
* implementation of gtags and global. |
* implementation of gtags and global. |
89 |
*/ |
* |
|
snprintf(comline, sizeof(comline), "global -fn%s", options[db]); |
|
|
input = &anchor_input[db]; |
|
|
input->command = strbuf_open(0); |
|
|
input->ib = strbuf_open(MAXBUFLEN); |
|
|
makecommand(comline, path_list, input->command); |
|
|
/* |
|
90 |
* Though the output of global -f is not necessarily sorted |
* Though the output of global -f is not necessarily sorted |
91 |
* by the path, it is guaranteed that the records concerning |
* by the path, it is guaranteed that the records concerning |
92 |
* the same file are consecutive. |
* the same file are consecutive. |
93 |
*/ |
*/ |
94 |
input->ip = popen(strbuf_value(input->command), "r"); |
snprintf(comline, sizeof(comline), "global -fn%s", options[db]); |
95 |
if (input->ip == NULL) |
anchor_input[db] = xargs_open_with_file(comline, 0, anchor_stream); |
|
die("cannot execute command '%s'.", strbuf_value(input->command)); |
|
|
if (input->ctags_x != NULL) { |
|
|
recover(&input->ptable); |
|
|
die("The output of parser is illegal.\n%s", input->ctags_x); |
|
|
} |
|
|
input->ctags_x = strbuf_fgets(input->ib, input->ip, STRBUF_NOCRLF); |
|
|
if (input->ctags_x == NULL) { |
|
|
if (pclose(input->ip) != 0) |
|
|
die("command '%s' failed.", strbuf_value(input->command)); |
|
|
strbuf_close(input->ib); |
|
|
strbuf_close(input->command); |
|
|
continue; |
|
|
} |
|
|
if (split(input->ctags_x, 4, &input->ptable) < 4) { |
|
|
recover(&input->ptable); |
|
|
die("too small number of parts in anchor_prepare().\n'%s'", input->ctags_x); |
|
|
} |
|
|
if (input->ptable.part[PART_PATH].start[0] != '.' |
|
|
|| input->ptable.part[PART_PATH].start[1] != '/') { |
|
|
recover(&input->ptable); |
|
|
die("The output of parser is illegal.\n%s", input->ctags_x); |
|
|
} |
|
96 |
} |
} |
97 |
} |
} |
98 |
/* |
/* |
99 |
* anchor_load: load anchor table |
* anchor_load: load anchor table |
100 |
* |
* |
101 |
* i) file file name |
* i) path path name |
102 |
*/ |
*/ |
103 |
void |
void |
104 |
anchor_load(const char *file) |
anchor_load(const char *path) |
105 |
{ |
{ |
106 |
struct anchor_input *input; |
int db; |
|
int i, db; |
|
107 |
|
|
108 |
FIRST = LAST = 0; |
FIRST = LAST = 0; |
109 |
end = CURRENT = NULL; |
end = CURRENT = NULL; |
114 |
varray_reset(vb); |
varray_reset(vb); |
115 |
|
|
116 |
for (db = GTAGS; db < GTAGLIM; db++) { |
for (db = GTAGS; db < GTAGLIM; db++) { |
117 |
|
XARGS *xp; |
118 |
|
char *ctags_x; |
119 |
|
|
120 |
if (!symbol && db == GSYMS) |
if (!symbol && db == GSYMS) |
121 |
continue; |
continue; |
122 |
input = &anchor_input[db]; |
if ((xp = anchor_input[db]) == NULL) |
123 |
|
continue; |
124 |
/* |
/* |
125 |
* Read from input stream until it reaches end of file |
* Read from input stream until it reaches end of file |
126 |
* or the line of another file appears. |
* or the line of another file appears. |
127 |
*/ |
*/ |
128 |
while (input->ctags_x != NULL |
while ((ctags_x = xargs_read(xp)) != NULL) { |
129 |
&& strcmp(input->ptable.part[PART_PATH].start + 2, file) == 0) { |
SPLIT ptable; |
130 |
struct anchor *a; |
struct anchor *a; |
131 |
int type; |
int type; |
132 |
|
|
133 |
|
if (split(ctags_x, 4, &ptable) < 4) { |
134 |
|
recover(&ptable); |
135 |
|
die("too small number of parts in anchor_prepare().\n'%s'", ctags_x); |
136 |
|
} |
137 |
|
if (!locatestring(ptable.part[PART_PATH].start, "./", MATCH_AT_FIRST)) { |
138 |
|
recover(&ptable); |
139 |
|
die("The output of parser is illegal.\n%s", ctags_x); |
140 |
|
} |
141 |
|
if (strcmp(ptable.part[PART_PATH].start, path) != 0) { |
142 |
|
recover(&ptable); |
143 |
|
xargs_unread(xp); |
144 |
|
break; |
145 |
|
} |
146 |
if (db == GTAGS) { |
if (db == GTAGS) { |
147 |
const char *p; |
char *p; |
148 |
|
|
149 |
for (p = input->ptable.part[PART_LINE].start; *p && isspace((unsigned char)*p); p++) |
for (p = ptable.part[PART_LINE].start; *p && isspace((unsigned char)*p); p++) |
150 |
; |
; |
151 |
if (!*p) { |
if (!*p) { |
152 |
recover(&input->ptable); |
recover(&ptable); |
153 |
die("The output of parser is illegal.\n%s", input->ctags_x); |
die("The output of parser is illegal.\n%s", ctags_x); |
154 |
} |
} |
155 |
type = 'D'; |
type = 'D'; |
156 |
if (*p == '#') { |
if (*p == '#') { |
169 |
type = 'Y'; |
type = 'Y'; |
170 |
/* allocate an entry */ |
/* allocate an entry */ |
171 |
a = varray_append(vb); |
a = varray_append(vb); |
172 |
a->lineno = atoi(input->ptable.part[PART_LNO].start); |
a->lineno = atoi(ptable.part[PART_LNO].start); |
173 |
a->type = type; |
a->type = type; |
174 |
a->done = 0; |
a->done = 0; |
175 |
settag(a, input->ptable.part[PART_TAG].start); |
settag(a, ptable.part[PART_TAG].start); |
176 |
recover(&input->ptable); |
recover(&ptable); |
177 |
input->ctags_x = strbuf_fgets(input->ib, input->ip, STRBUF_NOCRLF); |
} |
178 |
if (input->ctags_x == NULL) { |
if (ctags_x == NULL) { |
179 |
if (pclose(input->ip) != 0) |
xargs_close(anchor_input[db]); |
180 |
die("command '%s' failed.", strbuf_value(input->command)); |
anchor_input[db] = NULL; |
|
strbuf_close(input->ib); |
|
|
strbuf_close(input->command); |
|
|
break; |
|
|
} |
|
|
if (split(input->ctags_x, 4, &input->ptable) < 4) { |
|
|
recover(&input->ptable); |
|
|
die("too small number of parts in anchor_load().\n'%s'", input->ctags_x); |
|
|
} |
|
|
if (input->ptable.part[PART_PATH].start[0] != '.' |
|
|
|| input->ptable.part[PART_PATH].start[1] != '/') { |
|
|
recover(&input->ptable); |
|
|
die("The output of parser is illegal.\n%s", input->ctags_x); |
|
|
} |
|
181 |
} |
} |
182 |
} |
} |
183 |
if (vb->length == 0) { |
if (vb->length == 0) { |
184 |
table = NULL; |
table = NULL; |
185 |
} else { |
} else { |
186 |
int used = vb->length; |
int i, used = vb->length; |
187 |
/* |
/* |
188 |
* Sort by lineno. |
* Sort by lineno. |
189 |
*/ |
*/ |