"Fossies" - the Fresh Open Source Software Archive

Member "global-6.6.5/global/global.c" (3 Sep 2020, 49215 Bytes) of package /linux/misc/global-6.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "global.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.6.4_vs_6.6.5.

    1 /*
    2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
    3  *  2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
    4  *  2020
    5  *  Tama Communications Corporation
    6  *
    7  * This file is part of GNU GLOBAL.
    8  *
    9  * This program is free software: you can redistribute it and/or modify
   10  * it under the terms of the GNU General Public License as published by
   11  * the Free Software Foundation, either version 3 of the License, or
   12  * (at your option) any later version.
   13  * 
   14  * This program is distributed in the hope that it will be useful,
   15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  * GNU General Public License for more details.
   18  * 
   19  * You should have received a copy of the GNU General Public License
   20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   21  */
   22 
   23 #ifdef HAVE_CONFIG_H
   24 #include <config.h>
   25 #endif
   26 #include <sys/types.h>
   27 #include <sys/stat.h>
   28 #include <ctype.h>
   29 #include <stdio.h>
   30 #include <errno.h>
   31 #ifdef STDC_HEADERS
   32 #include <stdlib.h>
   33 #endif
   34 #ifdef HAVE_STRING_H
   35 #include <string.h>
   36 #else
   37 #include <strings.h>
   38 #endif
   39 #ifdef HAVE_UNISTD_H
   40 #include <unistd.h>
   41 #endif
   42 #if defined(_WIN32) && !defined(__CYGWIN__)
   43 #define WIN32_LEAN_AND_MEAN
   44 #include <windows.h>
   45 #undef SLIST_ENTRY
   46 #endif
   47 #include "getopt.h"
   48 
   49 #include "global.h"
   50 #include "parser.h"
   51 #include "regex.h"
   52 #include "const.h"
   53 #include "output.h"
   54 #include "literal.h"
   55 #include "convert.h"
   56 
   57 /*
   58  * ensure GTAGSLIBPATH compares correctly
   59  */
   60 #if defined(_WIN32) || defined(__DJGPP__)
   61 #define STRCMP stricmp
   62 #define back2slash(sb) do {     \
   63     char *p = strbuf_value(sb); \
   64     for (; *p; p++)         \
   65         if (*p == '\\')         \
   66             *p = '/';       \
   67 } while (0)
   68 #else
   69 #define STRCMP strcmp
   70 #define back2slash(sb)
   71 #endif
   72 
   73 /*
   74  * enable [set] globbing, if available
   75  */
   76 #ifdef __CRT_GLOB_BRACKET_GROUPS__
   77 int _CRT_glob = __CRT_GLOB_USE_MINGW__ | __CRT_GLOB_BRACKET_GROUPS__;
   78 #endif
   79 
   80 /**
   81  * global - print locations of the specified object.
   82  */
   83 static void usage(void);
   84 static void help(void);
   85 static void setcom(int);
   86 int decide_tag_by_context(const char *, const char *, int);
   87 int main(int, char **);
   88 int completion_tags(const char *, const char *, const char *, int);
   89 void completion(const char *, const char *, const char *, int);
   90 void completion_idutils(const char *, const char *, const char *);
   91 void completion_path(const char *, const char *);
   92 void idutils(const char *, const char *);
   93 void grep(const char *, char *const *, const char *);
   94 void pathlist(const char *, const char *);
   95 void parsefile(char *const *, const char *, const char *, const char *, int);
   96 int search(const char *, const char *, const char *, const char *, int);
   97 void tagsearch(const char *, const char *, const char *, const char *, int);
   98 void encode(char *, int, const char *);
   99 
  100 const char *localprefix;        /**< local prefix       */
  101 int aflag;              /* [option]     */
  102 int cflag;              /* command      */
  103 int dflag;              /* command      */
  104 int fflag;              /* command      */
  105 int gflag;              /* command      */
  106 int Gflag;              /* [option]     */
  107 int iflag;              /* [option]     */
  108 int Iflag;              /* command      */
  109 int Lflag;              /* [option]     */
  110 int Mflag;              /* [option]     */
  111 int Nflag;              /* [option]     */
  112 int nflag;              /* [option]     */
  113 int oflag;              /* [option]     */
  114 int Oflag;              /* [option]     */
  115 int pflag;              /* command      */
  116 int Pflag;              /* command      */
  117 int qflag;              /* [option]     */
  118 int rflag;              /* [option]     */
  119 int sflag;              /* [option]     */
  120 int Sflag;              /* [option]     */
  121 int tflag;              /* [option]     */
  122 int Tflag;              /* [option]     */
  123 int uflag;              /* command      */
  124 int vflag;              /* [option]     */
  125 int Vflag;              /* [option]     */
  126 int xflag;              /* [option]     */
  127 int show_version;
  128 int show_help;
  129 int nofilter;
  130 int nosource;               /**< undocumented command */
  131 int debug;
  132 int literal;                /**< 1: literal search  */
  133 int print0;             /**< --print0 option    */
  134 int format;
  135 int type;               /**< path conversion type */
  136 int match_part;             /**< match part only    */
  137 int abslib;             /**< absolute path only in library project */
  138 int use_color;              /**< coloring */
  139 const char *cwd;            /**< current directory  */
  140 const char *root;           /**< root of source tree    */
  141 const char *dbpath;         /**< dbpath directory   */
  142 const char *nearbase;           /**< nearbase directory */
  143 char *context_file;
  144 char *context_lineno;
  145 char *file_list;
  146 char *scope;
  147 char *encode_chars;
  148 char *single_update;
  149 char *path_style;
  150 char *print_target;
  151 
  152 /*
  153  * Path filter
  154  */
  155 int do_path;
  156 int convert_type = PATH_RELATIVE;
  157 
  158 static void
  159 usage(void)
  160 {
  161     if (!qflag)
  162         fputs(usage_const, stderr);
  163     exit(2);
  164 }
  165 static void
  166 help(void)
  167 {
  168     fputs(usage_const, stdout);
  169     fputs(help_const, stdout);
  170     exit(0);
  171 }
  172 
  173 #define OPT_RESULT      128
  174 #define OPT_FROM_HERE       129
  175 #define OPT_ENCODE_PATH     130
  176 #define OPT_MATCH_PART      131
  177 #define OPT_SINGLE_UPDATE   132
  178 #define OPT_PATH_STYLE      133
  179 #define OPT_PATH_CONVERT    134
  180 #define OPT_USE_COLOR       135
  181 #define OPT_PRINT       136
  182 #define SORT_FILTER     1
  183 #define PATH_FILTER     2
  184 #define BOTH_FILTER     (SORT_FILTER|PATH_FILTER)
  185 #define MATCH_PART_FIRST 1
  186 #define MATCH_PART_LAST  2
  187 #define MATCH_PART_ALL   3
  188 
  189 const char *short_options = "acC:de:EifFgGIlL:MnNoOpPqrsS:tTuvVx";
  190 struct option const long_options[] = {
  191     {"absolute", no_argument, NULL, 'a'},
  192     {"directory", required_argument, NULL, 'C'},
  193     {"completion", no_argument, NULL, 'c'},
  194     {"definition", no_argument, NULL, 'd'},
  195     {"extended-regexp", no_argument, NULL, 'E'},
  196     {"regexp", required_argument, NULL, 'e'},
  197     {"file", no_argument, NULL, 'f'},
  198     {"first-match", no_argument, NULL, 'F'},
  199     {"local", no_argument, NULL, 'l'},
  200     {"file-list", required_argument, NULL, 'L'},
  201     {"match-case", no_argument, NULL, 'M'},
  202     {"nofilter", optional_argument, NULL, 'n'},
  203     {"nearness", optional_argument, NULL, 'N'},
  204     {"grep", no_argument, NULL, 'g'},
  205     {"basic-regexp", no_argument, NULL, 'G'},
  206     {"ignore-case", no_argument, NULL, 'i'},
  207     {"idutils", no_argument, NULL, 'I'},
  208     {"other", no_argument, NULL, 'o'},
  209     {"only-other", no_argument, NULL, 'O'},
  210     {"print-dbpath", no_argument, NULL, 'p'},
  211     {"path", no_argument, NULL, 'P'},
  212     {"quiet", no_argument, NULL, 'q'},
  213     {"reference", no_argument, NULL, 'r'},
  214     {"rootdir", no_argument, NULL, 'r'},
  215     {"symbol", no_argument, NULL, 's'},
  216     {"scope", required_argument, NULL, 'S'},
  217     {"tags", no_argument, NULL, 't'},
  218     {"through", no_argument, NULL, 'T'},
  219     {"update", no_argument, NULL, 'u'},
  220     {"verbose", no_argument, NULL, 'v'},
  221     {"invert-match", optional_argument, NULL, 'V'},
  222     {"cxref", no_argument, NULL, 'x'},
  223 
  224     /* long name only */
  225     {"color", optional_argument, NULL, OPT_USE_COLOR},
  226     {"encode-path", required_argument, NULL, OPT_ENCODE_PATH},
  227     {"from-here", required_argument, NULL, OPT_FROM_HERE},
  228     {"debug", no_argument, &debug, 1},
  229     {"gtagsconf", required_argument, NULL, OPT_GTAGSCONF},
  230     {"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
  231     {"literal", no_argument, &literal, 1},
  232     {"match-part", required_argument, NULL, OPT_MATCH_PART},
  233     {"path-style", required_argument, NULL, OPT_PATH_STYLE},
  234     {"path-convert", required_argument, NULL, OPT_PATH_CONVERT},
  235     {"print", required_argument, NULL, OPT_PRINT},
  236     {"print0", no_argument, &print0, 1},
  237     {"version", no_argument, &show_version, 1},
  238     {"help", no_argument, &show_help, 1},
  239     {"result", required_argument, NULL, OPT_RESULT},
  240     {"nosource", no_argument, &nosource, 1},
  241     {"single-update", required_argument, NULL, OPT_SINGLE_UPDATE},
  242     { 0 }
  243 };
  244 
  245 static int command;
  246 static void
  247 setcom(int c)
  248 {
  249     if (command == 0)
  250         command = c;
  251     else if (c == 'c' && (command == 'I' || command == 'P'))
  252         command = c;
  253     else if (command == 'c' && (c == 'I' || c == 'P'))
  254         ;
  255     else if (command != c)
  256         usage();
  257 }
  258 /**
  259  * decide_tag_by_context: decide tag type by context
  260  *
  261  *  @param[in]  tag tag name
  262  *  @param[in]  file    context file
  263  *  @param[in]  lineno  context lineno
  264  *  @return     GTAGS, GRTAGS, GSYMS
  265  */
  266 int
  267 decide_tag_by_context(const char *tag, const char *file, int lineno)
  268 {
  269 #define NEXT_NUMBER(p) do {                                                         \
  270     for (n = 0; isdigit(*p); p++)                                               \
  271         n = n * 10 + (*p - '0');                                            \
  272 } while (0)
  273     STRBUF *sb = NULL;
  274     char path[MAXPATHLEN], s_fid[MAXFIDLEN];
  275     const char *p;
  276     GTOP *gtop;
  277     GTP *gtp;
  278     int db = GSYMS;
  279     int flags = GTOP_NOREGEX;
  280 
  281     if (iflag)
  282         flags |= GTOP_IGNORECASE;
  283     if (normalize(file, get_root_with_slash(), cwd, path, sizeof(path)) == NULL)
  284         die("'%s' is out of the source project.", file);
  285     /*
  286      * get file id
  287      */
  288     if (gpath_open(dbpath, 0) < 0)
  289         die("GPATH not found.");
  290     if ((p = gpath_path2fid(path, NULL)) == NULL)
  291         die("path name in the context is not found.");
  292     strlimcpy(s_fid, p, sizeof(s_fid));
  293     gpath_close();
  294 
  295     /*
  296      * Algorithm:
  297      *
  298      * (1) If context <file, lineno> is a definition of <tag> then use GRTAGS
  299      * (2) else if there is at least one definition of <tag> then use GTAGS
  300      * (3) else use GSYMS.
  301      */
  302     gtop = gtags_open(dbpath, root, GTAGS, GTAGS_READ, 0);
  303     gtp = gtags_first(gtop, tag, flags);
  304     if (gtp) {
  305         db = GTAGS;
  306         for (; gtp; gtp = gtags_next(gtop)) {
  307             /*
  308              * Examine whether each definition record includes the context.
  309              */
  310             p = locatestring(gtp->tagline, s_fid, MATCH_AT_FIRST);
  311             if (p != NULL && *p == ' ') {
  312                 for (p++; *p && *p != ' '; p++)
  313                     ;
  314                 if (*p++ != ' ' || !isdigit(*p))
  315                     die("Impossible! decide_tag_by_context(1)");
  316                 /*
  317                  * Standard format  n <blank> <image>$
  318                  * Compact format   d,d,d,d$
  319                  */
  320                 if (!(gtop->format & GTAGS_COMPACT)) {  /* Standard format */
  321                     if (atoi(p) == lineno) {
  322                         db = GRTAGS;
  323                         goto finish;
  324                     }
  325                 } else {                /* Compact format */
  326                     int n, cur, last = 0;
  327 
  328                     do {
  329                         if (!isdigit(*p))
  330                             die("Impossible! decide_tag_by_context(2)");
  331                         NEXT_NUMBER(p);
  332                         cur = last + n;
  333                         if (cur == lineno) {
  334                             db = GRTAGS;
  335                             goto finish;
  336                         }
  337                         last = cur;
  338                         if (*p == '-') {
  339                             if (!isdigit(*++p))
  340                                 die("Impossible! decide_tag_by_context(3)");
  341                             NEXT_NUMBER(p);
  342                             cur = last + n;
  343                             if (lineno >= last && lineno <= cur) {
  344                                 db = GRTAGS;
  345                                 goto finish;
  346                             }
  347                             last = cur;
  348                         }
  349                         if (*p) {
  350                             if (*p == ',')
  351                                 p++;
  352                             else
  353                                 die("Impossible! decide_tag_by_context(4)");
  354                         }
  355                     } while (*p);
  356                 }
  357             }
  358         }
  359     }
  360 finish:
  361     gtags_close(gtop);
  362     if (db == GSYMS && getenv("GTAGSLIBPATH")) {
  363         char libdbpath[MAXPATHLEN];
  364         char *libdir = NULL, *nextp = NULL;
  365 
  366         sb = strbuf_open(0);
  367         strbuf_puts(sb, getenv("GTAGSLIBPATH"));
  368         back2slash(sb);
  369         for (libdir = strbuf_value(sb); db != GTAGS && libdir; libdir = nextp) {
  370             if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL)
  371                 *nextp++ = 0;
  372             if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0))
  373                 continue;
  374             if (!STRCMP(dbpath, libdbpath))
  375                 continue;
  376             gtop = gtags_open(libdbpath, root, GTAGS, GTAGS_READ, 0);
  377             if ((gtp = gtags_first(gtop, tag, flags)) != NULL)
  378                 db = GTAGS;
  379             gtags_close(gtop);
  380         }
  381         strbuf_close(sb);
  382     }
  383     return db;
  384 }
  385 int
  386 main(int argc, char **argv)
  387 {
  388     const char *av = NULL;
  389     int db;
  390     int optchar;
  391     int option_index = 0;
  392     int status = 0;
  393 
  394     /*
  395      * pick up --gtagsconf, --gtagslabel and --directory (-C).
  396      */
  397     if (preparse_options(argc, argv) < 0)
  398         usage();
  399     /*
  400      * get path of following directories.
  401      *  o current directory
  402      *  o root of source tree
  403      *  o dbpath directory
  404      *
  405      * if GTAGS not found, exit with an error message.
  406      */
  407     status = setupdbpath(0);
  408     if (status == 0) {
  409         cwd = get_cwd();
  410         root = get_root();
  411         dbpath = get_dbpath();
  412     }
  413     /*
  414      * Open configuration file.
  415      */
  416     openconf(root);
  417     setenv_from_config();
  418     logging_arguments(argc, argv);
  419     while ((optchar = getopt_long(argc, argv, short_options, long_options, &option_index)) != EOF) {
  420         switch (optchar) {
  421         case 0:
  422             break;
  423         case 'a':
  424             aflag++;
  425             break;
  426         case 'c':
  427             cflag++;
  428             setcom(optchar);
  429             break;
  430         case 'd':
  431             dflag++;
  432             break;
  433         case 'e':
  434             av = optarg;
  435             break;
  436         case 'E':
  437             Gflag = 0;
  438             break;
  439         case 'f':
  440             fflag++;
  441             xflag++;
  442             setcom(optchar);
  443             break;
  444         case 'F':
  445             Tflag = 0;
  446             break;
  447         case 'g':
  448             gflag++;
  449             setcom(optchar);
  450             break;
  451         case 'G':
  452             Gflag++;
  453             break;
  454         case 'i':
  455             iflag++;
  456             break;
  457         case 'I':
  458             Iflag++;
  459             setcom(optchar);
  460             break;
  461         case 'l':
  462             Sflag++;
  463             scope = ".";
  464             break;
  465         case 'L':
  466             file_list = optarg;
  467             break;
  468         case 'M':
  469             Mflag++;
  470             iflag = 0;
  471             break;
  472         case 'n':
  473             nflag++;
  474             if (optarg) {
  475                 if (!strcmp(optarg, "sort"))
  476                     nofilter |= SORT_FILTER;
  477                 else if (!strcmp(optarg, "path"))
  478                     nofilter |= PATH_FILTER;
  479             } else {
  480                 nofilter = BOTH_FILTER;
  481             }
  482             break;
  483         case 'N':
  484             Nflag++;
  485             if (optarg)
  486                 nearbase = optarg;
  487             break;
  488         case 'o':
  489             oflag++;
  490             break;
  491         case 'O':
  492             Oflag++;
  493             break;
  494         case 'p':
  495             pflag++;
  496             setcom(optchar);
  497             break;
  498         case 'P':
  499             Pflag++;
  500             setcom(optchar);
  501             break;
  502         case 'q':
  503             qflag++;
  504             setquiet();
  505             break;
  506         case 'r':
  507             rflag++;
  508             break;
  509         case 's':
  510             sflag++;
  511             break;
  512         case 'S':
  513             Sflag++;
  514             scope = optarg;
  515             break;
  516         case 't':
  517             tflag++;
  518             break;
  519         case 'T':
  520             Tflag++;
  521             break;
  522         case 'u':
  523             uflag++;
  524             setcom(optchar);
  525             break;
  526         case 'v':
  527             vflag++;
  528             setverbose();
  529             break;
  530         case 'V':
  531             Vflag++;
  532             break;
  533         case 'x':
  534             xflag++;
  535             break;
  536         case OPT_USE_COLOR:
  537             if (optarg) {
  538                 if (!strcmp(optarg, "never"))
  539                     use_color = 0;
  540                 else if (!strcmp(optarg, "always"))
  541                     use_color = 1;
  542                 else if (!strcmp(optarg, "auto"))
  543                     use_color = 2;
  544                 else
  545                     die_with_code(2, "unknown color type.");
  546             } else {
  547                 use_color = 2;
  548             }
  549             break;
  550         case OPT_ENCODE_PATH:
  551             encode_chars = optarg;
  552             break;
  553         case OPT_FROM_HERE:
  554             {
  555             char *p = optarg;
  556             const char *usage = "usage: global --from-here=lineno:path.";
  557 
  558             context_lineno = p;
  559             while (*p && isdigit(*p))
  560                 p++;
  561             if (*p != ':')
  562                 die_with_code(2, "%s", usage);
  563             *p++ = '\0';
  564             if (!*p)
  565                 die_with_code(2, "%s", usage);
  566             context_file = p;
  567             }
  568             break;
  569         case OPT_GTAGSCONF:
  570         case OPT_GTAGSLABEL:
  571         case 'C':
  572             /* These options are already parsed in preparse_options(). */
  573             break;
  574         case OPT_MATCH_PART:
  575             if (!strcmp(optarg, "first"))
  576                 match_part = MATCH_PART_FIRST;
  577             else if (!strcmp(optarg, "last"))
  578                 match_part = MATCH_PART_LAST;
  579             else if (!strcmp(optarg, "all"))
  580                 match_part = MATCH_PART_ALL;
  581             else
  582                 die_with_code(2, "unknown part type for the --match-part option.");
  583             break;
  584         case OPT_PATH_CONVERT:
  585             do_path = 1;
  586             if (!strcmp("absolute", optarg))
  587                 convert_type = PATH_ABSOLUTE;
  588             else if (!strcmp("relative", optarg))
  589                 convert_type = PATH_RELATIVE;
  590             else if (!strcmp("through", optarg))
  591                 convert_type = PATH_THROUGH;
  592             else
  593                 die("Unknown path type.");
  594             break;
  595         case OPT_PATH_STYLE:
  596             path_style = optarg;
  597             break;
  598         case OPT_PRINT:
  599             print_target = optarg;
  600             break;
  601         case OPT_RESULT:
  602             if (!strcmp(optarg, "ctags-x"))
  603                 format = FORMAT_CTAGS_X;
  604             else if (!strcmp(optarg, "ctags-xid"))  /* undocumented */
  605                 format = FORMAT_CTAGS_XID;
  606             else if (!strcmp(optarg, "ctags"))
  607                 format = FORMAT_CTAGS;
  608             else if (!strcmp(optarg, "ctags-mod"))  /* undocumented */
  609                 format = FORMAT_CTAGS_MOD;
  610             else if (!strcmp(optarg, "ctags-plus")) /* undocumented */
  611                 format = FORMAT_CTAGS_PLUS;
  612             else if (!strcmp(optarg, "path"))
  613                 format = FORMAT_PATH;
  614             else if (!strcmp(optarg, "grep"))
  615                 format = FORMAT_GREP;
  616             else if (!strcmp(optarg, "cscope"))
  617                 format = FORMAT_CSCOPE;
  618             else
  619                 die_with_code(2, "unknown format type for the --result option.");
  620             break;
  621         case OPT_SINGLE_UPDATE:
  622             single_update = optarg;
  623             break;
  624         default:
  625             usage();
  626             break;
  627         }
  628     }
  629     if (qflag)
  630         vflag = 0;
  631     if (show_version)
  632         version(av, vflag);
  633     if (show_help)
  634         help();
  635     if (dbpath == NULL)
  636         die_with_code(-status, "%s", gtags_dbpath_error);
  637     if (print_target) {
  638         const char *target = NULL;
  639         if (!strcmp("dbpath", print_target))
  640             target = dbpath;
  641         else if (!strcmp("root", print_target))
  642             target = root;
  643         else if (!strcmp("conf", print_target))
  644             target = getconfigpath();
  645         if (target != NULL)
  646             fprintf(stdout, "%s\n", target);
  647         exit(0);
  648     }
  649     if (Nflag) {
  650         if (!nearbase)
  651             nearbase = get_cwd();
  652         /*
  653          * Nearbase is saved with regular form. You can get it
  654          * by get_nearbase_path() later.
  655          */
  656         if (set_nearbase_path(nearbase) == NULL)
  657             die("invalid nearness file or directory (--nearness=%s).", nearbase);
  658     }
  659     /*
  660      * decide format.
  661      * The --result option is given to priority more than the -t and -x option.
  662      */
  663     if (format == 0) {
  664         if (tflag) {            /* ctags format */
  665             format = FORMAT_CTAGS;
  666         } else if (xflag) {     /* print details */
  667             format = FORMAT_CTAGS_X;
  668         } else {            /* print just a file name */
  669             format = FORMAT_PATH;
  670         }
  671     }
  672     /*
  673      * GTAGSBLANKENCODE will be used in less(1).
  674      */
  675     switch (format) {
  676     case FORMAT_CTAGS_X:
  677     case FORMAT_CTAGS_XID:
  678         if (encode_chars == NULL && getenv("GTAGSBLANKENCODE"))
  679             encode_chars = " \t";
  680         break;
  681     }
  682     if (encode_chars) {
  683         if (strlen(encode_chars) > 255)
  684             die("too many encode chars.");
  685         if (strchr(encode_chars, '/') || strchr(encode_chars, '.'))
  686             warning("cannot encode '/' and '.' in the path. Ignored.");
  687         set_encode_chars((unsigned char *)encode_chars);
  688     }
  689     if (getenv("GTAGSTHROUGH"))
  690         Tflag++;
  691     if (use_color) {
  692 #if defined(_WIN32) && !defined(__CYGWIN__)
  693         if (!(getenv("ANSICON") || LoadLibrary("ANSI32.dll")) && use_color == 2)
  694             use_color = 0;
  695 #endif
  696         if (use_color == 2 && !isatty(1))
  697             use_color = 0;
  698         if (Vflag)
  699             use_color = 0;
  700     }
  701     argc -= optind;
  702     argv += optind;
  703     /*
  704      * Path filter
  705      */
  706     if (do_path) {
  707         /*
  708          * This code is needed for globash.rc.
  709          * This code extract path name from tag line and
  710          * replace it with the relative or the absolute path name.
  711          *
  712          * By default, if we are in src/ directory, the output
  713          * should be converted like follows:
  714          *
  715          * main      10 ./src/main.c  main(argc, argv)\n
  716          * main      22 ./libc/func.c   main(argc, argv)\n
  717          *      v
  718          * main      10 main.c  main(argc, argv)\n
  719          * main      22 ../libc/func.c   main(argc, argv)\n
  720          *
  721          * Similarly, the --path-convert=absolute option specified, then
  722          *      v
  723          * main      10 /prj/xxx/src/main.c  main(argc, argv)\n
  724          * main      22 /prj/xxx/libc/func.c   main(argc, argv)\n
  725          */
  726         STRBUF *ib = strbuf_open(MAXBUFLEN);
  727         CONVERT *cv;
  728         char *ctags_x;
  729 
  730         if (argc < 3)
  731             die("global --path-convert: 3 arguments needed.");
  732         cv = convert_open(convert_type, FORMAT_CTAGS_X, argv[0], argv[1], argv[2], stdout, NOTAGS);
  733         while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL)
  734             convert_put(cv, ctags_x);
  735         convert_close(cv);
  736         strbuf_close(ib);
  737         exit(0);
  738     }
  739     /*
  740      * At first, we pickup pattern from -e option. If it is not found
  741      * then use argument which is not option.
  742      */
  743     if (!av) {
  744         av = *argv;
  745         /*
  746          * global -g pattern [files ...]
  747          *           av      argv
  748          */
  749         if (gflag && av)
  750             argv++;
  751     }
  752     if (single_update) {
  753         if (command == 0) {
  754             uflag++;
  755             command = 'u';
  756         } else if (command != 'u') {
  757             ;   /* ignored */
  758         }
  759     }
  760     /*
  761      * only -c, -u, -P and -p allows no argument.
  762      */
  763     if (!av) {
  764         switch (command) {
  765         case 'c':
  766         case 'u':
  767         case 'p':
  768         case 'P':
  769             break;
  770         case 'f':
  771             if (file_list)
  772                 break;
  773         default:
  774             usage();
  775             break;
  776         }
  777     }
  778     /*
  779      * -u and -p cannot have any arguments.
  780      */
  781     if (av) {
  782         switch (command) {
  783         case 'u':
  784         case 'p':
  785             usage();
  786         default:
  787             break;
  788         }
  789     }
  790     if (tflag)
  791         xflag = 0;
  792     if (nflag > 1)
  793         nosource = 1;   /* to keep compatibility */
  794     if (print0)
  795         set_print0();
  796     if (cflag && match_part == 0)
  797         match_part = MATCH_PART_ALL;
  798     /*
  799      * remove leading blanks.
  800      */
  801     if (!Iflag && !gflag && av)
  802         for (; *av == ' ' || *av == '\t'; av++)
  803             ;
  804     if (cflag && !Pflag && av && isregex(av))
  805         die_with_code(2, "only name char is allowed with -c option.");
  806     /*
  807      * print dbpath or rootdir.
  808      */
  809     if (pflag) {
  810         fprintf(stdout, "%s\n", (rflag) ? root : dbpath);
  811         exit(0);
  812     }
  813     /*
  814      * incremental update of tag files.
  815      */
  816     if (uflag) {
  817         STRBUF  *sb = strbuf_open(0);
  818         char *gtags_path = usable("gtags");
  819 
  820         if (!gtags_path)
  821             die("gtags command not found.");
  822         if (chdir(root) < 0)
  823             die("cannot change directory to '%s'.", root);
  824 #if defined(_WIN32) && !defined(__CYGWIN__)
  825         /*
  826          * Get around CMD.EXE's weird quoting rules by sticking another
  827          * perceived whitespace in front (also works with Take Command).
  828          */
  829         strbuf_putc(sb, ';');
  830 #endif
  831         strbuf_puts(sb, quote_shell(gtags_path));
  832         strbuf_puts(sb, " -i");
  833         if (vflag)
  834             strbuf_puts(sb, " -v");
  835         if (single_update) {
  836             if (!isabspath(single_update)) {
  837                 static char regular_path_name[MAXPATHLEN];
  838 
  839                 if (rel2abs(single_update, cwd, regular_path_name, sizeof(regular_path_name)) == NULL)
  840                     die("rel2abs failed.");
  841                 single_update = regular_path_name;
  842             }
  843             strbuf_puts(sb, " --single-update ");
  844             strbuf_puts(sb, quote_shell(single_update));
  845         }
  846         strbuf_putc(sb, ' ');
  847         strbuf_puts(sb, quote_shell(dbpath));
  848         if (system(strbuf_value(sb)))
  849             exit(1);
  850         strbuf_close(sb);
  851         exit(0);
  852     }
  853     /*
  854      * decide tag type.
  855      */
  856     if (context_file) {
  857         if (!literal && isregex(av))
  858             die_with_code(2, "regular expression is not allowed with the --from-here option.");
  859         db = decide_tag_by_context(av, context_file, atoi(context_lineno));
  860     } else {
  861         if (dflag)
  862             db = GTAGS;
  863         else if (rflag && sflag)
  864             db = GRTAGS + GSYMS;
  865         else
  866             db = (rflag) ? GRTAGS : ((sflag) ? GSYMS : GTAGS);
  867     }
  868     /*
  869      * complete function name
  870      */
  871     if (cflag) {
  872         if (Iflag)
  873             completion_idutils(dbpath, root, av);
  874         else if (Pflag)
  875             completion_path(dbpath, av);
  876         else
  877             completion(dbpath, root, av, db);
  878         exit(0);
  879     }
  880     /*
  881      * make local prefix.
  882      * local prefix must starts with './' and ends with '/'.
  883      */
  884     if (Sflag) {
  885         STRBUF *sb = strbuf_open(0);
  886         static char buf[MAXPATHLEN];
  887         const char *path = scope;
  888     
  889         /*
  890          * normalize the path of scope directory.
  891          */
  892         if (!test("d", path))
  893             die("'%s' not found or not a directory.", scope);
  894         if (!isabspath(path))
  895             path = makepath(cwd, path, NULL);
  896         if (realpath(path, buf) == NULL)
  897             die("cannot get real path of '%s'.", scope);
  898         if (!in_the_project(buf))
  899             die("'%s' is out of the source project.", scope);
  900         scope = buf;
  901         /*
  902          * make local prefix.
  903          */
  904         strbuf_putc(sb, '.');
  905         if (strcmp(root, scope) != 0) {
  906             const char *p = scope + strlen(root);
  907             if (*p != '/')
  908                 strbuf_putc(sb, '/');
  909             strbuf_puts(sb, p);
  910         }
  911         strbuf_putc(sb, '/');
  912         localprefix = check_strdup(strbuf_value(sb));
  913         strbuf_close(sb);
  914 #ifdef DEBUG
  915         fprintf(stderr, "root=%s\n", root);
  916         fprintf(stderr, "cwd=%s\n", cwd);
  917         fprintf(stderr, "localprefix=%s\n", localprefix);
  918 #endif
  919     }
  920     /*
  921      * convert the file-list path into an absolute path.
  922      */
  923     if (file_list && strcmp(file_list, "-") && !isabspath(file_list)) {
  924         static char buf[MAXPATHLEN];
  925 
  926         if (realpath(file_list, buf) == NULL)
  927             die("'%s' not found.", file_list);
  928         file_list = buf;
  929     }
  930     /*
  931      * decide path conversion type.
  932      */
  933     if (nofilter & PATH_FILTER)
  934         type = PATH_THROUGH;
  935     else if (aflag)
  936         type = PATH_ABSOLUTE;
  937     else
  938         type = PATH_RELATIVE;
  939     if (path_style) {
  940         if (!strcmp(path_style, "relative"))
  941             type = PATH_RELATIVE;
  942         else if (!strcmp(path_style, "absolute"))
  943             type = PATH_ABSOLUTE;
  944         else if (!strcmp(path_style, "through"))
  945             type = PATH_THROUGH;
  946         else if (!strcmp(path_style, "shorter"))
  947             type = PATH_SHORTER;
  948         else if (!strcmp(path_style, "abslib")) {
  949             type = PATH_RELATIVE;
  950             abslib++;
  951         } else
  952             die("invalid path style.");
  953     }
  954     {
  955         int conv_flags = 0;
  956 
  957         if (use_color)
  958             conv_flags |= CONVERT_COLOR;
  959         if (gflag)
  960             conv_flags |= CONVERT_GREP;
  961         if (Gflag)
  962             conv_flags |= CONVERT_BASIC;
  963         if (iflag)
  964             conv_flags |= CONVERT_ICASE;
  965         if (Iflag)
  966             conv_flags |= CONVERT_IDUTILS;
  967         if (Pflag)
  968             conv_flags |= CONVERT_PATH;
  969         set_convert_flags(conv_flags);
  970     }
  971     /*
  972      * exec lid(idutils).
  973      */
  974     if (Iflag) {
  975         chdir(root);
  976         idutils(av, dbpath);
  977     }
  978     /*
  979      * search pattern (regular expression).
  980      */
  981     else if (gflag) {
  982         chdir(root);
  983         grep(av, argv, dbpath);
  984     }
  985     /*
  986      * locate paths including the pattern.
  987      */
  988     else if (Pflag) {
  989         chdir(root);
  990         pathlist(av, dbpath);
  991     }
  992     /*
  993      * parse source files.
  994      */
  995     else if (fflag) {
  996         chdir(root);
  997         parsefile(argv, cwd, root, dbpath, db);
  998     }
  999     /*
 1000      * tag search.
 1001      */
 1002     else {
 1003         tagsearch(av, cwd, root, dbpath, db);
 1004     }
 1005     return 0;
 1006 }
 1007 /**
 1008  * completion_tags: print completion list of specified prefix
 1009  *
 1010  *  @param[in]  dbpath  dbpath directory
 1011  *  @param[in]  root    root directory
 1012  *  @param[in]  prefix  prefix of primary key
 1013  *  @param[in]  db  GTAGS,GRTAGS,GSYMS
 1014  *  @return     number of words
 1015  */
 1016 int
 1017 completion_tags(const char *dbpath, const char *root, const char *prefix, int db)
 1018 {
 1019     int flags = GTOP_KEY | GTOP_NOREGEX | GTOP_PREFIX;
 1020     GTOP *gtop = gtags_open(dbpath, root, db, GTAGS_READ, 0);
 1021     GTP *gtp;
 1022     int count = 0;
 1023 
 1024     if (iflag)
 1025         flags |= GTOP_IGNORECASE;
 1026     for (gtp = gtags_first(gtop, prefix, flags); gtp; gtp = gtags_next(gtop)) {
 1027         fputs(gtp->tag, stdout);
 1028         fputc('\n', stdout);
 1029         count++;
 1030     }
 1031     if (debug)
 1032         gtags_show_statistics(gtop);
 1033     gtags_close(gtop);
 1034     return count;
 1035 }
 1036 /**
 1037  * completion: print completion list of specified prefix
 1038  *
 1039  *  @param[in]  dbpath  dbpath directory
 1040  *  @param[in]  root    root directory
 1041  *  @param[in]  prefix  prefix of primary key
 1042  *  @param[in]  db  GTAGS,GRTAGS,GSYMS
 1043  */
 1044 void
 1045 completion(const char *dbpath, const char *root, const char *prefix, int db)
 1046 {
 1047     int count, total = 0;
 1048     char libdbpath[MAXPATHLEN];
 1049 
 1050     if (prefix && *prefix == 0) /* In the case global -c '' */
 1051         prefix = NULL;
 1052     count = completion_tags(dbpath, root, prefix, db);
 1053     /*
 1054      * search in library path.
 1055      */
 1056     if (db == GTAGS && getenv("GTAGSLIBPATH") && (count == 0 || Tflag) && !Sflag) {
 1057         STRBUF *sb = strbuf_open(0);
 1058         char *libdir, *nextp = NULL;
 1059 
 1060         strbuf_puts(sb, getenv("GTAGSLIBPATH"));
 1061         back2slash(sb);
 1062         /*
 1063          * search for each tree in the library path.
 1064          */
 1065         for (libdir = strbuf_value(sb); libdir; libdir = nextp) {
 1066             if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL)
 1067                 *nextp++ = 0;
 1068             if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0))
 1069                 continue;
 1070             if (!STRCMP(dbpath, libdbpath))
 1071                 continue;
 1072             if (!test("f", makepath(libdbpath, dbname(db), NULL)))
 1073                 continue;
 1074             /*
 1075              * search again
 1076              */
 1077             count = completion_tags(libdbpath, libdir, prefix, db);
 1078             total += count;
 1079             if (count > 0 && !Tflag)
 1080                 break;
 1081         }
 1082         strbuf_close(sb);
 1083     }
 1084     /* return total; */
 1085 }
 1086 /**
 1087  * completion_idutils: print completion list of specified prefix
 1088  *
 1089  *  @param[in]  dbpath  dbpath directory
 1090  *  @param[in]  root    root directory
 1091  *  @param[in]  prefix  prefix of primary key
 1092  */
 1093 void
 1094 completion_idutils(const char *dbpath, const char *root, const char *prefix)
 1095 {
 1096     FILE *ip;
 1097     STRBUF *sb = strbuf_open(0);
 1098     char *lid = usable("lid");
 1099     char *line, *p;
 1100     char *argv[10];
 1101     int i = 0;
 1102 
 1103     if (prefix && *prefix == 0) /* In the case global -c '' */
 1104         prefix = NULL;
 1105     /*
 1106      * make lid command line.
 1107      * Invoke lid with the --result=grep option to generate grep format.
 1108      *
 1109      * When lid(1) not found in the PATH, use LID macro if it exists.
 1110      * This is needed because lid is called indirectly from CGI scripts. 
 1111      * In the CGI scripts, PATH is limited to '/bin:/usr/bin:/usr/local/bin'.
 1112      */
 1113     if (!lid) {
 1114         if (strcmp(LID, "no") != 0 && test("fx", LID))
 1115             lid = LID;
 1116         else
 1117             die("lid(idutils) not found.");
 1118     }
 1119     if (chdir(root) < 0)
 1120         die("cannot move to '%s' directory.", root);
 1121 #if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)
 1122     strbuf_puts(sb, lid);
 1123     strbuf_sprintf(sb, " --file=%s/ID", quote_shell(dbpath));
 1124     strbuf_puts(sb, " --key=token");
 1125     if (iflag)
 1126         strbuf_puts(sb, " --ignore-case");
 1127     if (prefix) {
 1128         strbuf_putc(sb, ' ');
 1129         strbuf_putc(sb, '"');
 1130         strbuf_putc(sb, '^');
 1131         strbuf_puts(sb, prefix);
 1132         strbuf_putc(sb, '"');
 1133     }
 1134     if (debug)
 1135         fprintf(stderr, "completion_idutils: %s\n", strbuf_value(sb));
 1136     if (!(ip = popen(strbuf_value(sb), "r")))
 1137         die("cannot execute '%s'.", strbuf_value(sb));
 1138 #else
 1139     /*
 1140      * This function is called from the CGI scripts of htags(1).
 1141      * In order not to cause unnecessary anxiety, popen(3) is not used in Unix.
 1142      */
 1143     strbuf_puts0(sb, makepath(dbpath, "ID", NULL));
 1144     if (prefix) {
 1145         strbuf_putc(sb, '^');
 1146         strbuf_puts0(sb, prefix);
 1147     }
 1148     p = strbuf_value(sb);
 1149     argv[i++] = lid;
 1150     argv[i++] = "--file";
 1151     argv[i++] = p;                  /* dbpath/ID */
 1152     argv[i++] = "--key=token";
 1153     if (iflag)
 1154         argv[i++] = "--ignore-case";
 1155     if (prefix)
 1156         argv[i++] = next_string(p);     /* ^prefix */
 1157     argv[i] = NULL;
 1158     if (debug) {
 1159         fprintf(stderr, "completion_idutils: \n");
 1160         for (i = 0; argv[i] != NULL; i++) 
 1161             fprintf(stderr, "argv[%d] = |%s|\n", i, argv[i]);
 1162     }
 1163     if (!(ip = secure_popen(lid, "r", argv)))
 1164         die("cannot execute '%s'.", lid);
 1165 #endif
 1166     while ((line = strbuf_fgets(sb, ip, STRBUF_NOCRLF)) != NULL) {
 1167         for (p = line; *p && *p != ' '; p++)
 1168             ;
 1169         if (*p == '\0') {
 1170             warning("Invalid line: %s", line);
 1171             continue;
 1172         }
 1173         *p = '\0';
 1174         puts(line);
 1175     }
 1176 #if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)
 1177     if (pclose(ip) != 0)
 1178         die("terminated abnormally (errno = %d).", errno);
 1179 #else
 1180     if (secure_pclose(ip) != 0)
 1181         die("terminated abnormally (errno = %d).", errno);
 1182 #endif
 1183     strbuf_close(sb);
 1184 }
 1185 /**
 1186  * completion_path: print candidate path list.
 1187  *
 1188  *  @param[in]  dbpath  dbpath directory
 1189  *  @param[in]  prefix  prefix of primary key
 1190  */
 1191 void
 1192 completion_path(const char *dbpath, const char *prefix)
 1193 {
 1194     GFIND *gp;
 1195     const char *localprefix = "./";
 1196     DBOP *dbop = dbop_open(NULL, 1, 0600, DBOP_RAW);
 1197     const char *path;
 1198     int prefix_length;
 1199     int target = GPATH_SOURCE;
 1200     int flags = (match_part == MATCH_PART_LAST) ? MATCH_LAST : MATCH_FIRST;
 1201 
 1202     if (dbop == NULL)
 1203         die("cannot open temporary file.");
 1204     if (prefix && *prefix == 0) /* In the case global -c '' */
 1205         prefix = NULL;
 1206     prefix_length = (prefix == NULL) ? 0 : strlen(prefix);
 1207     if (oflag)
 1208         target = GPATH_BOTH;
 1209     if (Oflag)
 1210         target = GPATH_OTHER;
 1211     if (iflag || getconfb("icase_path"))
 1212         flags |= IGNORE_CASE;
 1213 #if _WIN32 || __DJGPP__
 1214     else if (!Mflag)
 1215         flags |= IGNORE_CASE;
 1216 #endif
 1217     gp = gfind_open(dbpath, localprefix, target, 0);
 1218     while ((path = gfind_read(gp)) != NULL) {
 1219         path++;                 /* skip '.'*/
 1220         if (prefix == NULL) {
 1221             dbop_put(dbop, path + 1, "");
 1222         } else if (match_part == MATCH_PART_ALL) {
 1223             const char *p = path;
 1224 
 1225             while ((p = locatestring(p, prefix, flags)) != NULL) {
 1226                 dbop_put(dbop, p, "");
 1227                 p += prefix_length;
 1228             }
 1229         } else {
 1230             const char *p = locatestring(path, prefix, flags);
 1231             if (p != NULL) {
 1232                 dbop_put(dbop, p, "");
 1233             }
 1234         }
 1235     }
 1236     gfind_close(gp);
 1237     for (path = dbop_first(dbop, NULL, NULL, DBOP_KEY); path != NULL; path = dbop_next(dbop)) {
 1238         fputs(path, stdout);
 1239         fputc('\n', stdout);
 1240     }
 1241     dbop_close(dbop);
 1242 }
 1243 /*
 1244  * Output filter
 1245  *
 1246  * (1) Old architecture (- GLOBAL-4.7.8)
 1247  *
 1248  * process1          process2       process3
 1249  * +=============+  +===========+  +===========+
 1250  * |global(write)|->|sort filter|->|path filter|->[stdout]
 1251  * +=============+  +===========+  +===========+
 1252  *
 1253  * (2) Recent architecture (GLOBAL-5.0 - 5.3)
 1254  *
 1255  * 1 process
 1256  * +===========================================+
 1257  * |global(write)->[sort filter]->[path filter]|->[stdout]
 1258  * +===========================================+
 1259  *
 1260  * (3) Current architecture (GLOBAL-5.4 -)
 1261  *
 1262  * 1 process
 1263  * +===========================================+
 1264  * |[sort filter]->global(write)->[path filter]|->[stdout]
 1265  * +===========================================+
 1266  *
 1267  * Sort filter is implemented in gtagsop module (libutil/gtagsop.c).
 1268  * Path filter is implemented in convert module (global/convert.c).
 1269  */
 1270 /**
 1271  * print number of object.
 1272  *
 1273  * This procedure is commonly used except for the -P option.
 1274  */
 1275 void
 1276 print_count(int number)
 1277 {
 1278     const char *target = format == FORMAT_PATH ? "file" : "object";
 1279 
 1280     switch (number) {
 1281     case 0:
 1282         fprintf(stderr, "object not found");
 1283         break;
 1284     case 1:
 1285         fprintf(stderr, "1 %s located", target);
 1286         break;
 1287     default:
 1288         fprintf(stderr, "%d %ss located", number, target);
 1289         break;
 1290     }
 1291 }
 1292 /**
 1293  * idutils:  lid(idutils) pattern
 1294  *
 1295  *  @param[in]  pattern POSIX regular expression
 1296  *  @param[in]  dbpath  "GTAGS" directory
 1297  */
 1298 void
 1299 idutils(const char *pattern, const char *dbpath)
 1300 {
 1301     FILE *ip;
 1302     CONVERT *cv;
 1303     STRBUF *ib = strbuf_open(0);
 1304     char encoded_pattern[IDENTLEN];
 1305     char path[MAXPATHLEN];
 1306     char *lid = usable("lid");
 1307     int linenum, count;
 1308     char *p, *q, *grep;
 1309     char *argv[20];
 1310     int i = 0;
 1311 
 1312     /*
 1313      * When lid(1) not found in the PATH, use LID macro if it exists.
 1314      * This is needed because lid is called indirectly from CGI scripts. 
 1315      * In the CGI scripts, PATH is limited to '/bin:/usr/bin:/usr/local/bin'.
 1316      */
 1317     if (!lid) {
 1318         if (strcmp(LID, "no") != 0 && test("fx", LID))
 1319             lid = LID;
 1320         else
 1321             die("lid(idutils) not found.");
 1322     }
 1323     if (!test("f", makepath(dbpath, "ID", NULL)))
 1324         die("ID file not found.");
 1325     /*
 1326      * PWD is needed for lid.
 1327      */
 1328     set_env("PWD", root);
 1329     /*
 1330      * convert spaces into %FF format.
 1331      */
 1332     encode(encoded_pattern, sizeof(encoded_pattern), pattern);
 1333     /*
 1334      * make lid command line.
 1335      * Invoke lid with the --result=grep option to generate grep format.
 1336      */
 1337 #if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)
 1338     strbuf_puts(ib, lid);
 1339     strbuf_sprintf(ib, " --file=%s/ID", quote_shell(dbpath));
 1340     strbuf_puts(ib, " --separator=newline");
 1341     if (format == FORMAT_PATH)
 1342         strbuf_puts(ib, " --result=filenames --key=none");
 1343     else
 1344         strbuf_puts(ib, " --result=grep");
 1345     if (iflag)
 1346         strbuf_puts(ib, " --ignore-case");
 1347     if (literal)
 1348         strbuf_puts(ib, " --literal");
 1349     else if (isregex(pattern))
 1350         strbuf_puts(ib, " --regexp");
 1351     strbuf_putc(ib, ' ');
 1352     strbuf_puts(ib, quote_shell(pattern));
 1353     if (debug)
 1354         fprintf(stderr, "idutils: %s\n", strbuf_value(ib));
 1355     if (!(ip = popen(strbuf_value(ib), "r")))
 1356         die("cannot execute '%s'.", strbuf_value(ib));
 1357 #else
 1358     /*
 1359      * This function is called from the CGI scripts of htags(1).
 1360      * In order not to cause unnecessary anxiety, popen(3) is not used in Unix.
 1361      */
 1362     strbuf_puts0(ib, makepath(dbpath, "ID", NULL));
 1363     strbuf_puts0(ib, pattern);
 1364     p = strbuf_value(ib);
 1365     argv[i++] = lid;
 1366     argv[i++] = "--file";
 1367     argv[i++] = p;                  /* dbpath/ID */
 1368     argv[i++] = "--separator=newline";
 1369     if (format == FORMAT_PATH) {
 1370         argv[i++] = "--result=filenames";
 1371         argv[i++] = "--key=none";
 1372     } else {
 1373         argv[i++] = "--result=grep";
 1374     }
 1375     if (iflag)
 1376         argv[i++] = "--ignore-case";
 1377     if (literal)
 1378         argv[i++] = "--literal";
 1379     else if (isregex(pattern))
 1380         argv[i++] = "--regexp";
 1381     argv[i++] = next_string(p);         /* pattern */
 1382     argv[i] = NULL;
 1383     if (debug) {
 1384         fprintf(stderr, "idutils: \n");
 1385         for (i = 0; argv[i] != NULL; i++) 
 1386             fprintf(stderr, "argv[%d] = |%s|\n", i, argv[i]);
 1387     }
 1388     if (!(ip = secure_popen(lid, "r", argv)))
 1389         die("cannot execute '%s'.", strbuf_value(ib));
 1390 #endif
 1391     cv = convert_open(type, format, root, cwd, dbpath, stdout, NOTAGS);
 1392     cv->tag_for_display = encoded_pattern;
 1393     count = 0;
 1394     strcpy(path, "./");
 1395     while ((grep = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) {
 1396         q = path + 2;
 1397         /* extract path name */
 1398         if (*grep == '/')
 1399             die("The path in the output of lid is assumed relative.\n'%s'", grep);
 1400         p = grep;
 1401         while (*p && *p != ':')
 1402             *q++ = *p++;
 1403         *q = '\0'; 
 1404         if ((xflag || tflag) && !*p)
 1405             die("invalid lid(idutils) output format(1). '%s'", grep);
 1406         p++;
 1407         if (Sflag) {
 1408             if (!locatestring(path, localprefix, MATCH_AT_FIRST))
 1409                 continue;
 1410         }
 1411         count++;
 1412         switch (format) {
 1413         case FORMAT_PATH:
 1414             convert_put_path(cv, NULL, path);
 1415             break;
 1416         default:
 1417             /* extract line number */
 1418             while (*p && isspace(*p))
 1419                 p++;
 1420             linenum = 0;
 1421             for (linenum = 0; *p && isdigit(*p); linenum = linenum * 10 + (*p++ - '0'))
 1422                 ;
 1423             if (*p != ':')
 1424                 die("invalid lid(idutils) output format(2). '%s'", grep);
 1425             if (linenum <= 0)
 1426                 die("invalid lid(idutils) output format(3). '%s'", grep);
 1427             p++;
 1428             /*
 1429              * print out.
 1430              */
 1431             convert_put_using(cv, pattern, path, linenum, p, NULL);
 1432             break;
 1433         }
 1434     }
 1435 #if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)
 1436     if (pclose(ip) != 0)
 1437         die("terminated abnormally (errno = %d).", errno);
 1438 #else
 1439     if (secure_pclose(ip) != 0)
 1440         die("terminated abnormally (errno = %d).", errno);
 1441 #endif
 1442     convert_close(cv);
 1443     strbuf_close(ib);
 1444     if (vflag) {
 1445         print_count(count);
 1446         fprintf(stderr, " (using idutils index in '%s').\n", dbpath);
 1447     }
 1448 }
 1449 /**
 1450  * grep: grep pattern
 1451  *
 1452  *  @param[in]  pattern POSIX regular expression
 1453  *  @param  argv
 1454  *  @param  dbpath
 1455  */
 1456 void
 1457 grep(const char *pattern, char *const *argv, const char *dbpath)
 1458 {
 1459     FILE *fp;
 1460     CONVERT *cv;
 1461     GFIND *gp = NULL;
 1462     STRBUF *ib = strbuf_open(MAXBUFLEN);
 1463     const char *path;
 1464     char encoded_pattern[IDENTLEN];
 1465     const char *buffer;
 1466     int linenum, count;
 1467     int flags = 0;
 1468     int target = GPATH_SOURCE;
 1469     regex_t preg;
 1470     int user_specified = 1;
 1471     int gfind_flags = 0;
 1472 
 1473     /*
 1474      * convert spaces into %FF format.
 1475      */
 1476     encode(encoded_pattern, sizeof(encoded_pattern), pattern);
 1477     /*
 1478      * literal search available?
 1479      */
 1480     if (!literal) {
 1481         const char *p = pattern;
 1482         int normal = 1;
 1483 
 1484         for (; *p; p++) {
 1485             if (!(isalpha(*p) || isdigit(*p) || isblank(*p) || *p == '_')) {
 1486                 normal = 0;
 1487                 break;
 1488             }
 1489         }
 1490         if (normal)
 1491             literal = 1;
 1492     }
 1493     if (oflag)
 1494         target = GPATH_BOTH;
 1495     if (Oflag)
 1496         target = GPATH_OTHER;
 1497     if (Nflag)
 1498         gfind_flags |= GPATH_NEARSORT;
 1499     if (literal) {
 1500         literal_comple(pattern);
 1501     } else {
 1502         if (!Gflag)
 1503             flags |= REG_EXTENDED;
 1504         if (iflag)
 1505             flags |= REG_ICASE;
 1506         if (regcomp(&preg, pattern, flags) != 0)
 1507             die("invalid regular expression.");
 1508     }
 1509     cv = convert_open(type, format, root, cwd, dbpath, stdout, NOTAGS);
 1510     cv->tag_for_display = encoded_pattern;
 1511     count = 0;
 1512 
 1513     if (*argv && file_list)
 1514         args_open_both(argv, file_list);
 1515     else if (*argv)
 1516         args_open(argv);
 1517     else if (file_list)
 1518         args_open_filelist(file_list);
 1519     else {
 1520         args_open_gfind(gp = gfind_open(dbpath, localprefix, target, gfind_flags));
 1521         user_specified = 0;
 1522     }
 1523     while ((path = args_read()) != NULL) {
 1524         if (user_specified) {
 1525             static char buf[MAXPATHLEN];
 1526 
 1527             if (normalize(path, get_root_with_slash(), cwd, buf, sizeof(buf)) == NULL) {
 1528                 warning("'%s' is out of the source project.", path);
 1529                 continue;
 1530             }
 1531             if (test("d", buf)) {
 1532                 warning("'%s' is a directory. Ignored.", path);
 1533                 continue;
 1534             }
 1535             if (!test("f", buf)) {
 1536                 warning("'%s' not found. Ignored.", path);
 1537                 continue;
 1538             }
 1539             path = buf;
 1540         }
 1541         if (Sflag && !locatestring(path, localprefix, MATCH_AT_FIRST))
 1542             continue;
 1543         if (literal) {
 1544             int n = literal_search(cv, path);
 1545             if (n > 0)
 1546                 count += n;
 1547         } else {
 1548             if (!(fp = fopen(path, "r")))
 1549                 die("cannot open file '%s'.", path);
 1550             linenum = 0;
 1551             while ((buffer = strbuf_fgets(ib, fp, STRBUF_NOCRLF)) != NULL) {
 1552                 int result = regexec(&preg, buffer, 0, 0, 0);
 1553                 linenum++;
 1554                 if ((!Vflag && result == 0) || (Vflag && result != 0)) {
 1555                     count++;
 1556                     if (format == FORMAT_PATH) {
 1557                         convert_put_path(cv, NULL, path);
 1558                         break;
 1559                     } else {
 1560                         convert_put_using(cv, pattern, path, linenum, buffer,
 1561                             (user_specified) ? NULL : gp->dbop->lastdat);
 1562                     }
 1563                 }
 1564             }
 1565             fclose(fp);
 1566         }
 1567     }
 1568     args_close();
 1569     convert_close(cv);
 1570     strbuf_close(ib);
 1571     if (literal == 0)
 1572         regfree(&preg);
 1573     if (vflag) {
 1574         print_count(count);
 1575         fprintf(stderr, " (no index used).\n");
 1576     }
 1577 }
 1578 /**
 1579  * pathlist: print candidate path list.
 1580  *
 1581  *  @param[in]  pattern
 1582  *  @param[in]  dbpath
 1583  */
 1584 void
 1585 pathlist(const char *pattern, const char *dbpath)
 1586 {
 1587     GFIND *gp;
 1588     CONVERT *cv;
 1589     const char *path, *p;
 1590     regex_t preg;
 1591     int count;
 1592     int target = GPATH_SOURCE;
 1593     int gfind_flags = 0;
 1594 
 1595     if (oflag)
 1596         target = GPATH_BOTH;
 1597     if (Oflag)
 1598         target = GPATH_OTHER;
 1599     if (Nflag)
 1600         gfind_flags |= GPATH_NEARSORT;
 1601     if (pattern) {
 1602         int flags = 0;
 1603         char edit[IDENTLEN];
 1604 
 1605         if (!Gflag)
 1606             flags |= REG_EXTENDED;
 1607         if (iflag || getconfb("icase_path"))
 1608             flags |= REG_ICASE;
 1609 #if _WIN32 || __DJGPP__
 1610         else if (!Mflag)
 1611             flags |= REG_ICASE;
 1612 #endif /* _WIN32 */
 1613         /*
 1614          * We assume '^aaa' as '^/aaa'.
 1615          */
 1616         if (literal) {
 1617             strlimcpy(edit, quote_string(pattern), sizeof(edit));
 1618             pattern = edit;
 1619         } else if (*pattern == '^' && *(pattern + 1) != '/') {
 1620             snprintf(edit, sizeof(edit), "^/%s", pattern + 1);
 1621             pattern = edit;
 1622         }
 1623         if (regcomp(&preg, pattern, flags) != 0)
 1624             die("invalid regular expression.");
 1625     }
 1626     if (!localprefix)
 1627         localprefix = "./";
 1628     cv = convert_open(type, format, root, cwd, dbpath, stdout, GPATH);
 1629     cv->tag_for_display = "path";
 1630     count = 0;
 1631 
 1632     gp = gfind_open(dbpath, localprefix, target, gfind_flags);
 1633     while ((path = gfind_read(gp)) != NULL) {
 1634         /*
 1635          * skip localprefix because end-user doesn't see it.
 1636          */
 1637         p = path + strlen(localprefix) - 1;
 1638         if (pattern) {
 1639             int result = regexec(&preg, p, 0, 0, 0);
 1640 
 1641             if ((!Vflag && result != 0) || (Vflag && result == 0))
 1642                 continue;
 1643         } else if (Vflag)
 1644             continue;
 1645         if (format == FORMAT_PATH)
 1646             convert_put_path(cv, pattern, path);
 1647         else
 1648             convert_put_using(cv, pattern, path, 1, " ", gp->dbop->lastdat);
 1649         count++;
 1650     }
 1651     gfind_close(gp);
 1652     convert_close(cv);
 1653     if (pattern)
 1654         regfree(&preg);
 1655     if (vflag) {
 1656         switch (count) {
 1657         case 0:
 1658             fprintf(stderr, "file not found");
 1659             break;
 1660         case 1:
 1661             fprintf(stderr, "1 file located");
 1662             break;
 1663         default:
 1664             fprintf(stderr, "%d files located", count);
 1665             break;
 1666         }
 1667         fprintf(stderr, " (using '%s').\n", makepath(dbpath, dbname(GPATH), NULL));
 1668     }
 1669 }
 1670 /**
 1671  * void parsefile(char *const *argv, const char *cwd, const char *root, const char *dbpath, int db)
 1672  *
 1673  * parsefile: parse file to pick up tags.
 1674  *
 1675  *  @param[in]  argv
 1676  *  @param[in]  cwd current directory
 1677  *  @param[in]  root    root directory of source tree
 1678  *  @param[in]  dbpath  dbpath
 1679  *  @param[in]  db  type of parse
 1680  */
 1681 #define TARGET_DEF  (1 << GTAGS)
 1682 #define TARGET_REF  (1 << GRTAGS)
 1683 #define TARGET_SYM  (1 << GSYMS)
 1684 struct parsefile_data {
 1685     CONVERT *cv;
 1686     DBOP *dbop;
 1687     int target;
 1688     int extractmethod;
 1689     int count;
 1690     const char *fid;            /**< fid of the file under processing */
 1691 };
 1692 static void
 1693 put_syms(int type, const char *tag, int lno, const char *path, const char *line_image, void *arg)
 1694 {
 1695     struct parsefile_data *data = arg;
 1696     const char *key;
 1697 
 1698     if (format == FORMAT_PATH && data->count > 0)
 1699         return;
 1700     switch (type) {
 1701     case PARSER_DEF:
 1702         if (!(data->target & TARGET_DEF))
 1703             return;
 1704         break;
 1705     case PARSER_REF_SYM:
 1706         if (!(data->target & (TARGET_REF | TARGET_SYM)))
 1707             return;
 1708         /*
 1709          * extract method when class method definition.
 1710          *
 1711          * Ex: Class::method(...)
 1712          *
 1713          * key  = 'method'
 1714          * data = 'Class::method  103 ./class.cpp ...'
 1715          */
 1716         if (data->extractmethod) {
 1717             if ((key = locatestring(tag, ".", MATCH_LAST)) != NULL)
 1718                 key++;
 1719             else if ((key = locatestring(tag, "::", MATCH_LAST)) != NULL)
 1720                 key += 2;
 1721             else
 1722                 key = tag;
 1723         } else {
 1724             key = tag;
 1725         }
 1726         if (data->target == TARGET_REF || data->target == TARGET_SYM) {
 1727             if (dbop_get(data->dbop, key) != NULL) {
 1728                 if (!(data->target & TARGET_REF))
 1729                     return;
 1730             } else {
 1731                 if (!(data->target & TARGET_SYM))
 1732                     return;
 1733             }
 1734         }
 1735         break;
 1736     default:
 1737         return;
 1738     }
 1739     convert_put_using(data->cv, tag, path, lno, line_image, data->fid);
 1740     data->count++;
 1741 }
 1742 void
 1743 parsefile(char *const *argv, const char *cwd, const char *root, const char *dbpath, int db)
 1744 {
 1745     int count = 0;
 1746     int flags = 0;
 1747     STRBUF *sb = strbuf_open(0);
 1748     char *langmap;
 1749     const char *plugin_parser, *av;
 1750     char path[MAXPATHLEN];
 1751     struct parsefile_data data;
 1752 
 1753     flags = 0;
 1754     if (vflag)
 1755         flags |= PARSER_VERBOSE;
 1756     if (debug)
 1757         flags |= PARSER_DEBUG;
 1758     /*
 1759     if (wflag)
 1760         flags |= PARSER_WARNING;
 1761     */
 1762     if (getenv("GTAGSFORCEENDBLOCK"))
 1763         flags |= PARSER_END_BLOCK;
 1764     if (db == GRTAGS + GSYMS)
 1765         data.target = TARGET_REF|TARGET_SYM;
 1766     else
 1767         data.target = 1 << db;
 1768     data.extractmethod = getconfb("extractmethod");
 1769     if (getconfs("langmap", sb))
 1770         langmap = check_strdup(strbuf_value(sb));
 1771     else
 1772         langmap = NULL;
 1773     strbuf_reset(sb);
 1774     if (getconfs("gtags_parser", sb))
 1775         plugin_parser = strbuf_value(sb);
 1776     else
 1777         plugin_parser = NULL;
 1778     data.cv = convert_open(type, format, root, cwd, dbpath, stdout, db);
 1779     if (gpath_open(dbpath, 0) < 0)
 1780         die("GPATH not found.");
 1781     if (data.target == TARGET_REF || data.target == TARGET_SYM) {
 1782         data.dbop = dbop_open(makepath(dbpath, dbname(GTAGS), NULL), 0, 0, 0);
 1783         if (data.dbop == NULL)
 1784             die("%s not found.", dbname(GTAGS));
 1785     } else {
 1786         data.dbop = NULL;
 1787     }
 1788     data.fid = NULL;
 1789     parser_init(langmap, plugin_parser);
 1790     if (langmap != NULL)
 1791         free(langmap);
 1792 
 1793     if (*argv && file_list)
 1794         args_open_both(argv, file_list);
 1795     else if (*argv)
 1796         args_open(argv);
 1797     else if (file_list)
 1798         args_open_filelist(file_list);
 1799     else
 1800         args_open_nop();
 1801     while ((av = args_read()) != NULL) {
 1802         /*
 1803          * convert the path into relative to the root directory of source tree.
 1804          */
 1805         if (normalize(av, get_root_with_slash(), cwd, path, sizeof(path)) == NULL) {
 1806             if (!qflag)
 1807                 die("'%s' is out of the source project.", av);
 1808             continue;
 1809         }
 1810         if (!test("f", makepath(root, path, NULL))) {
 1811             if (!qflag) {
 1812                 if (test("d", NULL))
 1813                     die("'%s' is not a source file.", av);
 1814                 else
 1815                     die("'%s' not found.", av);
 1816             }
 1817             continue;
 1818         }
 1819         /*
 1820          * Memorize the file id of the path. This is used in put_syms().
 1821          */
 1822         {
 1823             static char s_fid[MAXFIDLEN];
 1824             int type = 0;
 1825             const char *p = gpath_path2fid(path, &type);
 1826 
 1827             if (!p || type != GPATH_SOURCE) {
 1828                 if (!qflag)
 1829                     die("'%s' is not a source file.", av);
 1830                 continue;
 1831             }
 1832             strlimcpy(s_fid, p, sizeof(s_fid));
 1833             data.fid = s_fid;
 1834         }
 1835         if (Sflag && !locatestring(path, localprefix, MATCH_AT_FIRST))
 1836             continue;
 1837         data.count = 0;
 1838         parse_file(path, flags, put_syms, &data);
 1839         count += data.count;
 1840     }
 1841     args_close();
 1842     parser_exit();
 1843     /*
 1844      * Settlement
 1845      */
 1846     if (data.dbop != NULL)
 1847         dbop_close(data.dbop);
 1848     gpath_close();
 1849     convert_close(data.cv);
 1850     strbuf_close(sb);
 1851     if (vflag) {
 1852         print_count(count);
 1853         fprintf(stderr, " (no index used).\n");
 1854     }
 1855 }
 1856 /**
 1857  * search: search specified function 
 1858  *
 1859  *  @param[in]  pattern     search pattern
 1860  *  @param[in]  root        root of source tree
 1861  *  @param[in]  cwd     current directory
 1862  *  @param[in]  dbpath      database directory
 1863  *  @param[in]  db      GTAGS,GRTAGS,GSYMS
 1864  *  @return         count of output lines
 1865  */
 1866 int
 1867 search(const char *pattern, const char *root, const char *cwd, const char *dbpath, int db)
 1868 {
 1869     CONVERT *cv;
 1870     int count = 0;
 1871     GTOP *gtop;
 1872     GTP *gtp;
 1873     int flags = 0;
 1874 
 1875     start_output(format, nosource);
 1876     /*
 1877      * open tag file.
 1878      */
 1879     gtop = gtags_open(dbpath, root, db, GTAGS_READ, debug ? GTAGS_DEBUG : 0);
 1880     cv = convert_open(type, format, root, cwd, dbpath, stdout, db);
 1881     /*
 1882      * search through tag file.
 1883      */
 1884     if (nofilter & SORT_FILTER)
 1885         flags |= GTOP_NOSORT;
 1886     else if (Nflag)
 1887         flags |= GTOP_NEARSORT;
 1888     if (literal)
 1889         flags |= GTOP_NOREGEX;
 1890     else if (Gflag)
 1891         flags |= GTOP_BASICREGEX;
 1892     if (format == FORMAT_PATH)
 1893         flags |= GTOP_PATH;
 1894     if (iflag)
 1895         flags |= GTOP_IGNORECASE;
 1896     for (gtp = gtags_first(gtop, pattern, flags); gtp; gtp = gtags_next(gtop)) {
 1897         if (Sflag && !locatestring(gtp->path, localprefix, MATCH_AT_FIRST))
 1898             continue;
 1899         count += output_with_formatting(cv, gtp, root, gtop->format);
 1900     }
 1901     convert_close(cv);
 1902     if (debug)
 1903         gtags_show_statistics(gtop);
 1904     gtags_close(gtop);
 1905     end_output();
 1906     return count;
 1907 }
 1908 /**
 1909  * tagsearch: execute tag search
 1910  *
 1911  *  @param[in]  pattern     search pattern
 1912  *  @param[in]  cwd     current directory
 1913  *  @param[in]  root        root of source tree
 1914  *  @param[in]  dbpath      database directory
 1915  *  @param[in]  db      GTAGS,GRTAGS,GSYMS
 1916  */
 1917 void
 1918 tagsearch(const char *pattern, const char *cwd, const char *root, const char *dbpath, int db)
 1919 {
 1920     int count, total = 0;
 1921     char buffer[IDENTLEN], *p = buffer;
 1922     char libdbpath[MAXPATHLEN];
 1923 
 1924     /*
 1925      * trim pattern (^<no regex>$ => <no regex>)
 1926      */
 1927     if (!literal && pattern) {
 1928         strlimcpy(p, pattern, sizeof(buffer));
 1929         if (*p++ == '^') {
 1930             char *q = p + strlen(p);
 1931             if (*--q == '$') {
 1932                 *q = 0;
 1933                 if (*p == 0 || !isregex(p))
 1934                     pattern = p;
 1935             }
 1936         }
 1937     }
 1938     /*
 1939      * search in current source tree.
 1940      */
 1941     count = search(pattern, root, cwd, dbpath, db);
 1942     total += count;
 1943     /*
 1944      * search in library path.
 1945      */
 1946     if (abslib)
 1947         type = PATH_ABSOLUTE;
 1948     if (db == GTAGS && getenv("GTAGSLIBPATH") && (count == 0 || Tflag) && !Sflag) {
 1949         STRBUF *sb = strbuf_open(0);
 1950         char *libdir, *nextp = NULL;
 1951 
 1952         strbuf_puts(sb, getenv("GTAGSLIBPATH"));
 1953         back2slash(sb);
 1954         /*
 1955          * search for each tree in the library path.
 1956          */
 1957         for (libdir = strbuf_value(sb); libdir; libdir = nextp) {
 1958             if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL)
 1959                 *nextp++ = 0;
 1960             if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0))
 1961                 continue;
 1962             if (!STRCMP(dbpath, libdbpath))
 1963                 continue;
 1964             if (!test("f", makepath(libdbpath, dbname(db), NULL)))
 1965                 continue;
 1966             /*
 1967              * search again
 1968              */
 1969             count = search(pattern, libdir, cwd, libdbpath, db);
 1970             total += count;
 1971             if (count > 0 && !Tflag) {
 1972                 /* for verbose message */
 1973                 dbpath = libdbpath;
 1974                 break;
 1975             }
 1976         }
 1977         strbuf_close(sb);
 1978     }
 1979     if (vflag) {
 1980         print_count(total);
 1981         if (!Tflag)
 1982             fprintf(stderr, " (using '%s')", makepath(dbpath, dbname(db), NULL));
 1983         fputs(".\n", stderr);
 1984     }
 1985 }
 1986 /*
 1987  * encode: string copy with converting blank chars into %ff format.
 1988  *
 1989  *  @param[out] to  result
 1990  *  @param[in]  size    size of to buffer
 1991  *  @param[in]  from    string
 1992  */
 1993 void
 1994 encode(char *to, int size, const char *from)
 1995 {
 1996     const char *p;
 1997     char *e = to;
 1998 
 1999     for (p = from; *p; p++) {
 2000         if (*p == '%' || *p == ' ' || *p == '\t') {
 2001             if (size <= 3)
 2002                 break;
 2003             snprintf(e, size, "%%%02x", *p);
 2004             e += 3;
 2005             size -= 3;
 2006         } else {
 2007             if (size <= 1)
 2008                 break;
 2009             *e++ = *p;
 2010             size--;
 2011         }
 2012     }
 2013     *e = 0;
 2014 }