root/gtags/gtags.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usage
  2. help
  3. main
  4. incremental
  5. put_syms
  6. updatetags
  7. createtags
  8. 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 }

/* [previous][next][first][last][top][bottom][index][help] */