/* */
This source file includes following definitions.
- usage
- help
- main
- incremental
- put_syms
- updatetags
- createtags
- printconf
1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008,
3 * 2009, 2010, 2012 Tama Communications Corporation
4 *
5 * This file is part of GNU GLOBAL.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <sys/types.h>
25 #include <sys/stat.h>
26
27 #include <ctype.h>
28 #include <utime.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #if TIME_WITH_SYS_TIME
32 #include <sys/time.h>
33 #include <time.h>
34 #else
35 #if HAVE_SYS_TIME_H
36 #include <sys/time.h>
37 #else
38 #include <time.h>
39 #endif
40 #endif
41 #ifdef STDC_HEADERS
42 #include <stdlib.h>
43 #endif
44 #ifdef HAVE_STRING_H
45 #include <string.h>
46 #else
47 #include <strings.h>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include "getopt.h"
53
54 #include "global.h"
55 #include "parser.h"
56 #include "const.h"
57
58 /**
59 @file
60 @NAME{gtags} - create tag files for @NAME{global}.
61 */
62
63 static void usage(void);
64 static void help(void);
65 int main(int, char **);
66 int incremental(const char *, const char *);
67 void updatetags(const char *, const char *, IDSET *, STRBUF *);
68 void createtags(const char *, const char *);
69 int printconf(const char *);
70
71 int cflag; /**< compact format */
72 int iflag; /**< incremental update */
73 int Iflag; /**< make idutils index */
74 int Oflag; /**< use objdir */
75 int qflag; /**< quiet mode */
76 int wflag; /**< warning message */
77 int vflag; /**< verbose mode */
78 int show_version;
79 int show_help;
80 int show_config;
81 char *gtagsconf;
82 char *gtagslabel;
83 int debug;
84 const char *config_name;
85 const char *file_list;
86 const char *dump_target;
87 char *single_update;
88 int statistics = STATISTICS_STYLE_NONE;
89
90 #define GTAGSFILES "gtags.files"
91
92 /**
93 * @name Path filter
94 */
95 /** @{ */
96 int do_path;
97 int convert_type = PATH_RELATIVE;
98 /** @} */
99
100 int extractmethod;
101 int total;
102
103 static void
104 usage(void)
105 {
106 if (!qflag)
107 fputs(usage_const, stderr);
108 exit(2);
109 }
110 static void
111 help(void)
112 {
113 fputs(usage_const, stdout);
114 fputs(help_const, stdout);
115 exit(0);
116 }
117
118 static struct option const long_options[] = {
119 /*
120 * These options have long name and short name.
121 * We throw them to the processing of short options.
122 *
123 * Though the -o(--omit-gsyms) was removed, this code
124 * is left for compatibility.
125 */
126 {"compact", no_argument, NULL, 'c'},
127 {"dump", required_argument, NULL, 'd'},
128 {"file", required_argument, NULL, 'f'},
129 {"idutils", no_argument, NULL, 'I'},
130 {"incremental", no_argument, NULL, 'i'},
131 {"max-args", required_argument, NULL, 'n'},
132 {"omit-gsyms", no_argument, NULL, 'o'}, /* removed */
133 {"objdir", no_argument, NULL, 'O'},
134 {"quiet", no_argument, NULL, 'q'},
135 {"verbose", no_argument, NULL, 'v'},
136 {"warning", no_argument, NULL, 'w'},
137
138 /*
139 * The following are long name only.
140 */
141 #define OPT_CONFIG 128
142 #define OPT_GTAGSCONF 129
143 #define OPT_GTAGSLABEL 130
144 #define OPT_PATH 131
145 #define OPT_SINGLE_UPDATE 132
146 #define OPT_ENCODE_PATH 133
147 #define OPT_ACCEPT_DOTFILES 134
148 /* flag value */
149 {"accept-dotfiles", no_argument, NULL, OPT_ACCEPT_DOTFILES},
150 {"debug", no_argument, &debug, 1},
151 {"statistics", no_argument, &statistics, STATISTICS_STYLE_TABLE},
152 {"version", no_argument, &show_version, 1},
153 {"help", no_argument, &show_help, 1},
154
155 /* accept value */
156 {"config", optional_argument, NULL, OPT_CONFIG},
157 {"encode-path", required_argument, NULL, OPT_ENCODE_PATH},
158 {"gtagsconf", required_argument, NULL, OPT_GTAGSCONF},
159 {"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
160 {"path", required_argument, NULL, OPT_PATH},
161 {"single-update", required_argument, NULL, OPT_SINGLE_UPDATE},
162 { 0 }
163 };
164
165 static const char *langmap = DEFAULTLANGMAP;
166 static const char *gtags_parser;
167
168 int
169 main(int argc, char **argv)
170 {
171 char dbpath[MAXPATHLEN];
172 char cwd[MAXPATHLEN];
173 STRBUF *sb = strbuf_open(0);
174 int optchar;
175 int option_index = 0;
176 STATISTICS_TIME *tim;
177
178 logging_arguments(argc, argv);
179 while ((optchar = getopt_long(argc, argv, "cd:f:iIn:oOqvwse", long_options, &option_index)) != EOF) {
180 switch (optchar) {
181 case 0:
182 /* already flags set */
183 break;
184 case OPT_CONFIG:
185 show_config = 1;
186 if (optarg)
187 config_name = optarg;
188 break;
189 case OPT_GTAGSCONF:
190 gtagsconf = optarg;
191 break;
192 case OPT_GTAGSLABEL:
193 gtagslabel = optarg;
194 break;
195 case OPT_PATH:
196 do_path = 1;
197 if (!strcmp("absolute", optarg))
198 convert_type = PATH_ABSOLUTE;
199 else if (!strcmp("relative", optarg))
200 convert_type = PATH_RELATIVE;
201 else if (!strcmp("through", optarg))
202 convert_type = PATH_THROUGH;
203 else
204 die("Unknown path type.");
205 break;
206 case OPT_SINGLE_UPDATE:
207 iflag++;
208 single_update = optarg;
209 break;
210 case OPT_ENCODE_PATH:
211 if (strlen(optarg) > 255)
212 die("too many encode chars.");
213 if (strchr(optarg, '/') || strchr(optarg, '.'))
214 die("cannot encode '/' and '.' in the path.");
215 set_encode_chars((unsigned char *)optarg);
216 break;
217 case OPT_ACCEPT_DOTFILES:
218 set_accept_dotfiles();
219 break;
220 case 'c':
221 cflag++;
222 break;
223 case 'd':
224 dump_target = optarg;
225 break;
226 case 'f':
227 file_list = optarg;
228 break;
229 case 'i':
230 iflag++;
231 break;
232 case 'I':
233 Iflag++;
234 break;
235 case 'o':
236 /*
237 * Though the -o(--omit-gsyms) was removed, this code
238 * is left for compatibility.
239 */
240 break;
241 case 'O':
242 Oflag++;
243 break;
244 case 'q':
245 qflag++;
246 setquiet();
247 break;
248 case 'w':
249 wflag++;
250 break;
251 case 'v':
252 vflag++;
253 setverbose();
254 break;
255 default:
256 usage();
257 break;
258 }
259 }
260 if (gtagsconf) {
261 char path[MAXPATHLEN];
262
263 if (realpath(gtagsconf, path) == NULL)
264 die("%s not found.", gtagsconf);
265 set_env("GTAGSCONF", path);
266 }
267 if (gtagslabel) {
268 set_env("GTAGSLABEL", gtagslabel);
269 }
270 if (qflag)
271 vflag = 0;
272 if (show_version)
273 version(NULL, vflag);
274 if (show_help)
275 help();
276
277 argc -= optind;
278 argv += optind;
279
280 /* If dbpath is specified, -O(--objdir) option is ignored. */
281 if (argc > 0)
282 Oflag = 0;
283 if (show_config) {
284 if (config_name)
285 printconf(config_name);
286 else
287 fprintf(stdout, "%s\n", getconfline());
288 exit(0);
289 } else if (do_path) {
290 /*
291 * This is the main body of path filter.
292 * This code extract path name from tag line and
293 * replace it with the relative or the absolute path name.
294 *
295 * By default, if we are in src/ directory, the output
296 * should be converted like follws:
297 *
298 * main 10 ./src/main.c main(argc, argv)\n
299 * main 22 ./libc/func.c main(argc, argv)\n
300 * v
301 * main 10 main.c main(argc, argv)\n
302 * main 22 ../libc/func.c main(argc, argv)\n
303 *
304 * Similarly, the --path=absolute option specified, then
305 * v
306 * main 10 /prj/xxx/src/main.c main(argc, argv)\n
307 * main 22 /prj/xxx/libc/func.c main(argc, argv)\n
308 */
309 STRBUF *ib = strbuf_open(MAXBUFLEN);
310 CONVERT *cv;
311 char *ctags_x;
312
313 if (argc < 3)
314 die("gtags --path: 3 arguments needed.");
315 cv = convert_open(convert_type, FORMAT_CTAGS_X, argv[0], argv[1], argv[2], stdout, NOTAGS);
316 while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL)
317 convert_put(cv, ctags_x);
318 convert_close(cv);
319 strbuf_close(ib);
320 exit(0);
321 } else if (dump_target) {
322 /*
323 * Dump a tag file.
324 */
325 DBOP *dbop = NULL;
326 const char *dat = 0;
327 int is_gpath = 0;
328
329 if (!test("f", dump_target))
330 die("file '%s' not found.", dump_target);
331 if ((dbop = dbop_open(dump_target, 0, 0, DBOP_RAW)) == NULL)
332 die("file '%s' is not a tag file.", dump_target);
333 /*
334 * The file which has a NEXTKEY record is GPATH.
335 */
336 if (dbop_get(dbop, NEXTKEY))
337 is_gpath = 1;
338 for (dat = dbop_first(dbop, NULL, NULL, 0); dat != NULL; dat = dbop_next(dbop)) {
339 const char *flag = is_gpath ? dbop_getflag(dbop) : "";
340
341 if (*flag)
342 printf("%s\t%s\t%s\n", dbop->lastkey, dat, flag);
343 else
344 printf("%s\t%s\n", dbop->lastkey, dat);
345 }
346 dbop_close(dbop);
347 exit(0);
348 } else if (Iflag) {
349 if (!usable("mkid"))
350 die("mkid not found.");
351 }
352
353 /*
354 * If 'gtags.files' exists, use it as a file list.
355 * If the file_list other than "-" is given, it must be readable file.
356 */
357 if (file_list == NULL && test("f", GTAGSFILES))
358 file_list = GTAGSFILES;
359 if (file_list && strcmp(file_list, "-")) {
360 if (test("d", file_list))
361 die("'%s' is a directory.", file_list);
362 else if (!test("f", file_list))
363 die("'%s' not found.", file_list);
364 else if (!test("r", file_list))
365 die("'%s' is not readable.", file_list);
366 }
367 if (!getcwd(cwd, MAXPATHLEN))
368 die("cannot get current directory.");
369 canonpath(cwd);
370 /*
371 * Regularize the path name for single updating (--single-update).
372 */
373 if (single_update) {
374 static char regular_path_name[MAXPATHLEN];
375 char *p = single_update;
376
377 if (!test("f", p))
378 die("'%s' not found.", p);
379 #if _WIN32 || __DJGPP__
380 for (; *p; p++)
381 if (*p == '\\')
382 *p = '/';
383 p = single_update;
384 #define LOCATEFLAG MATCH_AT_FIRST|IGNORE_CASE
385 #else
386 #define LOCATEFLAG MATCH_AT_FIRST
387 #endif
388 if (isabspath(p)) {
389 char *q = locatestring(p, cwd, LOCATEFLAG);
390
391 if (q && *q == '/')
392 snprintf(regular_path_name, MAXPATHLEN, "./%s", q + 1);
393 else
394 die("path '%s' is out of the project.", p);
395
396 } else {
397 if (p[0] == '.' && p[1] == '/')
398 snprintf(regular_path_name, MAXPATHLEN, "%s", p);
399 else
400 snprintf(regular_path_name, MAXPATHLEN, "./%s", p);
401 }
402 single_update = regular_path_name;
403 }
404 /*
405 * Decide directory (dbpath) in which gtags make tag files.
406 *
407 * Gtags create tag files at current directory by default.
408 * If dbpath is specified as an argument then use it.
409 * If the -i option specified and both GTAGS and GRTAGS exists
410 * at one of the candidate directories then gtags use existing
411 * tag files.
412 */
413 if (iflag) {
414 if (argc > 0)
415 realpath(*argv, dbpath);
416 else if (!gtagsexist(cwd, dbpath, MAXPATHLEN, vflag))
417 strlimcpy(dbpath, cwd, sizeof(dbpath));
418 } else {
419 if (argc > 0)
420 realpath(*argv, dbpath);
421 else if (Oflag) {
422 char *objdir = getobjdir(cwd, vflag);
423
424 if (objdir == NULL)
425 die("Objdir not found.");
426 strlimcpy(dbpath, objdir, sizeof(dbpath));
427 } else
428 strlimcpy(dbpath, cwd, sizeof(dbpath));
429 }
430 if (iflag && (!test("f", makepath(dbpath, dbname(GTAGS), NULL)) ||
431 !test("f", makepath(dbpath, dbname(GRTAGS), NULL)) ||
432 !test("f", makepath(dbpath, dbname(GPATH), NULL)))) {
433 if (wflag)
434 warning("GTAGS, GRTAGS or GPATH not found. -i option ignored.");
435 iflag = 0;
436 }
437 if (!test("d", dbpath))
438 die("directory '%s' not found.", dbpath);
439 if (vflag)
440 fprintf(stderr, "[%s] Gtags started.\n", now());
441 /*
442 * load configuration file.
443 */
444 openconf();
445 if (getconfb("extractmethod"))
446 extractmethod = 1;
447 strbuf_reset(sb);
448 if (getconfs("langmap", sb))
449 langmap = check_strdup(strbuf_value(sb));
450 strbuf_reset(sb);
451 if (getconfs("gtags_parser", sb))
452 gtags_parser = check_strdup(strbuf_value(sb));
453 /*
454 * initialize parser.
455 */
456 if (vflag && gtags_parser)
457 fprintf(stderr, " Using plug-in parser.\n");
458 parser_init(langmap, gtags_parser);
459 if (vflag && file_list)
460 fprintf(stderr, " Using '%s' as a file list.\n", file_list);
461 /*
462 * Start statistics.
463 */
464 init_statistics();
465 /*
466 * incremental update.
467 */
468 if (iflag) {
469 /*
470 * Version check. If existing tag files are old enough
471 * gtagsopen() abort with error message.
472 */
473 GTOP *gtop = gtags_open(dbpath, cwd, GTAGS, GTAGS_MODIFY, 0);
474 gtags_close(gtop);
475 /*
476 * GPATH is needed for incremental updating.
477 * Gtags check whether or not GPATH exist, since it may be
478 * removed by mistake.
479 */
480 if (!test("f", makepath(dbpath, dbname(GPATH), NULL)))
481 die("Old version tag file found. Please remake it.");
482 (void)incremental(dbpath, cwd);
483 print_statistics(statistics);
484 exit(0);
485 }
486 /*
487 * create GTAGS and GRTAGS
488 */
489 createtags(dbpath, cwd);
490 /*
491 * create idutils index.
492 */
493 if (Iflag) {
494 tim = statistics_time_start("Time of creating ID");
495 if (vflag)
496 fprintf(stderr, "[%s] Creating indexes for idutils.\n", now());
497 strbuf_reset(sb);
498 strbuf_puts(sb, "mkid");
499 if (vflag)
500 strbuf_puts(sb, " -v");
501 strbuf_sprintf(sb, " --file='%s/ID'", dbpath);
502 if (vflag) {
503 #ifdef __DJGPP__
504 if (is_unixy()) /* test for 4DOS as well? */
505 #endif
506 strbuf_puts(sb, " 1>&2");
507 } else {
508 strbuf_puts(sb, " >" NULL_DEVICE);
509 }
510 if (debug)
511 fprintf(stderr, "executing mkid like: %s\n", strbuf_value(sb));
512 if (system(strbuf_value(sb)))
513 die("mkid failed: %s", strbuf_value(sb));
514 if (chmod(makepath(dbpath, "ID", NULL), 0644) < 0)
515 die("cannot chmod ID file.");
516 statistics_time_end(tim);
517 }
518 if (vflag)
519 fprintf(stderr, "[%s] Done.\n", now());
520 closeconf();
521 strbuf_close(sb);
522 print_statistics(statistics);
523
524 return 0;
525 }
526 /**
527 * incremental: incremental update
528 *
529 * @param[in] dbpath dbpath directory
530 * @param[in] root root directory of source tree
531 * @return 0: not updated, 1: updated
532 */
533 int
534 incremental(const char *dbpath, const char *root)
535 {
536 STATISTICS_TIME *tim;
537 struct stat statp;
538 time_t gtags_mtime;
539 STRBUF *addlist = strbuf_open(0);
540 STRBUF *deletelist = strbuf_open(0);
541 STRBUF *addlist_other = strbuf_open(0);
542 IDSET *deleteset, *findset;
543 int updated = 0;
544 const char *path;
545 unsigned int id, limit;
546
547 tim = statistics_time_start("Time of inspecting %s and %s.", dbname(GTAGS), dbname(GRTAGS));
548 if (vflag) {
549 fprintf(stderr, " Tag found in '%s'.\n", dbpath);
550 fprintf(stderr, " Incremental updating.\n");
551 }
552 /*
553 * get modified time of GTAGS.
554 */
555 path = makepath(dbpath, dbname(GTAGS), NULL);
556 if (stat(path, &statp) < 0)
557 die("stat failed '%s'.", path);
558 gtags_mtime = statp.st_mtime;
559
560 if (gpath_open(dbpath, 2) < 0)
561 die("GPATH not found.");
562 /*
563 * deleteset:
564 * The list of the path name which should be deleted from GPATH.
565 * findset:
566 * The list of the path name which exists in the current project.
567 * A project is limited by the --file option.
568 */
569 deleteset = idset_open(gpath_nextkey());
570 findset = idset_open(gpath_nextkey());
571 total = 0;
572 /*
573 * Make add list and delete list for update.
574 */
575 if (single_update) {
576 int type;
577 const char *fid;
578
579 if (skipthisfile(single_update))
580 goto exit;
581 if (test("b", single_update))
582 goto exit;
583 fid = gpath_path2fid(single_update, &type);
584 if (fid == NULL) {
585 /* new file */
586 type = issourcefile(single_update) ? GPATH_SOURCE : GPATH_OTHER;
587 if (type == GPATH_OTHER)
588 strbuf_puts0(addlist_other, single_update);
589 else {
590 strbuf_puts0(addlist, single_update);
591 total++;
592 }
593 } else {
594 /* update file */
595 if (type == GPATH_OTHER)
596 goto exit;
597 idset_add(deleteset, atoi(fid));
598 strbuf_puts0(addlist, single_update);
599 total++;
600 }
601 } else {
602 if (file_list)
603 find_open_filelist(file_list, root);
604 else
605 find_open(NULL);
606 while ((path = find_read()) != NULL) {
607 const char *fid;
608 int n_fid = 0;
609 int other = 0;
610
611 /* a blank at the head of path means 'NOT SOURCE'. */
612 if (*path == ' ') {
613 if (test("b", ++path))
614 continue;
615 other = 1;
616 }
617 if (stat(path, &statp) < 0)
618 die("stat failed '%s'.", path);
619 fid = gpath_path2fid(path, NULL);
620 if (fid) {
621 n_fid = atoi(fid);
622 idset_add(findset, n_fid);
623 }
624 if (other) {
625 if (fid == NULL)
626 strbuf_puts0(addlist_other, path);
627 } else {
628 if (fid == NULL) {
629 strbuf_puts0(addlist, path);
630 total++;
631 } else if (gtags_mtime < statp.st_mtime) {
632 strbuf_puts0(addlist, path);
633 total++;
634 idset_add(deleteset, n_fid);
635 }
636 }
637 }
638 find_close();
639 /*
640 * make delete list.
641 */
642 limit = gpath_nextkey();
643 for (id = 1; id < limit; id++) {
644 char fid[MAXFIDLEN];
645 int type;
646
647 snprintf(fid, sizeof(fid), "%d", id);
648 /*
649 * This is a hole of GPATH. The hole increases if the deletion
650 * and the addition are repeated.
651 */
652 if ((path = gpath_fid2path(fid, &type)) == NULL)
653 continue;
654 /*
655 * The file which does not exist in the findset is treated
656 * assuming that it does not exist in the file system.
657 */
658 if (type == GPATH_OTHER) {
659 if (!idset_contains(findset, id) || !test("f", path) || test("b", path))
660 strbuf_puts0(deletelist, path);
661 } else {
662 if (!idset_contains(findset, id) || !test("f", path)) {
663 strbuf_puts0(deletelist, path);
664 idset_add(deleteset, id);
665 }
666 }
667 }
668 }
669 statistics_time_end(tim);
670 /*
671 * execute updating.
672 */
673 if ((!idset_empty(deleteset) || strbuf_getlen(addlist) > 0) ||
674 (strbuf_getlen(deletelist) + strbuf_getlen(addlist_other) > 0))
675 {
676 int db;
677 updated = 1;
678 tim = statistics_time_start("Time of updating %s and %s.", dbname(GTAGS), dbname(GRTAGS));
679 if (!idset_empty(deleteset) || strbuf_getlen(addlist) > 0)
680 updatetags(dbpath, root, deleteset, addlist);
681 if (strbuf_getlen(deletelist) + strbuf_getlen(addlist_other) > 0) {
682 const char *start, *end, *p;
683
684 if (vflag)
685 fprintf(stderr, "[%s] Updating '%s'.\n", now(), dbname(GPATH));
686 /* gpath_open(dbpath, 2); */
687 if (strbuf_getlen(deletelist) > 0) {
688 start = strbuf_value(deletelist);
689 end = start + strbuf_getlen(deletelist);
690
691 for (p = start; p < end; p += strlen(p) + 1)
692 gpath_delete(p);
693 }
694 if (strbuf_getlen(addlist_other) > 0) {
695 start = strbuf_value(addlist_other);
696 end = start + strbuf_getlen(addlist_other);
697
698 for (p = start; p < end; p += strlen(p) + 1) {
699 gpath_put(p, GPATH_OTHER);
700 }
701 }
702 /* gpath_close(); */
703 }
704 /*
705 * Update modification time of tag files
706 * because they may have no definitions.
707 */
708 for (db = GTAGS; db < GTAGLIM; db++)
709 utime(makepath(dbpath, dbname(db), NULL), NULL);
710 statistics_time_end(tim);
711 }
712 exit:
713 if (vflag) {
714 if (updated)
715 fprintf(stderr, " Global databases have been modified.\n");
716 else
717 fprintf(stderr, " Global databases are up to date.\n");
718 fprintf(stderr, "[%s] Done.\n", now());
719 }
720 strbuf_close(addlist);
721 strbuf_close(deletelist);
722 strbuf_close(addlist_other);
723 gpath_close();
724 idset_close(deleteset);
725 idset_close(findset);
726
727 return updated;
728 }
729 /**
730 * @fn static void put_syms(int type, const char *tag, int lno, const char *path, const char *line_image, void *arg)
731 *
732 * callback functions for built-in parser
733 */
734 struct put_func_data {
735 GTOP *gtop[GTAGLIM];
736 const char *fid;
737 };
738 static void
739 put_syms(int type, const char *tag, int lno, const char *path, const char *line_image, void *arg)
740 {
741 const struct put_func_data *data = arg;
742 GTOP *gtop;
743
744 switch (type) {
745 case PARSER_DEF:
746 gtop = data->gtop[GTAGS];
747 break;
748 case PARSER_REF_SYM:
749 gtop = data->gtop[GRTAGS];
750 if (gtop == NULL)
751 return;
752 break;
753 default:
754 return;
755 }
756 gtags_put_using(gtop, tag, lno, data->fid, line_image);
757 }
758 /**
759 * updatetags: update tag file.
760 *
761 * @param[in] dbpath directory in which tag file exist
762 * @param[in] root root directory of source tree
763 * @param[in] deleteset bit array of fid of deleted or modified files
764 * @param[in] addlist @CODE{\\0} separated list of added or modified files
765 */
766 void
767 updatetags(const char *dbpath, const char *root, IDSET *deleteset, STRBUF *addlist)
768 {
769 struct put_func_data data;
770 int seqno, flags;
771 const char *path, *start, *end;
772
773 if (vflag)
774 fprintf(stderr, "[%s] Updating '%s' and '%s'.\n", now(), dbname(GTAGS), dbname(GRTAGS));
775 /*
776 * Open tag files.
777 */
778 data.gtop[GTAGS] = gtags_open(dbpath, root, GTAGS, GTAGS_MODIFY, 0);
779 if (test("f", makepath(dbpath, dbname(GRTAGS), NULL))) {
780 data.gtop[GRTAGS] = gtags_open(dbpath, root, GRTAGS, GTAGS_MODIFY, 0);
781 } else {
782 /*
783 * If you set NULL to data.gtop[GRTAGS], parse_file() doesn't write to
784 * GRTAGS. See put_syms().
785 */
786 data.gtop[GRTAGS] = NULL;
787 }
788 /*
789 * Delete tags from GTAGS.
790 */
791 if (!idset_empty(deleteset)) {
792 if (vflag) {
793 char fid[MAXFIDLEN];
794 int total = idset_count(deleteset);
795 unsigned int id;
796
797 seqno = 1;
798 for (id = idset_first(deleteset); id != END_OF_ID; id = idset_next(deleteset)) {
799 snprintf(fid, sizeof(fid), "%d", id);
800 path = gpath_fid2path(fid, NULL);
801 if (path == NULL)
802 die("GPATH is corrupted.");
803 fprintf(stderr, " [%d/%d] deleting tags of %s\n", seqno++, total, path + 2);
804 }
805 }
806 gtags_delete(data.gtop[GTAGS], deleteset);
807 if (data.gtop[GRTAGS] != NULL)
808 gtags_delete(data.gtop[GRTAGS], deleteset);
809 }
810 /*
811 * Set flags.
812 */
813 data.gtop[GTAGS]->flags = 0;
814 if (extractmethod)
815 data.gtop[GTAGS]->flags |= GTAGS_EXTRACTMETHOD;
816 data.gtop[GRTAGS]->flags = data.gtop[GTAGS]->flags;
817 flags = 0;
818 if (vflag)
819 flags |= PARSER_VERBOSE;
820 if (debug)
821 flags |= PARSER_DEBUG;
822 if (wflag)
823 flags |= PARSER_WARNING;
824 /*
825 * Add tags to GTAGS and GRTAGS.
826 */
827 start = strbuf_value(addlist);
828 end = start + strbuf_getlen(addlist);
829 seqno = 0;
830 for (path = start; path < end; path += strlen(path) + 1) {
831 gpath_put(path, GPATH_SOURCE);
832 data.fid = gpath_path2fid(path, NULL);
833 if (data.fid == NULL)
834 die("GPATH is corrupted.('%s' not found)", path);
835 if (vflag)
836 fprintf(stderr, " [%d/%d] extracting tags of %s\n", ++seqno, total, path + 2);
837 parse_file(path, flags, put_syms, &data);
838 gtags_flush(data.gtop[GTAGS], data.fid);
839 if (data.gtop[GRTAGS] != NULL)
840 gtags_flush(data.gtop[GRTAGS], data.fid);
841 }
842 parser_exit();
843 gtags_close(data.gtop[GTAGS]);
844 if (data.gtop[GRTAGS] != NULL)
845 gtags_close(data.gtop[GRTAGS]);
846 }
847 /**
848 * createtags: create tags file
849 *
850 * @param[in] dbpath dbpath directory
851 * @param[in] root root directory of source tree
852 */
853 void
854 createtags(const char *dbpath, const char *root)
855 {
856 STATISTICS_TIME *tim;
857 STRBUF *sb = strbuf_open(0);
858 struct put_func_data data;
859 int openflags, flags, seqno;
860 const char *path;
861
862 tim = statistics_time_start("Time of creating %s and %s.", dbname(GTAGS), dbname(GRTAGS));
863 if (vflag)
864 fprintf(stderr, "[%s] Creating '%s' and '%s'.\n", now(), dbname(GTAGS), dbname(GRTAGS));
865 openflags = cflag ? GTAGS_COMPACT : 0;
866 data.gtop[GTAGS] = gtags_open(dbpath, root, GTAGS, GTAGS_CREATE, openflags);
867 data.gtop[GTAGS]->flags = 0;
868 if (extractmethod)
869 data.gtop[GTAGS]->flags |= GTAGS_EXTRACTMETHOD;
870 data.gtop[GRTAGS] = gtags_open(dbpath, root, GRTAGS, GTAGS_CREATE, openflags);
871 data.gtop[GRTAGS]->flags = data.gtop[GTAGS]->flags;
872 flags = 0;
873 if (vflag)
874 flags |= PARSER_VERBOSE;
875 if (debug)
876 flags |= PARSER_DEBUG;
877 if (wflag)
878 flags |= PARSER_WARNING;
879 /*
880 * Add tags to GTAGS and GRTAGS.
881 */
882 if (file_list)
883 find_open_filelist(file_list, root);
884 else
885 find_open(NULL);
886 seqno = 0;
887 while ((path = find_read()) != NULL) {
888 if (*path == ' ') {
889 path++;
890 if (!test("b", path))
891 gpath_put(path, GPATH_OTHER);
892 continue;
893 }
894 gpath_put(path, GPATH_SOURCE);
895 data.fid = gpath_path2fid(path, NULL);
896 if (data.fid == NULL)
897 die("GPATH is corrupted.('%s' not found)", path);
898 seqno++;
899 if (vflag)
900 fprintf(stderr, " [%d] extracting tags of %s\n", seqno, path + 2);
901 parse_file(path, flags, put_syms, &data);
902 gtags_flush(data.gtop[GTAGS], data.fid);
903 gtags_flush(data.gtop[GRTAGS], data.fid);
904 }
905 total = seqno;
906 parser_exit();
907 find_close();
908 statistics_time_end(tim);
909 tim = statistics_time_start("Time of flushing B-tree cache");
910 gtags_close(data.gtop[GTAGS]);
911 gtags_close(data.gtop[GRTAGS]);
912 statistics_time_end(tim);
913 strbuf_reset(sb);
914 if (getconfs("GTAGS_extra", sb)) {
915 tim = statistics_time_start("Time of executing GTAGS_extra command");
916 if (system(strbuf_value(sb)))
917 fprintf(stderr, "GTAGS_extra command failed: %s\n", strbuf_value(sb));
918 statistics_time_end(tim);
919 }
920 strbuf_reset(sb);
921 if (getconfs("GRTAGS_extra", sb)) {
922 tim = statistics_time_start("Time of executing GRTAGS_extra command");
923 if (system(strbuf_value(sb)))
924 fprintf(stderr, "GRTAGS_extra command failed: %s\n", strbuf_value(sb));
925 statistics_time_end(tim);
926 }
927 strbuf_close(sb);
928 }
929 /**
930 * printconf: print configuration data.
931 *
932 * @param[in] name label of config data
933 * @return exit code
934 */
935 int
936 printconf(const char *name)
937 {
938 int num;
939 int exist = 1;
940
941 if (getconfn(name, &num))
942 fprintf(stdout, "%d\n", num);
943 else if (getconfb(name))
944 fprintf(stdout, "1\n");
945 else {
946 STRBUF *sb = strbuf_open(0);
947 if (getconfs(name, sb))
948 fprintf(stdout, "%s\n", strbuf_value(sb));
949 else
950 exist = 0;
951 strbuf_close(sb);
952 }
953 return exist;
954 }
/* */