root/htags/htags.c

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

DEFINITIONS

This source file includes following definitions.
  1. usage
  2. help
  3. clean
  4. suddenly
  5. signal_setup
  6. make_directory_in_distpath
  7. make_file_in_distpath
  8. load_with_replace
  9. generate_file
  10. makeprogram
  11. makebless
  12. makeghtml
  13. makerebuild
  14. makehelp
  15. makesearchpart
  16. makeindex
  17. makemainindex
  18. makesearchindex
  19. makehtaccess
  20. makehtml
  21. loadfile_asis
  22. loadfile
  23. copyfile
  24. makecommonpart
  25. basic_check
  26. configuration
  27. save_environment
  28. append_options
  29. main

   1 /*
   2  * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
   3  *      2006, 2007, 2008, 2010, 2011 Tama Communications Corporation
   4  *
   5  * This file is part of GNU GLOBAL.
   6  *
   7  * This program is free software: you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation, either version 3 of the License, or
  10  * (at your option) any later version.
  11  * 
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  * 
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19  */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include <config.h>
  23 #endif
  24 #include <stdio.h>
  25 #ifdef STDC_HEADERS
  26 #include <stdlib.h>
  27 #endif
  28 #ifdef HAVE_UNISTD_H
  29 #include <unistd.h>
  30 #endif
  31 #ifdef HAVE_FCNTL_H
  32 #include <fcntl.h>
  33 #else
  34 #include <sys/file.h>
  35 #endif
  36 #include <signal.h>
  37 #include <sys/types.h>
  38 #include <sys/stat.h>
  39 #include <sys/param.h>
  40 #include <errno.h>
  41 
  42 #include "checkalloc.h"
  43 #include "getopt.h"
  44 #include "regex.h"
  45 #include "global.h"
  46 #include "anchor.h"
  47 #include "cache.h"
  48 #include "common.h"
  49 #include "htags.h"
  50 #include "incop.h"
  51 #include "path2url.h"
  52 #include "const.h"
  53 
  54 /**
  55  * @file
  56  * @NAME{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 int need_bless;
  79 const char *save_config;
  80 const char *save_argv;
  81 
  82 char cwdpath[MAXPATHLEN];
  83 char dbpath[MAXPATHLEN];
  84 char distpath[MAXPATHLEN];
  85 char gtagsconf[MAXPATHLEN];
  86 char datadir[MAXPATHLEN];
  87 char localstatedir[MAXPATHLEN];
  88 
  89 char gtags_path[MAXFILLEN];
  90 char global_path[MAXFILLEN];
  91 int gtags_exist[GTAGLIM];
  92 const char *null_device = NULL_DEVICE;
  93 const char *tmpdir = "/tmp";
  94 const char *sitekey = "";
  95 
  96 /**
  97  * @details
  98  * Order of items in the top page (This should be customisable variable in the future).
  99  *
 100  * @CODE{'c'}: caution <br>
 101  * @CODE{'s'}: search form <br>
 102  * @CODE{'m'}: mains <br>
 103  * @CODE{'d'}: definitions <br>
 104  * @CODE{'f'}: files <br>
 105  * @CODE{'t'}: call tree
 106  */
 107 char *item_order = "csmdft";
 108 /*
 109  * options
 110  */
 111 int aflag;                              /**< @OPTION{--alphabet(-a)} option     */
 112 int cflag;                              /**< @OPTION{--compact(-c)} option              */
 113 int fflag;                              /**< @OPTION{--form(-f)} option         */
 114 int Fflag;                              /**< @OPTION{--frame(-F)} option                */
 115 int gflag;                              /**< @OPTION{--gtags(-g)} option                */
 116 int Iflag;                              /**< @OPTION{--icon(-I)} option         */
 117 int nflag;                              /**< @OPTION{--line-number(-n)} option  */
 118 int Sflag;                              /**< @OPTION{--system-cgi} option               */
 119 int qflag;
 120 int vflag;                              /**< @OPTION{--verbose(-v)} option              */
 121 int wflag;                              /**< @OPTION{--warning(-w)} option              */
 122 int debug;                              /**< @OPTION{--debug} option            */
 123 
 124 int show_help;                          /**< @OPTION{--help} command            */
 125 int show_version;                       /**< @OPTION{--version} command         */
 126 int caution;                            /**< @OPTION{--caution} option          */
 127 int dynamic;                            /**< @OPTION{--dynamic(-D)} option              */
 128 int symbol;                             /**< @OPTION{--symbol(-s)} option          */
 129 int suggest;                            /**< @OPTION{--suggest} option          */
 130 int suggest2;                           /**< @OPTION{--suggest2} option         */
 131 int auto_completion;                    /**< @OPTION{--auto-completion}         */
 132 int tree_view;                          /**< @OPTION{--tree-view}                       */
 133 int fixed_guide;                        /**< @OPTION{--fixed-guide}             */
 134 const char *tree_view_type;             /**< @OPTION{--type-view=[type]}                */
 135 char *auto_completion_limit = "0";      /**< @OPTION{--auto-completion=limit}   */
 136 int statistics = STATISTICS_STYLE_NONE; /**< @OPTION{--statistics} option               */
 137 
 138 int no_order_list;                      /**< 1: doesn't use order list  */
 139 int other_files;                        /**< 1: list other files                */
 140 int enable_grep = 1;                    /**< 1: enable grep             */
 141 int enable_idutils = 1;                 /**< 1: enable idutils          */
 142 int enable_xhtml = 1;                   /**< 1: enable XHTML            */
 143 
 144 const char *main_func = "main";
 145 const char *cvsweb_url;
 146 int use_cvs_module;
 147 const char *cvsweb_cvsroot;
 148 const char *gtagslabel;
 149 const char *title;
 150 const char *xhtml_version = "1.0";
 151 const char *insert_header;              /**< @OPTION{--insert-header=\<file\>}  */
 152 const char *insert_footer;              /**< @OPTION{--insert-footer=\<file\>}  */
 153 const char *html_header;                /**< @OPTION{--html-header=\<file\>}            */
 154 const char *jscode;                     /**< javascript code            */
 155 /**
 156  * @name Constant values.
 157  */
 158 /** @{ */
 159 const char *title_define_index = "DEFINITIONS";
 160 const char *title_file_index = "FILES";
 161 const char *title_call_tree = "CALL TREE";
 162 const char *title_callee_tree = "CALLEE TREE";
 163 const char *title_included_from = "INCLUDED FROM";
 164 /** @} */
 165 /*
 166  * Function header items.
 167  */
 168 const char *anchor_label[] = {
 169         "&lt;",
 170         "&gt;",
 171         "^",
 172         "v",
 173         "top",
 174         "bottom",
 175         "index",
 176         "help"
 177 };
 178 const char *anchor_icons[] = {
 179         "left",
 180         "right",
 181         "first",
 182         "last",
 183         "top",
 184         "bottom",
 185         "index",
 186         "help"
 187 };
 188 const char *anchor_comment[] = {
 189         "previous",
 190         "next",
 191         "first",
 192         "last",
 193         "top",
 194         "bottom",
 195         "index",
 196         "help"
 197 };
 198 const char *anchor_msg[] = {
 199         "Previous definition.",
 200         "Next definition.",
 201         "First definition in this file.",
 202         "Last definition in this file.",
 203         "Top of this file.",
 204         "Bottom of this file.",
 205         "Return to index page.",
 206         "You are seeing now."
 207 };
 208 const char *back_icon = "back";
 209 const char *dir_icon  = "dir";
 210 const char *c_icon = "c";
 211 const char *file_icon = "text";
 212 
 213 const char *icon_files[] = {
 214         "first",
 215         "last",
 216         "left",
 217         "right",
 218         "top",
 219         "bottom",
 220         "n_first",
 221         "n_last",
 222         "n_left",
 223         "n_right",
 224         "n_top",
 225         "n_bottom",
 226         "index",
 227         "help",
 228         "back",
 229         "dir",
 230         "c",
 231         "text",
 232         "pglobe"
 233 };
 234 /**
 235  * @name Configuration parameters.
 236  */
 237 /** @{ */
 238 int ncol = 4;                           /**< columns of line number     */
 239 int tabs = 8;                           /**< tab skip                   */
 240 int flist_fields = 5;                   /**< fields number of file list */
 241 int full_path = 0;                      /**< file index format          */
 242 int map_file = 0;                       /**< 1: create MAP file         */
 243 int filemap_file = 1;                   /**< 1: create FILEMAP file     */
 244 int overwrite_key = 0;                  /**< 1: over write site key     */
 245 const char *icon_suffix = "png";        /**< icon suffix (jpg, png etc) */
 246 const char *icon_spec = "border='0' align='top'"; /**< parameter in IMG tag*/
 247 const char *prolog_script = NULL;       /**< include script at first    */
 248 const char *epilog_script = NULL;       /**< include script at last     */
 249 const char *call_file = NULL;           /**< file name of cflow output  */
 250 const char *callee_file = NULL;         /**< file name of cflow output  */
 251 int show_position = 0;                  /**< show current position      */
 252 int table_list = 0;                     /**< tag list using table tag   */
 253 int table_flist = 0;                    /**< file list using table tag  */
 254 int colorize_warned_line = 0;           /**< colorize warned line               */
 255 const char *script_alias = "/cgi-bin";  /**< script alias of WWW server */
 256 const char *gzipped_suffix = "ghtml";   /**< suffix of gzipped html file        */
 257 const char *normal_suffix = "html";     /**< suffix of normal html file */
 258 const char *HTML;                                       /**< HTML */
 259 const char *action = "cgi-bin/global.cgi"; /**< default action          */
 260 const char *completion_action = "cgi-bin/completion.cgi";       /**< completion_action */
 261 int definition_header=NO_HEADER;        /**< (NO|BEFORE|RIGHT|AFTER)_HEADER */
 262 const char *htags_options = NULL;       /**< htags_options */
 263 const char *include_file_suffixes = DEFAULTINCLUDEFILESUFFIXES; /**< include_file_suffixes */
 264 static const char *langmap = DEFAULTLANGMAP;    /**< langmap */
 265 int grtags_is_empty = 0;                                                /**< grtags_is_empty */
 266 /** @} */
 267 
 268 static struct option const long_options[] = {
 269         /*
 270          * These options have long name and short name.
 271          * We throw them to the processing of short options.
 272          */
 273         {"alphabet", no_argument, NULL, 'a'},
 274         {"compact", no_argument, NULL, 'c'},
 275         {"dbpath", required_argument, NULL, 'd'},
 276         {"dynamic", no_argument, NULL, 'D'},
 277         {"form", no_argument, NULL, 'f'},
 278         {"frame", no_argument, NULL, 'F'},
 279         {"func-header", optional_argument, NULL, 'h'},
 280         {"gtags", no_argument, NULL, 'g'},
 281         {"icon", no_argument, NULL, 'I'},
 282         {"line-number", optional_argument, NULL, 'n'},
 283         {"main-func", required_argument, NULL, 'm'},
 284         {"other", no_argument, NULL, 'o'},
 285         {"system-cgi", required_argument, NULL, 'S'},
 286         {"symbol", no_argument, NULL, 's'},
 287         {"table-flist", optional_argument, NULL, 'T'},
 288         {"title", required_argument, NULL, 't'},
 289         {"verbose", no_argument, NULL, 'v'},
 290         {"warning", no_argument, NULL, 'w'},
 291         {"xhtml", optional_argument, NULL, 'x'},
 292 
 293         /*
 294          * The following are long name only.
 295          */
 296         /* flag value */
 297         {"caution", no_argument, &caution, 1},
 298         {"debug", no_argument, &debug, 1},
 299         {"disable-grep", no_argument, &enable_grep, 0},
 300         {"disable-idutils", no_argument, &enable_idutils, 0},
 301         {"full-path", no_argument, &full_path, 1},
 302         {"fixed-guide",  no_argument, &fixed_guide, 1},
 303         {"map-file", no_argument, &map_file, 1},
 304         {"overwrite-key", no_argument, &overwrite_key, 1},
 305         {"show-position", no_argument, &show_position, 1},
 306         {"statistics", no_argument, &statistics, STATISTICS_STYLE_TABLE},
 307         {"suggest", no_argument, &suggest, 1},
 308         {"suggest2", no_argument, &suggest2, 1},
 309         {"table-list", no_argument, &table_list, 1},
 310         {"version", no_argument, &show_version, 1},
 311         {"help", no_argument, &show_help, 1},
 312 
 313         /* accept value */
 314 #define OPT_CVSWEB              128
 315 #define OPT_CVSWEB_CVSROOT      129
 316 #define OPT_GTAGSCONF           130
 317 #define OPT_GTAGSLABEL          131
 318 #define OPT_NCOL                132
 319 #define OPT_INSERT_FOOTER       133
 320 #define OPT_INSERT_HEADER       134
 321 #define OPT_ITEM_ORDER          135
 322 #define OPT_TABS                136
 323 #define OPT_CFLOW               137
 324 #define OPT_AUTO_COMPLETION     138
 325 #define OPT_TREE_VIEW           139
 326 #define OPT_HTML_HEADER         140
 327 #define OPT_CALL_TREE           141
 328 #define OPT_CALLEE_TREE         142
 329         {"auto-completion", optional_argument, NULL, OPT_AUTO_COMPLETION},
 330         {"call-tree", required_argument, NULL, OPT_CALL_TREE},
 331         {"callee-tree", required_argument, NULL, OPT_CALLEE_TREE},
 332         {"cflow", required_argument, NULL, OPT_CFLOW},
 333         {"cvsweb", required_argument, NULL, OPT_CVSWEB},
 334         {"cvsweb-cvsroot", required_argument, NULL, OPT_CVSWEB_CVSROOT},
 335         {"gtagsconf", required_argument, NULL, OPT_GTAGSCONF},
 336         {"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
 337         {"html-header", required_argument,NULL, OPT_HTML_HEADER},
 338         {"ncol", required_argument, NULL, OPT_NCOL},
 339         {"insert-footer", required_argument, NULL, OPT_INSERT_FOOTER},
 340         {"insert-header", required_argument, NULL, OPT_INSERT_HEADER},
 341         {"item-order", required_argument, NULL, OPT_ITEM_ORDER},
 342         {"tabs", required_argument, NULL, OPT_TABS},
 343         {"tree-view",  optional_argument, NULL, OPT_TREE_VIEW},
 344         { 0 }
 345 };
 346 
 347 static void
 348 usage(void)
 349 {
 350         if (!qflag)
 351                 fputs(usage_const, stderr);
 352         exit(2);
 353 }
 354 static void
 355 help(void)
 356 {
 357         fputs(usage_const, stdout);
 358         fputs(help_const, stdout);
 359         exit(0);
 360 }
 361 /**
 362  * Htags catch signal even if the parent ignore it.
 363  */
 364 void
 365 clean(void)
 366 {
 367         unload_gpath();
 368         cache_close();
 369 }
 370 /**
 371  * Signal handler.
 372  *
 373  * This handler is set up in signal_setup().
 374  */
 375 static void
 376 suddenly(int signo)
 377 {
 378         signo = 0;      /* to satisfy compiler */
 379 
 380         clean();
 381         exit(1);
 382 }
 383 
 384 /**
 385  * Setup signal hander.
 386  *
 387  * Makes signals @CODE{SIGINT}, @CODE{SIGTERM}, @CODE{SIGHUP} and @CODE{SIGQUIT}
 388  * call suddenly() if triggered.
 389  */
 390 static void
 391 signal_setup(void)
 392 {
 393         signal(SIGINT, suddenly);
 394         signal(SIGTERM, suddenly);
 395 #ifdef SIGHUP
 396         signal(SIGHUP, suddenly);
 397 #endif
 398 #ifdef SIGQUIT
 399         signal(SIGQUIT, suddenly);
 400 #endif
 401 }
 402 
 403 /**
 404  * make directory in the dist (#distpath) directory.
 405  *
 406  *     @param[in]      name    name of directory to create.
 407  *
 408  * Creates a file called @FILE{index.html} in the new directory.
 409  *
 410  * @remark @NAME{mkdir()} creates the directory in mode @CODE{0775}, if doesn't exist.
 411  */
 412 static void
 413 make_directory_in_distpath(const char *name)
 414 {
 415         char path[MAXPATHLEN];
 416         FILE *op;
 417 
 418         strlimcpy(path, makepath(distpath, name, NULL), sizeof(path));
 419         if (!test("d", path))
 420                 if (mkdir(path, 0775))
 421                         die("cannot make directory '%s'.", path);
 422         /*
 423          * Not to publish the directory list.
 424          */
 425         op = fopen(makepath(path, "index.html", NULL), "w");
 426         if (op == NULL)
 427                 die("cannot make file '%s'.", makepath(path, "index.html", NULL));
 428         fputs(html_begin, op);
 429         fputs(html_end, op);
 430         fputc('\n', op);
 431         fclose(op);
 432 }
 433 /**
 434  * make file in the dist (#distpath) directory.
 435  */
 436 static void
 437 make_file_in_distpath(const char *name, const char *data)
 438 {
 439         FILE *op;
 440         const char *path = makepath(distpath, name, NULL);
 441 
 442         op = fopen(path, "w");
 443         if (op) {
 444                 if (data && *data) {
 445                         fputs(data, op);
 446                         fputc('\n', op);
 447                 }
 448                 fclose(op);
 449         } else {
 450                 die("cannot make file '%s'.", path); 
 451         }
 452 }
 453 void
 454 load_with_replace(const char *file, STRBUF *result, int place)
 455 {
 456         STRBUF *sb = strbuf_open(0);
 457         FILE *ip;
 458         regex_t preg;
 459         regmatch_t pmatch[2];
 460         char *_;
 461         int i;
 462 
 463         struct map {
 464                 const char *name;
 465                 const char *value;
 466         } tab[] = {
 467                 /* dynamic initialization */
 468                 {"@page_begin@", NULL},
 469                 {"@page_end@", NULL},
 470 
 471                 /* static initialization */
 472                 {"@body_begin@", body_begin},
 473                 {"@body_end@", body_end},
 474                 {"@title_begin@", title_begin},
 475                 {"@title_end@", title_end},
 476                 {"@error_begin@", error_begin},
 477                 {"@error_end@", error_end},
 478                 {"@message_begin@", message_begin},
 479                 {"@message_end@", message_end},
 480                 {"@verbatim_begin@", verbatim_begin},
 481                 {"@verbatim_end@", verbatim_end},
 482                 {"@normal_suffix@", normal_suffix},
 483                 {"@hr@", hr},
 484                 {"@br@", br},
 485                 {"@HTML@", HTML},
 486                 {"@DATADIR@", datadir},
 487                 {"@LOCALSTATEDIR@", localstatedir},
 488                 {"@action@", action},
 489                 {"@completion_action@", completion_action},
 490                 {"@limit@", auto_completion_limit},
 491                 {"@sitekey@", sitekey},
 492                 {"@script_alias@", script_alias},
 493                 {"@null_device@", null_device},
 494                 {"@globalpath@", global_path},
 495                 {"@gtagspath@", gtags_path},
 496         };
 497         int tabsize = sizeof(tab) / sizeof(struct map);
 498 
 499         tab[0].value = gen_page_begin("Result", place);
 500         tab[1].value = gen_page_end();
 501         /*
 502          * construct regular expression.
 503          */
 504         strbuf_putc(sb, '(');
 505         for (i = 0; i < tabsize; i++) {
 506                 strbuf_puts(sb, tab[i].name);
 507                 strbuf_putc(sb, '|');
 508         }
 509         strbuf_unputc(sb, '|');
 510         strbuf_putc(sb, ')');
 511         if (regcomp(&preg, strbuf_value(sb), REG_EXTENDED) != 0)
 512                 die("cannot compile regular expression.");
 513         /*
 514          * construct skeleton file name in the system datadir directory.
 515          */
 516         strbuf_reset(sb);
 517         strbuf_sprintf(sb, "%s/gtags/%s.tmpl", datadir, file);
 518         ip = fopen(strbuf_value(sb), "r");
 519         if (!ip) {
 520 #ifdef __DJGPP__
 521                 strbuf_reset(sb);
 522                 strbuf_sprintf(sb, "%s/gtags/%s", datadir, file);
 523                 ip = fopen(strbuf_value(sb), "r");
 524                 if (!ip)
 525 #endif
 526                         die("skeleton file '%s' not found.", strbuf_value(sb));
 527         }
 528         strbuf_reset(sb);
 529         /*
 530          * Read template file and evaluate macros.
 531          */
 532         while ((_ = strbuf_fgets(sb, ip, STRBUF_NOCRLF)) != NULL) {
 533                 const char *p;
 534 
 535                 /* Pick up macro name */
 536                 for (p = _; !regexec(&preg, p, 2, pmatch, 0); p += pmatch[0].rm_eo) {
 537                         const char *start = p + pmatch[0].rm_so;
 538                         int length = pmatch[0].rm_eo - pmatch[0].rm_so;
 539 
 540                         /* print before macro */
 541                         for (i = 0; i < pmatch[0].rm_so; i++)
 542                                 strbuf_putc(result, p[i]);
 543                         for (i = 0; i < tabsize; i++)
 544                                 if (!strncmp(start, tab[i].name, length))
 545                                         break;
 546                         if (i >= tabsize)
 547                                 die("something wrong.");
 548                         /* print macro value */
 549                         if (i < tabsize) {
 550                                 const char *q;
 551                                 /*
 552                                  * Double quote should be quoted using '\\'.
 553                                  */
 554                                 for (q = tab[i].value; *q; q++) {
 555                                         if (*q == '"')
 556                                                 strbuf_putc(result, '\\');
 557                                         else if (*q == '\n')
 558                                                 strbuf_putc(result, '\\');
 559                                         strbuf_putc(result, *q);
 560                                 }
 561                         }
 562                 }
 563                 strbuf_puts_nl(result, p);
 564         }
 565         fclose(ip);
 566         strbuf_close(sb);
 567         regfree(&preg);
 568 }
 569 /**
 570  * generate_file: generate file with replacing macro.
 571  *
 572  *      @param[in]      dist    directory where the file should be created
 573  *      @param[in]      file    file name
 574  *      @param[in]      place   #TOPDIR, #SUBDIR, #CGIDIR
 575  */
 576 static void
 577 generate_file(const char *dist, const char *file, int place)
 578 {
 579         FILE *op;
 580         STRBUF *result = strbuf_open(0);
 581 
 582         op = fopen(makepath(dist, file, NULL), "w");
 583         if (!op)
 584                 die("cannot create file '%s'.", file);
 585         load_with_replace(file, result, place);
 586         fputs(strbuf_value(result), op);
 587         fclose(op);
 588         html_count++;
 589         strbuf_close(result);
 590 }
 591 /**
 592  * makeprogram: make @NAME{CGI} program
 593  */
 594 static void
 595 makeprogram(const char *cgidir, const char *file)
 596 {
 597         generate_file(cgidir, file, CGIDIR);
 598 }
 599 /**
 600  * makebless: make @FILE{bless.sh} file.
 601  */
 602 static void
 603 makebless(const char *file)
 604 {
 605         generate_file(distpath, file, SUBDIR);
 606 }
 607 /**
 608  * makeghtml: make @FILE{ghtml.cgi} file.
 609  *
 610  *      @param[in]      cgidir  directory where the file should be created
 611  *      @param[in]      file    file name
 612  */
 613 static void
 614 makeghtml(const char *cgidir, const char *file)
 615 {
 616         generate_file(cgidir, file, SUBDIR);
 617 }
 618 /**
 619  * makerebuild: make rebuild script
 620  */
 621 static void
 622 makerebuild(const char *file)
 623 {
 624         FILE *op;
 625 
 626         op = fopen(makepath(distpath, file, NULL), "w");
 627         if (!op)
 628                 die("cannot make rebuild script.");
 629         fputs_nl("#!/bin/sh", op);
 630         fputs_nl("#", op);
 631         fputs_nl("# rebuild.sh: rebuild hypertext with the previous context.", op);
 632         fputs_nl("#", op);
 633         fputs_nl("# Usage:", op);
 634         fputs_nl("#\t% sh rebuild.sh", op);
 635         fputs_nl("#", op);
 636         fprintf(op, "cd %s && GTAGSCONF='%s' htags%s\n", cwdpath, save_config, save_argv);
 637         fclose(op);
 638 }
 639 /**
 640  * makehelp: make help file
 641  */
 642 static void
 643 makehelp(const char *file)
 644 {
 645         const char **label = Iflag ? anchor_comment : anchor_label;
 646         const char **icons = anchor_icons;
 647         const char **msg   = anchor_msg;
 648         int n, last = 7;
 649         FILE *op;
 650 
 651         op = fopen(makepath(distpath, file, NULL), "w");
 652         if (!op)
 653                 die("cannot make help file.");
 654         fputs_nl(gen_page_begin("HELP", TOPDIR), op);
 655         fputs_nl(body_begin, op);
 656         fputs(header_begin, op);
 657         fputs("Usage of Links", op);
 658         fputs_nl(header_end, op);
 659         if (!Iflag)
 660                 fputs(verbatim_begin, op);
 661         fputs("/* ", op);
 662         for (n = 0; n <= last; n++) {
 663                 if (Iflag) {
 664                         fputs(gen_image(CURRENT, icons[n], label[n]), op);
 665                         if (n < last)
 666                                 fputc(' ', op);
 667                 } else {
 668                         fprintf(op, "[%s]", label[n]);
 669                 }
 670         }
 671         if (show_position)
 672                 fprintf(op, "[+line file]");
 673         fputs(" */", op);
 674         if (!Iflag)
 675                 fputs_nl(verbatim_end, op);
 676         else
 677                 fputc('\n', op);
 678         fputs_nl(define_list_begin, op);
 679         for (n = 0; n <= last; n++) {
 680                 fputs(define_term_begin, op);
 681                 if (Iflag) {
 682                         fputs(gen_image(CURRENT, icons[n], label[n]), op);
 683                 } else {
 684                         fprintf(op, "[%s]", label[n]);
 685                 }
 686                 fputs(define_term_end, op);
 687                 fputs(define_desc_begin, op);
 688                 fputs(msg[n], op);
 689                 fputs_nl(define_desc_end, op);
 690         }
 691         if (show_position) {
 692                 fputs(define_term_begin, op);
 693                 fputs("[+line file]", op);
 694                 fputs(define_term_end, op);
 695                 fputs(define_desc_begin, op);
 696                 fputs("Current position (line number and file name).", op);
 697                 fputs_nl(define_desc_end, op);
 698         }
 699         fputs_nl(define_list_end, op);
 700         fputs_nl(body_end, op);
 701         fputs_nl(gen_page_end(), op);
 702         fclose(op);
 703         html_count++;
 704 }
 705 /**
 706  * makesearchpart: make search part
 707  *
 708  *      @param[in]      target  \$target
 709  *      @return         html
 710  */
 711 static char *
 712 makesearchpart(const char *target)
 713 {
 714         STATIC_STRBUF(sb);
 715 
 716         strbuf_clear(sb);
 717         strbuf_puts(sb, header_begin);
 718         if (Fflag)
 719                 strbuf_puts(sb, gen_href_begin(NULL, "search", normal_suffix, NULL));
 720         strbuf_puts(sb, "SEARCH");
 721         if (Fflag)
 722                 strbuf_puts(sb, gen_href_end());
 723         strbuf_puts_nl(sb, header_end);
 724         if (!target) {
 725                 strbuf_puts(sb, "Please input object name and select [Search]. POSIX's regular expression is allowed.");
 726                 strbuf_puts_nl(sb, br);
 727         }
 728         strbuf_puts_nl(sb, gen_form_begin(target));
 729         strbuf_puts_nl(sb, gen_input("pattern", NULL, NULL));
 730         strbuf_puts_nl(sb, gen_input("id", sitekey, "hidden"));
 731         strbuf_puts_nl(sb, gen_input(NULL, "Search", "submit"));
 732         strbuf_puts(sb, gen_input(NULL, "Reset", "reset"));
 733         strbuf_puts_nl(sb, br);
 734         strbuf_puts(sb, gen_input_radio("type", "definition", 1, "Retrieve the definition place of the specified symbol."));
 735         strbuf_puts_nl(sb, target ? "Def" : "Definition");
 736         strbuf_puts(sb, gen_input_radio("type", "reference", 0, "Retrieve the reference place of the specified symbol."));
 737         strbuf_puts_nl(sb, target ? "Ref" : "Reference");
 738         strbuf_puts(sb, gen_input_radio("type", "symbol", 0, "Retrieve the place of the specified symbol is used."));
 739         strbuf_puts_nl(sb, target ? "Sym" : "Other symbol");
 740         strbuf_puts(sb, gen_input_radio("type", "path", 0, "Look for path name which matches to the specified pattern."));
 741         strbuf_puts_nl(sb, target ? "Path" : "Path name");
 742         if (enable_grep) {
 743                 strbuf_puts(sb, gen_input_radio("type", "grep", 0, "Retrieve lines which matches to the specified pattern."));
 744                 strbuf_puts_nl(sb, target ? "Grep" : "Grep pattern");
 745         }
 746         if (enable_idutils && test("f", makepath(dbpath, "ID", NULL))) {
 747                 strbuf_puts(sb, gen_input_radio("type", "idutils", 0, "Retrieve lines which matches to the specified pattern using idutils(1)."));
 748                 strbuf_puts_nl(sb, target ? "Id" : "Id pattern");
 749         }
 750         strbuf_puts_nl(sb, br);
 751         strbuf_puts(sb, gen_input_checkbox("icase", NULL, "Ignore case distinctions in the pattern."));
 752         strbuf_puts_nl(sb, target ? "Icase" : "Ignore case");
 753         if (other_files) {
 754                 strbuf_puts(sb, gen_input_checkbox("other", NULL, "Files other than the source code are also retrieved."));
 755                 strbuf_puts_nl(sb, target ? "Other" : "Other files");
 756         }
 757         if (other_files && !target) {
 758                 strbuf_puts_nl(sb, br);
 759                 strbuf_puts(sb, "('Other files' is effective only to 'Path name'");
 760                 if (enable_grep)
 761                         strbuf_puts(sb, " and 'Grep pattern'");
 762                 strbuf_puts_nl(sb, ".)");
 763         }
 764         strbuf_puts_nl(sb, gen_form_end());
 765         return strbuf_value(sb);
 766 }
 767 /**
 768  * makeindex: make index file
 769  *
 770  *      @param[in]      file    file name
 771  *      @param[in]      title   title of index file
 772  *      @param[in]      index   common part
 773  */
 774 static void
 775 makeindex(const char *file, const char *title, const char *index)
 776 {
 777         FILE *op;
 778 
 779         op = fopen(makepath(distpath, file, NULL), "w");
 780         if (!op)
 781                 die("cannot make file '%s'.", file);
 782         if (Fflag) {
 783                 fputs_nl(gen_page_frameset_begin(title), op);
 784                 fputs_nl(gen_frameset_begin("cols='200,*'"), op);
 785                 if (fflag) {
 786                         fputs_nl(gen_frameset_begin("rows='33%,33%,*'"), op);
 787                         fputs_nl(gen_frame("search", makepath(NULL, "search", normal_suffix)), op);
 788                 } else {
 789                         fputs_nl(gen_frameset_begin("rows='50%,*'"), op);
 790                 }
 791                 /*
 792                  * id='xxx' for XHTML
 793                  * name='xxx' for HTML
 794                  */
 795                 fputs_nl(gen_frame("defines", makepath(NULL, "defines", normal_suffix)), op);
 796                 fputs_nl(gen_frame("files", makepath(NULL, "files", normal_suffix)), op);
 797                 fputs_nl(gen_frameset_end(), op);
 798                 fputs_nl(gen_frame("mains", makepath(NULL, "mains", normal_suffix)), op);
 799                 fputs_nl(noframes_begin, op);
 800                 fputs_nl(body_begin, op);
 801                 fputs(index, op);
 802                 fputs_nl(body_end, op);
 803                 fputs_nl(noframes_end, op);
 804                 fputs_nl(gen_frameset_end(), op);
 805                 fputs_nl(gen_page_end(), op);
 806         } else {
 807                 fputs_nl(gen_page_index_begin(title, jscode), op);
 808                 fputs_nl(body_begin, op);
 809                 if (insert_header)
 810                         fputs(gen_insert_header(TOPDIR), op);
 811                 fputs(index, op);
 812                 if (insert_footer)
 813                         fputs(gen_insert_footer(TOPDIR), op);
 814                 fputs_nl(body_end, op);
 815                 fputs_nl(gen_page_end(), op);
 816         }
 817         fclose(op);
 818         html_count++;
 819 }
 820 /**
 821  * makemainindex: make main index
 822  *
 823  *      @param[in]      file    file name
 824  *      @param[in]      index   common part
 825  */
 826 static void
 827 makemainindex(const char *file, const char *index)
 828 {
 829         FILE *op;
 830 
 831         op = fopen(makepath(distpath, file, NULL), "w");
 832         if (!op)
 833                 die("cannot make file '%s'.", file);
 834         fputs_nl(gen_page_index_begin(title, jscode), op);
 835         fputs_nl(body_begin, op);
 836         if (insert_header)
 837                 fputs(gen_insert_header(TOPDIR), op);
 838         fputs(index, op);
 839         if (insert_footer)
 840                 fputs(gen_insert_footer(TOPDIR), op);
 841         fputs_nl(body_end, op);
 842         fputs_nl(gen_page_end(), op);
 843         fclose(op);
 844         html_count++;
 845 }
 846 /**
 847  * makesearchindex: make search html
 848  *
 849  *      @param[in]      file    file name
 850  */
 851 static void
 852 makesearchindex(const char *file)
 853 {
 854         FILE *op;
 855 
 856         op = fopen(makepath(distpath, file, NULL), "w");
 857         if (!op)
 858                 die("cannot create file '%s'.", file);
 859         fputs_nl(gen_page_index_begin("SEARCH", jscode), op);
 860         fputs_nl(body_begin, op);
 861         fputs(makesearchpart("mains"), op);
 862         fputs_nl(body_end, op);
 863         fputs_nl(gen_page_end(), op);
 864         fclose(op);
 865         html_count++;
 866 }
 867 /**
 868  * makehtaccess: make @FILE{.htaccess} skeleton file.
 869  */
 870 static void
 871 makehtaccess(const char *cgidir, const char *file)
 872 {
 873         FILE *op;
 874 
 875         op = fopen(makepath(distpath, file, NULL), "w");
 876         if (!op)
 877                 die("cannot make .htaccess skeleton file.");
 878         fputs_nl("#", op);
 879         fputs_nl("# Skeleton file for .htaccess -- This file was generated by htags(1).", op);
 880         fputs_nl("#", op);
 881         fputs_nl("# To make this file effective, undermentioned description is necessary", op);
 882         fputs_nl("# in your system's configuration file.", op);
 883         fputs_nl("#", op);
 884         fputs_nl("# [/usr/local/apache/conf/http.conf]", op);
 885         fputs_nl("# +-------------------------------------", op);
 886         fputs_nl("# |...", op);
 887         fputs_nl("# |AllowOverride Options FileInfo", op);
 888         fputs_nl("#", op);
 889         fputs_nl("# Htags was invoked with the -f, -c or -D option.", op);
 890         fprintf(op, "# You should start http server so that %s/*.cgi is executed\n", cgidir);
 891         fputs_nl("# as a CGI script.", op);
 892         fputs_nl("#", op);
 893         fputs_nl("Options +ExecCGI", op);
 894         fputs_nl("AddHandler cgi-script .cgi", op);
 895         if (cflag) {
 896                 fputs_nl("#", op);
 897                 fputs_nl("# Htags have made gzipped html files because you specified the -c option.", op);
 898                 fputs_nl("# If your browser doesn't decompress gzipped files, you should start", op);
 899                 fputs_nl("# http server so that they are decompressed.", op);
 900                 fputs_nl("#", op);
 901                 fputs_nl("# Please rewrite appropriately the string '/cgi-bin/ghtml.cgi' below, or", op);
 902                 fputs_nl("# copy the file 'cgi-bin/ghtml.cgi' itself to the system's CGI directory.", op);
 903                 fputs_nl("#", op);
 904                 fprintf(op, "AddHandler htags-gzipped-html %s\n", gzipped_suffix);
 905                 fputs_nl("Action htags-gzipped-html /cgi-bin/ghtml.cgi", op);
 906                 fputs_nl("#                         ==================", op);
 907         }
 908         fclose(op);
 909 }
 910 /**
 911  * makehtml: make html files
 912  *
 913  *      @param[in]      total   number of files.
 914  */
 915 static void
 916 makehtml(int total)
 917 {
 918         GFIND *gp;
 919         FILE *anchor_stream;
 920         const char *path;
 921         int count = 0;
 922 
 923         /*
 924          * Create anchor stream for anchor_load().
 925          */
 926         anchor_stream = tmpfile();
 927 #if defined(_WIN32) && !defined(__CYGWIN__)
 928         /*
 929          * tmpfile is created in the root, which user's can't write on Vista+.
 930          * Use _tempnam and open it directly.
 931          */
 932         if (anchor_stream == NULL) {
 933                 char *name = _tempnam(tmpdir, "htags");
 934                 anchor_stream = fopen(name, "w+bD");
 935                 free(name);
 936         }
 937 #endif
 938         gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE);
 939         while ((path = gfind_read(gp)) != NULL) {
 940                 if (gp->type == GPATH_OTHER)
 941                         fputc(' ', anchor_stream);
 942                 fputs(path, anchor_stream);
 943                 fputc('\n', anchor_stream);
 944         }
 945         gfind_close(gp);
 946         /*
 947          * Prepare anchor stream for anchor_load().
 948          */
 949         anchor_prepare(anchor_stream);
 950         /*
 951          * For each path in GPATH, convert the path into HTML file.
 952          */
 953         gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE);
 954         while ((path = gfind_read(gp)) != NULL) {
 955                 char html[MAXPATHLEN];
 956 
 957                 if (gp->type == GPATH_OTHER && !other_files)
 958                         continue;
 959                 /*
 960                  * load tags belonging to the path.
 961                  * The path must be start "./".
 962                  */
 963                 anchor_load(path);
 964                 /*
 965                  * inform the current path name to lex() function.
 966                  */
 967                 save_current_path(path);
 968                 count++;
 969                 path += 2;              /* remove './' at the head */
 970                 message(" [%d/%d] converting %s", count, total, path);
 971                 snprintf(html, sizeof(html), "%s/%s/%s.%s", distpath, SRCS, path2fid(path), HTML);
 972                 src2html(path, html, gp->type == GPATH_OTHER);
 973         }
 974         gfind_close(gp);
 975 }
 976 /**
 977  * Load file.
 978  */
 979 void
 980 loadfile_asis(const char *file, STRBUF *result)
 981 {
 982         STRBUF *sb = strbuf_open(0);
 983         FILE *ip = fopen(file, "r");
 984         if (!ip)
 985                 die("file '%s' not found.", file);
 986         while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL)
 987                 strbuf_puts_nl(result, strbuf_value(sb));
 988         fclose(ip);
 989         strbuf_close(sb);
 990 }
 991 void
 992 loadfile(const char *file, STRBUF *result)
 993 {
 994         load_with_replace(file, result, 0);
 995 }
 996 /**
 997  * copy file.
 998  */
 999 static void
