/* */
This source file includes following definitions.
- usage
- help
- clean
- suddenly
- signal_setup
- make_directory_in_distpath
- make_file_in_distpath
- load_with_replace
- generate_file
- makeprogram
- makebless
- makeghtml
- makerebuild
- makehelp
- makesearchpart
- makeindex
- makemainindex
- makesearchindex
- makehtaccess
- makehtml
- loadfile_asis
- loadfile
- copyfile
- makecommonpart
- basic_check
- configuration
- save_environment
- append_options
- 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 "<",
170 ">",
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 }
/* */