/* */
This source file includes following definitions.
- set_encode_chars
- set_print0
- decode_path
- convert_pathname
- convert_open
- convert_put
- convert_put_path
- convert_put_using
- convert_close
1 /*
2 * Copyright (c) 2005, 2006, 2010 Tama Communications Corporation
3 *
4 * This file is part of GNU GLOBAL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef STDC_HEADERS
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32
33 #include "abs2rel.h"
34 #include "checkalloc.h"
35 #include "die.h"
36 #include "format.h"
37 #include "gparam.h"
38 #include "gpathop.h"
39 #include "gtagsop.h"
40 #include "pathconvert.h"
41 #include "strbuf.h"
42 #include "strlimcpy.h"
43
44 static unsigned char encode[256];
45 static int encoding;
46 static int newline = '\n';
47
48 #define required_encode(c) encode[(unsigned char)c]
49 /**
50 * set_encode_chars: stores chars to be encoded.
51 */
52 void
53 set_encode_chars(const unsigned char *chars)
54 {
55 unsigned int i;
56
57 /* clean the table */
58 memset(encode, 0, sizeof(encode));
59 /* set bits */
60 for (i = 0; chars[i]; i++) {
61 encode[(unsigned char)chars[i]] = 1;
62 }
63 /* You cannot encode '.' and '/'. */
64 encode['.'] = 0;
65 encode['/'] = 0;
66 /* '%' is always encoded when encode is enable. */
67 encode['%'] = 1;
68 encoding = 1;
69 }
70 /**
71 * set_print0: change newline to @CODE{'\0'}.
72 */
73 void
74 set_print0(void)
75 {
76 newline = '\0';
77 }
78 #define outofrange(c) (c < '0' || c > 'f')
79 #define h2int(c) (c >= 'a' ? c - 'a' + 10 : c - '0')
80 /**
81 * decode_path: decode encoded path name.
82 *
83 * @param[in] path encoded path name
84 * @return decoded path name
85 */
86 char *
87 decode_path(const char *path)
88 {
89 STATIC_STRBUF(sb);
90 const char *p;
91
92 if (strchr(path, '%') == NULL)
93 return (char *)path;
94 strbuf_clear(sb);
95 for (p = path; *p; p++) {
96 if (*p == '%') {
97 unsigned char c1, c2;
98 c1 = *++p;
99 c2 = *++p;
100 if (outofrange(c1) || outofrange(c2))
101 die("decode_path: unexpected character. (%%%c%c)", c1, c2);
102 strbuf_putc(sb, h2int(c1) * 16 + h2int(c2));
103 } else
104 strbuf_putc(sb, *p);
105 }
106 return strbuf_value(sb);
107 }
108 /**
109 * Path filter for the output of @XREF{global,1}.
110 */
111 static const char *
112 convert_pathname(CONVERT *cv, const char *path)
113 {
114 static char buf[MAXPATHLEN];
115 const char *a, *b;
116
117 if (cv->type != PATH_THROUGH) {
118 /*
119 * make absolute path name.
120 * 'path + 1' means skipping "." at the head.
121 */
122 strbuf_setlen(cv->abspath, cv->start_point);
123 strbuf_puts(cv->abspath, path + 1);
124 /*
125 * print path name with converting.
126 */
127 switch (cv->type) {
128 case PATH_ABSOLUTE:
129 path = strbuf_value(cv->abspath);
130 break;
131 case PATH_RELATIVE:
132 case PATH_SHORTER:
133 a = strbuf_value(cv->abspath);
134 b = cv->basedir;
135 #if defined(_WIN32) || defined(__DJGPP__)
136 while (*a != '/')
137 a++;
138 while (*b != '/')
139 b++;
140 #endif
141 if (!abs2rel(a, b, buf, sizeof(buf)))
142 die("abs2rel failed. (path=%s, base=%s).", a, b);
143 path = buf;
144 if (cv->type == PATH_SHORTER && strlen(path) > strbuf_getlen(cv->abspath))
145 path = strbuf_value(cv->abspath);
146 break;
147 default:
148 die("unknown path type.");
149 break;
150 }
151 }
152 /*
153 * encoding of the path name.
154 */
155 if (encoding) {
156 const char *p;
157 int required = 0;
158
159 for (p = path; *p; p++) {
160 if (required_encode(*p)) {
161 required = 1;
162 break;
163 }
164 }
165 if (required) {
166 static char buf[MAXPATHLEN];
167 char c[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
168 char *q = buf;
169
170 for (p = path; *p; p++) {
171 if (required_encode(*p)) {
172 *q++ = '%';
173 *q++ = c[*p / 16];
174 *q++ = c[*p % 16];
175 } else
176 *q++ = *p;
177 }
178 *q = '\0';
179 path = buf;
180 }
181 }
182 return (const char *)path;
183 }
184 /**
185 * convert_open: open convert filter
186 *
187 * @param[in] type #PATH_ABSOLUTE, #PATH_RELATIVE, #PATH_THROUGH
188 * @param[in] format tag record format
189 * @param[in] root root directory of source tree
190 * @param[in] cwd current directory
191 * @param[in] dbpath dbpath directory
192 * @param[in] op output file
193 * @param[in] db tag type (#GTAGS, #GRTAGS, #GSYMS, #GPATH, #NOTAGS) <br>
194 * only for @NAME{cscope} format
195 */
196 CONVERT *
197 convert_open(int type, int format, const char *root, const char *cwd, const char *dbpath, FILE *op, int db)
198 {
199 CONVERT *cv = (CONVERT *)check_calloc(sizeof(CONVERT), 1);
200 /*
201 * set base directory.
202 */
203 cv->abspath = strbuf_open(MAXPATHLEN);
204 strbuf_puts(cv->abspath, root);
205 strbuf_unputc(cv->abspath, '/');
206 cv->start_point = strbuf_getlen(cv->abspath);
207 /*
208 * copy elements.
209 */
210 if (strlen(cwd) > MAXPATHLEN)
211 die("current directory name too long.");
212 strlimcpy(cv->basedir, cwd, sizeof(cv->basedir));
213 cv->type = type;
214 cv->format = format;
215 cv->op = op;
216 cv->db = db;
217 /*
218 * open GPATH.
219 */
220 if (gpath_open(dbpath, 0) < 0)
221 die("GPATH not found.");
222 return cv;
223 }
224 /**
225 * convert_put: convert path into relative or absolute and print.
226 *
227 * @param[in] cv #CONVERT structure
228 * @param[in] ctags_x tag record (@NAME{ctags-x} format)
229 *
230 * @note This function is only called by @NAME{gtags} with the @OPTION{--path} option.
231 */
232 void
233 convert_put(CONVERT *cv, const char *ctags_x)
234 {
235 char *tagnextp = NULL;
236 int tagnextc = 0;
237 char *tag = NULL, *lineno = NULL, *path, *rest = NULL;
238 const char *fid = NULL;
239
240 if (cv->format == FORMAT_PATH)
241 die("convert_put: internal error."); /* Use convert_put_path() */
242 /*
243 * parse tag line.
244 * Don't use split() function not to destroy line image.
245 */
246 {
247 char *p = (char *)ctags_x;
248 /*
249 * tag name
250 */
251 tag = p;
252 for (; *p && !isspace(*p); p++)
253 ;
254 if (*p == '\0')
255 die("illegal ctags-x format (line number not found).");
256 tagnextp = p;
257 tagnextc = *p;
258 *p++ = '\0';
259 /* skip blanks */
260 for (; *p && isspace(*p); p++)
261 ;
262 if (*p == '\0')
263 die("illegal ctags-x format (line number not found).");
264 /*
265 * line number
266 */
267 lineno = p;
268 for (; *p && !isspace(*p); p++)
269 ;
270 if (*p == '\0')
271 die("illegal ctags-x format (path name not found).");
272 *p++ = '\0';
273 /* skip blanks */
274 for (; *p && isspace(*p); p++)
275 ;
276 if (*p == '\0')
277 die("illegal ctags-x format (path name not found).");
278 /*
279 * path name
280 */
281 path = p;
282 for (; *p && !isspace(*p); p++)
283 ;
284 if (*p == '\0')
285 die("illegal ctags-x format (line image not found).");
286 *p++ = '\0';
287 rest = p;
288 }
289 /*
290 * The path name has already been encoded.
291 */
292 path = decode_path(path);
293 switch (cv->format) {
294 case FORMAT_CTAGS:
295 fputs(tag, cv->op);
296 fputc('\t', cv->op);
297 fputs(convert_pathname(cv, path), cv->op);
298 fputc('\t', cv->op);
299 fputs(lineno, cv->op);
300 break;
301 case FORMAT_CTAGS_XID:
302 fid = gpath_path2fid(path, NULL);
303 if (fid == NULL)
304 die("convert_put: unknown file. '%s'", path);
305 fputs(fid, cv->op);
306 fputc(' ', cv->op);
307 /* PASS THROUGH */
308 case FORMAT_CTAGS_X:
309 /*
310 * print until path name.
311 */
312 *tagnextp = tagnextc;
313 fputs(ctags_x, cv->op);
314 fputc(' ', cv->op);
315 /*
316 * print path name and the rest.
317 */
318 fputs(convert_pathname(cv, path), cv->op);
319 fputc(' ', cv->op);
320 fputs(rest, cv->op);
321 break;
322 case FORMAT_CTAGS_MOD:
323 fputs(convert_pathname(cv, path), cv->op);
324 fputc('\t', cv->op);
325 fputs(lineno, cv->op);
326 fputc('\t', cv->op);
327 fputs(rest, cv->op);
328 break;
329 case FORMAT_GREP:
330 fputs(convert_pathname(cv, path), cv->op);
331 fputc(':', cv->op);
332 fputs(lineno, cv->op);
333 fputc(':', cv->op);
334 fputs(rest, cv->op);
335 break;
336 case FORMAT_CSCOPE:
337 fputs(convert_pathname(cv, path), cv->op);
338 fputc(' ', cv->op);
339 fputs(tag, cv->op);
340 fputc(' ', cv->op);
341 fputs(lineno, cv->op);
342 fputc(' ', cv->op);
343 for (; *rest && isspace(*rest); rest++)
344 ;
345 if (*rest)
346 fputs(rest, cv->op);
347 else
348 fputs("<unknown>", cv->op);
349 break;
350 default:
351 die("unknown format type.");
352 }
353 (void)fputc(newline, cv->op);
354 }
355 /**
356 * convert_put_path: convert @a path into relative or absolute and print.
357 *
358 * @param[in] cv #CONVERT structure
359 * @param[in] path path name
360 */
361 void
362 convert_put_path(CONVERT *cv, const char *path)
363 {
364 if (cv->format != FORMAT_PATH)
365 die("convert_put_path: internal error.");
366 fputs(convert_pathname(cv, path), cv->op);
367 (void)fputc(newline, cv->op);
368 }
369 /**
370 * convert_put_using: convert @a path into relative or absolute and print.
371 *
372 * @param[in] cv #CONVERT structure
373 * @param[in] tag tag name
374 * @param[in] path path name
375 * @param[in] lineno line number
376 * @param[in] rest line image
377 * @param[in] fid file id (only when @CODE{fid != NULL})
378 */
379 void
380 convert_put_using(CONVERT *cv, const char *tag, const char *path, int lineno, const char *rest, const char *fid)
381 {
382 switch (cv->format) {
383 case FORMAT_PATH:
384 fputs(convert_pathname(cv, path), cv->op);
385 break;
386 case FORMAT_CTAGS:
387 fputs(tag, cv->op);
388 fputc('\t', cv->op);
389 fputs(convert_pathname(cv, path), cv->op);
390 fputc('\t', cv->op);
391 fprintf(cv->op, "%d", lineno);
392 break;
393 case FORMAT_CTAGS_XID:
394 if (fid == NULL) {
395 fid = gpath_path2fid(path, NULL);
396 if (fid == NULL)
397 die("convert_put_using: unknown file. '%s'", path);
398 }
399 fputs(fid, cv->op);
400 fputc(' ', cv->op);
401 /* PASS THROUGH */
402 case FORMAT_CTAGS_X:
403 fprintf(cv->op, "%-16s %4d %-16s %s",
404 tag, lineno, convert_pathname(cv, path), rest);
405 break;
406 case FORMAT_CTAGS_MOD:
407 fputs(convert_pathname(cv, path), cv->op);
408 fputc('\t', cv->op);
409 fprintf(cv->op, "%d", lineno);
410 fputc('\t', cv->op);
411 fputs(rest, cv->op);
412 break;
413 case FORMAT_GREP:
414 fputs(convert_pathname(cv, path), cv->op);
415 fputc(':', cv->op);
416 fprintf(cv->op, "%d", lineno);
417 fputc(':', cv->op);
418 fputs(rest, cv->op);
419 break;
420 case FORMAT_CSCOPE:
421 fputs(convert_pathname(cv, path), cv->op);
422 fputc(' ', cv->op);
423 fputs(tag, cv->op);
424 fputc(' ', cv->op);
425 fprintf(cv->op, "%d", lineno);
426 fputc(' ', cv->op);
427 for (; *rest && isspace(*rest); rest++)
428 ;
429 if (*rest)
430 fputs(rest, cv->op);
431 else
432 fputs("<unknown>", cv->op);
433 break;
434 default:
435 die("unknown format type.");
436 }
437 (void)fputc(newline, cv->op);
438 }
439 void
440 convert_close(CONVERT *cv)
441 {
442 strbuf_close(cv->abspath);
443 gpath_close();
444 free(cv);
445 }
/* */