"Fossies" - the Fresh Open Source Software Archive

Member "global-6.6.5/htags/htags.c" (3 Sep 2020, 47476 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 "htags.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) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    3  *      2006, 2007, 2008, 2010, 2011, 2016
    4  *  Tama Communications Corporation
    5  *
    6  * This file is part of GNU GLOBAL.
    7  *
    8  * This program is free software: you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
   10  * the Free Software Foundation, either version 3 of the License, or
   11  * (at your option) any later version.
   12  * 
   13  * This program is distributed in the hope that it will be useful,
   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  * GNU General Public License for more details.
   17  * 
   18  * You should have received a copy of the GNU General Public License
   19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   20  */
   21 
   22 #ifdef HAVE_CONFIG_H
   23 #include <config.h>
   24 #endif
   25 #include <stdio.h>
   26 #include <errno.h>
   27 #ifdef STDC_HEADERS
   28 #include <stdlib.h>
   29 #endif
   30 #ifdef HAVE_UNISTD_H
   31 #include <unistd.h>
   32 #endif
   33 #ifdef HAVE_FCNTL_H
   34 #include <fcntl.h>
   35 #else
   36 #include <sys/file.h>
   37 #endif
   38 #include <signal.h>
   39 #include <sys/types.h>
   40 #include <sys/stat.h>
   41 #include <sys/param.h>
   42 #include <errno.h>
   43 
   44 #include "getopt.h"
   45 #include "regex.h"
   46 #include "global.h"
   47 #include "anchor.h"
   48 #include "cache.h"
   49 #include "common.h"
   50 #include "htags.h"
   51 #include "incop.h"
   52 #include "path2url.h"
   53 #include "const.h"
   54 
   55 /*
   56  * htags - generate hypertext (XHTML or HTML) pages from a set of source files.
   57  */
   58 
   59 void src2html(const char *, const char *, int);
   60 int makedupindex(void);
   61 int makedefineindex(const char *, int, STRBUF *);
   62 int makefileindex(const char *, STRBUF *);
   63 void makeincludeindex(void);
   64 int makecflowindex(const char *, const char *);
   65 
   66 #if defined(_WIN32) && !defined(__CYGWIN__)
   67 #define mkdir(path,mode) mkdir(path)
   68 #define link(one,two) (-1)
   69 #endif
   70 
   71 /*
   72  * Global data.
   73  */
   74 int w32 = W32;              /**< Windows32 environment  */
   75 const char *www = "http://www.gnu.org/software/global/";
   76 int html_count = 0;
   77 int sep = '/';
   78 const char *save_config;
   79 const char *save_argv;
   80 
   81 char cwdpath[MAXPATHLEN];
   82 char dbpath[MAXPATHLEN];
   83 char distpath[MAXPATHLEN];
   84 char gtagsconf[MAXPATHLEN];
   85 char datadir[MAXPATHLEN];
   86 char localstatedir[MAXPATHLEN];
   87 
   88 char gtags_path[MAXFILLEN];
   89 char global_path[MAXFILLEN];
   90 int gtags_exist[GTAGLIM];
   91 const char *null_device = NULL_DEVICE;
   92 const char *tmpdir = "/tmp";
   93 
   94 /**
   95  * Order of items in the top page (This should be customisable variable in the future).
   96  *
   97  * 'c': caution
   98  * 's': search form
   99  * 'm': mains
  100  * 'd': definitions
  101  * 'f': files
  102  * 't': call tree
  103  */
  104 char *item_order = "csmdft";
  105 /*
  106  * options
  107  */
  108 int aflag;              /**< --alphabet(-a) option  */
  109 int fflag;              /**< --form(-f) option      */
  110 int Fflag;              /**< --frame(-F) option     */
  111 int gflag;              /**< --gtags(-g) option     */
  112 int Iflag;              /**< --icon(-I) option      */
  113 int nflag;              /**< --line-number(-n) option   */
  114 int qflag;
  115 int vflag;              /**< --verbose(-v) option       */
  116 int wflag;              /**< --warning(-w) option       */
  117 int debug;              /**< --debug option     */
  118 
  119 int show_help;              /**< --help command     */
  120 int show_version;           /**< --version command      */
  121 int caution;                /**< --caution option       */
  122 int dynamic;                /**< --dynamic(-D) option       */
  123 int symbol;             /**< --symbol(-s) option          */
  124 int suggest;                /**< --suggest option       */
  125 int suggest2;               /**< --suggest2 option      */
  126 int auto_completion;            /**< --auto-completion      */
  127 int tree_view;              /**< --tree-view            */
  128 int fixed_guide;            /**< --fixed-guide      */
  129 const char *tree_view_type;     /**< --type-view=[type]     */
  130 char *auto_completion_limit = "0";  /**< --auto-completion=limit    */
  131 int statistics = STATISTICS_STYLE_NONE; /**< --statistics option        */
  132 
  133 int no_order_list;          /**< 1: doesn't use order list  */
  134 int other_files;            /**< 1: list other files        */
  135 int enable_grep = 1;            /**< 1: enable grep     */
  136 int enable_idutils = 1;         /**< 1: enable idutils      */
  137 int enable_xhtml = 1;           /**< 1: enable XHTML        */
  138 
  139 const char *main_func = "main";
  140 const char *cvsweb_url;
  141 int use_cvs_module;
  142 const char *cvsweb_cvsroot;
  143 const char *gtagslabel;
  144 const char *title;
  145 const char *insert_header;      /* --insert-header=<file>   */
  146 const char *insert_footer;      /* --insert-footer=<file>   */
  147 const char *html_header;        /* --html-header=<file>     */
  148 const char *jscode;         /**< javascript code        */
  149 /*
  150  * Constant values.
  151  */
  152 const char *title_define_index = "DEFINITIONS";
  153 const char *title_file_index = "FILES";
  154 const char *title_call_tree = "CALL TREE";
  155 const char *title_callee_tree = "CALLEE TREE";
  156 const char *title_included_from = "INCLUDED FROM";
  157 /*
  158  * Function header items.
  159  */
  160 const char *anchor_label[] = {
  161     "&lt;",
  162     "&gt;",
  163     "^",
  164     "v",
  165     "top",
  166     "bottom",
  167     "index",
  168     "help"
  169 };
  170 const char *anchor_icons[] = {
  171     "left",
  172     "right",
  173     "first",
  174     "last",
  175     "top",
  176     "bottom",
  177     "index",
  178     "help"
  179 };
  180 const char *anchor_comment[] = {
  181     "previous",
  182     "next",
  183     "first",
  184     "last",
  185     "top",
  186     "bottom",
  187     "index",
  188     "help"
  189 };
  190 const char *anchor_msg[] = {
  191     "Previous definition.",
  192     "Next definition.",
  193     "First definition in this file.",
  194     "Last definition in this file.",
  195     "Top of this file.",
  196     "Bottom of this file.",
  197     "Return to index page.",
  198     "You are seeing now."
  199 };
  200 const char *back_icon = "back";
  201 const char *dir_icon  = "dir";
  202 const char *c_icon = "c";
  203 const char *file_icon = "text";
  204 
  205 const char *icon_files[] = {
  206     "first",
  207     "last",
  208     "left",
  209     "right",
  210     "top",
  211     "bottom",
  212     "n_first",
  213     "n_last",
  214     "n_left",
  215     "n_right",
  216     "n_top",
  217     "n_bottom",
  218     "index",
  219     "help",
  220     "back",
  221     "dir",
  222     "c",
  223     "text",
  224     "pglobe"
  225 };
  226 /*
  227  * Configuration parameters.
  228  */
  229 int ncol = 4;               /**< columns of line number */
  230 int tabs = 8;               /**< tab skip           */
  231 int flist_fields = 5;           /**< fields number of file list */
  232 int full_path = 0;          /**< file index format      */
  233 int map_file = 0;           /**< 1: create MAP file     */
  234 int filemap_file = 1;           /**< 1: create FILEMAP file */
  235 const char *icon_suffix = "png";    /**< icon suffix (jpg, png etc) */
  236 const char *icon_spec = "border='0' align='top'"; /**< parameter in IMG tag*/
  237 const char *prolog_script = NULL;   /**< include script at first    */
  238 const char *epilog_script = NULL;   /**< include script at last */
  239 const char *call_file = NULL;       /**< file name of cflow output  */
  240 const char *callee_file = NULL;     /**< file name of cflow output  */
  241 int show_position = 0;          /**< show current position  */
  242 int table_list = 0;         /**< tag list using table tag   */
  243 int table_flist = 0;            /**< file list using table tag  */
  244 int colorize_warned_line = 0;       /**< colorize warned line       */
  245 const char *normal_suffix = "html"; /**< suffix of normal html file */
  246 const char *HTML;                   /**< HTML */
  247 const char *action = "cgi-bin/global.cgi"; /**< default action      */
  248 const char *completion_action = "cgi-bin/completion.cgi";   /**< completion_action */
  249 int definition_header=NO_HEADER;    /**< (NO|BEFORE|RIGHT|AFTER)_HEADER */
  250 const char *include_file_suffixes = DEFAULTINCLUDEFILESUFFIXES; /**< include_file_suffixes */
  251 static const char *langmap = DEFAULTLANGMAP;    /**< langmap */
  252 int grtags_is_empty = 0;                        /**< grtags_is_empty */
  253 
  254 const char *short_options = "acC:d:DfFghIm:nNoqst:Tvwx";
  255 struct option const long_options[] = {
  256     /*
  257      * These options have long name and short name.
  258      * We throw them to the processing of short options.
  259      */
  260         {"alphabet", no_argument, NULL, 'a'},
  261         {"directory", required_argument, NULL, 'C'},
  262         {"dbpath", required_argument, NULL, 'd'},
  263         {"dynamic", no_argument, NULL, 'D'},
  264         {"form", no_argument, NULL, 'f'},
  265         {"frame", no_argument, NULL, 'F'},
  266         {"func-header", optional_argument, NULL, 'h'},
  267         {"gtags", no_argument, NULL, 'g'},
  268         {"icon", no_argument, NULL, 'I'},
  269         {"line-number", optional_argument, NULL, 'n'},
  270         {"main-func", required_argument, NULL, 'm'},
  271         {"other", no_argument, NULL, 'o'},
  272         {"symbol", no_argument, NULL, 's'},
  273         {"table-flist", optional_argument, NULL, 'T'},
  274         {"title", required_argument, NULL, 't'},
  275         {"verbose", no_argument, NULL, 'v'},
  276         {"warning", no_argument, NULL, 'w'},
  277 
  278         /*
  279      * The following are long name only.
  280      */
  281     /* flag value */
  282         {"caution", no_argument, &caution, 1},
  283         {"colorize-warned-line", no_argument, &colorize_warned_line, 1},
  284         {"debug", no_argument, &debug, 1},
  285         {"disable-grep", no_argument, &enable_grep, 0},
  286         {"disable-idutils", no_argument, &enable_idutils, 0},
  287         {"full-path", no_argument, &full_path, 1},
  288         {"fixed-guide",  no_argument, &fixed_guide, 1},
  289         {"map-file", no_argument, &map_file, 1},
  290         {"no-order-list", no_argument, &no_order_list, 1},
  291         {"show-position", no_argument, &show_position, 1},
  292         {"statistics", no_argument, &statistics, STATISTICS_STYLE_TABLE},
  293         {"suggest", no_argument, &suggest, 1},
  294         {"suggest2", no_argument, &suggest2, 1},
  295         {"table-list", no_argument, &table_list, 1},
  296         {"version", no_argument, &show_version, 1},
  297         {"help", no_argument, &show_help, 1},
  298 
  299     /* accept value */
  300 #define OPT_CVSWEB      128
  301 #define OPT_CVSWEB_CVSROOT  129
  302 #define OPT_NCOL        130
  303 #define OPT_INSERT_FOOTER   131
  304 #define OPT_INSERT_HEADER   132
  305 #define OPT_ITEM_ORDER      133
  306 #define OPT_TABS        134
  307 #define OPT_CFLOW       135
  308 #define OPT_AUTO_COMPLETION 136
  309 #define OPT_TREE_VIEW       137
  310 #define OPT_HTML_HEADER     138
  311 #define OPT_CALL_TREE       139
  312 #define OPT_CALLEE_TREE     140
  313         {"auto-completion", optional_argument, NULL, OPT_AUTO_COMPLETION},
  314         {"call-tree", required_argument, NULL, OPT_CALL_TREE},
  315         {"callee-tree", required_argument, NULL, OPT_CALLEE_TREE},
  316         {"cflow", required_argument, NULL, OPT_CFLOW},
  317         {"cvsweb", required_argument, NULL, OPT_CVSWEB},
  318         {"cvsweb-cvsroot", required_argument, NULL, OPT_CVSWEB_CVSROOT},
  319         {"gtagsconf", required_argument, NULL, OPT_GTAGSCONF},
  320         {"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
  321         {"html-header", required_argument,NULL, OPT_HTML_HEADER},
  322         {"ncol", required_argument, NULL, OPT_NCOL},
  323         {"insert-footer", required_argument, NULL, OPT_INSERT_FOOTER},
  324         {"insert-header", required_argument, NULL, OPT_INSERT_HEADER},
  325         {"item-order", required_argument, NULL, OPT_ITEM_ORDER},
  326     {"tabs", required_argument, NULL, OPT_TABS},
  327         {"tree-view",  optional_argument, NULL, OPT_TREE_VIEW},
  328         { 0 }
  329 };
  330 
  331 static void
  332 usage(void)
  333 {
  334         if (!qflag)
  335                 fputs(usage_const, stderr);
  336         exit(2);
  337 }
  338 static void
  339 help(void)
  340 {
  341         fputs(usage_const, stdout);
  342         fputs(help_const, stdout);
  343         exit(0);
  344 }
  345 /**
  346  * Htags catch signal even if the parent ignore it.
  347  */
  348 void
  349 clean(void)
  350 {
  351     unload_gpath();
  352     cache_close();
  353 }
  354 /**
  355  * Signal handler.
  356  *
  357  * This handler is set up in signal_setup().
  358  */
  359 static void
  360 suddenly(int signo)
  361 {
  362         signo = 0;      /* to satisfy compiler */
  363 
  364     clean();
  365     exit(1);
  366 }
  367 
  368 /**
  369  * Setup signal hander.
  370  *
  371  * Makes signals SIGINT, SIGTERM, SIGHUP and SIGQUIT
  372  * call suddenly() if triggered.
  373  */
  374 static void
  375 signal_setup(void)
  376 {
  377         signal(SIGINT, suddenly);
  378         signal(SIGTERM, suddenly);
  379 #ifdef SIGHUP
  380         signal(SIGHUP, suddenly);
  381 #endif
  382 #ifdef SIGQUIT
  383         signal(SIGQUIT, suddenly);
  384 #endif
  385 }
  386 
  387 /**
  388  * make directory in the dist (distpath) directory.
  389  *
  390  *     @param[in]      name    name of directory to create.
  391  *
  392  * Creates a file called "index.html" in the new directory.
  393  *
  394  * mkdir() creates the directory in mode 0775, if doesn't exist.
  395  */
  396 static void
  397 make_directory_in_distpath(const char *name)
  398 {
  399     char path[MAXPATHLEN];
  400     FILE *op;
  401 
  402     strlimcpy(path, makepath(distpath, name, NULL), sizeof(path));
  403     if (!test("d", path))
  404         if (mkdir(path, 0775))
  405             die("cannot make directory '%s'.", path);
  406     /*
  407      * Not to publish the directory list.
  408      */
  409     op = fopen(makepath(path, "index.html", NULL), "w");
  410     if (op == NULL)
  411         die("cannot make file '%s'.", makepath(path, "index.html", NULL));
  412     fputs(html_begin, op);
  413     fputs(html_end, op);
  414     fputc('\n', op);
  415     fclose(op);
  416 }
  417 /**
  418  * Load file.
  419  */
  420 void
  421 loadfile(const char *file, STRBUF *result)
  422 {
  423     STRBUF *sb = strbuf_open(0);
  424     FILE *ip = fopen(file, "r");
  425     if (!ip)
  426         die("file '%s' not found.", file);
  427     while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL)
  428         strbuf_puts_nl(result, strbuf_value(sb));
  429     fclose(ip);
  430     strbuf_close(sb);
  431 }
  432 /**
  433  * makeprogram: make CGI program
  434  */
  435 static void
  436 makeprogram(const char *cgidir, const char *file, int perm)
  437 {
  438     char src[MAXPATHLEN];
  439     const char *dst = makepath(cgidir, file, NULL);
  440 
  441     snprintf(src, sizeof(src), "%s/gtags/%s", datadir, file);
  442     copyfile(src, dst);
  443     if (chmod(dst, perm) < 0)
  444         die("cannot chmod CGI program (%s).", dst);
  445     html_count++;
  446 }
  447 /**
  448  * makerebuild: make rebuild script
  449  */
  450 static void
  451 makerebuild(const char *file)
  452 {
  453     FILE *op;
  454 
  455     op = fopen(makepath(distpath, file, NULL), "w");
  456     if (!op)
  457         die("cannot make rebuild script.");
  458     fputs_nl("#!/bin/sh", op);
  459     fputs_nl("#", op);
  460     fputs_nl("# rebuild.sh: rebuild hypertext with the previous context.", op);
  461     fputs_nl("#", op);
  462     fputs_nl("# Usage:", op);
  463     fputs_nl("#\t% sh rebuild.sh", op);
  464     fputs_nl("#", op);
  465     fprintf(op, "cd %s && GTAGSCONF='%s' htags%s\n", cwdpath, save_config, save_argv);
  466         fclose(op);
  467 }
  468 /**
  469  * makehelp: make help file
  470  */
  471 static void
  472 makehelp(const char *file)
  473 {
  474     const char **label = Iflag ? anchor_comment : anchor_label;
  475     const char **icons = anchor_icons;
  476     const char **msg   = anchor_msg;
  477     int n, last = 7;
  478     FILE *op;
  479 
  480     op = fopen(makepath(distpath, file, NULL), "w");
  481     if (!op)
  482         die("cannot make help file.");
  483     fputs_nl(gen_page_begin("HELP", TOPDIR), op);
  484     fputs_nl(body_begin, op);
  485     fputs(header_begin, op);
  486     fputs("Usage of Links", op);
  487     fputs_nl(header_end, op);
  488     if (!Iflag)
  489         fputs(verbatim_begin, op);
  490     fputs("/* ", op);
  491     for (n = 0; n <= last; n++) {
  492         if (Iflag) {
  493             fputs(gen_image(CURRENT, icons[n], label[n]), op);
  494             if (n < last)
  495                 fputc(' ', op);
  496         } else {
  497             fprintf(op, "[%s]", label[n]);
  498         }
  499     }
  500     if (show_position)
  501         fprintf(op, "%s%s value='+<line number> <file>' %s", quote_space, position_begin, position_end);
  502     fputs(" */", op);
  503     if (!Iflag)
  504         fputs_nl(verbatim_end, op);
  505     else
  506         fputc('\n', op);
  507     fputs_nl(define_list_begin, op);
  508     for (n = 0; n <= last; n++) {
  509         fputs(define_term_begin, op);
  510         if (Iflag) {
  511             fputs(gen_image(CURRENT, icons[n], label[n]), op);
  512         } else {
  513             fprintf(op, "[%s]", label[n]);
  514         }
  515         fputs(define_term_end, op);
  516         fputs(define_desc_begin, op);
  517         fputs(msg[n], op);
  518         fputs_nl(define_desc_end, op);
  519     }
  520     if (show_position) {
  521         fputs(define_term_begin, op);
  522         fprintf(op, "%s%s value='+<line number> <file>' %s", quote_space, position_begin, position_end);
  523         fputs(define_term_end, op);
  524         fputs(define_desc_begin, op);
  525         fputs("The current position (line number and file name).", op);
  526         fputs_nl(define_desc_end, op);
  527     }
  528     fputs_nl(define_list_end, op);
  529     fputs_nl(body_end, op);
  530     fputs_nl(gen_page_end(), op);
  531     fclose(op);
  532     html_count++;
  533 }
  534 /*
  535  * makesearchpart: make search part
  536  *
  537  *  @param[in]  target  $target
  538  *  @return     html
  539  */
  540 static char *
  541 makesearchpart(const char *target)
  542 {
  543     STATIC_STRBUF(sb);
  544 
  545     strbuf_clear(sb);
  546     strbuf_puts(sb, header_begin);
  547     if (Fflag)
  548         strbuf_puts(sb, gen_href_begin(NULL, "search", normal_suffix, NULL));
  549     strbuf_puts(sb, "SEARCH");
  550     if (Fflag)
  551         strbuf_puts(sb, gen_href_end());
  552     strbuf_puts_nl(sb, header_end);
  553     if (!target) {
  554         strbuf_puts(sb, "Please input object name and select [Search]. POSIX's regular expression is allowed.");
  555         strbuf_puts_nl(sb, br);
  556     }
  557     strbuf_puts_nl(sb, gen_form_begin(target));
  558     strbuf_puts_nl(sb, gen_input("pattern", NULL, NULL));
  559     strbuf_puts_nl(sb, gen_input(NULL, "Search", "submit"));
  560     strbuf_puts(sb, gen_input(NULL, "Reset", "reset"));
  561     strbuf_puts_nl(sb, br);
  562     strbuf_puts(sb, gen_input_radio("type", "definition", 1, "Retrieve the definition place of the specified symbol."));
  563     strbuf_puts_nl(sb, target ? "Def" : "Definition");
  564     strbuf_puts(sb, gen_input_radio("type", "reference", 0, "Retrieve the reference place of the specified symbol."));
  565     strbuf_puts_nl(sb, target ? "Ref" : "Reference");
  566     strbuf_puts(sb, gen_input_radio("type", "symbol", 0, "Retrieve the place of the specified symbol is used."));
  567     strbuf_puts_nl(sb, target ? "Sym" : "Other symbol");
  568     strbuf_puts(sb, gen_input_radio("type", "path", 0, "Look for path name which matches to the specified pattern."));
  569     strbuf_puts_nl(sb, target ? "Path" : "Path name");
  570     if (enable_grep) {
  571         strbuf_puts(sb, gen_input_radio("type", "grep", 0, "Retrieve lines which matches to the specified pattern."));
  572         strbuf_puts_nl(sb, target ? "Grep" : "Grep pattern");
  573     }
  574     if (enable_idutils && test("f", makepath(dbpath, "ID", NULL))) {
  575         strbuf_puts(sb, gen_input_radio("type", "idutils", 0, "Retrieve lines which matches to the specified pattern using idutils(1)."));
  576         strbuf_puts_nl(sb, target ? "Id" : "Id pattern");
  577     }
  578     strbuf_puts_nl(sb, br);
  579     strbuf_puts(sb, gen_input_checkbox("icase", NULL, "Ignore case distinctions in the pattern."));
  580     strbuf_puts_nl(sb, target ? "Icase" : "Ignore case");
  581     if (other_files) {
  582         strbuf_puts(sb, gen_input_checkbox("other", NULL, "Files other than the source code are also retrieved."));
  583         strbuf_puts_nl(sb, target ? "Other" : "Other files");
  584     }
  585     if (other_files && !target) {
  586         strbuf_puts_nl(sb, br);
  587         strbuf_puts(sb, "('Other files' is effective only to 'Path name'");
  588         if (enable_grep)
  589             strbuf_puts(sb, " and 'Grep pattern'");
  590         strbuf_puts_nl(sb, ".)");
  591     }
  592     strbuf_puts_nl(sb, gen_form_end());
  593     return strbuf_value(sb);
  594 }
  595 /**
  596  * makeindex: make index file
  597  *
  598  *  @param[in]  file    file name
  599  *  @param[in]  title   title of index file
  600  *  @param[in]  index   common part
  601  */
  602 static void
  603 makeindex(const char *file, const char *title, const char *index)
  604 {
  605     FILE *op;
  606 
  607     op = fopen(makepath(distpath, file, NULL), "w");
  608     if (!op)
  609         die("cannot make file '%s'.", file);
  610     if (Fflag) {
  611         fputs_nl(gen_page_frameset_begin(title), op);
  612         fputs_nl(gen_frameset_begin("cols='200,*'"), op);
  613         if (fflag) {
  614             fputs_nl(gen_frameset_begin("rows='33%,33%,*'"), op);
  615             fputs_nl(gen_frame("search", makepath(NULL, "search", normal_suffix)), op);
  616         } else {
  617             fputs_nl(gen_frameset_begin("rows='50%,*'"), op);
  618         }
  619         /*
  620          * id='xxx' for XHTML
  621          * name='xxx' for HTML
  622          */
  623         fputs_nl(gen_frame("defines", makepath(NULL, "defines", normal_suffix)), op);
  624         fputs_nl(gen_frame("files", makepath(NULL, "files", normal_suffix)), op);
  625         fputs_nl(gen_frameset_end(), op);
  626         fputs_nl(gen_frame("mains", makepath(NULL, "mains", normal_suffix)), op);
  627         fputs_nl(noframes_begin, op);
  628         fputs_nl(body_begin, op);
  629         fputs(index, op);
  630         fputs_nl(body_end, op);
  631         fputs_nl(noframes_end, op);
  632         fputs_nl(gen_frameset_end(), op);
  633         fputs_nl(gen_page_end(), op);
  634     } else {
  635         fputs_nl(gen_page_index_begin(title, jscode), op);
  636         fputs_nl(body_begin, op);
  637         if (insert_header)
  638             fputs(gen_insert_header(TOPDIR), op);
  639         fputs(index, op);
  640         if (insert_footer)
  641             fputs(gen_insert_footer(TOPDIR), op);
  642         fputs_nl(body_end, op);
  643         fputs_nl(gen_page_end(), op);
  644     }
  645     fclose(op);
  646     html_count++;
  647 }
  648 /**
  649  * makemainindex: make main index
  650  *
  651  *  @param[in]  file    file name
  652  *  @param[in]  index   common part
  653  */
  654 static void
  655 makemainindex(const char *file, const char *index)
  656 {
  657     FILE *op;
  658 
  659     op = fopen(makepath(distpath, file, NULL), "w");
  660     if (!op)
  661         die("cannot make file '%s'.", file);
  662     fputs_nl(gen_page_index_begin(title, jscode), op);
  663     fputs_nl(body_begin, op);
  664     if (insert_header)
  665         fputs(gen_insert_header(TOPDIR), op);
  666     fputs(index, op);
  667     if (insert_footer)
  668         fputs(gen_insert_footer(TOPDIR), op);
  669     fputs_nl(body_end, op);
  670     fputs_nl(gen_page_end(), op);
  671     fclose(op);
  672     html_count++;
  673 }
  674 /**
  675  * makesearchindex: make search html
  676  *
  677  *  @param[in]  file    file name
  678  */
  679 static void
  680 makesearchindex(const char *file)
  681 {
  682     FILE *op;
  683 
  684     op = fopen(makepath(distpath, file, NULL), "w");
  685     if (!op)
  686         die("cannot create file '%s'.", file);
  687     fputs_nl(gen_page_index_begin("SEARCH", jscode), op);
  688     fputs_nl(body_begin, op);
  689     fputs(makesearchpart("mains"), op);
  690     fputs_nl(body_end, op);
  691     fputs_nl(gen_page_end(), op);
  692     fclose(op);
  693     html_count++;
  694 }
  695 /**
  696  * makehtaccess: make ".htaccess" skeleton file.
  697  */
  698 static void
  699 makehtaccess(const char *file, int perm)
  700 {
  701     char src[MAXPATHLEN];
  702     const char *dst = makepath(distpath, file, NULL);
  703 
  704     snprintf(src, sizeof(src), "%s/gtags/dot_htaccess", datadir);
  705     copyfile(src, dst);
  706     if (chmod(dst, perm) < 0)
  707         die("cannot chmod .htaccess skeleton.");
  708 }
  709 /**
  710  * makehtml: make html files
  711  *
  712  *  @param[in]  total   number of files.
  713  */
  714 static void
  715 makehtml(int total)
  716 {
  717     GFIND *gp;
  718     FILE *anchor_stream;
  719     const char *path;
  720     int count = 0;
  721 
  722     /*
  723      * Create anchor stream for anchor_load().
  724      */
  725     anchor_stream = tmpfile();
  726 #if defined(_WIN32) && !defined(__CYGWIN__)
  727     /*
  728      * tmpfile is created in the root, which user's can't write on Vista+.
  729      * Use _tempnam and open it directly.
  730      */
  731     if (anchor_stream == NULL) {
  732         char *name = _tempnam(tmpdir, "htags");
  733         anchor_stream = fopen(name, "w+bD");
  734         free(name);
  735     }
  736 #endif
  737     gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0);
  738     while ((path = gfind_read(gp)) != NULL) {
  739         if (gp->type == GPATH_OTHER)
  740             fputc(' ', anchor_stream);
  741         fputs(path, anchor_stream);
  742         fputc('\n', anchor_stream);
  743     }
  744     gfind_close(gp);
  745     /*
  746      * Prepare anchor stream for anchor_load().
  747      */
  748     anchor_prepare(anchor_stream);
  749     /*
  750      * For each path in GPATH, convert the path into HTML file.
  751      */
  752     gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0);
  753     while ((path = gfind_read(gp)) != NULL) {
  754         char html[MAXPATHLEN];
  755 
  756         if (gp->type == GPATH_OTHER && !other_files)
  757             continue;
  758         /*
  759          * load tags belonging to the path.
  760          * The path must be start "./".
  761          */
  762         anchor_load(path);
  763         /*
  764          * inform the current path name to lex() function.
  765          */
  766         save_current_path(path);
  767         count++;
  768         path += 2;      /* remove './' at the head */
  769         message(" [%d/%d] converting %s", count, total, path);
  770         snprintf(html, sizeof(html), "%s/%s/%s.%s", distpath, SRCS, path2fid(path), HTML);
  771         src2html(path, html, gp->type == GPATH_OTHER);
  772     }
  773     gfind_close(gp);
  774 }
  775 /**
  776  * makecommonpart: make a common part for "mains.html" and "index.html"
  777  *
  778  *  @param[in]  title
  779  *  @param[in]  defines
  780  *  @param[in]  files
  781  *  @return index   common part
  782  */
  783 static char *
  784 makecommonpart(const char *title, const char *defines, const char *files)
  785 {
  786     FILE *ip;
  787     STRBUF *sb = strbuf_open(0);
  788     STRBUF *ib = strbuf_open(0);
  789     char buf[MAXFILLEN];
  790     const char *tips = "Go to the GLOBAL project page.";
  791     const char *_, *item;
  792 
  793     strbuf_puts(sb, title_begin);
  794     strbuf_puts(sb, title);
  795     strbuf_puts_nl(sb, title_end);
  796     strbuf_puts_nl(sb, poweredby_begin);
  797     strbuf_sprintf(sb, "Last updated %s%s\n", now(), br);
  798     if (Iflag) {
  799         snprintf(buf, sizeof(buf), "Powered by GLOBAL-%s.", get_version());
  800         strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips,"_top"));
  801         strbuf_puts(sb, gen_image(CURRENT, "pglobe", buf));
  802         strbuf_puts(sb, gen_href_end());
  803         strbuf_puts(sb, br);
  804     } else {
  805         strbuf_sprintf(sb, "Powered by %sGLOBAL-%s%s.%s\n",
  806             gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips, "_top"),
  807             get_version(),
  808             gen_href_end(),
  809             br);
  810     }
  811     strbuf_puts_nl(sb, poweredby_end);
  812     strbuf_puts_nl(sb, hr);
  813     /*
  814      * Print items according to the value of variable 'item_order'.
  815      */
  816     for (item = item_order; *item; item++) {
  817         switch (*item) {
  818         case 'c':
  819             if (caution) {
  820                 strbuf_puts_nl(sb, caution_begin);
  821                 strbuf_sprintf(sb, "<font size='+2' color='red'>CAUTION</font>%s\n", br);
  822                 strbuf_sprintf(sb, "This hypertext consists of %d files.\n", html_count);
  823                 strbuf_puts_nl(sb, "Please don't download the whole hypertext using a hypertext copy tool.");
  824                 strbuf_puts_nl(sb, "Our network cannot afford such traffic.");
  825                 strbuf_puts_nl(sb, "Instead, you can generate the same thing in your computer using");
  826                 strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, NULL, "_top"));
  827                 strbuf_puts(sb, "GLOBAL source code tag system");
  828                 strbuf_puts_nl(sb, gen_href_end());
  829                 strbuf_puts_nl(sb, "Thank you.");
  830                 strbuf_puts_nl(sb, caution_end);
  831                 strbuf_sprintf(sb, "\n%s\n", hr);
  832             }
  833             break;
  834         case 's':
  835             if (fflag) {
  836                 strbuf_puts(sb, makesearchpart(NULL));
  837                 strbuf_puts_nl(sb, hr);
  838             }
  839             break;
  840         case 't':
  841             if (call_file || callee_file) {
  842                 strbuf_puts(sb, header_begin);
  843                 if (call_file) {
  844                     strbuf_puts(sb, gen_href_begin(NULL, "call", normal_suffix, NULL));
  845                     strbuf_puts(sb, title_call_tree);
  846                     strbuf_puts(sb, gen_href_end());
  847                 }
  848                 if (call_file && callee_file)
  849                     strbuf_puts(sb, " / ");
  850                 if (callee_file) {
  851                     strbuf_puts(sb, gen_href_begin(NULL, "callee", normal_suffix, NULL));
  852                     strbuf_puts(sb, title_callee_tree);
  853                     strbuf_puts(sb, gen_href_end());
  854                 }
  855                 strbuf_puts_nl(sb, header_end);
  856                 strbuf_puts_nl(sb, hr);
  857             }
  858             break;
  859         case 'm':
  860             strbuf_sprintf(sb, "%sMAINS%s\n", header_begin, header_end);
  861 
  862             snprintf(buf, sizeof(buf), PQUOTE "%s --result=ctags-xid --encode-path=\" \t\" --nofilter=path %s" PQUOTE, quote_shell(global_path), main_func);
  863             ip = popen(buf, "r");
  864             if (!ip)
  865                 die("cannot execute '%s'.", buf);
  866             strbuf_puts_nl(sb, gen_list_begin());
  867             while ((_ = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) {
  868                 char fid[MAXFIDLEN];
  869                 const char *ctags_x = parse_xid(_, fid, NULL);
  870 
  871                 strbuf_puts_nl(sb, gen_list_body(SRCS, ctags_x, fid));
  872             }
  873             strbuf_puts_nl(sb, gen_list_end());
  874             if (pclose(ip) != 0)
  875                 die("terminated abnormally '%s' (errno = %d).", buf, errno);
  876             strbuf_puts_nl(sb, hr);
  877             break;
  878         case 'd':
  879             if (aflag && !Fflag) {
  880                 strbuf_puts(sb, header_begin);
  881                 strbuf_puts(sb, title_define_index);
  882                 strbuf_puts_nl(sb, header_end);
  883                 strbuf_puts(sb, defines);
  884             } else {
  885                 strbuf_puts(sb, header_begin);
  886                 strbuf_puts(sb, gen_href_begin(NULL, "defines", normal_suffix, NULL));
  887                 strbuf_puts(sb, title_define_index);
  888                 strbuf_puts(sb, gen_href_end());
  889                 strbuf_puts_nl(sb, header_end);
  890             }
  891             strbuf_puts_nl(sb, hr);
  892             break;
  893         case 'f':
  894             if (Fflag) {
  895                 strbuf_puts(sb, header_begin);
  896                 strbuf_puts(sb, gen_href_begin(NULL, "files", normal_suffix, NULL));
  897                 strbuf_puts(sb, title_file_index);
  898                 strbuf_puts(sb, gen_href_end());
  899                 strbuf_puts_nl(sb, header_end);
  900             } else {
  901                 strbuf_puts(sb, header_begin);
  902                 strbuf_puts(sb, title_file_index);
  903                 strbuf_puts_nl(sb, header_end);
  904                 if (tree_view) {
  905                     strbuf_puts_nl(sb, tree_control);
  906                     strbuf_puts_nl(sb, tree_loading);
  907                     if (tree_view_type) {
  908                         strbuf_sprintf(sb, tree_begin_using, tree_view_type);
  909                         strbuf_putc(sb, '\n');
  910                     } else {
  911                         strbuf_puts_nl(sb, tree_begin);
  912                     }
  913                 } else if (table_flist)
  914                     strbuf_puts_nl(sb, flist_begin);
  915                 else if (!no_order_list)
  916                     strbuf_puts_nl(sb, list_begin);
  917                 strbuf_puts(sb, files);
  918                 if (tree_view)
  919                     strbuf_puts_nl(sb, tree_end);
  920                 else if (table_flist)
  921                     strbuf_puts_nl(sb, flist_end);
  922                 else if (!no_order_list)
  923                     strbuf_puts_nl(sb, list_end);
  924                 else
  925                     strbuf_puts_nl(sb, br);
  926             }
  927             strbuf_puts_nl(sb, hr);
  928             break;
  929         default:
  930             warning("unknown item '%c'. (Ignored)", *item);
  931             break;
  932         }
  933     }
  934     strbuf_close(ib);
  935 
  936     return strbuf_value(sb);
  937     /* doesn't close string buffer */
  938 }
  939 /**
  940  * basic check.
  941  */
  942 static void
  943 basic_check(void)
  944 {
  945     const char *p;
  946 
  947     /*
  948      * COMMAND EXISTENCE CHECK
  949      */
  950     if (!(p = usable("gtags")))
  951         die("gtags command required but not found.");
  952     strlimcpy(gtags_path, p, sizeof(gtags_path));
  953     if (!(p = usable("global")))
  954         die("global command required but not found.");
  955     strlimcpy(global_path, p, sizeof(global_path));
  956     /*
  957      * Temporary directory.
  958      */
  959     if ((p = getenv("TMPDIR")) == NULL)
  960         p = getenv("TMP");
  961     if (p != NULL && test("d", p))
  962         tmpdir = p;
  963 }
  964 /**
  965  * load configuration variables.
  966  */
  967 static void
  968 configuration(void)
  969 {
  970     STRBUF *sb = strbuf_open(0);
  971 
  972     /*
  973      * Config variables.
  974      */
  975     strbuf_reset(sb);
  976     if (!getconfs("datadir", sb))
  977         die("cannot get datadir directory name.");
  978     strlimcpy(datadir, strbuf_value(sb), sizeof(datadir));
  979     strbuf_reset(sb);
  980     if (!getconfs("localstatedir", sb))
  981         die("cannot get localstatedir directory name.");
  982     strlimcpy(localstatedir, strbuf_value(sb), sizeof(localstatedir));
  983     strbuf_reset(sb);
  984     if (getconfs("prolog_script", sb))
  985         prolog_script = check_strdup(strbuf_value(sb));
  986     strbuf_reset(sb);
  987     if (getconfs("epilog_script", sb))
  988         epilog_script = check_strdup(strbuf_value(sb));
  989     if (getconfb("colorize_warned_line"))
  990         colorize_warned_line = 1;
  991     strbuf_reset(sb);
  992     if (getconfs("include_file_suffixes", sb))
  993         include_file_suffixes = check_strdup(strbuf_value(sb));
  994     strbuf_reset(sb);
  995     if (getconfs("langmap", sb))
  996         langmap = check_strdup(strbuf_value(sb));
  997     strbuf_close(sb);
  998 }
  999 /**
 1000  * save_environment: save configuration data and arguments.
 1001  */
 1002 static void
 1003 save_environment(int argc, char *const *argv)
 1004 {
 1005     char command[MAXFILLEN];
 1006     STRBUF *sb = strbuf_open(0);
 1007     STRBUF *save_c = strbuf_open(0);
 1008     STRBUF *save_a = strbuf_open(0);
 1009     int i;
 1010     const char *p;
 1011     FILE *ip;
 1012 
 1013     /*
 1014      * save config values.
 1015      */
 1016     snprintf(command, sizeof(command), PQUOTE "%s --config" PQUOTE, quote_shell(gtags_path));
 1017     if ((ip = popen(command, "r")) == NULL)
 1018         die("cannot execute '%s'.", command);
 1019     while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL) {
 1020         for (p = strbuf_value(sb); *p; p++) {
 1021             if (*p == '\'') {
 1022                 strbuf_putc(save_c, '\'');
 1023                 strbuf_putc(save_c, '"');
 1024                 strbuf_putc(save_c, '\'');
 1025                 strbuf_putc(save_c, '"');
 1026                 strbuf_putc(save_c, '\'');
 1027             } else
 1028                 strbuf_putc(save_c, *p);
 1029         }
 1030     }
 1031     if (pclose(ip) != 0)
 1032         die("terminated abnormally '%s' (errno = %d).", command, errno);
 1033     strbuf_close(sb);
 1034     save_config = strbuf_value(save_c);
 1035     /* doesn't close string buffer for save config. */
 1036     /* strbuf_close(save_c); */
 1037 
 1038     /*
 1039      * save arguments.
 1040      */
 1041     {
 1042         char *opt_gtagsconf = "--gtagsconf";
 1043 
 1044         for (i = 1; i < argc; i++) {
 1045             char *blank;
 1046 
 1047             /*
 1048              * skip --gtagsconf because it is already read
 1049              * as config value.
 1050              */
 1051             if ((p = locatestring(argv[i], opt_gtagsconf, MATCH_AT_FIRST))) {
 1052                 if (*p == '\0')
 1053                     i++;
 1054                 continue;
 1055             }
 1056             blank = locatestring(argv[i], " ", MATCH_FIRST);
 1057             strbuf_putc(save_a, ' ');
 1058             if (blank)
 1059                 strbuf_putc(save_a, '\'');
 1060             strbuf_puts(save_a, argv[i]);
 1061             if (blank)
 1062                 strbuf_putc(save_a, '\'');
 1063         }
 1064     }
 1065     save_argv = strbuf_value(save_a);
 1066     /* doesn't close string buffer for save arguments. */
 1067     /* strbuf_close(save_a); */
 1068 }
 1069 
 1070 int
 1071 main(int argc, char **argv)
 1072 {
 1073     const char *av = NULL;
 1074     int func_total, file_total;
 1075         char arg_dbpath[MAXPATHLEN];
 1076     const char *index = NULL;
 1077     int optchar;
 1078         int option_index = 0;
 1079     STATISTICS_TIME *tim;
 1080 
 1081     /*
 1082      * pick up --gtagsconf, --gtagslabel and --directory (-C).
 1083      */
 1084     if (preparse_options(argc, argv) < 0)
 1085         usage();
 1086 
 1087     arg_dbpath[0] = 0;
 1088     basic_check();
 1089     /*
 1090      * Load configuration values.
 1091      */
 1092     if (!vgetcwd(cwdpath, sizeof(cwdpath)))
 1093         die("cannot get current directory.");
 1094     openconf(cwdpath);
 1095     configuration();
 1096     /*
 1097      * setup_langmap() is needed to use decide_lang().
 1098      */
 1099     setup_langmap(langmap);
 1100     save_environment(argc, argv);
 1101     /*
 1102      * insert htags_options at the head of argv.
 1103      */
 1104     setenv_from_config();
 1105     {
 1106         char *env = getenv("HTAGS_OPTIONS");
 1107         if (env && *env)
 1108             argv = prepend_options(&argc, argv, env);
 1109     }
 1110     while ((optchar = getopt_long(argc, argv, short_options, long_options, &option_index)) != EOF) {
 1111         switch (optchar) {
 1112         case 0:
 1113             /* already flags set */
 1114             break;
 1115         case OPT_AUTO_COMPLETION:
 1116             auto_completion = 1;
 1117             if (optarg) {
 1118                 if (atoi(optarg) > 0)
 1119                     auto_completion_limit = optarg;
 1120                 else
 1121                     die("The option value of --auto-completion must be numeric.");
 1122             }
 1123             break;
 1124         case OPT_CFLOW:
 1125             call_file = optarg;
 1126             break;
 1127         case OPT_CALL_TREE:
 1128             call_file = optarg;
 1129             break;
 1130         case OPT_CALLEE_TREE:
 1131             callee_file = optarg;
 1132             break;
 1133         case OPT_CVSWEB:
 1134             cvsweb_url = optarg;
 1135             break;
 1136         case OPT_CVSWEB_CVSROOT:
 1137             cvsweb_cvsroot = optarg;
 1138             break;
 1139         case OPT_GTAGSCONF:
 1140         case OPT_GTAGSLABEL:
 1141         case 'C':
 1142             /* These options are already parsed in preparse_options(). */
 1143             break;
 1144         case OPT_INSERT_FOOTER:
 1145             insert_footer = optarg;
 1146             break;
 1147         case OPT_INSERT_HEADER:
 1148             insert_header = optarg;
 1149             break;
 1150         case OPT_HTML_HEADER:
 1151             {
 1152                 STATIC_STRBUF(sb);
 1153                 if (!test("r", optarg))
 1154                     die("file '%s' not found.", optarg);
 1155                 strbuf_clear(sb);
 1156                 loadfile(optarg, sb);
 1157                 html_header = strbuf_value(sb);
 1158             }
 1159             break;
 1160         case OPT_ITEM_ORDER:
 1161             item_order = optarg;
 1162             break;
 1163         case OPT_TABS:
 1164             if (atoi(optarg) > 0)
 1165                 tabs = atoi(optarg);
 1166             else
 1167                 die("--tabs option requires numeric value.");
 1168                         break;
 1169         case OPT_NCOL:
 1170             if (atoi(optarg) > 0)
 1171                 ncol = atoi(optarg);
 1172             else
 1173                 die("--ncol option requires numeric value.");
 1174                         break;
 1175         case OPT_TREE_VIEW:
 1176             tree_view = 1;
 1177             if (optarg)
 1178                 tree_view_type = optarg;
 1179             break;
 1180                 case 'a':
 1181                         aflag++;
 1182                         break;
 1183                 case 'd':
 1184             strlimcpy(arg_dbpath, optarg, sizeof(arg_dbpath));
 1185                         break;
 1186                 case 'D':
 1187             dynamic = 1;
 1188                         break;
 1189                 case 'f':
 1190                         fflag++;
 1191                         break;
 1192                 case 'F':
 1193                         Fflag++;
 1194                         break;
 1195                 case 'g':
 1196                         gflag++;
 1197                         break;
 1198                 case 'h':
 1199             definition_header = AFTER_HEADER;
 1200             if (optarg) {
 1201                 if (!strcmp(optarg, "before"))
 1202                     definition_header = BEFORE_HEADER;
 1203                 else if (!strcmp(optarg, "right"))
 1204                     definition_header = RIGHT_HEADER;
 1205                 else if (!strcmp(optarg, "after"))
 1206                     definition_header = AFTER_HEADER;
 1207                 else
 1208                     die("The option value of --func-header must be one of 'before', 'right' and 'after'.");
 1209             }
 1210                         break;
 1211                 case 'I':
 1212                         Iflag++;
 1213                         break;
 1214                 case 'm':
 1215             main_func = optarg;
 1216                         break;
 1217                 case 'n':
 1218                         nflag++;
 1219             if (optarg) {
 1220                 if (atoi(optarg) > 0)
 1221                     ncol = atoi(optarg);
 1222                 else
 1223                     die("The option value of --line-number must be numeric.");
 1224             }
 1225                         break;
 1226                 case 'o':
 1227             other_files = 1;
 1228                         break;
 1229                 case 's':
 1230             symbol = 1;
 1231                         break;
 1232                 case 'T':
 1233             table_flist = 1;
 1234             if (optarg) {
 1235                 if (atoi(optarg) > 0)
 1236                     flist_fields = atoi(optarg);
 1237                 else
 1238                     die("The option value of the --table-flist must be numeric.");
 1239             }
 1240                         break;
 1241                 case 't':
 1242             title = optarg;
 1243                         break;
 1244                 case 'q':
 1245                         qflag++;
 1246                         break;
 1247                 case 'v':
 1248                         vflag++;
 1249                         break;
 1250                 case 'w':
 1251                         wflag++;
 1252                         break;
 1253                 default:
 1254                         usage();
 1255                         break;
 1256         }
 1257     }
 1258     if (qflag) {
 1259         vflag = 0;
 1260         setquiet();
 1261     }
 1262     if (vflag)
 1263         setverbose();
 1264     /*
 1265      * Leaving everything to htags.
 1266      * Htags selects popular options for you.
 1267      */
 1268     if (suggest2)
 1269         suggest = 1;
 1270     if (suggest) {
 1271         int gtags_not_found = 0;
 1272         char dbpath[MAXPATHLEN];
 1273 
 1274         aflag = Iflag = nflag = vflag = 1;
 1275         setverbose();
 1276         definition_header = AFTER_HEADER;
 1277         other_files = symbol = show_position = table_flist = fixed_guide = 1;
 1278         if (arg_dbpath[0]) {
 1279             if (!test("f", makepath(arg_dbpath, dbname(GTAGS), NULL)))
 1280                 gtags_not_found = 1;
 1281         } else if (gtagsexist(".", dbpath, sizeof(dbpath), 0) == 0) {
 1282             gtags_not_found = 1;
 1283         }
 1284         if (gtags_not_found)
 1285             gflag = 1;
 1286     }
 1287     if (suggest2) {
 1288         Fflag = 1;              /* uses frame */
 1289         fflag = dynamic = 1;            /* needs a HTTP server */
 1290         auto_completion = tree_view = 1;    /* needs javascript */
 1291     }
 1292     if (call_file && !test("fr", call_file))
 1293         die("cflow file not found. '%s'", call_file);
 1294     if (callee_file && !test("fr", callee_file))
 1295         die("cflow file not found. '%s'", callee_file);
 1296     if (insert_header && !test("fr", insert_header))
 1297         die("page header file '%s' not found.", insert_header);
 1298     if (insert_footer && !test("fr", insert_footer))
 1299         die("page footer file '%s' not found.", insert_footer);
 1300     if (!fflag)
 1301         auto_completion = 0;
 1302         argc -= optind;
 1303         argv += optind;
 1304         if (!av)
 1305                 av = (argc > 0) ? *argv : NULL;
 1306 
 1307     if (debug)
 1308         setdebug();
 1309     settabs(tabs);                  /* setup tab skip */
 1310         if (qflag) {
 1311                 setquiet();
 1312         vflag = 0;
 1313     }
 1314         if (show_version)
 1315                 version(av, vflag);
 1316         if (show_help)
 1317                 help();
 1318     /*
 1319      * Invokes gtags beforehand.
 1320      */
 1321     if (gflag) {
 1322         STRBUF *sb = strbuf_open(0);
 1323 
 1324         strbuf_puts(sb, gtags_path);
 1325         if (vflag)
 1326             strbuf_puts(sb, " -v");
 1327         if (wflag)
 1328             strbuf_puts(sb, " -w");
 1329         /*
 1330          * Please see the release note of global-6.6.4.
 1331         if (suggest2 && enable_idutils && usable("mkid"))
 1332             strbuf_puts(sb, " -I");
 1333         */
 1334         if (arg_dbpath[0]) {
 1335             strbuf_putc(sb, ' ');
 1336             strbuf_puts(sb, arg_dbpath);
 1337         }
 1338         if (system(strbuf_value(sb)))
 1339             die("cannot execute gtags(1) command.");
 1340         strbuf_close(sb);
 1341     }
 1342     /*
 1343      * get dbpath.
 1344      */
 1345     if (arg_dbpath[0]) {
 1346         strlimcpy(dbpath, arg_dbpath, sizeof(dbpath));
 1347     } else {
 1348         int status = setupdbpath(0);
 1349         if (status < 0)
 1350             die_with_code(-status, "%s", gtags_dbpath_error);
 1351         strlimcpy(dbpath, get_dbpath(), sizeof(dbpath));
 1352     }
 1353     if (!title) {
 1354         char *p = strrchr(cwdpath, sep);
 1355         title = p ? p + 1 : cwdpath;
 1356     }
 1357     if (cvsweb_url && test("d", "CVS"))
 1358         use_cvs_module = 1;
 1359     /*
 1360      * decide directory in which we make hypertext.
 1361      */
 1362     if (av) {
 1363         char realpath[MAXPATHLEN];
 1364 
 1365         if (!test("dw", av))
 1366             die("'%s' is not writable directory.", av);
 1367         if (chdir(av) < 0)
 1368             die("directory '%s' not found.", av);
 1369         if (!vgetcwd(realpath, sizeof(realpath)))
 1370             die("cannot get current directory");
 1371         if (chdir(cwdpath) < 0)
 1372             die("cannot return to original directory.");
 1373         snprintf(distpath, sizeof(distpath), "%s/HTML", realpath);
 1374     } else {
 1375         snprintf(distpath, sizeof(distpath), "%s/HTML", cwdpath);
 1376     }
 1377     /*
 1378      * Existence check of tag files.
 1379      */
 1380     {
 1381         int i;
 1382         const char *path;
 1383         GTOP *gtop;
 1384 
 1385         for (i = GPATH; i < GTAGLIM; i++) {
 1386             path = makepath(dbpath, dbname(i), NULL);
 1387             gtags_exist[i] = test("fr", path);
 1388         }
 1389         /*
 1390          * Real GRTAGS includes virtual GSYMS.
 1391          */
 1392         gtags_exist[GSYMS] = symbol ? 1 : 0;
 1393         if (!gtags_exist[GPATH] || !gtags_exist[GTAGS] || !gtags_exist[GRTAGS])
 1394             die("GPATH, GTAGS and/or GRTAGS not found. Please reexecute htags with the -g option.");
 1395         /*
 1396          * version check.
 1397          * Do nothing, but the version of tag file will be checked.
 1398          */
 1399         gtop = gtags_open(dbpath, cwdpath, GTAGS, GTAGS_READ, 0);
 1400         gtags_close(gtop);
 1401         /*
 1402          * Check whether GRTAGS is empty.
 1403          */
 1404         gtop = gtags_open(dbpath, cwdpath, GRTAGS, GTAGS_READ, 0);
 1405         if (gtags_first(gtop, NULL, 0) == NULL)
 1406             grtags_is_empty = 1;
 1407         gtags_close(gtop);
 1408     }
 1409     /*
 1410      * make dbpath absolute.
 1411      */
 1412     {
 1413         char buf[MAXPATHLEN];
 1414         if (realpath(dbpath, buf) == NULL)
 1415             die("cannot get realpath of dbpath.");
 1416         strlimcpy(dbpath, buf, sizeof(dbpath));
 1417     }
 1418     /*
 1419      * The older version (4.8.7 or former) of GPATH doesn't have files
 1420          * other than source file. The oflag requires new version of GPATH.
 1421      */
 1422     if (other_files) {
 1423         GFIND *gp = gfind_open(dbpath, NULL, 0, 0);
 1424         if (gp->version < 2)
 1425             die("GPATH is old format. Please remake it by invoking gtags(1).");
 1426         gfind_close(gp);
 1427     }
 1428     /*
 1429      * for global(1) and gtags(1).
 1430      */
 1431     set_env("GTAGSROOT", cwdpath);
 1432     set_env("GTAGSDBPATH", dbpath);
 1433     set_env("GTAGSLIBPATH", "");
 1434     /*------------------------------------------------------------------
 1435      * MAKE FILES
 1436      *------------------------------------------------------------------
 1437      *       HTML/cgi-bin/global.cgi ... CGI program (1)
 1438      *       HTML/cgi-bin/ghtml.cgi  ... unzip script (1)
 1439      *       HTML/.htaccess          ... skeleton of .htaccess (1)
 1440      *       HTML/help.html          ... help file (2)
 1441      *       HTML/R/                 ... references (3)
 1442      *       HTML/D/                 ... definitions (3)
 1443      *       HTML/search.html        ... search index (4)
 1444      *       HTML/defines.html       ... definitions index (5)
 1445      *       HTML/defines/           ... definitions index (5)
 1446      *       HTML/files/             ... file index (6)
 1447      *       HTML/index.html         ... index file (7)
 1448      *       HTML/mains.html         ... main index (8)
 1449      *       HTML/null.html          ... main null html (8)
 1450      *       HTML/S/                 ... source files (9)
 1451      *       HTML/I/                 ... include file index (9)
 1452      *       HTML/rebuild.sh         ... rebuild script (10)
 1453      *       HTML/style.css          ... style sheet (11)
 1454      *------------------------------------------------------------------
 1455      */
 1456     /* for clean up */
 1457     signal_setup();
 1458     sethandler(clean);
 1459 
 1460         HTML = normal_suffix;
 1461 
 1462     message("[%s] Htags started", now());
 1463     init_statistics();
 1464     /*
 1465      * (#) check if GTAGS, GRTAGS is the latest.
 1466      */
 1467     if (get_dbpath())
 1468         message(" Using %s/GTAGS.", get_dbpath());
 1469     if (grtags_is_empty)
 1470         message(" GRTAGS is empty.");
 1471     if (gpath_open(dbpath, 0) < 0)
 1472         die("GPATH not found.");
 1473     if (!w32) {
 1474         /* UNDER CONSTRUCTION */
 1475     }
 1476     if (auto_completion || tree_view) {
 1477         STATIC_STRBUF(sb);
 1478         strbuf_clear(sb);
 1479         strbuf_puts_nl(sb, "<script type='text/javascript' src='js/jquery.js'></script>");
 1480         if (auto_completion)
 1481             loadfile(makepath(datadir, "gtags/jscode_suggest", NULL), sb);
 1482         if (tree_view)
 1483             loadfile(makepath(datadir, "gtags/jscode_treeview", NULL), sb);
 1484         jscode = strbuf_value(sb);
 1485     }
 1486     /*
 1487      * (0) make directories
 1488      */
 1489     message("[%s] (0) making directories ...", now());
 1490     if (!test("d", distpath))
 1491         if (mkdir(distpath, 0777) < 0)
 1492             die("cannot make directory '%s'.", distpath);
 1493     make_directory_in_distpath("files");
 1494     make_directory_in_distpath("defines");
 1495     make_directory_in_distpath(SRCS);
 1496     make_directory_in_distpath(INCS);
 1497     make_directory_in_distpath(INCREFS);
 1498     if (!dynamic) {
 1499         make_directory_in_distpath(DEFS);
 1500         make_directory_in_distpath(REFS);
 1501         if (symbol)
 1502             make_directory_in_distpath(SYMS);
 1503     }
 1504     if (fflag || dynamic)
 1505         make_directory_in_distpath("cgi-bin");
 1506     if (Iflag)
 1507         make_directory_in_distpath("icons");
 1508     if (auto_completion || tree_view)
 1509          make_directory_in_distpath("js");
 1510     /*
 1511      * (1) make CGI program
 1512      */
 1513     if (fflag || dynamic) {
 1514         char cgidir[MAXPATHLEN];
 1515 
 1516         snprintf(cgidir, sizeof(cgidir), "%s/cgi-bin", distpath);
 1517         message("[%s] (1) making CGI program ...", now());
 1518         if (fflag || dynamic)
 1519             makeprogram(cgidir, "global.cgi", 0755);
 1520         if (auto_completion)
 1521             makeprogram(cgidir, "completion.cgi", 0755);
 1522         makehtaccess(".htaccess", 0644);
 1523     } else {
 1524         message("[%s] (1) making CGI program ...(skipped)", now());
 1525     }
 1526     if (av) {
 1527         const char *path = makepath(distpath, "GTAGSROOT", NULL);
 1528         FILE *op = fopen(path, "w");
 1529         if (op == NULL)
 1530             die("cannot make file '%s'.", path);
 1531         fputs(cwdpath, op);
 1532         fputc('\n', op);
 1533         fclose(op);
 1534     }
 1535     /*
 1536      * (2) make help file
 1537      */
 1538     message("[%s] (2) making help.html ...", now());
 1539     makehelp("help.html");
 1540     /*
 1541      * (#) load GPATH
 1542      */
 1543     load_gpath(dbpath);
 1544 
 1545     /*
 1546      * (3) make function entries (D/ and R/)
 1547      *     MAKING TAG CACHE
 1548      */
 1549     message("[%s] (3) making tag lists ...", now());
 1550     cache_open();
 1551     tim = statistics_time_start("Time of making tag lists");
 1552     func_total = makedupindex();
 1553     statistics_time_end(tim);
 1554     message("Total %d functions.", func_total);
 1555     /*
 1556      * (4) search index. (search.html)
 1557      */
 1558     if (Fflag && fflag) {
 1559         message("[%s] (4) making search index ...", now());
 1560         makesearchindex("search.html");
 1561     }
 1562     {
 1563         STRBUF *defines = strbuf_open(0);
 1564         STRBUF *files = strbuf_open(0);
 1565 
 1566         /*
 1567          * (5) make definition index (defines.html and defines/)
 1568          *     PRODUCE @defines
 1569          */
 1570         message("[%s] (5) making definition index ...", now());
 1571         tim = statistics_time_start("Time of making definition index");
 1572         func_total = makedefineindex("defines.html", func_total, defines);
 1573         statistics_time_end(tim);
 1574         message("Total %d functions.", func_total);
 1575         /*
 1576          * (6) make file index (files.html and files/)
 1577          *     PRODUCE @files, %includes
 1578          */
 1579         message("[%s] (6) making file index ...", now());
 1580         init_inc();
 1581         tim = statistics_time_start("Time of making file index");
 1582         file_total = makefileindex("files.html", files);
 1583         statistics_time_end(tim);
 1584         message("Total %d files.", file_total);
 1585         html_count += file_total;
 1586         /*
 1587          * (7) make call tree using cflow(1)'s output (cflow.html)
 1588          */
 1589         if (call_file || callee_file) {
 1590             message("[%s] (7) making cflow index ...", now());
 1591             tim = statistics_time_start("Time of making cflow index");
 1592             if (call_file)
 1593                 if (makecflowindex("call.html", call_file) < 0)
 1594                     call_file = NULL;
 1595             if (callee_file)
 1596                 if (makecflowindex("callee.html", callee_file) < 0)
 1597                     callee_file = NULL;
 1598             statistics_time_end(tim);
 1599         }
 1600         /*
 1601          * [#] make include file index.
 1602          */
 1603         message("[%s] (#) making include file index ...", now());
 1604         tim = statistics_time_start("Time of making include file index");
 1605         makeincludeindex();
 1606         statistics_time_end(tim);
 1607         /*
 1608          * [#] make a common part for mains.html and index.html
 1609          *     USING @defines @files
 1610          */
 1611         message("[%s] (#) making a common part ...", now());
 1612         index = makecommonpart(title, strbuf_value(defines), strbuf_value(files));
 1613 
 1614         strbuf_close(defines);
 1615         strbuf_close(files);
 1616     }
 1617     /*
 1618      * (7)make index file (index.html)
 1619      */
 1620     message("[%s] (7) making index file ...", now());
 1621     makeindex("index.html", title, index);
 1622     /*
 1623      * (8) make main index (mains.html)
 1624      */
 1625     message("[%s] (8) making main index ...", now());
 1626     makemainindex("mains.html", index);
 1627     /*
 1628      * (9) make HTML files (SRCS/)
 1629      *     USING TAG CACHE, %includes and anchor database.
 1630      */
 1631     message("[%s] (9) making hypertext from source code ...", now());
 1632     tim = statistics_time_start("Time of making hypertext");
 1633     makehtml(file_total);
 1634     statistics_time_end(tim);
 1635     /*
 1636      * (10) rebuild script. (rebuild.sh)
 1637      *
 1638      * Don't grant execute permission to rebuild script.
 1639      */
 1640     makerebuild("rebuild.sh");
 1641     if (chmod(makepath(distpath, "rebuild.sh", NULL), 0640) < 0)
 1642         die("cannot chmod rebuild script.");
 1643     /*
 1644      * (11) style sheet file (style.css)
 1645      */
 1646     if (enable_xhtml) {
 1647         char src[MAXPATHLEN];
 1648         char dist[MAXPATHLEN];
 1649         snprintf(src, sizeof(src), "%s/gtags/style.css", datadir);
 1650         snprintf(dist, sizeof(dist), "%s/style.css", distpath);
 1651         copyfile(src, dist);
 1652     }
 1653     if (auto_completion || tree_view) {
 1654         char src[MAXPATHLEN];
 1655         char dist[MAXPATHLEN];
 1656 
 1657         snprintf(src, sizeof(src), "%s/gtags/jquery", datadir);
 1658         snprintf(dist, sizeof(dist), "%s/js", distpath);
 1659         copydirectory(src, dist);
 1660         snprintf(src, sizeof(src), "%s/gtags/jquery/images", datadir);
 1661         snprintf(dist, sizeof(dist), "%s/js/images", distpath);
 1662         copydirectory(src, dist);
 1663     }
 1664     message("[%s] Done.", now());
 1665     if (vflag && (fflag || dynamic || auto_completion)) {
 1666         message("\n[Information]\n");
 1667         message(" o Htags was invoked with the -f, -c, -D or --auto-completion option. You should");
 1668         message("   start http server so that cgi-bin/*.cgi is executed as a CGI script.");
 1669         message("   Use of htags-server(1) is recommended.");
 1670         message("\n If you are using Apache, 'HTML/.htaccess' might be helpful for you.\n");
 1671         message(" Good luck!\n");
 1672     }
 1673     if (Iflag) {
 1674         char src[MAXPATHLEN];
 1675         char dist[MAXPATHLEN];
 1676 
 1677         snprintf(src, sizeof(src), "%s/gtags/icons", datadir);
 1678         snprintf(dist, sizeof(dist), "%s/icons", distpath);
 1679         copydirectory(src, dist);
 1680     }
 1681     gpath_close();
 1682     /*
 1683      * Print statistics information.
 1684      */
 1685     print_statistics(statistics);
 1686     clean();
 1687     return 0;
 1688 }