1000 copyfile(const char *from, const char *to)
1001 {
1002         int ip, op, size;
1003         char buf[8192];
1004 
1005 #ifndef O_BINARY
1006 #define O_BINARY 0
1007 #endif
1008         ip = open(from, O_RDONLY|O_BINARY);
1009         if (ip < 0)
1010                 die("cannot open input file '%s'.", from);
1011         op = open(to, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0775);
1012         if (op < 0)
1013                 die("cannot create output file '%s'.", to);
1014         while ((size = read(ip, buf, sizeof(buf))) != 0) {
1015                 if (size < 0)
1016                         die("file read error.");
1017                 if (write(op, buf, size) != size)
1018                         die("file write error.");
1019         }
1020         close(op);
1021         close(ip);
1022 }
1023 /**
1024  * makecommonpart: make a common part for @FILE{mains.html} and @FILE{index.html}
1025  *
1026  *      @param[in]      title
1027  *      @param[in]      defines
1028  *      @param[in]      files
1029  *      @return index   common part
1030  */
1031 static char *
1032 makecommonpart(const char *title, const char *defines, const char *files)
1033 {
1034         FILE *ip;
1035         STRBUF *sb = strbuf_open(0);
1036         STRBUF *ib = strbuf_open(0);
1037         char buf[MAXFILLEN];
1038         const char *tips = "Go to the GLOBAL project page.";
1039         const char *_, *item;
1040 
1041         strbuf_puts(sb, title_begin);
1042         strbuf_puts(sb, title);
1043         strbuf_puts_nl(sb, title_end);
1044         strbuf_puts_nl(sb, poweredby_begin);
1045         strbuf_sprintf(sb, "Last updated %s%s\n", now(), br);
1046         if (Iflag) {
1047                 snprintf(buf, sizeof(buf), "Powered by GLOBAL-%s.", get_version());
1048                 strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips,"_top"));
1049                 strbuf_puts(sb, gen_image(CURRENT, "pglobe", buf));
1050                 strbuf_puts(sb, gen_href_end());
1051                 strbuf_puts(sb, br);
1052         } else {
1053                 strbuf_sprintf(sb, "Powered by %sGLOBAL-%s%s.%s\n",
1054                         gen_href_begin_with_title_target(NULL, www, NULL, NULL, tips, "_top"),
1055                         get_version(),
1056                         gen_href_end(),
1057                         br);
1058         }
1059         strbuf_puts_nl(sb, poweredby_end);
1060         strbuf_puts_nl(sb, hr);
1061         /*
1062          * Print items according to the value of variable 'item_order'.
1063          */
1064         for (item = item_order; *item; item++) {
1065                 switch (*item) {
1066                 case 'c':
1067                         if (caution) {
1068                                 strbuf_puts_nl(sb, caution_begin);
1069                                 strbuf_sprintf(sb, "<font size='+2' color='red'>CAUTION</font>%s\n", br);
1070                                 strbuf_sprintf(sb, "This hypertext consist of %d files.\n", html_count);
1071                                 strbuf_puts_nl(sb, "Please don't download whole hypertext using hypertext copy tools.");
1072                                 strbuf_puts_nl(sb, "Our network cannot afford such traffic.");
1073                                 strbuf_puts_nl(sb, "Instead, you can generate same thing in your computer using");
1074                                 strbuf_puts(sb, gen_href_begin_with_title_target(NULL, www, NULL, NULL, NULL, "_top"));
1075                                 strbuf_puts(sb, "GLOBAL source code tag system");
1076                                 strbuf_puts_nl(sb, gen_href_end());
1077                                 strbuf_puts_nl(sb, "Thank you.");
1078                                 strbuf_puts_nl(sb, caution_end);
1079                                 strbuf_sprintf(sb, "\n%s\n", hr);
1080                         }
1081                         break;
1082                 case 's':
1083                         if (fflag) {
1084                                 strbuf_puts(sb, makesearchpart(NULL));
1085                                 strbuf_puts_nl(sb, hr);
1086                         }
1087                         break;
1088                 case 't':
1089                         if (call_file || callee_file) {
1090                                 strbuf_puts(sb, header_begin);
1091                                 if (call_file) {
1092                                         strbuf_puts(sb, gen_href_begin(NULL, "call", normal_suffix, NULL));
1093                                         strbuf_puts(sb, title_call_tree);
1094                                         strbuf_puts(sb, gen_href_end());
1095                                 }
1096                                 if (call_file && callee_file)
1097                                         strbuf_puts(sb, " / ");
1098                                 if (callee_file) {
1099                                         strbuf_puts(sb, gen_href_begin(NULL, "callee", normal_suffix, NULL));
1100                                         strbuf_puts(sb, title_callee_tree);
1101                                         strbuf_puts(sb, gen_href_end());
1102                                 }
1103                                 strbuf_puts_nl(sb, header_end);
1104                                 strbuf_puts_nl(sb, hr);
1105                         }
1106                         break;
1107                 case 'm':
1108                         strbuf_sprintf(sb, "%sMAINS%s\n", header_begin, header_end);
1109 
1110                         snprintf(buf, sizeof(buf), PQUOTE "%s --result=ctags-xid --encode-path=\" \t\" --nofilter=path %s" PQUOTE, quote_shell(global_path), main_func);
1111                         ip = popen(buf, "r");
1112                         if (!ip)
1113                                 die("cannot execute command '%s'.", buf);
1114                         strbuf_puts_nl(sb, gen_list_begin());
1115                         while ((_ = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) {
1116                                 char fid[MAXFIDLEN];
1117                                 const char *ctags_x = parse_xid(_, fid, NULL);
1118 
1119                                 strbuf_puts_nl(sb, gen_list_body(SRCS, ctags_x, fid));
1120                         }
1121                         strbuf_puts_nl(sb, gen_list_end());
1122                         if (pclose(ip) != 0)
1123                         die("cannot execute command '%s'.", buf);
1124                         strbuf_puts_nl(sb, hr);
1125                         break;
1126                 case 'd':
1127                         if (aflag && !Fflag) {
1128                                 strbuf_puts(sb, header_begin);
1129                                 strbuf_puts(sb, title_define_index);
1130                                 strbuf_puts_nl(sb, header_end);
1131                                 strbuf_puts(sb, defines);
1132                         } else {
1133                                 strbuf_puts(sb, header_begin);
1134                                 strbuf_puts(sb, gen_href_begin(NULL, "defines", normal_suffix, NULL));
1135                                 strbuf_puts(sb, title_define_index);
1136                                 strbuf_puts(sb, gen_href_end());
1137                                 strbuf_puts_nl(sb, header_end);
1138                         }
1139                         strbuf_puts_nl(sb, hr);
1140                         break;
1141                 case 'f':
1142                         if (Fflag) {
1143                                 strbuf_puts(sb, header_begin);
1144                                 strbuf_puts(sb, gen_href_begin(NULL, "files", normal_suffix, NULL));
1145                                 strbuf_puts(sb, title_file_index);
1146                                 strbuf_puts(sb, gen_href_end());
1147                                 strbuf_puts_nl(sb, header_end);
1148                         } else {
1149                                 strbuf_puts(sb, header_begin);
1150                                 strbuf_puts(sb, title_file_index);
1151                                 strbuf_puts_nl(sb, header_end);
1152                                 if (tree_view) {
1153                                         strbuf_puts_nl(sb, tree_control);
1154                                         strbuf_puts_nl(sb, tree_begin);
1155                                 } else if (table_flist)
1156                                         strbuf_puts_nl(sb, flist_begin);
1157                                 else if (!no_order_list)
1158                                         strbuf_puts_nl(sb, list_begin);
1159                                 strbuf_puts(sb, files);
1160                                 if (tree_view)
1161                                         strbuf_puts_nl(sb, tree_end);
1162                                 else if (table_flist)
1163                                         strbuf_puts_nl(sb, flist_end);
1164                                 else if (!no_order_list)
1165                                         strbuf_puts_nl(sb, list_end);
1166                                 else
1167                                         strbuf_puts_nl(sb, br);
1168                         }
1169                         strbuf_puts_nl(sb, hr);
1170                         break;
1171                 default:
1172                         warning("unknown item '%c'. (Ignored)", *item);
1173                         break;
1174                 }
1175         }
1176         strbuf_close(ib);
1177 
1178         return strbuf_value(sb);
1179         /* doesn't close string buffer */
1180 }
1181 /**
1182  * basic check.
1183  */
1184 static void
1185 basic_check(void)
1186 {
1187         const char *p;
1188 
1189         /*
1190          * COMMAND EXISTENCE CHECK
1191          */
1192         if (!(p = usable("gtags")))
1193                 die("gtags command required but not found.");
1194         strlimcpy(gtags_path, p, sizeof(gtags_path));
1195         if (!(p = usable("global")))
1196                 die("global command required but not found.");
1197         strlimcpy(global_path, p, sizeof(global_path));
1198         /*
1199          * Temporary directory.
1200          */
1201         if ((p = getenv("TMPDIR")) == NULL)
1202                 p = getenv("TMP");
1203         if (p != NULL && test("d", p))
1204                 tmpdir = p;
1205 }
1206 /**
1207  * load configuration variables.
1208  */
1209 static void
1210 configuration(int argc, char *const *argv)
1211 {
1212         STRBUF *sb = strbuf_open(0);
1213         int i, n;
1214         char *p, *q;
1215 
1216         /*
1217          * Setup the GTAGSCONF and the GTAGSLABEL environment variable
1218          * according to the --gtagsconf and --gtagslabel option.
1219          */
1220         {
1221                 char *confpath = NULL;
1222                 char *label = NULL;
1223                 char *opt_gtagsconf = "--gtagsconf";
1224                 char *opt_gtagslabel = "--gtagslabel";
1225 
1226                 for (i = 1; i < argc; i++) {
1227                         if ((p = locatestring(argv[i], opt_gtagsconf, MATCH_AT_FIRST))) {
1228                                 if (*p == '\0') {
1229                                         if (++i >= argc)
1230                                                 die("%s needs an argument.", opt_gtagsconf);
1231                                         confpath = argv[i];
1232                                 } else {
1233                                         if (*p++ == '=' && *p)
1234                                                 confpath = p;
1235                                 }
1236                         } else if ((p = locatestring(argv[i], opt_gtagslabel, MATCH_AT_FIRST))) {
1237                                 if (*p == '\0') {
1238                                         if (++i >= argc)
1239                                                 die("%s needs an argument.", opt_gtagslabel);
1240                                         label = argv[i];
1241                                 } else {
1242                                         if (*p++ == '=' && *p)
1243                                                 label = p;
1244                                 }
1245                         }
1246                 }
1247                 if (confpath) {
1248                         char real[MAXPATHLEN];
1249 
1250                         if (!test("f", confpath))
1251                                 die("%s file not found.", opt_gtagsconf);
1252                         if (!realpath(confpath, real))
1253                                 die("cannot get absolute path of %s file.", opt_gtagsconf);
1254                         set_env("GTAGSCONF", real);
1255                 }
1256                 if (label)
1257                         set_env("GTAGSLABEL", label);
1258         }
1259         /*
1260          * Config variables.
1261          */
1262         strbuf_reset(sb);
1263         if (!getconfs("datadir", sb))
1264                 die("cannot get datadir directory name.");
1265         strlimcpy(datadir, strbuf_value(sb), sizeof(datadir));
1266         strbuf_reset(sb);
1267         if (!getconfs("localstatedir", sb))
1268                 die("cannot get localstatedir directory name.");
1269         strlimcpy(localstatedir, strbuf_value(sb), sizeof(localstatedir));
1270         if (getconfn("ncol", &n)) {
1271                 if (n < 1 || n > 10)
1272                         warning("parameter 'ncol' ignored because the value (=%d) is too large or too small.", n);
1273                 else
1274                         ncol = n;
1275         }
1276         if (getconfn("tabs", &n)) {
1277                 if (n < 1 || n > 32)
1278                         warning("parameter 'tabs' ignored because the value (=%d) is too large or too small.", n);
1279                 else
1280                         tabs = n;
1281         }
1282         strbuf_reset(sb);
1283         if (getconfs("gzipped_suffix", sb))
1284                 gzipped_suffix = check_strdup(strbuf_value(sb));
1285         strbuf_reset(sb);
1286         if (getconfs("normal_suffix", sb))
1287                 normal_suffix = check_strdup(strbuf_value(sb));
1288         if (getconfb("no_order_list"))
1289                 no_order_list = 1;
1290         strbuf_reset(sb);
1291         if (getconfs("prolog_script", sb))
1292                 prolog_script = check_strdup(strbuf_value(sb));
1293         strbuf_reset(sb);
1294         if (getconfs("epilog_script", sb))
1295                 epilog_script = check_strdup(strbuf_value(sb));
1296         if (getconfb("colorize_warned_line"))
1297                 colorize_warned_line = 1;
1298         strbuf_reset(sb);
1299         if (getconfs("script_alias", sb)) {
1300                 p = check_strdup(strbuf_value(sb));
1301                 /* remove the last '/' */
1302                 q = p + strlen(p) - 1;
1303                 if (*q == '/')
1304                         *q = '\0';
1305                 script_alias = p;
1306         }
1307         strbuf_reset(sb);
1308         if (getconfs("body_begin", sb)) {
1309                 p = check_strdup(strbuf_value(sb));
1310                 strbuf_reset(sb);
1311                 if (getconfs("body_end", sb)) {
1312                         q = check_strdup(strbuf_value(sb));
1313                         body_begin = p;
1314                         body_end = q;
1315                 } else {
1316                         free(p);
1317                 }
1318         }
1319         strbuf_reset(sb);
1320         if (getconfs("table_begin", sb)) {
1321                 p = check_strdup(strbuf_value(sb));
1322                 strbuf_reset(sb);
1323                 if (getconfs("table_end", sb)) {
1324                         q = check_strdup(strbuf_value(sb));
1325                         table_begin = p;
1326                         table_end = q;
1327                 } else {
1328                         free(p);
1329                 }
1330         }
1331         strbuf_reset(sb);
1332         if (getconfs("title_begin", sb)) {
1333                 p = check_strdup(strbuf_value(sb));
1334                 strbuf_reset(sb);
1335                 if (getconfs("title_end", sb)) {
1336                         q = check_strdup(strbuf_value(sb));
1337                         title_begin = p;
1338                         title_end = q;
1339                 } else {
1340                         free(p);
1341                 }
1342         }
1343         strbuf_reset(sb);
1344         if (getconfs("comment_begin", sb)) {
1345                 p = check_strdup(strbuf_value(sb));
1346                 strbuf_reset(sb);
1347                 if (getconfs("comment_end", sb)) {
1348                         q = check_strdup(strbuf_value(sb));
1349                         comment_begin = p;
1350                         comment_end = q;
1351                 } else {
1352                         free(p);
1353                 }
1354         }
1355         strbuf_reset(sb);
1356         if (getconfs("sharp_begin", sb)) {
1357                 p = check_strdup(strbuf_value(sb));
1358                 strbuf_reset(sb);
1359                 if (getconfs("sharp_end", sb)) {
1360                         q = check_strdup(strbuf_value(sb));
1361                         sharp_begin = p;
1362                         sharp_end = q;
1363                 } else {
1364                         free(p);
1365                 }
1366         }
1367         strbuf_reset(sb);
1368         if (getconfs("brace_begin", sb)) {
1369                 p = check_strdup(strbuf_value(sb));
1370                 strbuf_reset(sb);
1371                 if (getconfs("brace_end", sb)) {
1372                         q = check_strdup(strbuf_value(sb));
1373                         brace_begin = p;
1374                         brace_end = q;
1375                 } else {
1376                         free(p);
1377                 }
1378         }
1379         strbuf_reset(sb);
1380         if (getconfs("reserved_begin", sb)) {
1381                 p = check_strdup(strbuf_value(sb));
1382                 strbuf_reset(sb);
1383                 if (getconfs("reserved_end", sb)) {
1384                         q = check_strdup(strbuf_value(sb));
1385                         reserved_begin = p;
1386                         reserved_end = q;
1387                 } else {
1388                         free(p);
1389                 }
1390         }
1391         strbuf_reset(sb);
1392         if (getconfs("position_begin", sb)) {
1393                 p = check_strdup(strbuf_value(sb));
1394                 strbuf_reset(sb);
1395                 if (getconfs("position_end", sb)) {
1396                         q = check_strdup(strbuf_value(sb));
1397                         position_begin = p;
1398                         position_end = q;
1399                 } else {
1400                         free(p);
1401                 }
1402         }
1403         strbuf_reset(sb);
1404         if (getconfs("warned_line_begin", sb)) {
1405                 p = check_strdup(strbuf_value(sb));
1406                 strbuf_reset(sb);
1407                 if (getconfs("warned_line_end", sb)) {
1408                         q = check_strdup(strbuf_value(sb));
1409                         warned_line_begin = p;
1410                         warned_line_end = q;
1411                 } else {
1412                         free(p);
1413                 }
1414         }
1415         strbuf_reset(sb);
1416         if (getconfs("include_file_suffixes", sb))
1417                 include_file_suffixes = check_strdup(strbuf_value(sb));
1418         strbuf_reset(sb);
1419         if (getconfs("langmap", sb))
1420                 langmap = check_strdup(strbuf_value(sb));
1421         strbuf_reset(sb);
1422         if (getconfs("xhtml_version", sb))
1423                 xhtml_version = check_strdup(strbuf_value(sb));
1424         /* insert htags_options into the head of ARGSV array. */
1425         strbuf_reset(sb);
1426         if (getconfs("htags_options", sb))
1427                 htags_options = check_strdup(strbuf_value(sb));
1428         strbuf_close(sb);
1429 }
1430 /**
1431  * save_environment: save configuration data and arguments.
1432  */
1433 static void
1434 save_environment(int argc, char *const *argv)
1435 {
1436         char command[MAXFILLEN];
1437         STRBUF *sb = strbuf_open(0);
1438         STRBUF *save_c = strbuf_open(0);
1439         STRBUF *save_a = strbuf_open(0);
1440         int i;
1441         const char *p;
1442         FILE *ip;
1443 
1444         /*
1445          * save config values.
1446          */
1447         snprintf(command, sizeof(command), PQUOTE "%s --config" PQUOTE, quote_shell(gtags_path));
1448         if ((ip = popen(command, "r")) == NULL)
1449                 die("cannot execute '%s'.", command);
1450         while (strbuf_fgets(sb, ip, STRBUF_NOCRLF) != NULL) {
1451                 for (p = strbuf_value(sb); *p; p++) {
1452                         if (*p == '\'') {
1453                                 strbuf_putc(save_c, '\'');
1454                                 strbuf_putc(save_c, '"');
1455                                 strbuf_putc(save_c, '\'');
1456                                 strbuf_putc(save_c, '"');
1457                                 strbuf_putc(save_c, '\'');
1458                         } else
1459                                 strbuf_putc(save_c, *p);
1460                 }
1461         }
1462         if (pclose(ip) != 0)
1463                 die("cannot execute '%s'.", command);
1464         strbuf_close(sb);
1465         save_config = strbuf_value(save_c);
1466         /* doesn't close string buffer for save config. */
1467         /* strbuf_close(save_c); */
1468 
1469         /*
1470          * save arguments.
1471          */
1472         {
1473                 char *opt_gtagsconf = "--gtagsconf";
1474 
1475                 for (i = 1; i < argc; i++) {
1476                         char *blank;
1477 
1478                         /*
1479                          * skip --gtagsconf because it is already read
1480                          * as config value.
1481                          */
1482                         if ((p = locatestring(argv[i], opt_gtagsconf, MATCH_AT_FIRST))) {
1483                                 if (*p == '\0')
1484                                         i++;
1485                                 continue;
1486                         }
1487                         blank = locatestring(argv[i], " ", MATCH_FIRST);
1488                         strbuf_putc(save_a, ' ');
1489                         if (blank)
1490                                 strbuf_putc(save_a, '\'');
1491                         strbuf_puts(save_a, argv[i]);
1492                         if (blank)
1493                                 strbuf_putc(save_a, '\'');
1494                 }
1495         }
1496         save_argv = strbuf_value(save_a);
1497         /* doesn't close string buffer for save arguments. */
1498         /* strbuf_close(save_a); */
1499 }
1500 
1501 char **
1502 append_options(int *argc, char *const *argv)
1503 {
1504 
1505         STRBUF *sb = strbuf_open(0);
1506         const char *p, *opt = check_strdup(htags_options);
1507         int count = 1;
1508         int quote = 0;
1509         const char **newargv;
1510         int i = 0, j = 1;
1511 
1512         if (!opt)
1513                 die("Short of memory.");
1514         for (p = opt; *p && isspace(*p); p++)
1515                 ;
1516         for (; *p; p++) {
1517                 int c = *p;
1518 
1519                 if (quote) {
1520                         if (quote == c)
1521                                 quote = 0;
1522                         else
1523                                 strbuf_putc(sb, c);
1524                 } else if (c == '\\') {
1525                         strbuf_putc(sb, c);
1526                 } else if (c == '\'' || c == '"') {
1527                         quote = c;
1528                 } else if (isspace(c)) {
1529                         strbuf_putc(sb, '\0');
1530                         count++;
1531                         while (*p && isspace(*p))
1532                                 p++;
1533                         p--;
1534                 } else {
1535                         strbuf_putc(sb, *p);
1536                 }
1537         }
1538         newargv = (const char **)check_malloc(sizeof(char *) * (*argc + count + 1));
1539         newargv[i++] = argv[0];
1540         p = strbuf_value(sb);
1541         while (count--) {
1542                 newargv[i++] = p;
1543                 p += strlen(p) + 1;
1544         }
1545         while (j < *argc)
1546                 newargv[i++] = argv[j++];
1547         newargv[i] = NULL;
1548         *argc = i;
1549 #ifdef DEBUG
1550         for (i = 0; i < *argc; i++)
1551                 fprintf(stderr, "newargv[%d] = '%s'\n", i, newargv[i]);
1552 #endif
1553         /* doesn't close string buffer. */
1554 
1555         return (char **)newargv;
1556 }
1557 int
1558 main(int argc, char **argv)
1559 {
1560         const char *av = NULL;
1561         int func_total, file_total;
1562         char arg_dbpath[MAXPATHLEN];
1563         const char *index = NULL;
1564         int optchar;
1565         int option_index = 0;
1566         STATISTICS_TIME *tim;
1567 
1568         arg_dbpath[0] = 0;
1569         basic_check();
1570         configuration(argc, argv);
1571         setup_langmap(langmap);
1572         save_environment(argc, argv);
1573 
1574         /*
1575          * insert htags_options at the head of argv.
1576          */
1577         if (htags_options)
1578                 argv = append_options(&argc, argv);
1579 
1580         while ((optchar = getopt_long(argc, argv, "acd:DfFghIm:noqst:Tvwx", long_options, &option_index)) != EOF) {
1581                 switch (optchar) {
1582                 case 0:
1583                         /* already flags set */
1584                         break;
1585                 case OPT_AUTO_COMPLETION:
1586                         auto_completion = 1;
1587                         if (optarg) {
1588                                 if (atoi(optarg) > 0)
1589                                         auto_completion_limit = optarg;
1590                                 else
1591                                         die("The option value of --auto-completion must be numeric.");
1592                         }
1593                         break;
1594                 case OPT_CFLOW:
1595                         call_file = optarg;
1596                         break;
1597                 case OPT_CALL_TREE:
1598                         call_file = optarg;
1599                         break;
1600                 case OPT_CALLEE_TREE:
1601                         callee_file = optarg;
1602                         break;
1603                 case OPT_CVSWEB:
1604                         cvsweb_url = optarg;
1605                         break;
1606                 case OPT_CVSWEB_CVSROOT:
1607                         cvsweb_cvsroot = optarg;
1608                         break;
1609                 case OPT_GTAGSCONF:     /* --gtagsconf is estimated only once. */
1610                 case OPT_GTAGSLABEL:    /* --gtagslabel is estimated only once. */
1611                         break;
1612                 case OPT_INSERT_FOOTER:
1613                         insert_footer = optarg;
1614                         break;
1615                 case OPT_INSERT_HEADER:
1616                         insert_header = optarg;
1617                         break;
1618                 case OPT_HTML_HEADER:
1619                         {
1620                                 STATIC_STRBUF(sb);
1621                                 if (!test("r", optarg))
1622                                         die("file '%s' not found.", optarg);
1623                                 loadfile_asis(optarg, sb);
1624                                 html_header = strbuf_value(sb);
1625                         }
1626                         break;
1627                 case OPT_ITEM_ORDER:
1628                         item_order = optarg;
1629                         break;
1630                 case OPT_TABS:
1631                         if (atoi(optarg) > 0)
1632                                 tabs = atoi(optarg);
1633                         else
1634                                 die("--tabs option requires numeric value.");
1635                         break;
1636                 case OPT_NCOL:
1637                         if (atoi(optarg) > 0)
1638                                 ncol = atoi(optarg);
1639                         else
1640                                 die("--ncol option requires numeric value.");
1641                         break;
1642                 case OPT_TREE_VIEW:
1643                         tree_view = 1;
1644                         if (optarg)
1645                                 tree_view_type = optarg;
1646                         break;
1647                 case 'a':
1648                         aflag++;
1649                         break;
1650                 case 'c':
1651                         cflag++;
1652                         break;
1653                 case 'd':
1654                         strlimcpy(arg_dbpath, optarg, sizeof(arg_dbpath));
1655                         break;
1656                 case 'D':
1657                         dynamic = 1;
1658                         break;
1659                 case 'f':
1660                         fflag++;
1661                         break;
1662                 case 'F':
1663                         Fflag++;
1664                         break;
1665                 case 'g':
1666                         gflag++;
1667                         break;
1668                 case 'h':
1669                         definition_header = AFTER_HEADER;
1670                         if (optarg) {
1671                                 if (!strcmp(optarg, "before"))
1672                                         definition_header = BEFORE_HEADER;
1673                                 else if (!strcmp(optarg, "right"))
1674                                         definition_header = RIGHT_HEADER;
1675                                 else if (!strcmp(optarg, "after"))
1676                                         definition_header = AFTER_HEADER;
1677                                 else
1678                                         die("The option value of --func-header must be one of 'before', 'right' and 'after'.");
1679                         }
1680                         break;
1681                 case 'I':
1682                         Iflag++;
1683                         break;
1684                 case 'm':
1685                         main_func = optarg;
1686                         break;
1687                 case 'n':
1688                         nflag++;
1689                         if (optarg) {
1690                                 if (atoi(optarg) > 0)
1691                                         ncol = atoi(optarg);
1692                                 else
1693                                         die("The option value of --line-number must be numeric.");
1694                         }
1695                         break;
1696                 case 'o':
1697                         other_files = 1;
1698                         break;
1699                 case 's':
1700                         symbol = 1;
1701                         break;
1702                 case 'S':
1703                         Sflag++;
1704                         sitekey = optarg;
1705                         break;
1706                 case 'T':
1707                         table_flist = 1;
1708                         if (optarg) {
1709                                 if (atoi(optarg) > 0)
1710                                         flist_fields = atoi(optarg);
1711                                 else
1712                                         die("The option value of the --table-flist must be numeric.");
1713                         }
1714                         break;
1715                 case 't':
1716                         title = optarg;
1717                         break;
1718                 case 'q':
1719                         qflag++;
1720                         setquiet();
1721                         break;
1722                 case 'v':
1723                         vflag++;
1724                         setverbose();
1725                         break;
1726                 case 'w':
1727                         wflag++;
1728                         break;
1729                 case 'x':
1730                         enable_xhtml = 1;
1731                         if (optarg) {
1732                                 if (!strcmp("1.0", optarg) || !strcmp("1.1", optarg))
1733                                         xhtml_version = optarg;
1734                                 else
1735                                         die("The option value of the --xhtml must be '1.0' or '1.1'.");
1736                         }
1737                         break;
1738                 default:
1739                         usage();
1740                         break;
1741                 }
1742         }
1743         /*
1744          * Leaving everything to htags.
1745          * Htags selects popular options for you.
1746          */
1747         if (suggest2)
1748                 suggest = 1;
1749         if (suggest) {
1750                 int gtags_not_found = 0;
1751 
1752                 aflag = Iflag = nflag = vflag = 1;
1753                 setverbose();
1754                 definition_header = AFTER_HEADER;
1755                 other_files = symbol = show_position = table_flist = fixed_guide = 1;
1756                 if (arg_dbpath[0]) {
1757                         if (!test("f", makepath(arg_dbpath, dbname(GTAGS), NULL)))
1758                                 gtags_not_found = 1;
1759                 } else {
1760                         if (!test("f", dbname(GTAGS)))
1761                                 gtags_not_found = 1;
1762                 }
1763                 if (gtags_not_found)
1764                         gflag = 1;
1765         }
1766         if (suggest2) {
1767                 Fflag = 1;                              /* uses frame */
1768                 fflag = dynamic = 1;                    /* needs a HTTP server */
1769                 auto_completion = tree_view = 1;        /* needs javascript */
1770         }
1771         if (strchr(sitekey, '.') || strchr(sitekey, '/'))
1772                 die("site key must not include '.' and '/'.");
1773         if (!enable_xhtml && (tree_view || auto_completion || fixed_guide))
1774                 die("The --html option cannot accept the --tree-view, --auto-completion and --fixed-guide option.");
1775         if (call_file && !test("fr", call_file))
1776                 die("cflow file not found. '%s'", call_file);
1777         if (callee_file && !test("fr", callee_file))
1778                 die("cflow file not found. '%s'", callee_file);
1779         if (insert_header && !test("fr", insert_header))
1780                 die("page header file '%s' not found.", insert_header);
1781         if (insert_footer && !test("fr", insert_footer))
1782                 die("page footer file '%s' not found.", insert_footer);
1783         if (!fflag)
1784                 auto_completion = 0;
1785         argc -= optind;
1786         argv += optind;
1787         if (!av)
1788                 av = (argc > 0) ? *argv : NULL;
1789 
1790         if (debug)
1791                 setdebug();
1792         settabs(tabs);                                  /* setup tab skip */
1793         if (qflag) {
1794                 setquiet();
1795                 vflag = 0;
1796         }
1797         if (!cflag && !fflag && !dynamic)
1798                 Sflag = 0;
1799         if (enable_xhtml)
1800                 setup_xhtml();
1801         if (show_version)
1802                 version(av, vflag);
1803         if (show_help)
1804                 help();
1805         /*
1806          * Invokes gtags beforehand.
1807          */
1808         if (gflag) {
1809                 STRBUF *sb = strbuf_open(0);
1810 
1811                 strbuf_puts(sb, gtags_path);
1812                 if (vflag)
1813                         strbuf_puts(sb, " -v");
1814                 if (wflag)
1815                         strbuf_puts(sb, " -w");
1816                 if (suggest2 && enable_idutils && usable("mkid"))
1817                         strbuf_puts(sb, " -I");
1818                 if (arg_dbpath[0]) {
1819                         strbuf_putc(sb, ' ');
1820                         strbuf_puts(sb, arg_dbpath);
1821                 }
1822                 if (system(strbuf_value(sb)))
1823                         die("cannot execute gtags(1) command.");
1824                 strbuf_close(sb);
1825         }
1826         /*
1827          * get dbpath.
1828          */
1829         if (!getcwd(cwdpath, sizeof(cwdpath)))
1830                 die("cannot get current directory.");
1831         if (arg_dbpath[0]) {
1832                 strlimcpy(dbpath, arg_dbpath, sizeof(dbpath));
1833                 set_env("GTAGSROOT", cwdpath);
1834                 set_env("GTAGSDBPATH", dbpath);
1835         } else
1836                 strlimcpy(dbpath, cwdpath, sizeof(dbpath));
1837         {
1838                 int status = setupdbpath(0);                    /* for parsers */
1839                 if (status < 0)
1840                         die_with_code(-status, gtags_dbpath_error);
1841         }
1842         if (cflag && !usable("gzip")) {
1843                 warning("'gzip' command not found. -c option ignored.");
1844                 cflag = 0;
1845         }
1846         if (!title) {
1847                 char *p = strrchr(cwdpath, sep);
1848                 title = p ? p + 1 : cwdpath;
1849         }
1850         if (cvsweb_url && test("d", "CVS"))
1851                 use_cvs_module = 1;
1852         /*
1853          * decide directory in which we make hypertext.
1854          */
1855         if (av) {
1856                 char realpath[MAXPATHLEN];
1857 
1858                 if (!test("dw", av))
1859                         die("'%s' is not writable directory.", av);
1860                 if (chdir(av) < 0)
1861                         die("directory '%s' not found.", av);
1862                 if (!getcwd(realpath, sizeof(realpath)))
1863                         die("cannot get current directory");
1864                 if (chdir(cwdpath) < 0)
1865                         die("cannot return to original directory.");
1866                 snprintf(distpath, sizeof(distpath), "%s/HTML", realpath);
1867         } else {
1868                 snprintf(distpath, sizeof(distpath), "%s/HTML", cwdpath);
1869         }
1870         /*
1871          * Site key management for center CGI.
1872          */
1873         if (Sflag) {
1874                 STRBUF *sb = strbuf_open(0);
1875                 static char saction[MAXBUFLEN];
1876                 static char completion_saction[MAXBUFLEN];
1877                 char path[MAXBUFLEN];
1878                 int try_writing = 0;
1879 
1880                 snprintf(saction, sizeof(saction), "%s/global.cgi", script_alias);
1881                 action = saction;
1882                 snprintf(completion_saction, sizeof(completion_saction), "%s/completion.cgi", script_alias);
1883                 completion_action = completion_saction;
1884                 snprintf(path, sizeof(path), "%s/gtags/%s", localstatedir, SITEKEYDIRNAME);
1885                 if (!test("d", path)) {
1886                         setverbose();
1887                         message("htags: directory '%s' not found.", path);
1888                         message("\n[Information]\n");
1889                         message("It seems that GLOBAL is not install correctly. Please reinstall.");
1890                         exit(0);
1891                 }
1892                 /*
1893                  * Load the sitekey if it exists.
1894                  */
1895                 snprintf(path, sizeof(path), "%s/gtags/%s/%s", localstatedir, SITEKEYDIRNAME, sitekey);
1896                 if (test("f", path)) {
1897                         FILE *ip = fopen(path, "r");
1898 
1899                         if (ip == NULL)
1900                                 die("cannot open file '%s'.", path);
1901                         strbuf_fgets(sb, ip, STRBUF_NOCRLF);
1902                         fclose(ip);
1903                 }
1904                 if (!test("f", path))
1905                         try_writing = 1;
1906                 else if (!strcmp(distpath, strbuf_value(sb)))
1907                         ; /* nothing to do */
1908                 else if (overwrite_key == 0)
1909                         die("The site key '%s' is not unique, please change it or use --overwrite-key option.", sitekey);
1910                 else    /* New key value without --overwrite-key option */
1911                         try_writing = 1;
1912                 /*
1913                  * In almost case, the following procedures are done
1914                  * using bless.sh script by the root user.
1915                  */
1916                 if (try_writing) {
1917                         FILE *op = fopen(path, "w");
1918                         
1919                         if (op == NULL)
1920                                 need_bless = 1;
1921                         else {
1922                                 fprintf(op, "%s\n", distpath);
1923                                 fclose(op);
1924                                 if (chmod(path, 0644) < 0)
1925                                         die("cannot chmod file '%s'(errno = %d).", path, errno);
1926                         }
1927                 }
1928                 strbuf_close(sb);
1929         }
1930         /*
1931          * Existence check of tag files.
1932          */
1933         {
1934                 int i;
1935                 const char *path;
1936                 GTOP *gtop;
1937 
1938                 for (i = GPATH; i < GTAGLIM; i++) {
1939                         path = makepath(dbpath, dbname(i), NULL);
1940                         gtags_exist[i] = test("fr", path);
1941                 }
1942                 /*
1943                  * Real GRTAGS includes virtual GSYMS.
1944                  */
1945                 gtags_exist[GSYMS] = symbol ? 1 : 0;
1946                 if (!gtags_exist[GPATH] || !gtags_exist[GTAGS] || !gtags_exist[GRTAGS])
1947                         die("GPATH, GTAGS and/or GRTAGS not found. Please reexecute htags with the -g option.");
1948                 /*
1949                  * version check.
1950                  * Do nothing, but the version of tag file will be checked.
1951                  */
1952                 gtop = gtags_open(dbpath, cwdpath, GTAGS, GTAGS_READ, 0);
1953                 gtags_close(gtop);
1954                 /*
1955                  * Check whether GRTAGS is empty.
1956                  */
1957                 gtop = gtags_open(dbpath, cwdpath, GRTAGS, GTAGS_READ, 0);
1958                 if (gtags_first(gtop, NULL, 0) == NULL)
1959                         grtags_is_empty = 1;
1960                 gtags_close(gtop);
1961         }
1962         /*
1963          * make dbpath absolute.
1964          */
1965         {
1966                 char buf[MAXPATHLEN];
1967                 if (realpath(dbpath, buf) == NULL)
1968                         die("cannot get realpath of dbpath.");
1969                 strlimcpy(dbpath, buf, sizeof(dbpath));
1970         }
1971         /*
1972          * The older version (4.8.7 or former) of GPATH doesn't have files
1973          * other than source file. The oflag requires new version of GPATH.
1974          */
1975         if (other_files) {
1976                 GFIND *gp = gfind_open(dbpath, NULL, 0);
1977                 if (gp->version < 2)
1978                         die("GPATH is old format. Please remake it by invoking gtags(1).");
1979                 gfind_close(gp);
1980         }
1981         /*
1982          * for global(1) and gtags(1).
1983          */
1984         set_env("GTAGSROOT", cwdpath);
1985         set_env("GTAGSDBPATH", dbpath);
1986         set_env("GTAGSLIBPATH", "");
1987         /*------------------------------------------------------------------
1988          * MAKE FILES
1989          *------------------------------------------------------------------
1990          *       HTML/cgi-bin/global.cgi ... CGI program (1)
1991          *       HTML/cgi-bin/ghtml.cgi  ... unzip script (1)
1992          *       HTML/.htaccess          ... skeleton of .htaccess (1)
1993          *       HTML/help.html          ... help file (2)
1994          *       HTML/R/                 ... references (3)
1995          *       HTML/D/                 ... definitions (3)
1996          *       HTML/search.html        ... search index (4)
1997          *       HTML/defines.html       ... definitions index (5)
1998          *       HTML/defines/           ... definitions index (5)
1999          *       HTML/files/             ... file index (6)
2000          *       HTML/index.html         ... index file (7)
2001          *       HTML/mains.html         ... main index (8)
2002          *       HTML/null.html          ... main null html (8)
2003          *       HTML/S/                 ... source files (9)
2004          *       HTML/I/                 ... include file index (9)
2005          *       HTML/rebuild.sh         ... rebuild script (10)
2006          *       HTML/style.css          ... style sheet (11)
2007          *------------------------------------------------------------------
2008          */
2009         /* for clean up */
2010         signal_setup();
2011         sethandler(clean);
2012 
2013         HTML = (cflag) ? gzipped_suffix : normal_suffix;
2014 
2015         message("[%s] Htags started", now());
2016         init_statistics();
2017         /*
2018          * (#) check if GTAGS, GRTAGS is the latest.
2019          */
2020         if (get_dbpath())
2021                 message(" Using %s/GTAGS.", get_dbpath());
2022         if (grtags_is_empty)
2023                 message(" GRTAGS is empty.");
2024         if (gpath_open(get_dbpath(), 0) < 0)
2025                 die("GPATH not found.");
2026         if (!w32) {
2027                 /* UNDER CONSTRUCTION */
2028         }
2029         if (auto_completion || tree_view) {
2030                 STATIC_STRBUF(sb);
2031                 strbuf_clear(sb);
2032                 strbuf_puts_nl(sb, "<script type='text/javascript' src='js/jquery.js'></script>");
2033                 if (auto_completion)
2034                         loadfile("jscode_suggest", sb);
2035                 if (tree_view)
2036                         loadfile("jscode_treeview", sb);
2037                 jscode = strbuf_value(sb);
2038         }
2039         /*
2040          * (0) make directories
2041          */
2042         message("[%s] (0) making directories ...", now());
2043         if (!test("d", distpath))
2044                 if (mkdir(distpath, 0777) < 0)
2045                         die("cannot make directory '%s'.", distpath);
2046         make_directory_in_distpath("files");
2047         make_directory_in_distpath("defines");
2048         make_directory_in_distpath(SRCS);
2049         make_directory_in_distpath(INCS);
2050         make_directory_in_distpath(INCREFS);
2051         /*
2052          * 'sitekey' file will be removed in near future, because it is not used.
2053          */
2054         make_file_in_distpath("sitekey", sitekey);
2055         if (!dynamic) {
2056                 make_directory_in_distpath(DEFS);
2057                 make_directory_in_distpath(REFS);
2058                 if (symbol)
2059                         make_directory_in_distpath(SYMS);
2060         }
2061         if (fflag || cflag || dynamic)
2062                 make_directory_in_distpath("cgi-bin");
2063         if (Iflag)
2064                 make_directory_in_distpath("icons");
2065         if (auto_completion || tree_view)
2066                  make_directory_in_distpath("js");
2067         /*
2068          * (1) make CGI program
2069          */
2070         if (fflag || cflag || dynamic) {
2071                 char cgidir[MAXPATHLEN];
2072                 int perm;
2073 
2074                 snprintf(cgidir, sizeof(cgidir), "%s/cgi-bin", distpath);
2075                 message("[%s] (1) making CGI program ...", now());
2076                 /*
2077                  * If the Sflag is specified, CGI script is invalidated.
2078                  */
2079                 perm = Sflag ? 0644 : 0755;
2080                 if (fflag || dynamic) {
2081                         makeprogram(cgidir, "global.cgi");
2082                         if (chmod(makepath(cgidir, "global.cgi", NULL), perm) < 0)
2083                                 die("cannot chmod CGI program.");
2084                 }
2085                 if (auto_completion) {
2086                         makeprogram(cgidir, "completion.cgi");
2087                         if (chmod(makepath(cgidir, "completion.cgi", NULL), perm) < 0)
2088                                 die("cannot chmod CGI program.");
2089                 }
2090                 if (cflag) {
2091                         makeghtml(cgidir, "ghtml.cgi");
2092                         if (chmod(makepath(cgidir, "ghtml.cgi", NULL), perm) < 0)
2093                                 die("cannot chmod unzip script.");
2094                 }
2095                 makehtaccess(cgidir, ".htaccess");
2096                 if (chmod(makepath(distpath, ".htaccess", NULL), 0644) < 0)
2097                         die("cannot chmod .htaccess skeleton.");
2098                 /*
2099                  * Don't grant execute permission to bless script.
2100                  */
2101                 if (Sflag) {
2102                         makebless("bless.sh");
2103                         if (chmod(makepath(distpath, "bless.sh", NULL), 0640) < 0)
2104                                 die("cannot chmod bless script.");
2105                 }
2106         } else {
2107                 message("[%s] (1) making CGI program ...(skipped)", now());
2108         }
2109         /*
2110          * Save the suffix of compress format for the safe CGI script.
2111          */
2112         {
2113                 const char *path = makepath(distpath, "compress", NULL);
2114                 FILE *op = fopen(path, "w");
2115                 if (op == NULL)
2116                         die("cannot make file '%s'.", path);
2117                 if (cflag) {
2118                         fputs(HTML, op);
2119                         fputc('\n', op);
2120                 }
2121                 fclose(op);
2122         }
2123         if (av) {
2124                 const char *path = makepath(distpath, "GTAGSROOT", NULL);
2125                 FILE *op = fopen(path, "w");
2126                 if (op == NULL)
2127                         die("cannot make file '%s'.", path);
2128                 fputs(cwdpath, op);
2129                 fputc('\n', op);
2130                 fclose(op);
2131         }
2132         /*
2133          * (2) make help file
2134          */
2135         message("[%s] (2) making help.html ...", now());
2136         makehelp("help.html");
2137         /*
2138          * (#) load GPATH
2139          */
2140         load_gpath(dbpath);
2141 
2142         /*
2143          * (3) make function entries (D/ and R/)
2144          *     MAKING TAG CACHE
2145          */
2146         message("[%s] (3) making tag lists ...", now());
2147         cache_open();
2148         tim = statistics_time_start("Time of making tag lists");
2149         func_total = makedupindex();
2150         statistics_time_end(tim);
2151         message("Total %d functions.", func_total);
2152         /*
2153          * (4) search index. (search.html)
2154          */
2155         if (Fflag && fflag) {
2156                 message("[%s] (4) making search index ...", now());
2157                 makesearchindex("search.html");
2158         }
2159         {
2160                 STRBUF *defines = strbuf_open(0);
2161                 STRBUF *files = strbuf_open(0);
2162 
2163                 /*
2164                  * (5) make definition index (defines.html and defines/)
2165                  *     PRODUCE @defines
2166                  */
2167                 message("[%s] (5) making definition index ...", now());
2168                 tim = statistics_time_start("Time of making definition index");
2169                 func_total = makedefineindex("defines.html", func_total, defines);
2170                 statistics_time_end(tim);
2171                 message("Total %d functions.", func_total);
2172                 /*
2173                  * (6) make file index (files.html and files/)
2174                  *     PRODUCE @files, %includes
2175                  */
2176                 message("[%s] (6) making file index ...", now());
2177                 init_inc();
2178                 tim = statistics_time_start("Time of making file index");
2179                 file_total = makefileindex("files.html", files);
2180                 statistics_time_end(tim);
2181                 message("Total %d files.", file_total);
2182                 html_count += file_total;
2183                 /*
2184                  * (7) make call tree using cflow(1)'s output (cflow.html)
2185                  */
2186                 if (call_file || callee_file) {
2187                         message("[%s] (7) making cflow index ...", now());
2188                         tim = statistics_time_start("Time of making cflow index");
2189                         if (call_file)
2190                                 if (makecflowindex("call.html", call_file) < 0)
2191                                         call_file = NULL;
2192                         if (callee_file)
2193                                 if (makecflowindex("callee.html", callee_file) < 0)
2194                                         callee_file = NULL;
2195                         statistics_time_end(tim);
2196                 }
2197                 /*
2198                  * [#] make include file index.
2199                  */
2200                 message("[%s] (#) making include file index ...", now());
2201                 tim = statistics_time_start("Time of making include file index");
2202                 makeincludeindex();
2203                 statistics_time_end(tim);
2204                 /*
2205                  * [#] make a common part for mains.html and index.html
2206                  *     USING @defines @files
2207                  */
2208                 message("[%s] (#) making a common part ...", now());
2209                 index = makecommonpart(title, strbuf_value(defines), strbuf_value(files));
2210 
2211                 strbuf_close(defines);
2212                 strbuf_close(files);
2213         }
2214         /*
2215          * (7)make index file (index.html)
2216          */
2217         message("[%s] (7) making index file ...", now());
2218         makeindex("index.html", title, index);
2219         /*
2220          * (8) make main index (mains.html)
2221          */
2222         message("[%s] (8) making main index ...", now());
2223         makemainindex("mains.html", index);
2224         /*
2225          * (9) make HTML files (SRCS/)
2226          *     USING TAG CACHE, %includes and anchor database.
2227          */
2228         message("[%s] (9) making hypertext from source code ...", now());
2229         tim = statistics_time_start("Time of making hypertext");
2230         makehtml(file_total);
2231         statistics_time_end(tim);
2232         /*
2233          * (10) rebuild script. (rebuild.sh)
2234          *
2235          * Don't grant execute permission to rebuild script.
2236          */
2237         makerebuild("rebuild.sh");
2238         if (chmod(makepath(distpath, "rebuild.sh", NULL), 0640) < 0)
2239                 die("cannot chmod rebuild script.");
2240         /*
2241          * (11) style sheet file (style.css)
2242          */
2243         if (enable_xhtml) {
2244                 char com[MAXPATHLEN*2+32];
2245 #ifdef __DJGPP__
2246                 const char *template = "";
2247                 snprintf(com, sizeof(com), "%s/gtags/style.css.tmpl", datadir, distpath);
2248                 if (test("f", com))
2249                        template = ".tmpl";
2250                 snprintf(com, sizeof(com), "cp %s/gtags/style.css%s %s/style.css", datadir, template, distpath);
2251 #else
2252                 snprintf(com, sizeof(com), "cp %s/gtags/style.css.tmpl %s/style.css", datadir, distpath);
2253 #endif
2254                 system(com);
2255         }
2256         if (auto_completion || tree_view) {
2257                 char com[MAXPATHLEN*2+32];
2258                 snprintf(com, sizeof(com), "cp -r %s/gtags/jquery/* %s/js", datadir, distpath);
2259                 system(com);
2260         }
2261         message("[%s] Done.", now());
2262         if (vflag && (cflag || fflag || dynamic || auto_completion)) {
2263                 message("\n[Information]\n");
2264                 message(" o Htags was invoked with the -f, -c, -D or --auto-completion option. You should");
2265                 message("   start http server so that cgi-bin/*.cgi is executed as a CGI script.");
2266                 if (cflag) {
2267                         message(" o Htags was invoked with the -c option. You should start a http server to");
2268                         message("   decompress *.%s files.", gzipped_suffix);
2269                 }
2270                 if (Sflag && need_bless) {
2271                         char path[MAXBUFLEN];
2272                         snprintf(path, sizeof(path), "%s/gtags/%s/%s", localstatedir, SITEKEYDIRNAME, sitekey);
2273 
2274                         message(" o Though htags was invoked with the --system-cgi option with a unique key '%s',", sitekey);
2275                         message("   you don't have the permission to create file '%s'.", path);
2276                         message("   You should ask the root user to bless the hypertext by executing");
2277                         message("   like follows:");
2278                         message("       # cd HTML");
2279                         message("       # sh bless.sh");
2280                 }
2281                 message("\n If you are using Apache, 'HTML/.htaccess' might be helpful for you.\n");
2282                 message(" Good luck!\n");
2283         }
2284         if (Iflag) {
2285                 char com[MAXPATHLEN*2+32];
2286 
2287                 snprintf(com, sizeof(com), "cp -r %s/gtags/icons %s", datadir, distpath);
2288                 system(com);
2289         }
2290         gpath_close();
2291         /*
2292          * Print statistics information.
2293          */
2294         print_statistics(statistics);
2295         clean();
2296         return 0;
2297 }

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