## root/gtags/gtags.c(258.html)

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. usage
2. help
3. output
4. main
5. incremental
6. verbose_updatetags
7. updatetags
8. verbose_createtags
9. createtags
10. printconf

    /*
     * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006
     *      Tama Communications Corporation
     *
     * This file is part of GNU GLOBAL.
     *
     * This program is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     */

    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #include <sys/types.h>
    #include <sys/stat.h>

    #include <ctype.h>
    #include <utime.h>
    #include <signal.h>
    #include <stdio.h>
    #if TIME_WITH_SYS_TIME
    #include <sys/time.h>
    #include <time.h>
    #else
    #if HAVE_SYS_TIME_H
    #include <sys/time.h>
    #else
    #include <time.h>
    #endif
    #endif
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #ifdef HAVE_STRING_H
    #include <string.h>
    #else
    #include <strings.h>
    #endif
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #include "getopt.h"

    #include "global.h"
    #include "const.h"

    static void usage(void);
    static void help(void);
    int main(int, char **);
    int incremental(const char *, const char *);
    void updatetags(const char *, const char *, IDSET *, STRBUF *, int);
    void createtags(const char *, const char *, int);
    int printconf(const char *);
    void set_base_directory(const char *, const char *);

    int iflag;                                      /* incremental update */
    int Iflag;                                      /* make  idutils index */
    int qflag;                                      /* quiet mode */
    int wflag;                                      /* warning message */
    int vflag;                                      /* verbose mode */
    int max_args;
    int show_version;
    int show_help;
    int show_config;
    char *gtagsconf;
    char *gtagslabel;
    int debug;
    const char *config_name;
    const char *file_list;

    /*
     * Path filter
     */
    int do_path;
    int convert_type = PATH_RELATIVE;

    int extractmethod;
    int total;

    static void
    usage(void)
    {
            if (!qflag)
                    fputs(usage_const, stderr);
            exit(2);
    }
    static void
    help(void)
    {
            fputs(usage_const, stdout);
            fputs(help_const, stdout);
            exit(0);
    }

    static struct option const long_options[] = {
            /*
             * These options have long name and short name.
             * We throw them to the processing of short options.
             *
             * Though the -o(--omit-gsyms) was removed, this code
             * is left for compatibility.
             */
            {"file", required_argument, NULL, 'f'},
            {"idutils", no_argument, NULL, 'I'},
            {"incremental", no_argument, NULL, 'i'},
            {"max-args", required_argument, NULL, 'n'},
            {"omit-gsyms", no_argument, NULL, 'o'},         /* removed */
            {"quiet", no_argument, NULL, 'q'},
            {"verbose", no_argument, NULL, 'v'},
            {"warning", no_argument, NULL, 'w'},

            /*
             * The following are long name only.
             */
            /* flag value */
            {"debug", no_argument, &debug, 1},
            {"version", no_argument, &show_version, 1},
            {"help", no_argument, &show_help, 1},

            /* accept value */
    #define OPT_CONFIG              128
    #define OPT_GTAGSCONF           129
    #define OPT_GTAGSLABEL          130
    #define OPT_PATH                131
            {"config", optional_argument, NULL, OPT_CONFIG},
            {"gtagsconf", required_argument, NULL, OPT_GTAGSCONF},
            {"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
            {"path", required_argument, NULL, OPT_PATH},
            { 0 }
    };

    static const char *langmap = DEFAULTLANGMAP;

    void
    output(const char *s)
    {
            fputs(s, stdout);
            fputc('\n', stdout);
    }

    int
    main(int argc, char **argv)
    {
            char dbpath[MAXPATHLEN+1];
            char cwd[MAXPATHLEN+1];
            STRBUF *sb = strbuf_open(0);
            int db;
            int optchar;
            int option_index = 0;

            while ((optchar = getopt_long(argc, argv, "f:iIn:oqvwse", long_options, &option_index)) != EOF) {
                    switch (optchar) {
                    case 0:
                            /* already flags set */
                            break;
                    case OPT_CONFIG:
                            show_config = 1;
                            if (optarg)
                                    config_name = optarg;
                            break;
                    case OPT_GTAGSCONF:
                            gtagsconf = optarg;
                            break;
                    case OPT_GTAGSLABEL:
                            gtagslabel = optarg;
                            break;
                    case OPT_PATH:
                            do_path = 1;
                            if (!strcmp("absolute", optarg))
                                    convert_type = PATH_ABSOLUTE;
                            else if (!strcmp("relative", optarg))
                                    convert_type = PATH_RELATIVE;
                            else if (!strcmp("through", optarg))
                                    convert_type = PATH_THROUGH;
                            else
                                    die("Unknown path type.");
                            break;
                    case 'f':
                            file_list = optarg;
                            break;
                    case 'i':
                            iflag++;
                            break;
                    case 'I':
                            Iflag++;
                            break;
                    case 'n':
                            max_args = atoi(optarg);
                            if (max_args <= 0)
                                    die("--max-args option requires number > 0.");
                            break;
                    case 'o':
                            /*
                             * Though the -o(--omit-gsyms) was removed, this code
                             * is left for compatibility.
                             */
                            break;
                    case 'q':
                            qflag++;
                            setquiet();
                            break;
                    case 'w':
                            wflag++;
                            break;
                    case 'v':
                            vflag++;
                            break;
                    default:
                            usage();
                            break;
                    }
            }
            if (gtagsconf) {
                    char path[MAXPATHLEN+1];

                    if (realpath(gtagsconf, path) == NULL)
                            die("%s not found.", gtagsconf);
                    set_env("GTAGSCONF", path);
                    if (gtagslabel)
                            set_env("GTAGSLABEL", gtagslabel);
            }
            if (qflag)
                    vflag = 0;
            if (show_version)
                    version(NULL, vflag);
            if (show_help)
                    help();

            argc -= optind;
            argv += optind;

            if (show_config) {
                    if (config_name)
                            printconf(config_name);
                    else
                            fprintf(stdout, "%s\n", getconfline());
                    exit(0);
            } else if (do_path) {
                    /*
                     * This is the main body of path filter.
                     * This code extract path name from tag line and
                     * replace it with the relative or the absolute path name.
                     *
                     * By default, if we are in src/ directory, the output
                     * should be converted like follws:
                     *
                     * main      10 ./src/main.c  main(argc, argv)\n
                     * main      22 ./libc/func.c   main(argc, argv)\n
                     *              v
                     * main      10 main.c  main(argc, argv)\n
                     * main      22 ../libc/func.c   main(argc, argv)\n
                     *
                     * Similarly, the --path=absolute option specified, then
                     *              v
                     * main      10 /prj/xxx/src/main.c  main(argc, argv)\n
                     * main      22 /prj/xxx/libc/func.c   main(argc, argv)\n
                     */
                    STRBUF *ib = strbuf_open(MAXBUFLEN);
                    CONVERT *cv = convert_open(convert_type, FORMAT_CTAGS_X, argv[0], argv[1], argv[2], stdout);
                    char *ctags_x;

                    if (argc < 3)
                            die("gtags --path: 3 arguments needed.");
                    while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL)
                            convert_put(cv, ctags_x);
                    convert_close(cv);
                    strbuf_close(ib);
                    exit(0);
            } else if (Iflag) {
                    if (!usable("mkid"))
                            die("mkid not found.");
            }

            /*
             * If the file_list other than "-" is given, it must be readable file.
             */
            if (file_list && strcmp(file_list, "-")) {
                    if (test("d", file_list))
                            die("'%s' is a directory.", file_list);
                    else if (!test("f", file_list))
                            die("'%s' not found.", file_list);
                    else if (!test("r", file_list))
                            die("'%s' is not readable.", file_list);
            }
            if (!getcwd(cwd, MAXPATHLEN))
                    die("cannot get current directory.");
            canonpath(cwd);
            /*
             * Decide directory (dbpath) in which gtags make tag files.
             *
             * Gtags create tag files at current directory by default.
             * If dbpath is specified as an argument then use it.
             * If the -i option specified and both GTAGS and GRTAGS exists
             * at one of the candedite directories then gtags use existing
             * tag files.
             */
            if (iflag) {
                    if (argc > 0)
                            realpath(*argv, dbpath);
                    else if (!gtagsexist(cwd, dbpath, MAXPATHLEN, vflag))
                            strlimcpy(dbpath, cwd, sizeof(dbpath));
            } else {
                    if (argc > 0)
                            realpath(*argv, dbpath);
                    else
                            strlimcpy(dbpath, cwd, sizeof(dbpath));
            }
            if (iflag && (!test("f", makepath(dbpath, dbname(GTAGS), NULL)) ||
                    !test("f", makepath(dbpath, dbname(GPATH), NULL)))) {
                    if (wflag)
                            warning("GTAGS or GPATH not found. -i option ignored.");
                    iflag = 0;
            }
            if (!test("d", dbpath))
                    die("directory '%s' not found.", dbpath);
            if (vflag)
                    fprintf(stderr, "[%s] Gtags started.\n", now());
            /*
             * load .globalrc or /etc/gtags.conf
             */
            openconf();
            if (getconfb("extractmethod"))
                    extractmethod = 1;
            strbuf_reset(sb);
            /*
             * Pass the following information to gtags-parser(1)
             * using environment variable.
             *
             * o langmap
             * o DBPATH
             */
            strbuf_reset(sb);
            if (getconfs("langmap", sb))
                    langmap = check_strdup(strbuf_value(sb));
            set_env("GTAGSLANGMAP", langmap);
            set_env("GTAGSDBPATH", dbpath);

            if (wflag)
                    set_env("GTAGSWARNING", "1");
            /*
             * incremental update.
             */
            if (iflag) {
                    /*
                     * Version check. If existing tag files are old enough
                     * gtagsopen() abort with error message.
                     */
                    GTOP *gtop = gtags_open(dbpath, cwd, GTAGS, GTAGS_MODIFY);
                    gtags_close(gtop);
                    /*
                     * GPATH is needed for incremental updating.
                     * Gtags check whether or not GPATH exist, since it may be
                     * removed by mistake.
                     */
                    if (!test("f", makepath(dbpath, dbname(GPATH), NULL)))
                            die("Old version tag file found. Please remake it.");
                    (void)incremental(dbpath, cwd);
                    exit(0);
            }
            /*
             * create GTAGS, GRTAGS and GSYMS
             */
            for (db = GTAGS; db < GTAGLIM; db++) {

                    strbuf_reset(sb);
                    /*
                     * get parser for db. (gtags-parser by default)
                     */
                    if (!getconfs(dbname(db), sb))
                            continue;
                    if (!usable(strmake(strbuf_value(sb), " \t")))
                            die("Parser '%s' not found or not executable.", strmake(strbuf_value(sb), " \t"));
                    if (vflag)
                            fprintf(stderr, "[%s] Creating '%s'.\n", now(), dbname(db));
                    createtags(dbpath, cwd, db);
                    strbuf_reset(sb);
                    if (db == GTAGS) {
                            if (getconfs("GTAGS_extra", sb))
                                    if (system(strbuf_value(sb)))
                                            fprintf(stderr, "GTAGS_extra command failed: %s\n", strbuf_value(sb));
                    } else if (db == GRTAGS) {
                            if (getconfs("GRTAGS_extra", sb))
                                    if (system(strbuf_value(sb)))
                                            fprintf(stderr, "GRTAGS_extra command failed: %s\n", strbuf_value(sb));
                    } else if (db == GSYMS) {
                            if (getconfs("GSYMS_extra", sb))
                                    if (system(strbuf_value(sb)))
                                            fprintf(stderr, "GSYMS_extra command failed: %s\n", strbuf_value(sb));
                    }
            }
            /*
             * create idutils index.
             */
            if (Iflag) {
                    if (vflag)
                            fprintf(stderr, "[%s] Creating indexes for idutils.\n", now());
                    strbuf_reset(sb);
                    strbuf_puts(sb, "mkid");
                    if (vflag)
                            strbuf_puts(sb, " -v");
                    if (vflag) {
    #ifdef __DJGPP__
                            if (is_unixy()) /* test for 4DOS as well? */
    #endif
                            strbuf_puts(sb, " 1>&2");
                    } else {
                            strbuf_puts(sb, " >/dev/null");
                    }
                    if (debug)
                            fprintf(stderr, "executing mkid like: %s\n", strbuf_value(sb));
                    if (system(strbuf_value(sb)))
                            die("mkid failed: %s", strbuf_value(sb));
                    strbuf_reset(sb);
                    strbuf_puts(sb, "chmod 644 ");
                    strbuf_puts(sb, makepath(dbpath, "ID", NULL));
                    if (system(strbuf_value(sb)))
                            die("chmod failed: %s", strbuf_value(sb));
            }
            if (vflag)
                    fprintf(stderr, "[%s] Done.\n", now());
            closeconf();
            strbuf_close(sb);

            return 0;
    }
    /*
     * incremental: incremental update
     *
     *      i)      dbpath  dbpath directory
     *      i)      root    root directory of source tree
     *      r)              0: not updated, 1: updated
     */
    int
    incremental(const char *dbpath, const char *root)
    {
            struct stat statp;
            time_t gtags_mtime;
            STRBUF *addlist = strbuf_open(0);
            STRBUF *deletelist = strbuf_open(0);
            STRBUF *addlist_other = strbuf_open(0);
            IDSET *deleteset, *findset;
            int updated = 0;
            const char *path;
            unsigned int id, limit;

            if (vflag) {
                    fprintf(stderr, " Tag found in '%s'.\n", dbpath);
                    fprintf(stderr, " Incremental update.\n");
            }
            /*
             * get modified time of GTAGS.
             */
            path = makepath(dbpath, dbname(GTAGS), NULL);
            if (stat(path, &statp) < 0)
                    die("stat failed '%s'.", path);
            gtags_mtime = statp.st_mtime;

            if (gpath_open(dbpath, 0) < 0)
                    die("GPATH not found.");
            /*
             * deleteset:
             *      The list of the path name which should be deleted from GPATH.
             * findset:
             *      The list of the path name which exists in the current project.
             *      A project is limited by the --file option.
             */
            deleteset = idset_open(gpath_nextkey());
            findset = idset_open(gpath_nextkey());
            /*
             * make add list and delete list for update.
             */
            if (file_list)
                    find_open_filelist(file_list, root);
            else
                    find_open(NULL);
            total = 0;
            while ((path = find_read()) != NULL) {
                    const char *fid;
                    int n_fid = 0;
                    int other = 0;

                    /* a blank at the head of path means 'NOT SOURCE'. */
                    if (*path == ' ') {
                            if (test("b", ++path))
                                    continue;
                            other = 1;
                    }
                    if (stat(path, &statp) < 0)
                            die("stat failed '%s'.", path);
                    fid = gpath_path2fid(path, NULL);
                    if (fid) {
                            n_fid = atoi(fid);
                            idset_add(findset, n_fid);
                    }
                    if (other) {
                            if (fid == NULL)
                                    strbuf_puts0(addlist_other, path);
                    } else {
                            if (fid == NULL) {
                                    strbuf_puts0(addlist, path);
                                    total++;
                            } else if (gtags_mtime < statp.st_mtime) {
                                    strbuf_puts0(addlist, path);
                                    total++;
                                    idset_add(deleteset, n_fid);
                            }
                    }
            }
            find_close();
            /*
             * make delete list.
             */
            limit = gpath_nextkey();
            for (id = 1; id < limit; id++) {
                    char fid[32];
                    int type;

                    snprintf(fid, sizeof(fid), "%d", id);
                    /*
                     * This is a hole of GPATH. The hole increases if the deletion
                     * and the addition are repeated.
                     */
                    if ((path = gpath_fid2path(fid, &type)) == NULL)
                            continue;
                    /*
                     * The file which does not exist in the findset is treated
                     * assuming that it does not exist in the file system.
                     */
                    if (type == GPATH_OTHER) {
                            if (!idset_contains(findset, id) || !test("f", path) || test("b", path))
                                    strbuf_puts0(deletelist, path);
                    } else {
                            if (!idset_contains(findset, id) || !test("f", path)) {
                                    strbuf_puts0(deletelist, path);
                                    idset_add(deleteset, id);
                            }
                    }
            }
            gpath_close();
            /*
             * execute updating.
             */
            if (!idset_empty(deleteset) || strbuf_getlen(addlist) > 0) {
                    int db;

                    for (db = GTAGS; db < GTAGLIM; db++) {
                            /*
                             * GTAGS needed at least.
                             */
                            if ((db == GRTAGS || db == GSYMS)
                                && !test("f", makepath(dbpath, dbname(db), NULL)))
                                    continue;
                            if (vflag)
                                    fprintf(stderr, "[%s] Updating '%s'.\n", now(), dbname(db));
                            updatetags(dbpath, root, deleteset, addlist, db);
                    }
                    updated = 1;
            }
            if (strbuf_getlen(deletelist) + strbuf_getlen(addlist_other) > 0) {
                    const char *start, *end, *p;

                    if (vflag)
                            fprintf(stderr, "[%s] Updating '%s'.\n", now(), dbname(0));
                    gpath_open(dbpath, 2);
                    if (strbuf_getlen(deletelist) > 0) {
                            start = strbuf_value(deletelist);
                            end = start + strbuf_getlen(deletelist);

                            for (p = start; p < end; p += strlen(p) + 1)
                                    gpath_delete(p);
                    }
                    if (strbuf_getlen(addlist_other) > 0) {
                            start = strbuf_value(addlist_other);
                            end = start + strbuf_getlen(addlist_other);

                            for (p = start; p < end; p += strlen(p) + 1)
                                    gpath_put(p, GPATH_OTHER);
                    }
                    gpath_close();
                    updated = 1;
            }
            if (updated) {
                    int db;
                    /*
                     * Update modification time of tag files
                     * because they may have no definitions.
                     */
                    for (db = GTAGS; db < GTAGLIM; db++)
                            utime(makepath(dbpath, dbname(db), NULL), NULL);
            }
            if (vflag) {
                    if (updated)
                            fprintf(stderr, " Global databases have been modified.\n");
                    else
                            fprintf(stderr, " Global databases are up to date.\n");
                    fprintf(stderr, "[%s] Done.\n", now());
            }
            strbuf_close(addlist);
            strbuf_close(deletelist);
            strbuf_close(addlist_other);
            idset_close(deleteset);
            idset_close(findset);

            return updated;
    }
    /*
     * updatetags: update tag file.
     *
     *      i)      dbpath          directory in which tag file exist
     *      i)      root            root directory of source tree
     *      i)      deleteset       bit array of fid of deleted or modified files
     *      i)      addlist         \0 separated list of added or modified files
     *      i)      db              GTAGS, GRTAGS, GSYMS
     */
    static void
    verbose_updatetags(char *path, int seqno, int skip)
    {
            if (total)
                    fprintf(stderr, " [%d/%d]", seqno, total);
            else
                    fprintf(stderr, " [%d]", seqno);
            fprintf(stderr, " adding tags of %s", path);
            if (skip)
                    fprintf(stderr, " (skipped)");
            fputc('\n', stderr);
    }
    void
    updatetags(const char *dbpath, const char *root, IDSET *deleteset, STRBUF *addlist, int db)
    {
            GTOP *gtop;
            STRBUF *comline = strbuf_open(0);
            int seqno;

            /*
             * GTAGS needed to make GRTAGS.
             */
            if (db == GRTAGS && !test("f", makepath(dbpath, dbname(GTAGS), NULL)))
                    die("GTAGS needed to create GRTAGS.");

            /*
             * get tag command.
             */
            if (!getconfs(dbname(db), comline))
                    die("cannot get tag command. (%s)", dbname(db));
            gtop = gtags_open(dbpath, root, db, GTAGS_MODIFY);
            if (vflag) {
                    char fid[32];
                    const char *path;
                    int total = idset_count(deleteset);
                    unsigned int id;

                    seqno = 1;
                    for (id = idset_first(deleteset); id != END_OF_ID; id = idset_next(deleteset)) {
                            snprintf(fid, sizeof(fid), "%d", id);
                            path = gpath_fid2path(fid, NULL);
                            if (path == NULL)
                                    die("GPATH is corrupted.");
                            fprintf(stderr, " [%d/%d] deleting tags of %s\n", seqno++, total, path + 2);
                    }
            }
            if (!idset_empty(deleteset))
                    gtags_delete(gtop, deleteset);
            gtop->flags = 0;
            if (extractmethod)
                    gtop->flags |= GTAGS_EXTRACTMETHOD;
            if (debug)
                    gtop->flags |= GTAGS_DEBUG;
            /*
             * Compact format requires the tag records of the same file are
             * consecutive. We assume that the output of gtags-parser and
             * any plug-in parsers are consecutive for each file.
             * if (gtop->format & GTAGS_COMPACT) {
             *      nothing to do
             * }
             */
            /*
             * If the --max-args option is not specified, we pass the parser
             * the source file as a lot as possible to decrease the invoking
             * frequency of the parser.
             */
            {
                    XARGS *xp;
                    char *ctags_x;
                    char tag[MAXTOKEN], *p;

                    xp = xargs_open_with_strbuf(strbuf_value(comline), max_args, addlist);
                    xp->put_gpath = 1;
                    if (vflag)
                            xp->verbose = verbose_updatetags;
                    while ((ctags_x = xargs_read(xp)) != NULL) {
                            strlimcpy(tag, strmake(ctags_x, " \t"), sizeof(tag));
                            /*
                             * extract method when class method definition.
                             *
                             * Ex: Class::method(...)
                             *
                             * key  = 'method'
                             * data = 'Class::method  103 ./class.cpp ...'
                             */
                            p = tag;
                            if (gtop->flags & GTAGS_EXTRACTMETHOD) {
                                    if ((p = locatestring(tag, ".", MATCH_LAST)) != NULL)
                                            p++;
                                    else if ((p = locatestring(tag, "::", MATCH_LAST)) != NULL)
                                            p += 2;
                                    else
                                            p = tag;
                            }
                            gtags_put(gtop, p, ctags_x);
                    }
                    total = xargs_close(xp);
            }
            gtags_close(gtop);
            strbuf_close(comline);
    }
    /*
     * createtags: create tags file
     *
     *      i)      dbpath  dbpath directory
     *      i)      root    root directory of source tree
     *      i)      db      GTAGS, GRTAGS, GSYMS
     */
    static void
    verbose_createtags(char *path, int seqno, int skip)
    {
            if (total)
                    fprintf(stderr, " [%d/%d]", seqno, total);
            else
                    fprintf(stderr, " [%d]", seqno);
            fprintf(stderr, " extracting tags of %s", path);
            if (skip)
                    fprintf(stderr, " (skipped)");
            fputc('\n', stderr);
    }
    void
    createtags(const char *dbpath, const char *root, int db)
    {
            GTOP *gtop;
            XARGS *xp;
            char *ctags_x;
            STRBUF *comline = strbuf_open(0);
            STRBUF *path_list = strbuf_open(MAXPATHLEN);

            /*
             * get tag command.
             */
            if (!getconfs(dbname(db), comline))
                    die("cannot get tag command. (%s)", dbname(db));
            /*
             * GTAGS needed to make GRTAGS.
             */
            if (db == GRTAGS && !test("f", makepath(dbpath, dbname(GTAGS), NULL)))
                    die("GTAGS needed to create GRTAGS.");
            gtop = gtags_open(dbpath, root, db, GTAGS_CREATE);
            /*
             * Set flags.
             */
            gtop->flags = 0;
            if (extractmethod)
                    gtop->flags |= GTAGS_EXTRACTMETHOD;
            if (debug)
                    gtop->flags |= GTAGS_DEBUG;
            /*
             * Compact format requires the tag records of the same file are
             * consecutive. We assume that the output of gtags-parser and
             * any plug-in parsers are consecutive for each file.
             * if (gtop->format & GTAGS_COMPACT) {
             *      nothing to do
             * }
             */
            /*
             * If the --max-args option is not specified, we pass the parser
             * the source file as a lot as possible to decrease the invoking
             * frequency of the parser.
             */
            if (file_list)
                    find_open_filelist(file_list, root);
            else
                    find_open(NULL);
            /*
             * Add tags.
             */
            xp = xargs_open_with_find(strbuf_value(comline), max_args);
            xp->put_gpath = 1;
            if (vflag)
                    xp->verbose = verbose_createtags;
            while ((ctags_x = xargs_read(xp)) != NULL) {
                    char tag[MAXTOKEN], *p;

                    strlimcpy(tag, strmake(ctags_x, " \t"), sizeof(tag));
                    /*
                     * extract method when class method definition.
                     *
                     * Ex: Class::method(...)
                     *
                     * key  = 'method'
                     * data = 'Class::method  103 ./class.cpp ...'
                     */
                    p = tag;
                    if (gtop->flags & GTAGS_EXTRACTMETHOD) {
                            if ((p = locatestring(tag, ".", MATCH_LAST)) != NULL)
                                    p++;
                            else if ((p = locatestring(tag, "::", MATCH_LAST)) != NULL)
                                    p += 2;
                            else
                                    p = tag;
                    }
                    gtags_put(gtop, p, ctags_x);
            }
            total = xargs_close(xp);
            find_close();
            gtags_close(gtop);
            strbuf_close(comline);
            strbuf_close(path_list);
    }
    /*
     * printconf: print configuration data.
     *
     *      i)      name    label of config data
     *      r)              exit code
     */
    int
    printconf(const char *name)
    {
            int num;
            int exist = 1;

            if (getconfn(name, &num))
                    fprintf(stdout, "%d\n", num);
            else if (getconfb(name))
                    fprintf(stdout, "1\n");
            else {
                    STRBUF *sb = strbuf_open(0);
                    if (getconfs(name, sb))
                            fprintf(stdout, "%s\n", strbuf_value(sb));
                    else
                            exist = 0;
                    strbuf_close(sb);
            }
            return exist;
    }

/* [<][>][^][v][top][bottom][index][help] */