#! /dev/d/djgpp/bin/perl
# This part is generated automatically by convert.pl from htags/manual.in.
$program = 'htags';
$usage_const = "Usage: htags [-a][-c][-D][-f][-F][-g][-n][-o][-s][-v][-w][-d dbpath][-m name][-S cgidir][-t title][htmldir]";
$help_const = "$usage_const\
Options:\
-a, --alphabet\
       Make an alphabetical function index, suitable for a large project.\
--caution\
       Include caution message to prohibit downloading.\
-c, --compact\
       Compress html files  by gzip(1).\
       You need to set up a HTTP server so that gzip(1)\
       is invoked for each compressed file.\
       See 'HTML/.htaccess' that is generated by htags.\
--cvsweb url\
       Include cvsweb URL. url is used as base of URL.\
--cvsweb-cvsroot cvsroot\
       Specifies cvsroot in cvsweb URL.\
-D, --dynamic\
       Generate object list dynamically using CGI program.\
       By default, object list is generated statically.\
       If hypertext is moved from source directory, line image will be\
       omitted from the list of other symbols.\
       If -c option of gtags(1) is used and hypertext is moved from source directory,\
       line image will be omitted from the list of definitions and references.\
-d, --dbpath dbpath\
       Specifies the directory in which 'GTAGS' and 'GRTAGS'\
       exist. The default is the current directory.\
-f, --form\
       Support search form using CGI program.\
       You need to set up a HTTP server for this.\
       If hypertext is moved from source directory, line image will be\
       omitted from the list of other symbols.\
       If -c option of gtags(1) is used and hypertext is moved from source directory,\
       line image will be omitted from the list of definitions and references.\
-F, --frame\
       Use frame for each part of the contents.\
-g, --gtags\
       Execute gtags(1) before creating hypertext.\
       The -v, -w and dbpath are passed to gtags.\
--gtagsconf file\
       Load user's configuration from file.\
--gtagslabel label\
       label is used as the label of configuration file.\
       The default is default.\
-m, --main-func name\
       Specify the main function name. The default is main.\
-n, --line-number\
       Print the line numbers. By default, doesn't print it.\
--no-map-file\
       Doesn't generate 'MAP' file. By default, htags generates it.\
-o, --other\
       Pick up not only source files but also other files except for\
       binary files.\
--statistics\
       Print statistics information.\
--style-sheet file\
       Load style sheet file and insert it into <HEAD> tag.\
-s, --symbol\
       Make anchors not only for functions but also other symbols.\
       'GSYMS' tag file needed.\
-S, --secure-cgi cgidir\
       write cgi script into cgidir to realize a centralised\
       cgi script. Script alias is '/cgi-bin' by default.\
       You can overwrite this value with config variable\
       script_alias in 'gtags.conf'.\
-t, --title title\
       The title of this hypertext. The default is the last\
       component of the current directory.\
-v, --verbose\
       Verbose mode.\
-w, --warning\
       Print warning messages.\
htmldir\
       The directory in which hypertext is generated.\
       The default is the current directory.\
";
# end of generated part.
# This part is generated automatically by reserved.pl from 'c_res.in'.
$'sharp_macros = "(include|warning|assert|define|ifndef|pragma|ident|ifdef|endif|undef|error|line|else|elif|if)";
# end of generated part.
# This part is generated automatically by reserved.pl from 'c_res.in'.
$'c_reserved_words = "(__attribute__|__extension__|__restrict__|__volatile__|__attribute|__volatile|__restrict|_Imaginary|__signed__|__inline__|__const__|restrict|continue|register|__signed|unsigned|_Complex|volatile|__inline|default|__const|__asm__|typedef|extern|inline|signed|sizeof|static|struct|switch|return|double|__asm|const|_Bool|break|float|union|short|while|char|goto|long|auto|else|enum|void|case|__P|for|int|asm|do|if)";
# end of generated part.
# This part is generated automatically by reserved.pl from 'cpp_res.in'.
$'cpp_reserved_words = "(reinterpret_cast|__attribute__|__extension__|__volatile__|dynamic_cast|__attribute|static_cast|__volatile|__inline__|const_cast|__signed__|__const__|protected|namespace|__signed|operator|volatile|explicit|__inline|continue|register|template|typename|unsigned|mutable|__asm__|__const|typedef|private|default|virtual|wchar_t|public|return|sizeof|static|extern|struct|switch|signed|inline|export|typeid|delete|friend|double|false|float|throw|__asm|short|const|union|break|using|catch|class|while|auto|void|long|else|enum|this|goto|true|case|char|bool|__P|int|for|new|try|asm|if|do)";
# end of generated part.
# This part is generated automatically by reserved.pl from 'java_res.in'.
$'java_reserved_words = "(synchronized|instanceof|implements|transient|interface|protected|volatile|strictfp|abstract|continue|boolean|extends|finally|package|default|private|static|native|double|switch|throws|import|public|return|widefp|break|catch|float|final|false|short|super|union|class|const|while|throw|this|char|else|goto|long|true|void|null|byte|case|try|new|int|for|do|if)";
# end of generated part.
# This part is generated automatically by reserved.pl from 'php_res.in'.
$'php_reserved_words = "(Require_once|REQUIRE_ONCE|__FUNCTION__|require_once|include_once|Old_Function|OLD_FUNCTION|Old_function|Include_once|Include_Once|old_function|INCLUDE_ONCE|Require_Once|EndForeach|enddeclare|ENDDECLARE|EndDeclare|Enddeclare|endforeach|ENDFOREACH|Endforeach|SetCookie|Setcookie|__CLASS__|SETCOOKIE|CFunction|Cfunction|CFUNCTION|endswitch|ENDSWITCH|Endswitch|EndSwitch|cfunction|setcookie|Is_Array|continue|Is_array|IS_ARRAY|is_array|__FILE__|endwhile|ENDWHILE|Endwhile|EndWhile|__LINE__|Function|FUNCTION|function|CONTINUE|Continue|DECLARE|Declare|default|DEFAULT|Default|failure|FAILURE|Failure|foreach|FOREACH|Foreach|ForEach|include|INCLUDE|Include|require|REQUIRE|Require|success|SUCCESS|Success|declare|Elseif|ElseIf|Return|RETURN|global|GLOBAL|Global|header|HEADER|Header|return|Printf|PRINTF|printf|endfor|ENDFOR|Endfor|Is_Set|EndFor|Is_set|IS_SET|define|DEFINE|Define|is_set|Switch|SWITCH|switch|Static|STATIC|static|elseif|ELSEIF|FALSE|False|EMPTY|array|ARRAY|Array|empty|while|WHILE|break|BREAK|Break|While|unset|UNSET|class|CLASS|Class|const|CONST|Const|Unset|false|EndIf|Endif|endif|ENDIF|Empty|print|PRINT|Print|ECHO|echo|Each|EACH|Else|ELSE|case|CASE|Case|Exit|EVAL|Eval|EXIT|exit|List|LIST|list|else|Echo|each|true|TRUE|True|eval|and|AND|And|VAR|Var|xor|XOR|For|Xor|new|NEW|for|New|FOR|Die|DIE|die|var|as|AS|As|do|if|Do|or|OR|Or|DO|If|IF)";
# end of generated part.
#
# Copyright (c) 1996, 1997, 1998, 1999 Shigio Yamaguchi
# Copyright (c) 1999, 2000, 2001, 2002, 2003 Tama Communications Corporation
#
# This file is part of GNU GLOBAL.
#
# GNU GLOBAL is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# GNU GLOBAL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
$'w32 = ($^O =~ /^(ms)?(dos|win(32|nt))/i) ? 1 : 0;
$www = "http://www.gnu.org/software/global/";
$file_count = 0;
$caution_message = <<'END_OF_CAUTION';
<CENTER>
<BLOCKQUOTE>
<FONT SIZE=+2 COLOR=red>CAUTION</FONT><BR>
This hypertext consist of @FILE_COUNT@ files.
Please don't download whole hypertext using hypertext copy tools.
Our network cannot afford such traffic.
Instead, you can generate same thing in your computer using
<A HREF=@WWW@ TARGET=_top>GLOBAL source code tag system</A>.
Thank you. 
</BLOCKQUOTE>
</CENTER>
END_OF_CAUTION
#-------------------------------------------------------------------------
# SELF CHECK
#-------------------------------------------------------------------------
if (!defined($program) || !defined($usage_const) || !defined($help_const) ||
	!defined($'c_reserved_words) ||
	!defined($'cpp_reserved_words) ||
	!defined($'java_reserved_words)||
	!defined($'php_reserved_words) ||
	!defined($'sharp_macros))
{
	die("htags: Required variables not found. It seems that htags wasn't built correctly.\n");
}
#-------------------------------------------------------------------------
# COMMAND EXISTENCE CHECK
#-------------------------------------------------------------------------
foreach $c ('sort', 'gtags', 'global') {
	if (!&'usable($c)) {
		&'error("'$c' command is required but not found.");
	}
}
#
# find filter
#
$'gtags = &'usable("gtags");
$'findcom = "$'gtags --find";
#-------------------------------------------------------------------------
# CONFIGURATION
#-------------------------------------------------------------------------
$version = `global --version`;
chop($version);
# null device
$'null_device = $'w32 ? 'NUL' : '/dev/null';
# temporary directory
$'tmp = '/tmp';
if (defined($ENV{'TMPDIR'}) && -d $ENV{'TMPDIR'}) {
	$tmp = $ENV{'TMPDIR'};
}
if (! -d $tmp || ! -w $tmp) {
	&'error("temporary directory '$tmp' not exist or not writable.");
}
$'ncol = 4;					# columns of line number
$'tabs = 8;					# tab skip
#
# File index
#
$'full_path = 0;				# file index format
$'icon_list = '';				# use icon for file index
$'no_order_list = 0;				# doesn't use order list
$'icon_suffix = '';				# icon suffix (jpg, png etc)
$'icon_spec = 'BORDER=0 ALIGN=top';		# parameter in IMG tag

$'prolog_script = '';				# include script at first
$'epilog_script = '';				# include script at last
$'show_position = 0;				# show current position
$'table_list = 0;				# tag list using table tag
$'colorize_warned_line = 0;			# colorize warned line
$'script_alias = '/cgi-bin';			# script alias of WWW server
$'gzipped_suffix = 'ghtml';			# suffix of gzipped html file
$'normal_suffix = 'html';			# suffix of normal html file
$'action = 'cgi-bin/global.cgi';		# default action
$'id = '';					# id (default non)
$'cgi = 1;					# 1: make cgi-bin/
$'definition_header='no';			# {no|after|before}
$'other_files = 0;				# 1: list other files
$'map_file = 1;					# generate HTML/MAP
$'use_cache_file = 1;				# make temporary db
#
# tag
#
$'body_begin     = '<BODY>';
$'body_end       = '</BODY>';
$'table_begin    = '<TABLE>';
$'table_end      = '</TABLE>';
$'title_begin	 = '<H1><FONT COLOR=#cc0000>';
$'title_end	 = '</FONT></H1>';
$'comment_begin  = '<I><FONT COLOR=green>';	# /* ... */
$'comment_end    = '</FONT></I>';
$'sharp_begin    = '<FONT COLOR=darkred>';	# #define, #include or so on
$'sharp_end      = '</FONT>';
$'brace_begin    = '<FONT COLOR=blue>';		# { ... }
$'brace_end      = '</FONT>';
$'reserved_begin = '<B>';			# if, while, for or so on
$'reserved_end   = '</B>';
$'position_begin = '<FONT COLOR=gray>';
$'position_end   = '</FONT>';
$'warned_line_begin = '<SPAN STYLE="background-color:yellow">';
$'warned_line_end   = '</SPAN>';
$'hr		 = '<HR>';
{
	#
	# Setup the GTAGSCONF environment variable according to
	# the --gtagsconf option.
	#
	# --gtagsconf=<config file> or <config value itself>
	# --gtagslabel=<label>.
	#
	local(@a, $confpath, $label);
	for ($i = 0; $i < @ARGV; $i++) {
		if ($ARGV[$i] =~ /^--gtagsconf/) {
			if ($ARGV[$i] =~ /^--gtagsconf=(.*)$/) {
				$confpath = $1;
			} elsif ($ARGV[$i] =~ /^--gtagsconf$/) {
				if (++$i >= @ARGV) {
					&'error("--gtagsconf needs an argument.");
				}
				$confpath = $ARGV[$i];
			}
			$ENV{'GTAGSCONF'} = (-f $confpath) ? &realpath($confpath) : $confpath;
		} elsif ($ARGV[$i] =~ /^--gtagslabel/) {
			if ($ARGV[$i] =~ /^--gtagslabel=(.*)$/) {
				$label = $1;
			} elsif ($ARGV[$i] =~ /^--gtagslabel$/) {
				if (++$i >= @ARGV) {
					&'error("--gtagslabel needs an argument.");
				}
				$label = $ARGV[$i];
			}
			$ENV{'GTAGSLABEL'} = $label;
		} else {
			push(@a, $ARGV[$i]);
		}
	}
	@ARGV = @a;
}
#
# load configuration variables.
#
if ($var1 = &'getconf('ncol')) {
	if ($var1 < 1 || $var1 > 10) {
		print STDERR "Warning: parameter 'ncol' ignored becase the value is too large or too small.\n";
	} else {
		$'ncol = $var1;
	}
}
if ($var1 = &'getconf('tabs')) {
	if ($var1 < 1 || $var1 > 32) {
		print STDERR "Warning: parameter 'tabs' ignored becase the value is too large or too small.\n";
	} else {
		$'tabs = $var1;
	}
}
if ($var1 = &'getconf('gzipped_suffix')) {
	$'gzipped_suffix = $var1;
}
if ($var1 = &'getconf('normal_suffix')) {
	$'normal_suffix = $var1;
}
if ($var1 = &'getconf('definition_header')) {
	$'definition_header = $var1;
}
if ($var1 = &'getconf('other_files')) {
	$'other_files = $var1;
}
if ($var1 = &'getconf('enable_grep')) {
	$'enable_grep = $var1;
}
if ($var1 = &'getconf('enable_idutils')) {
	$'enable_idutils = $var1;
}
if ($var1 = &'getconf('full_path')) {
	$'full_path = $var1;
}
if ($var1 = &'getconf('table_list')) {
	$'table_list = $var1;
}
if ($var1 = &'getconf('icon_list')) {
	$'icon_list = $var1;
}
if ($var1 = &'getconf('icon_spec')) {
	$'icon_spec = $var1;
}
if ($var1 = &'getconf('icon_suffix')) {
	$'icon_suffix = $var1;
}
if ($var1 = &'getconf('no_order_list')) {
	$'no_order_list = $var1;
}
if ($var1 = &'getconf('prolog_script')) {
	$'prolog_script = $var1;
}
if ($var1 = &'getconf('epilog_script')) {
	$'epilog_script = $var1;
}
if (&'getconf('no_map_file')) {
	$'map_file = 0;
}
#
# If enough momory exist and perl is configured so that vfork might be used,
# set this variable.
# Note that vfork is no longer used in perl-5.8.
#
if (&'getconf('no_cache_file')) {	# undocumented
	$'use_cache_file = 0;
}
if ($var1 = &'getconf('show_position')) {
	$'show_position = $var1;
}
if ($var1 = &'getconf('colorize_warned_line')) {
	$'colorize_warned_line = $var1;
}
if ($var1 = &'getconf('script_alias')) {
	$'script_alias = $var1;
	$'script_alias =~ s!/$!!;
}
if (&'getconf('symbol')) {
	$'symbol = 1;
}
if (&'getconf('symbols')) {		# for backward compatibility
	$'symbol = 1;
}
if (&'getconf('dynamic')) {
	$'dynamic = 1;
}
if (($var1 = &'getconf('body_begin')) && ($var2 = &'getconf('body_end'))) {
	$'body_begin  = $var1;
	$'body_end    = $var2;
}
if (($var1 = &'getconf('table_begin')) && ($var2 = &'getconf('table_end'))) {
	$'table_begin  = $var1;
	$'table_end    = $var2;
}
if (($var1 = &'getconf('title_begin')) && ($var2 = &'getconf('title_end'))) {
	$'title_begin  = $var1;
	$'title_end    = $var2;
}
if (($var1 = &'getconf('comment_begin')) && ($var2 = &'getconf('comment_end'))) {
	$'comment_begin  = $var1;
	$'comment_end    = $var2;
}
if (($var1 = &'getconf('sharp_begin')) && ($var2 = &'getconf('sharp_end'))) {
	$'sharp_begin  = $var1;
	$'sharp_end    = $var2;
}
if (($var1 = &'getconf('brace_begin')) && ($var2 = &'getconf('brace_end'))) {
	$'brace_begin  = $var1;
	$'brace_end    = $var2;
}
if (($var1 = &'getconf('reserved_begin')) && ($var2 = &'getconf('reserved_end'))) {
	$'reserved_begin  = $var1;
	$'reserved_end    = $var2;
}
if (($var1 = &'getconf('position_begin')) && ($var2 = &'getconf('position_end'))) {
	$'position_begin  = $var1;
	$'position_end    = $var2;
}
if (($var1 = &'getconf('warned_line_begin')) && ($var2 = &'getconf('warned_line_end'))) {
	$'warned_line_begin  = $var1;
	$'warned_line_end    = $var2;
}
if (($var1 = &'getconf('hr'))) {
	$'hr  = $var1;
}
# insert htags_options into the head of ARGSV array.
if (($var1 = &'getconf('htags_options'))) {
	$'htags_options = $var1;
}
# HTML tag
$'html_begin  = '<HTML>';
$'html_end    = '</HTML>';
$'meta_robots = "<META NAME='ROBOTS' CONTENT='NOINDEX,NOFOLLOW'>";
$'meta_generator = "<META NAME='GENERATOR' CONTENT='GLOBAL-$version'>";
# Titles
$'title_define_index = 'DEFINITIONS';
$'title_file_index = 'FILES';
$'title_included_from = 'INCLUDED FROM';

# Anchor image
@anchor_label = ('&lt;', '&gt;', '^', 'v', 'top', 'bottom', 'index', 'help');
@anchor_icons = ('left', 'right', 'first', 'last', 'top', 'bottom', 'index', 'help');
@anchor_comment = ('previous', 'next', 'first', 'last', 'top', 'bottom', 'index', 'help');
foreach $a (@anchor_icons) {
	$a .= '.' . $'icon_suffix;
}
$back_icon = 'back' . '.' . $'icon_suffix;
$dir_icon  = 'dir' . '.' . $'icon_suffix;
$c_icon = 'c' . '.' . $'icon_suffix;
$file_icon = 'text' . '.' . $'icon_suffix;
@anchor_msg   = ('Previous definition.',
		'Next definition.',
		'First definition in this file.',
		'Last definition in this file.',
		'Top of this file.',
		'Bottom of this file.',
		'Return to index page.',
		'You are seeing now.',
);
#
# This is alternative for title string.
#
#	i)	type	D, I, R, Y
#	i)	lno	>0: line number, -1: multi line
#	i)	opt	lno > 0: file name
#			lno == -1: entry count
#
sub show {
	local($type, $lno, $opt) = @_;
	local($msg) = '';

	if ($lno > 0) {
		if ($type eq 'I') {
			$msg .= 'Included from';
		} elsif ($type eq 'R') {
			$msg .= 'Defined at';
		} elsif ($type eq 'Y') {
			$msg .= 'Used at';
		} else {
			$msg .= 'Refered from';
		}
		$msg .= ' ' . $lno;
		if ($opt ne '') {
			$msg .= ' in ' . $opt;
		}
	} else {
		$msg .= 'Multiple ';
		if ($type eq 'I') {
			$msg .= 'included from';
		} elsif ($type eq 'R') {
			$msg .= 'defined in';
		} elsif ($type eq 'Y') {
			$msg .= 'used in';
		} else {
			$msg .= 'refered from';
		}
		$msg .= ' ' . $opt . ' places';
	}
	$msg .= '.';
	$msg;
}
#-------------------------------------------------------------------------
# DIRECTORIES
#-------------------------------------------------------------------------
# unit for a path
$'SRCS   = 'S';				# source file directory.
$'DEFS   = 'D';				# object definition directory.
$'REFS   = 'R';				# object reference directory.
$'INCS   = 'I';				# include file directory.
$'INCREFS = 'J';			# include file reference directory.
$'SYMS   = 'Y';				# symbols directory.
sub get_dirlist {
	local(@dir) = (files, defines, $'SRCS, $'INCS, $'INCREFS);
	if (!$'dynamic) {
		push(@dir, $'DEFS, $'REFS);
		push(@dir, $'SYMS) if ($'symbol);
	}
	@dir;
}
sub get_taglist {
	local(@tags) = ('GTAGS', 'GRTAGS');
	push(@tags, 'GSYMS') if ($'symbol);
	@tags;
}
sub get_dirhash {
	local(%dir) = ('GTAGS', $'DEFS, 'GRTAGS', $'REFS, 'GSYMS', $'SYMS);
	%dir;
}
sub get_option {
	local($db) = @_;
	local(%option) = ('GTAGS', '', 'GRTAGS', 'r', 'GSYMS', 's');
	$option{$db};
}
#-------------------------------------------------------------------------
# UTILITIES
#-------------------------------------------------------------------------
#
# get current working directory.
#
sub getcwd {
	local($dir) = `$'gtags --pwd`;
	if ($'w32) { $dir =~ s!\\!/!g; }
	chop($dir);
	$dir;
}
#
# get real absolute path name.
#
sub realpath {
        local($path) = @_;
        local($cwd) = &getcwd;		# for recovery
        local($real);			# real directory

        if (! -d $path && ! -f $path) {
		&'error("'$path' not found.");
	}
        local($dir,$file) = ($path =~ m#^(.*/)?(.*)#);
	if ($dir) {
		chdir($dir) || &'error("directory '$dir' not found.");
	}
        $real = &getcwd;
        $path = $real . '/' . $file;
        $path =~ s!//!/!;
        chdir($cwd) || &'error("cannot recover current directory '$cwd'.");
        $path;
}
#
# get date string.
#
sub date {
	local($date) = `$'gtags --date`;
	chop($date);
	$date;
}
#
# print message and exit with error status.
#
sub error {
	&clean();
	printf STDERR "$program: $_[0]\n";
	exit 1;
}
#
# set things right before exiting.
#
sub clean {
	&cache'close();
}
#
# locate executable command and return it's absolute path name.
#
sub usable {
	local($command) = @_;
	local($pathsep) = ($'w32) ? ';' : ':';
	foreach (split(/$pathsep/, $ENV{'PATH'})) {
		if ($'w32) {
			return "$_\\$command.com" if (-f "$_\\$command.com");
			return "$_\\$command.exe" if (-f "$_\\$command.exe");
		} else {
			return "$_/$command" if (-x "$_/$command");
		}
	}
	return '';
}
#
# duplicate file. if possible, link it without making a copy.
#
sub duplicatefile {
	local($file, $from, $to) = @_;
	if ($'w32) {
		&'copy("$from/$file", "$to/$file")
	} else {
		link("$from/$file", "$to/$file")
			|| &'copy("$from/$file", "$to/$file")
	}
}
#
# copy file.
#
sub copy {
	local($from, $to) = @_;
	local($command) = ($'w32) ? 'copy' : 'cp';
	$command .= " $from $to";
	$command =~ s!/!\\!g if ($'w32);
	system($command);
	if ($? != 0) {
		&'error("cannot execute '$command'.");
	}
	return 1;
}
#
# get value of configuration variable.
#
sub getconf {
	local($name) = @_;
	local($val);
	chop($val = `$'gtags --config $name`);
	if ($? != 0) {
		&'error("cannot get config value.");
	}
	$val;
}
#
# convert source file path name into url.
#
sub path2url {
	local($path) = @_;
	$path = './' . $path if ($path !~ /^\./);
	if (!defined($'GPATH{$path})) {
		$'GPATH{$path} = ++$nextkey;
	}
	$'GPATH{$path} . '.' . $'HTML;
}
#
# return header.
#
sub set_header {
	local($title) = @_;
	local($head) = '';
	$head .= "<HEAD>\n";
	$head .= "<TITLE>$title</TITLE>\n";
	$head .= "$'meta_robots\n$'meta_generator\n";
	$head .= $'style_sheet if ($'style_sheet);
	$head .= "</HEAD>\n";
	$head;
}
#-------------------------------------------------------------------------
# LIST PROCEDURE
#-------------------------------------------------------------------------
sub list_begin {
	$'table_list ? "$'table_begin\n<TR><TH NOWRAP ALIGN=left>tag</TH><TH NOWRAP ALIGN=right>line</TH><TH NOWRAP ALIGN=center>file</TH><TH NOWRAP ALIGN=left>source code</TH></TR>\n" :  "<PRE>\n";
}
sub list_body {
	local($srcdir, $s) = @_;	# $s must be choped.
	local($name, $lno, $filename, $line) = ($s =~ /^(\S+)\s+(\d+)\s+\.\/(\S+) (.*)$/);
	local($html) = &'path2url($filename);

	if ($'table_list) {
		$line =~ s/&/&amp;/g;
		$line =~ s/</&lt;/g;
		$line =~ s/>/&gt;/g;
		$line =~ s/ /&nbsp;&nbsp;/g;
		$line =~ s/	/&nbsp;&nbsp;&nbsp;&nbsp;/g;
		$s = "<TR><TD NOWRAP><A HREF=$srcdir\/$html#$lno>$name</A></TD><TD NOWRAP ALIGN=right>$lno</TD><TD NOWRAP ALIGN=left>$filename</TD><TD NOWRAP>$line</TD></TR>";
	} else {
		$name =~ s/([^\w])/\\\1/g;	# Quote name
		$s =~ s/\.\///;
		$s =~ s/&/&amp;/g;
		$s =~ s/</&lt;/g;
		$s =~ s/>/&gt;/g;
		$s =~ s/^($name)/<A HREF=$srcdir\/$html#$lno>$1<\/A>/;
	}
	$s . "\n";
}
sub list_end {
	local($s) = $'table_list ? $'table_end : "</PRE>";
	$s . "\n";
}
#-------------------------------------------------------------------------
# PROCESS START
#-------------------------------------------------------------------------
# include prolog_script if needed.
require($'prolog_script) if ($'prolog_script && -f $'prolog_script);
#
# save config values and option values.
#
$save_config = `$'gtags --config`;
chop($save_config);
$save_config =~ s/'/'"'"'/g;			# keep single quote
$save_argv   = '';
foreach (@ARGV) {
	$save_argv .= ' ' if ($save_argv);
	$save_argv .= (/[ \t]/) ? "'$_'" : $_;	# quote arg include blank.
}
if ($'htags_options) {
	#
	# insert $'htags_options at the head of ARGV.
	#
	local($a) = $'htags_options;
	local(@a, $skip);
	while ($a) {
		$a =~ s/^[ \t]+//;
		if ($a =~ s/^'([^']*)'// || $a =~ s/^"([^"]*)"// || $a =~ s/^([^ \t]+)//) {
			push(@a, $1);
		}
	}
	@ARGV = (@a, @ARGV);
}
#
# options check.
#
$'aflag = $'cflag = $'Dflag = $'fflag = $'Fflag = $'gflag = $'nflag = $'sflag = $'Sflag = $'vflag = $'wflag = '';
$show_version = 0;
$show_help = 0;
$include_caution = '';
$action_value = '';
$id_value = '';
$cgidir = '';
$main_func = 'main';
$style_sheet = '';
$cvsweb_url = '';
$cvsweb_cvsroot = '';
$statistics = 0;
while ($ARGV[0] =~ /^-/) {
	$opt = shift;
	if ($opt =~ /^--action=(.*)$/) {
		$action_value = $1;
	} elsif ($opt =~ /^--id=(.*)$/) {
		$id_value = $1;
	} elsif ($opt =~ /^--nocgi$/) {
		$'cgi = 0;
	} elsif ($opt =~ /^--version$/) {
		$show_version = 1;
	} elsif ($opt =~ /^--help$/) {
		$show_help = 1;
	} elsif ($opt =~ /^--alphabet$/) {
		$'aflag = 'a';
	} elsif ($opt =~ /^--compact$/) {
		$'cflag = 'c';
	} elsif ($opt =~ /^--dynamic$/) {
		$'dynamic = 1;
	} elsif ($opt =~ /^--each-line-tag$/) {
		;		# for backward compatibility.
	} elsif ($opt =~ /^--form$/) {
		$'fflag = 'f';
	} elsif ($opt =~ /^--frame$/) {
		$'Fflag = 'F';
	} elsif ($opt =~ /^--gtags$/) {
		$'gflag = 'g';
	} elsif ($opt =~ /^--gtagsconf=(.*)$/) {
		;		# --gtagsconf is estimated only once.
	} elsif ($opt =~ /^--gtagsconf$/) {
		shift;		# --gtagsconf is estimated only once.
	} elsif ($opt =~ /^--gtagslabel=(.*)$/) {
		;		# --gtagslabel is estimated only once.
	} elsif ($opt =~ /^--gtagslabel$/) {
		shift;		# --gtagslabel is estimated only once.
	} elsif ($opt =~ /^--no-map-file$/) {
		$'map_file = 0;
	} elsif ($opt =~ /^--line-number$/) {
		$'nflag = 'n';
	} elsif ($opt =~ /^--other$/) {
		$'oflag = 'o';
	} elsif ($opt =~ /^--style-sheet=(.*)$/) {
		$'style_sheet = $1;
	} elsif ($opt =~ /^--style-sheet$/) {
		$'style_sheet = shift;
	} elsif ($opt =~ /^--symbol$/) {
		$'symbol = 1;
	} elsif ($opt =~ /^--symbols$/) {	# for backward compatibility
		$'symbol = 1;
	} elsif ($opt =~ /^--verbose$/) {
		$'vflag = 'v';
	} elsif ($opt =~ /^--warning$/) {
		$'wflag = 'w';
	} elsif ($opt =~ /^--caution$/) {
		$'include_caution = $'caution_message;
	} elsif ($opt =~ /^--title=(.*)$/) {
		$'title = $1;
	} elsif ($opt =~ /^--title$/) {
		$'title = shift;
	} elsif ($opt =~ /^--dbpath$/) {
		$opt = shift;
		last if ($opt eq '');
		$dbpath = $opt;
	} elsif ($opt =~ /^--main-func=(.*)$/) {
		$'main_func = $1;
	} elsif ($opt =~ /^--main-func$/) {
		$'main_func = shift;
	} elsif ($opt =~ /^--secure-cgi=(.*)$/) {
		$'Sflag = 'S';
		$'cgidir = $1;
	} elsif ($opt =~ /^--secure-cgi$/) {
		$'Sflag = 'S';
		$'cgidir = shift;
	} elsif ($opt =~ /^--statistics$/) {
		$'statistics = 1;
	} elsif ($opt =~ /^--cvsweb=(.*)$/) {
		$'cvsweb_url = $1;
	} elsif ($opt =~ /^--cvsweb$/) {
		$'cvsweb_url = shift;
	} elsif ($opt =~ /^--cvsweb-cvsroot=(.*)$/) {
		$'cvsweb_cvsroot = $1;
	} elsif ($opt =~ /^--cvsweb-cvsroot$/) {
		$'cvsweb_cvsroot = shift;
	} elsif ($opt =~ /^--/) {
		print STDERR "$program: unrecognized option `$opt'\n";
		print STDERR $usage_const, "\n";
		exit 1;
	} elsif ($opt =~ /[^-acdDfFglmnosStvwtd]/) {
				# include 'l' for backward compatibility.
		print STDERR "$program: unrecognized option `$opt'\n";
		print STDERR $usage_const, "\n";
		exit 1;
	} else {
		if ($opt =~ /a/) { $'aflag = 'a'; }
		if ($opt =~ /c/) { $'cflag = 'c'; }
		if ($opt =~ /D/) { $'Dflag = 'd'; }
		if ($opt =~ /f/) { $'fflag = 'f'; }
		if ($opt =~ /F/) { $'Fflag = 'F'; }
		if ($opt =~ /g/) { $'gflag = 'g'; }
		if ($opt =~ /n/) { $'nflag = 'n'; }
		if ($opt =~ /o/) { $'oflag = 'o'; }
		if ($opt =~ /s/) { $'sflag = 's'; }
		if ($opt =~ /v/) { $'vflag = 'v'; }
		if ($opt =~ /w/) { $'wflag = 'w'; }
		if ($opt =~ /t/) {
			$opt = shift;
			last if ($opt eq '');
			$title = $opt;
		} elsif ($opt =~ /d/) {
			$opt = shift;
			last if ($opt eq '');
			$dbpath = $opt;
		} elsif ($opt =~ /m/) {
			$opt = shift;
			last if ($opt eq '');
			$'main_func = $opt;
		} elsif ($opt =~ /S/) {
			$'Sflag = 'S';
			$'cgidir = shift;
		}
	}
}
if ($show_version) {
	local($command) = 'global --version';
	$command .= ' --verbose' if ($vflag);
	$command .= ' htags';
	system($command);
	exit 0;
}
if ($show_help) {
	print STDOUT $help_const;
	exit 0;
}
if ($'gflag) {
	local($command) = $'gtags;
	$command .= " -v" if ($'vflag);
	$command .= " -w" if ($'wflag);
	$command .= " -I" if ($'enable_idutils);
	$command .= " $dbpath" if ($dbpath);
	system($command);
	if ($?) { &'error("cannot execute gtags(1) command."); }
}
if ($'cflag && !&'usable('gzip')) {
	print STDERR "Warning: 'gzip' command not found. -c option ignored.\n";
	$'cflag = '';
}
if ($'Dflag) {
	$'dynamic = 1;
}
if ($'oflag) {
	$'other_files = 1;
}
if ($'sflag) {
	$'symbol = 1;
}
if (!$title) {
	@cwd = split('/', &'getcwd);
	$title = $cwd[$#cwd];
}
if ($'Dflag && $'Sflag) {
	&'error("Current implementation doesn't allow both -D(--dynamic) and the -S(--secure-cgi).");
}
#
# load style sheet.
#
if ($style_sheet) {
	local($style_path) = $style_sheet;
	$style_sheet = '';
	if (open(SHEET, $style_path)) {
		while (<SHEET>) {
			# insert \t for gtags --write command.
			$style_sheet .= "\t" if (! /^[\t<]/);
			$style_sheet .= $_;
		}
		close(SHEET);
	}
}
#
# decide directory in which we make hypertext.
#
$dist = &'getcwd() . '/HTML';
if ($ARGV[0]) {
	$cwd = &'getcwd();
	unless (-w $ARGV[0]) {
		 &'error("'$ARGV[0]' is not writable directory.");
	}
	chdir($ARGV[0]) || &'error("directory '$ARGV[0]' not found.");
	$dist = &'getcwd() . '/HTML';
	chdir($cwd) || &'error("cannot return to original directory.");
}
if ($'Sflag) {
	$'action = "$'script_alias/global.cgi";
	$'id = $dist;
}
# --action, --id overwrite Sflag's value.
if ($action_value) {
	$'action = $action_value;
}
if ($id_value) {
	$'id = $id_value;
}
# If $dbpath is not specified then listen to global(1).
if (!$dbpath) {
	local($cwd) = &'getcwd();
	local($root) = `global -pqr`;
	chop($root);
	if ($cwd eq $root) {
		$dbpath = `global -pq`;
		chop($dbpath);
	} else {
		$dbpath = '.';
	}
}
unless (-r "$dbpath/GTAGS" && -r "$dbpath/GRTAGS") {
	&'error("GTAGS and/or GRTAGS not found. Htags needs both of them.");
}
if ($'symbol && ! -r "$dbpath/GSYMS") {
	&'error("-s(--symbol) option needs GSYMS tag file.");
}
$dbpath = &'realpath($dbpath);
#
# for global(1)
#
$ENV{'GTAGSROOT'} = &'getcwd();
$ENV{'GTAGSDBPATH'} = $dbpath;
delete $ENV{'GTAGSLIBPATH'};
#
# check directories
#
if ($'fflag || $'cflag || $'dynamic) {
	if ($'cgidir && ! -d $'cgidir) {
		&'error("'$'cgidir' not found.");
	}
	if (!$'Sflag) {
		$'cgidir = "$dist/cgi-bin";
	}
} else {
	$'Sflag = $'cgidir = '';
}
#-------------------------------------------------------------------------
# MAKE FILES
#-------------------------------------------------------------------------
#	HTML/cgi-bin/global.cgi	... CGI program (1)
#	HTML/cgi-bin/ghtml.cgi	... unzip script (1)
#	HTML/.htaccess		... skeleton of .htaccess (1)
#	HTML/help.html		... help file (2)
#	HTML/R/*		... references (3)
#	HTML/D/*		... definitions (3)
#	HTML/search.html	... search index (4)
#	HTML/defines.html	... definitions index (5)
#	HTML/defines/*		... definitions index (5)
#	HTML/files.html		... file index (6)
#	HTML/files/*		... file index (6)
#	HTML/index.html		... index file (7)
#	HTML/mains.html		... main index (8)
#	HTML/null.html		... main null html (8)
#	HTML/S/			... source files (9)
#	HTML/I/			... include file index (9)
#	HTML/rebuild.sh		... rebuild script (10)
#-------------------------------------------------------------------------
$'HTML = ($'cflag) ? $'gzipped_suffix : $'normal_suffix;
print STDERR "[", &'date, "] ", "Htags started\n" if ($'vflag);
$start_all_time = time();
#
# (#) check if GTAGS, GRTAGS is the latest.
#
if (!$'w32) {
	$mtime_argc = 9;
	print STDERR "[", &'date, "] ", "(#) checking tag files ...\n" if ($'vflag);
	$gtags_mtime = (stat("$dbpath/GTAGS"))[$mtime_argc];
	open(FIND, "$'findcom |") || &'error("cannot fork.");
	while (<FIND>) {
		chop;
		if ($gtags_mtime < (stat($_))[$mtime_argc]) {
			&'error("GTAGS is not the latest one. Please execute gtags(1) again.");
		}
	}
	close(FIND);
	if ($?) { &'error("cannot traverse directory."); }
}
#
# (0) make directories
#
print STDERR "[", &'date, "] ", "(0) making directories ...\n" if ($'vflag);
mkdir($dist, 0777) || &'error("cannot make directory '$dist'.") if (! -d $dist);
foreach $d (&'get_dirlist()) {
	mkdir("$dist/$d", 0775) || &'error("cannot make HTML directory") if (! -d "$dist/$d");
}
if ($'cgi && ($'fflag || $'cflag || $'dynamic)) {
	mkdir("$dist/cgi-bin", 0775) || &'error("cannot make cgi-bin directory") if (! -d "$dist/cgi-bin");
}
#
# (1) make CGI program
#
if ($'cgi && ($'fflag || $'dynamic)) {
	if ($'cgidir) {
		print STDERR "[", &'date, "] ", "(1) making CGI program ...\n" if ($'vflag);
		&makeprogram("$cgidir/global.cgi");
		chmod(0755, "$cgidir/global.cgi") || &'error("cannot chmod CGI program.");
	}
	# Always make bless.sh.
	# Don't grant execute permission to bless script.
	&makebless("$dist/bless.sh");
	chmod(0640, "$dist/bless.sh") || &'error("cannot chmod bless script.");

	foreach $f ('GTAGS', 'GRTAGS', 'GSYMS', 'GPATH') {
		if (-f "$dbpath/$f") {
			unlink("$dist/cgi-bin/$f");
			&duplicatefile($f, $dbpath, "$dist/cgi-bin");
		}
	}
} else {
	print STDERR "[", &'date, "] ", "(1) making CGI program ...(skipped)\n" if ($'vflag);
}
if ($'cgi && $'cflag) {
	&makehtaccess("$dist/.htaccess");
	chmod(0644, "$dist/.htaccess") || &'error("cannot chmod .htaccess skeleton.");
	if ($'cgidir) {
		&makeghtml("$cgidir/ghtml.cgi") || &'error("cannot make unzip script.");
		chmod(0755, "$cgidir/ghtml.cgi") || &'error("cannot chmod unzip script.");
	}
}
#
# (2) make help file
#
print STDERR "[", &'date, "] ", "(2) making help.html ...\n" if ($'vflag);
&makehelp("$dist/help.$'normal_suffix");
#
# (#) load GPATH
#
local($command) = "$'gtags --scandb=\"$dbpath/GPATH\" \"./\"";
open(GPATH, "$command |") || &'error("cannot fork.");
$nextkey = 0;
while (<GPATH>) {
	chop;
	local($path, $no) = split;
	$'GPATH{$path} = $no;
	if ($no > $nextkey) {
		$nextkey = $no;
	}
}
close(GPATH);
if ($?) {&'error("'$command' failed."); }
#
# (3) make function entries ($DEFS/* and $REFS/*)
#     MAKING TAG CACHE
#
print STDERR "[", &'date, "] ", "(3) making duplicate entries ...\n" if ($'vflag);
sub suddenly { &'clean(); exit 1}
$SIG{'INT'} = 'suddenly';
$SIG{'QUIT'} = 'suddenly';
$SIG{'TERM'} = 'suddenly';
&cache'open();
$start_time = time();
$func_total = &makedupindex($dist);
$end_time = time();
print STDERR "Total $func_total functions.\n" if ($'vflag);
$T_makedupindex = $end_time - $start_time;
#
# (4) search index. (search.html)
#
if ($'Fflag && $'fflag) {
	print STDERR "[", &'date, "] ", "(4) making search index ...\n" if ($'vflag);
	&makesearchindex("$dist/search.$'normal_suffix");
}
#
# (5) make function index (defines.html and defines/*)
#     PRODUCE @defines
#
print STDERR "[", &'date, "] ", "(5) making function index ...\n" if ($'vflag);
sub suddenly { &'clean(); exit 1}
$start_time = time();
$func_total = &makedefineindex($dist, "$dist/defines.$'normal_suffix", $func_total);
$end_time = time();
print STDERR "Total $func_total functions.\n" if ($'vflag);
$T_makedefineindex = $end_time - $start_time;
#
# (6) make file index (files.html and files/*)
#     PRODUCE @files %includes
#
print STDERR "[", &'date, "] ", "(6) making file index ...\n" if ($'vflag);
$start_time = time();
$file_total = &makefileindex($dist, "$dist/files.$'normal_suffix", "$dist/$INCS");
$end_time = time();
print STDERR "Total $file_total files.\n" if ($'vflag);
$T_makefileindex = $end_time - $start_time;
$file_count += $file_total;
#
# [#] make a common part for mains.html and index.html
#     USING @defines @files
#
print STDERR "[", &'date, "] ", "(#) making a common part ...\n" if ($'vflag);
$index = &makecommonpart($title);
#
# (7)make index file (index.html)
#
print STDERR "[", &'date, "] ", "(7) making index file ...\n" if ($'vflag);
&makeindex("$dist/index.$'normal_suffix", $title, $index);
#
# (8) make main index (mains.html)
#
print STDERR "[", &'date, "] ", "(8) making main index ...\n" if ($'vflag);
&makemainindex("$dist/mains.$'normal_suffix", $index);
#
# (9) make HTML files ($SRCS/*)
#     USING TAG CACHE, %includes and anchor database.
#
print STDERR "[", &'date, "] ", "(9) making hypertext from source code ...\n" if ($'vflag);
$start_time = time();
&makehtml($dist, $file_total);
$end_time = time();
$T_makehtml = $end_time - $start_time;
#
# (10) rebuild script. (rebuild.sh)
#
# Don't grant execute permission to rebuild script.
&makerebuild("$dist/rebuild.sh");
chmod(0640, "$dist/rebuild.sh") || &'error("cannot chmod rebuild script.");

&'clean();

$end_all_time = time();
print STDERR "[", &'date, "] ", "Done.\n" if ($'vflag);
$T_all = $end_all_time - $start_all_time;
if ($'vflag && $'cgi && ($'cflag || $'fflag)) {
	print STDERR "\n";
	print STDERR "[Information]\n";
	print STDERR "\n";
	if ($'cflag) {
		print STDERR " Your system may need to be setup to decompress *.$'gzipped_suffix files.\n";
		print STDERR " This can be done by having your browser compiled with the relevant\n";
		print STDERR " options, or by configuring your http server to treat these as\n";
		print STDERR " gzipped files. (Please see 'HTML/.htaccess')\n";
		print STDERR "\n";
	}
	if ($'fflag || $'dynamic) {
		local($path) = ($'action =~ /^\//) ? "DOCUMENT_ROOT$'action" : "HTML/$'action";
		print STDERR " You need to setup http server so that $path\n";
		print STDERR " is executed as a CGI script. (DOCUMENT_ROOT means WWW server's data root.)\n";
		print STDERR "\n";
	}
	print STDERR " Good luck!\n";
	print STDERR "\n";
}
# This is not supported.
if ($'icon_list && -f $'icon_list) {
	system("tar xzf $'icon_list -C $dist");
}
# include epilog_script if needed.
require($'epilog_script) if ($'epilog_script && -f $'epilog_script);
#
# Print statistics information.
#
if ($'statistics) {
	printf STDERR "- Elapsed time of making duplicate entries ............ %10d seconds.\n", $T_makedupindex;
	printf STDERR "- Elapsed time of making function index ............... %10d seconds.\n", $T_makedefineindex;
	printf STDERR "- Elapsed time of making file index ................... %10d seconds.\n", $T_makefileindex;
	printf STDERR "- Elapsed time of making hypertext .................... %10d seconds.\n", $T_makehtml;
	printf STDERR "- The entire elapsed time ............................. %10d seconds.\n", $T_all;
}
exit 0;
#-------------------------------------------------------------------------
# SUBROUTINES
#-------------------------------------------------------------------------
#
# makeprogram: make CGI program
#
sub makeprogram {
	local($file) = @_;
	local($globalpath) = &'usable('global');
	local($gtagspath) = &'usable('gtags');

	open(PROGRAM, ">$file") || &'error("cannot make CGI program.");
	local($script) = <<'END_OF_SCRIPT';
#! /dev/d/djgpp/bin/perl
#------------------------------------------------------------------
# SORRY TO HAVE SURPRISED YOU!
# IF YOU SEE THIS UNREASONABLE FILE WHILE BROUSING, FORGET PLEASE.
# IF YOU ARE A ADMINISTRATOR OF THIS SITE, PLEASE SETUP HTTP SERVER
# SO THAT THIS SCRIPT CAN BE EXECUTED AS A CGI COMMAND. THANK YOU.
#------------------------------------------------------------------
print "Content-type: text/html\n\n";
print "@html_begin@\n";
print "@body_begin@\n";
$htmlbase = $ENV{'HTTP_REFERER'};
if (!$htmlbase) {
	print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
	print "<H3>Your browser doesn't send HTTP_REFERER.</H3>\n";
	print "</BODY>\n";
	print "</HTML>\n";
	exit 0;
}
$htmlbase =~ s!/[^\/]+$!!;		# remove file name.
$htmlbase =~ s!/defines$!!;
$htmlbase =~ s!/S$!!;
$htmlbase =~ s!/$!!;
if (! -x '@globalpath@' || ! -x '@gtagspath@') {
	print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
	print "<H3>Server side command not found. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
	print "@body_end@\n";
	print "@html_end@\n";
	exit 0;
}
@pairs = split (/&/, $ENV{'QUERY_STRING'});
foreach $p (@pairs) {
	($name, $value) = split(/=/, $p);
	$value =~ tr/+/ /;
	$value =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack("C", hex($1))/eg;
	$form{$name} = $value;
}
if ($form{'pattern'} eq '') {
	print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
	print "<H3>Pattern not specified. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
	print "@body_end@\n";
	print "@html_end@\n";
	exit 0;
}
$pattern = $form{'pattern'};
$from = $form{'from'};
$flag = '';
$words = 'definitions';
if ($form{'type'} eq 'reference') {
	$flag = 'r';
	$words = 'references';
} elsif ($form{'type'} eq 'symbol') {
	$flag = 's';
	$words = 'symbols';
} elsif ($form{'type'} eq 'path') {
	$flag = 'P';
	$words = 'paths';
} elsif ($form{'type'} eq 'grep') {
	$flag = 'g';
	$words = 'patterns';
} elsif ($form{'type'} eq 'idutils') {
	$flag = 'I';
	$words = 'patterns';
}
$iflag = '';
if ($form{'icase'}) {
	$iflag = 'i';
}
$oflag = '';
if ($form{'other'} && $flag eq 'g') {
	$oflag = 'o';
}
if ($form{'id'}) {
	chdir("$form{'id'}/cgi-bin");
	if ($?) {	
		print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
		print "<H3>Couldn't find tag directory in secure mode. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
		print "@body_end@\n";
		print "@html_end@\n";
		exit 0;
	}
}
if ($flag eq 'g' || $flag eq 'I' || $form{'type'} eq 'source') {
	if (($flag eq 'g' && ! -f "../../GTAGS")
	 || ($flag eq 'I' && ! -f "../../ID")
	 || ($form{'type'} eq 'source' && ! -f "../../GTAGS")) {
		print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
		print "<H3>Couldn't execute command. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
		print "@body_end@\n";
		print "@html_end@\n";
		exit 0;
	}
	chdir("../..");
	if ($?) {	
		print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
		print "<H3>Couldn't change directory for $form{'type'} search. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
		print "@body_end@\n";
		print "@html_end@\n";
		exit 0;
	}
} else {
	if (-f "../../GTAGS" &&
	(($flag eq '') || ($flag eq 'r' && -f "../../GRTAGS") || $flag eq 's' && -f "../../GSYMS")) {
		chdir("../..");
	}
}
local(%ctab) = ('&', '&amp;', '<', '&lt;', '>', '&gt;');
if ($form{'type'} eq 'source') {
	open(PIPE, "-|") || exec '@gtagspath@', '--secure', '--expand', '-@tabs@', './'.$pattern;
	if ($?) {	
		print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
		print "<H3>Cannot execute gtags. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
		print "@body_end@\n";
		print "@html_end@\n";
		exit 0;
	}
	print "<PRE>\n";
	while (<PIPE>) {
		s/([&<>])/$ctab{$1}/ge;
		print "<A NAME=$.>";
		print;
	}
	close(PIPE);
	print "</PRE>\n";
	print "@body_end@\n";
	print "@html_end@\n";
	exit 0;
}
#
# fork and exec global(1) to avoid command substitutions in $pattern.
#
open(PIPE, "-|") || exec '@globalpath@', '-x'.$flag.$iflag.$oflag, '-e', $pattern;
if ($?) {	
	print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
	print "<H3>Cannot execute global. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
	print "@body_end@\n";
	print "@html_end@\n";
	exit 0;
}
$pattern =~ s/([&<>])/$ctab{$1}/ge;
print "<H1><FONT COLOR=#cc0000>" . $pattern . "</FONT></H1>\n";
print "Following $words are matched to above pattern.@hr@\n";
$cnt = 0;
local($tag, $lno, $filename, $fileno);
print "<PRE>\n";
open(PIPEOUT, "| @gtagspath@ --convert");
if ($?) {	
	print "<H1><FONT COLOR=#cc0000>Error</FONT></H1>\n";
	print "<H3>Cannot execute gtags --convert. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
	print "@body_end@\n";
	print "@html_end@\n";
	exit 0;
}
$| = 1;	# flush buffer
while (<PIPE>) {
	$cnt++;
	($tag, $lno, $filename) = split;
	s/([&<>])/$ctab{$1}/ge;
	# " ./$filename " is replaced with file number by gtags --convert.
	s!(^[^ \t]+)!<A HREF=$htmlbase/S/ ./$filename .@HTML@#$lno>$1<\/A>!;
	print PIPEOUT;
}
$| = 1;	# flush buffer
close(PIPE);
close(PIPEOUT);
print "</PRE>\n";
if ($cnt == 0) {
	print "<H3>Pattern not found. <A HREF=$htmlbase/mains.@normal_suffix@>[return]</A></H3>\n";
}
print "@body_end@\n";
print "@html_end@\n";
exit 0;
#------------------------------------------------------------------
# SORRY TO HAVE SURPRISED YOU!
# IF YOU SEE THIS UNREASONABLE FILE WHILE BROUSING, FORGET PLEASE.
# IF YOU ARE A ADMINISTRATOR OF THIS SITE, PLEASE SETUP HTTP SERVER
# SO THAT THIS SCRIPT CAN BE EXECUTED AS A CGI COMMAND. THANK YOU.
#------------------------------------------------------------------
END_OF_SCRIPT

	$quoted_body_begin = $'body_begin;
	$quoted_body_begin =~ s/"/\\"/g;
	$quoted_body_end = $'body_end;
	$quoted_body_end =~ s/"/\\"/g;
	$script =~ s/\@html_begin\@/$'html_begin/g;
	$script =~ s/\@html_end\@/$'html_end/g;
	$script =~ s/\@body_begin\@/$quoted_body_begin/g;
	$script =~ s/\@body_end\@/$quoted_body_end/g;
	$script =~ s/\@normal_suffix\@/$'normal_suffix/g;
	$script =~ s/\@SRCS\@/$'SRCS/g;
	$script =~ s/\@HTML\@/$'HTML/g;
	$script =~ s/\@tabs\@/$'tabs/g;
	$script =~ s/\@hr\@/$'hr/g;
	$script =~ s/\@globalpath\@/$globalpath/g;
	$script =~ s/\@gtagspath\@/$gtagspath/g;
	print PROGRAM $script;
	close(PROGRAM) || &'error("cannot make CGI program.");
	$'file_count++;
}
#
# makebless: make bless script
#
sub makebless {
	local($file) = @_;
	local($action) = "$'script_alias/global.cgi";

	open(SCRIPT, ">$file") || &'error("cannot make bless script.");
	local($script) = <<'END_OF_SCRIPT';
#!/bin/sh
#
# Bless.sh: rewrite id's value of html for centralised cgi script.
#
# Usage:
#	% htags -fS		<- works well at generated place.
#	% mv HTML /var/obj	<- move to another place. It doesn't work.
#	% cd /var/obj/HTML
#	% sh bless.sh		<- OK. It will work well!
#
pattern1='INPUT TYPE=hidden NAME=id VALUE'
pattern2='FORM METHOD=GET ACTION'
action=@action@
case $1 in
-v)	verbose=1;;
esac
id=`pwd`
for f in mains.html index.html search.html; do
	if [ -f $f ]; then
		sed -e "s!<$pattern1=.*>!<$pattern1=$id>!" -e "s!<$pattern2=[^ >]*!<$pattern2=$action!" $f > $f.new;
		if cmp $f $f.new >@null_device@; then
			rm -f $f.new
		else
			mv $f.new $f
			[ $verbose ] && echo "$f was blessed."
		fi
	fi
done
rm -f cgi-bin/global.cgi
END_OF_SCRIPT
	$script =~ s/\@null_device\@/$'null_device/g;
	$script =~ s/\@action\@/$action/g;
	print SCRIPT $script;
	close(SCRIPT) || &'error("cannot make bless script.");
}
#
# makeghtml: make unzip script
#
sub makeghtml {
	local($file) = @_;
	open(PROGRAM, ">$file") || &'error("cannot make unzip script.");
	local($script) = <<END_OF_SCRIPT;
#!/bin/sh
echo "content-type: text/html"
echo
gzip -S $'HTML -d -c "\$PATH_TRANSLATED"
END_OF_SCRIPT

	print PROGRAM $script;
	close(PROGRAM);
}
#
# makehtaccess: make .htaccess skeleton file.
#
sub makehtaccess {
	local($file) = @_;
	open(SKELETON, ">$file") || &'error("cannot make .htaccess skeleton file.");
	$skeleton = <<END_OF_SCRIPT;
#
# Skelton file for .htaccess -- This file was generated by htags(1).
#
# Htags have made gzipped hypertext because you specified -c option.
# If your browser doesn't decompress gzipped hypertext, you will need to
# setup your http server to treat this hypertext as gzipped files first.
# There are many way to do it, but one of the method is to put .htaccess
# file in 'HTML' directory.
#
# Please rewrite '/cgi-bin/ghtml.cgi' to the true value in your web site.
#
AddHandler htags-gzipped-html $'gzipped_suffix
Action htags-gzipped-html /cgi-bin/ghtml.cgi
END_OF_SCRIPT
	print SKELETON $skeleton;
	close(SKELETON) || &'error("cannot make .htaccess skeleton.");
}
#
# makerebuild: make rebuild script
#
sub makerebuild {
	local($file) = @_;
	local($cwd) = getcwd;
	open(FILE, ">$file") || &'error("cannot make rebuild script.");
	print FILE "#!/bin/sh\n";
	print FILE "#\n";
	print FILE "# rebuild.sh: rebuild hypertext with the previous context.\n";
	print FILE "#\n";
	print FILE "# Usage:\n";
	print FILE "#\t% sh rebuild.sh\n";
	print FILE "#\n";
	print FILE "cd $cwd && GTAGSCONF='$save_config' htags $save_argv\n";
	close(FILE);
}
#
# makehelp: make help file
#
sub makehelp {
	local($file) = @_;
	local(@label) = ($'icon_list) ? @'anchor_comment : @'anchor_label;
	local(@icons) = @'anchor_icons;
	local(@msg)   = @'anchor_msg;

	open(HELP, ">$file") || &'error("cannot make help file.");
	print HELP $'html_begin, "\n";
	print HELP &'set_header('HELP');
	print HELP $'body_begin, "\n";
	print HELP "<H2>Usage of Links</H2>\n";

	print HELP "<PRE>/* ";
	foreach $n (0 .. $#label) {
		if ($'icon_list) {
			print HELP "<IMG SRC=icons/$icons[$n] ALT=\[$label[$n]\] $'icon_spec>";
			if ($n < $#label) {
				print HELP " ";
			}
		} else {
			print HELP "\[$label[$n]\]";
		}
	}
	if ($'show_position) {
		print HELP "[+line file]";
	}
	print HELP " */</PRE>\n";
	print HELP "<DL>\n";
	foreach $n (0 .. $#label) {
		print HELP "<DT>";
		if ($'icon_list) {
			print HELP "<IMG SRC=icons/$icons[$n] ALT=\[$label[$n]\] $'icon_spec>";
		} else {
			print HELP "[$label[$n]]";
		}
		print HELP "<DD>$msg[$n]\n";
	}
	if ($'show_position) {
		print HELP "<DT>[+line file]";
		print HELP "<DD>Current position (line number and file name).\n";
	}
	print HELP "</DL>\n";
	print HELP $'body_end, "\n";
	print HELP $'html_end, "\n";
	close(HELP);
	$'file_count++;
}
#
# makedupindex: make duplicate entries index (D/*, R/* and Y/*)
#
#	go)	tag cache
#	r)	$count
#
sub makedupindex {
	local($dist) = @_;
	local($definition_count) = 0;
	local($srcdir) = "../$'SRCS";
	local(%kind) = ('GTAGS', 'definition', 'GRTAGS', 'reference', 'GSYMS', 'symbol');
	local(%dir) = &'get_dirhash();
	local($flag) = ($'cflag) ? 'C' : 'N';

	#
	# Gtags with --write option create file and put data for each
	# duplicate entries index.
	#
	if (!$'dynamic) {
		open(FILE, "| $'gtags --write") || &'error("cannot fork.");
	}
	foreach $db (&'get_taglist()) {
		local($kind) = $kind{$db};
		local($option) = &'get_option($db);
		local($prev) = '';
		local($first_line);
		local($writing) = 0;
		local($count) = 0;
		local($entry_count) = 0;
		local($command);

		#
		# It is not necessary to sort here. In addition, the line
		# image of the source code is also unnecessary with the
		# --dynamic option, 
		#
		$option .= $'dynamic ? 'nn' : 'n';

		$command = "global -x$option \".*\" | $'gtags --sort";
		open(LIST, "$command |") || &'error("cannot fork.");
		while (<LIST>) {
			chop;
			local($tag) = split;
			if ($prev ne $tag) {
				$count++;
				print STDERR " [$count] adding $kind $tag\n" if ($'vflag);
				if ($writing) {
					if (!$'dynamic) {
						print FILE &'list_end;
						print FILE $'body_end, "\n";
						print FILE $'html_end, "\n";
						$'file_count++;
					}
					$writing = 0;
					#
					# cache record: " <file id> <entry number>"
					#
					local($prev_count) = $count - 1;
					&cache'put($db, $prev, " $prev_count $entry_count");
				}
				# single entry
				if ($first_line) {
					local($nouse, $lno, $filename) = split(/[ \t]+/, $first_line);
					&cache'put($db, $prev, "$lno $filename");
				}
				$first_line = $_;
				$prev = $tag;
				$entry_count = 0;
			} else {
				# duplicate entry
				if ($first_line) {
					#
					# Protocol:
					# N<file>	create normal file.
					# C<file>	create gzipped file.
					#
					if (!$'dynamic) {
						local($dir) = $dir{$db};
						print FILE "$flag$dist/$dir/$count.$'HTML\n";
						print FILE $'html_begin, "\n";
						print FILE &'set_header($tag);
						print FILE $'body_begin, "\n";
						print FILE &'list_begin;
						print FILE &'list_body($srcdir, $first_line);
					}
					$writing = 1;
					$entry_count++;
					$first_line = '';
				}
				if (!$'dynamic) {
					print FILE &'list_body($srcdir, $_);
				}
				$entry_count++;
			}
		}
		$definition_count = $count if ($db eq 'GTAGS');
		close(LIST);
		if ($?) { &'error("'$command' failed."); }
		if ($writing) {
			if (!$'dynamic) {
				print FILE &'list_end;
				print FILE $'body_end, "\n";
				print FILE $'html_end, "\n";
				$'file_count++;
			}
			#
			# cache record: " <file id> <entry number>"
			#
			&cache'put($db, $prev, " $count $entry_count");
		}
		if ($first_line) {
			local($nouse, $lno, $filename) = split(/[ \t]+/, $first_line);
			&cache'put($db, $prev, "$lno $filename");
		}
	}
	if (!$'dynamic) {
		close(FILE);
	}
	$definition_count;
}
#
# makedefineindex: make definition index (including alphabetic index)
#
#	i)	dist		distribution directory
#	i)	file		definition index file
#	i)	total		definitions total
#	gi)	tag cache
#	go)	@defines
#
sub makedefineindex {
	local($dist, $file, $total) = @_;
	local($count) = 0;
	local($alpha_count) = 0;
	local($indexlink) = ($'Fflag) ? "../defines.$'normal_suffix" : "../mains.$'normal_suffix";
	local($index_string) = 'Index Page';
	local($target) = ($'Fflag) ? 'mains' : '_top';

	if ($'map_file) {
		open(MAP, ">$'dist/MAP") || &'error("cannot open.");
	}
	open(DEFINES, ">$file") || &'error("cannot make function index '$file'.");
	print DEFINES $'html_begin, "\n";
	print DEFINES &'set_header($'title_define_index);
	print DEFINES $'body_begin, "\n";
	if ($'Fflag) {
		print DEFINES "<A HREF=defines.$'normal_suffix><H2>$'title_define_index</H2></A>\n";
	} else {
		print DEFINES "<H2>$'title_define_index</H2>\n";
	}
	if (!$'aflag && !$'Fflag) {
		$indexlink = "mains.$'normal_suffix";
		print DEFINES "<A HREF=$indexlink TITLE='$index_string'>" .
			($'icon_list ? "<IMG SRC=icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]") .
			"</A>\n";
	}
	if (!$'no_order_list) {
		print DEFINES "<OL>\n" if (!$'aflag);
	}
	local($old) = select(DEFINES);
	local($command) = "global -c";
	open(TAGS, "$command |") || &'error("cannot fork.");
	local($alpha, $alpha_f);
	@defines = ();	# [A][B][C]...
	while (<TAGS>) {
		$count++;
		chop;
		local($tag) = $_;
		print STDERR " [$count/$total] adding $tag\n" if ($'vflag);
		if ($'aflag && ($alpha eq '' || $tag !~ /^$alpha/)) {
			if ($alpha) {
				local($msg) = $alpha_count == 1 ? 'definition is containded.' : 'definitions are containded.';
				push(@defines, "<A HREF=defines/$alpha_f.$'HTML TITLE='$alpha_count $msg'>[$alpha]</A>\n");
				$alpha_count = 0;
				if (!$'no_order_list) {
					print ALPHA "</OL>\n";
				} else {
					print ALPHA "<BR>\n";
				}
				print ALPHA "<A HREF=$indexlink TITLE='$index_string'>";
				print ALPHA $'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]";
				print ALPHA "</A>\n";
				print ALPHA $'body_end, "\n";
				print ALPHA $'html_end, "\n";
				close(ALPHA);
				$'file_count++;
			}
			# for multi-byte code
			local($c0, $c1);
			$c0 = substr($tag, 0, 1);
			if (ord($c0) > 127) {
				$c1 = substr($tag, 1, 1);
				$alpha   = $c0 . $c1;
				$alpha_f = "" . ord($c0) . ord($c1);
			} else {
				$alpha = $alpha_f = $c0;
				# for CD9660 or FAT file system
				# 97 == 'a', 122 == 'z'
				if (ord($c0) >= 97 && ord($c0) <= 122) {
					$alpha_f = "l$c0";
				}
			}
			if ($'cflag) {
				open(ALPHA, "| gzip -c >$dist/defines/$alpha_f.$'HTML") || &'error("cannot make alphabetical function index.");
			} else {
				open(ALPHA, ">$dist/defines/$alpha_f.$'HTML") || &'error("cannot make alphabetical function index.");
			}
			print ALPHA $'html_begin, "\n";
			print ALPHA &'set_header("[$alpha]");
			print ALPHA $'body_begin, "\n";
			print ALPHA "<H2>[$alpha]</H2>\n";
			print ALPHA "<A HREF=$indexlink TITLE='$index_string'>";
			print ALPHA $'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]";
			print ALPHA "</A>\n";
			if (!$'no_order_list) {
				print ALPHA "<OL>\n";
			} else {
				print ALPHA "<BR><BR>\n";
			}
			select(ALPHA);
		}
		$alpha_count++;
		#
		# generating url for function definition.
		#
		local($line) = &cache'get('GTAGS', $tag);
		local($url);
		local($guide);
		if ($line =~ /^ (\d+) (\d+)/) {
			$url = "$'DEFS/$1.$'HTML";
			if ($'dynamic) {
				local($cgi) = $'action;
				if ($'action !~ /^\// && $'aflag) {
					$cgi = "../" . $'action;
				}
				$url = "${cgi}?pattern=$tag&type=definitions";
			} else {
				$url = "$'DEFS/$1.$'HTML";
				if ($'aflag) {
					$url = "../" . $url;
				}
			}
			$guide = "Multiple defined in $2 places.";
		} else {
			local($lno, $path) = split(/[ \t]+/, $line);
			local($filename) = &'path2url($path);
			$path =~ s!^\./!!;
			$url = "$'SRCS/$filename#$lno";
			if ($'aflag) {
				$url = "../" . $url;
			}
			$guide = "Defined at $lno in $path.";
		}
		if (!$'no_order_list) {
			print "<LI>";
		}
		print "<A HREF=$url TARGET=$target";
		print " TITLE='$guide'" if ($guide);
		print ">$tag</A>\n";
		if ($'no_order_list) {
			print "<BR>";
		}
		if ($'map_file) {
			print MAP "$tag\t$url\n";
		}
	}
	close(TAGS);
	if ($?) { &'error("'$command' failed."); }
	select($old);
	if ($'aflag) {
		push(@defines, "<A HREF=defines/$alpha_f.$'HTML TITLE='$alpha_count definitions are containded.'>[$alpha]</A>\n");
		if (!$'no_order_list) {
			print ALPHA "</OL>\n";
		} else {
			print ALPHA "<BR>\n";
		}
		print ALPHA "<A HREF=$indexlink TITLE='$index_string'>";
		print ALPHA $'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]";
		print ALPHA "</A>\n";
		print ALPHA $'body_end, "\n";
		print ALPHA $'html_end, "\n";
		close(ALPHA);
		$'file_count++;

		print DEFINES @defines;
	}
	if (!$'no_order_list) {
		print DEFINES "</OL>\n" if (!$'aflag);
	}
	if (!$'aflag && !$'Fflag) {
		print DEFINES "<A HREF=$indexlink TITLE='$index_string'>" .
			($'icon_list ? "<IMG SRC=icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]") .
			"</A>\n";
	}
	print DEFINES $'body_end, "\n";
	print DEFINES $'html_end, "\n";
	close(DEFINES);
	$'file_count++;
	if ($'map_file) {
		close(MAP);
	}
	$count;
}
#
# makefileindex: make file index
#
#	i)	dist		distribution directory
#	i)	file		file name
#	i)	$incdir		$INC directory
#	go)	@files
#	go)	%includes
#
sub makefileindex {
	local($dist, $file, $incdir) = @_;
	local($count) = 0;
	local($indexlink) = ($'Fflag) ? "../files.$'normal_suffix" : "../mains.$'normal_suffix";
	local($target) = ($'Fflag) ? 'mains' : '_top';
	local(@dirstack, @fdstack);
	local($findcom) = ($'other_files) ? "$'findcom --other | sort -t / +1" : $'findcom;
	local($parent_string) = 'Parent Directory';

	open(FIND, "$findcom |") || &'error("cannot fork.");
	open(FILES, ">$file") || &'error("cannot make file '$file'.");
	print FILES $'html_begin, "\n";
	print FILES &'set_header($'title_file_index);
	print FILES $'body_begin, "\n";
	print FILES "<A HREF=files.$'normal_suffix><H2>$'title_file_index</H2></A>\n";
	if (!$'no_order_list) {
		print FILES "<OL>\n";
	}
	local($org) = select(FILES);
	local(@push, @pop, $file);

	while (<FIND>) {
		local($notsource) = 0;
		chop;
		if (/^ /) {
			next if (!$'other_files);
			s/^ //;
			next if (-B $_);
			$notsource = 1;
		}
		$count++;
		s!^\./!!;
		print STDERR " [$count] adding $_\n" if ($'vflag);
		@push = split('/');
		$file = pop(@push);
		@pop  = @dirstack;
		while ($push[0] && $pop[0] && $push[0] eq $pop[0]) {
			shift @push;
			shift @pop;
		}
		if (@push || @pop) {
			while (@pop) {
				pop(@dirstack);
				local($parent) = (@dirstack) ? &'path2url(join('/', @dirstack)) : $indexlink;
				print $'no_order_list ? "<BR>\n" : "</OL>\n";
				print "<A HREF=$parent TITLE='$parent_string'>" .
					($'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]") .
					"</A>\n";
				print $'body_end, "\n";
				print $'html_end, "\n";
				$path = pop(@fdstack);
				close($path);
				$'file_count++;
				select($fdstack[$#fdstack]) if (@fdstack);
				pop(@pop);
			}
			while (@push) {
				local($parent) = (@dirstack) ? &'path2url(join('/', @dirstack)) : $indexlink;
				push(@dirstack, shift @push);
				$path = join('/', @dirstack);
				$cur = "$dist/files/" . &'path2url($path);
				local($last) = $path;
				if (!$'full_path) {
					$last =~ s!.*/!!;
				}
				local($li) = '';
				if (!$'no_order_list) {
					$li .="<LI>";
				}
				$li .= "<A HREF=" . (@dirstack == 1 ? 'files/' : '') . &path2url($path) . " TITLE='$path/'>" .
					($'icon_list ? "<IMG SRC=" . (@dirstack == 1 ? '' : '../') . "icons/$'dir_icon ALT=[$path/] HSPACE=3 $'icon_spec>" : '') .
					"$last/</A>\n";
				if ($'no_order_list) {
					$li .="<BR>";
				}
				if (@dirstack == 1) {
					push(@files, $li);
				} else {
					print $li;
				}
				if ($'cflag) {
					open($cur, "| gzip -c >\"$cur\"") || &'error("cannot make directory index.");
				} else {
					open($cur, ">$cur") || &'error("cannot make directory index.");
				}
				select($cur);
				push(@fdstack, $cur);
				print $'html_begin, "\n";
				print &'set_header("$path/");
				print $'body_begin, "\n";
				print "<H2>";
				print "<A HREF=$indexlink>root</A>/";
				local(@p);
				foreach $n (0 .. $#dirstack) {
					push(@p, $dirstack[$n]);
					local($url) = &'path2url(join('/', @p));
					print "<A HREF=$url>" if ($n < $#dirstack);
					print "$dirstack[$n]";
					print "</A>" if ($n < $#dirstack);
					print "/";
				}
				print "</H2>\n";
				print "<A HREF=$parent TITLE='$parent_string'>" .
					($'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]") .
					"</A>\n";
				if (!$'no_order_list) {
					print "<OL>\n";
				} else {
					print "<BR><BR>\n";
				}
			}
		}
		#
		# We assume the file which has one of the following suffixes
		# as a candidate of include file.
		#
		# C: .h
		# C++: .hxx, .hpp, .H
		# PHP: .inc.php
		#
		# collect include files. format is
		#	counter + '\n' + path1 + '\n' + path2 ...
		#
		if (/.*\.(h|hxx|hpp|H|inc\.php)$/) {
			if (!defined $includes{$file}) {
				$includes{$file} = "$count\n$_";
			} else {
				# duplicate entries
				$includes{$file} = "$includes{$file}\n$_";
			}
		}
		local($url);
		if ($notsource && $'dynamic) {
			local($cgi) = ($'action =~ /^\// || @dirstack == 0) ? $'action : "../$'action";
			$url = "${cgi}?pattern=$_&type=source";
		} else {
			$url = (@dirstack == 0 ? '' : '../') . "$'SRCS/" . &'path2url($_);
		}
		local($last) = $_;
		if (!$'full_path) {
			$last =~ s!.*/!!;
		}
		local($icon) = ($last =~ /\.[chy]$/) ? $'c_icon : $'file_icon;
		local($li) = '';
		if (!$'no_order_list) {
			$li .= "<LI>\n";
		}
		$li .= "<A HREF=$url TARGET=$target TITLE='$_'>" .
			($'icon_list ? "<IMG SRC=" . (@dirstack == 0 ? '' : '../') . "icons/$icon ALT=[$_] HSPACE=3 $'icon_spec>" : '') .
			"$last</A>\n";
		if ($'no_order_list) {
			$li .= "<BR>\n";
		}
		if (@dirstack == 0) {
			push(@files, $li);
		} else {
			print $li;
		}
	}
	close(FIND);
	if ($?) { &'error("cannot traverse directory.($findcom)"); }
	while (@dirstack) {
		pop(@dirstack);
		local($parent) = (@dirstack) ? &'path2url(join('/', @dirstack)) : $indexlink;
		print $'no_order_list ? "<BR>\n": "</OL>\n";
		print "<A HREF=$parent TITLE='$parent_string'>" .
			($'icon_list ? "<IMG SRC=../icons/$'back_icon ALT='[..]' $'icon_spec>" : "[..]") .
			"</A>\n";
		print $'body_end, "\n";
		print $'html_end, "\n";
		$path = pop(@fdstack);
		close($path);
		$'file_count++;
		select($fdstack[$#fdstack]) if (@fdstack);
	}
	print FILES @files;
	print FILES $'no_order_list ? "<BR>\n" : "</OL>\n";
	print FILES $'body_end, "\n";
	print FILES $'html_end, "\n";
        close(FILES);
	$'file_count++;

	#
	# Pick up include pattern.
	#
	# C: #include "xxx.h"
	# PHP: include("xxx.inc.php");
	#
	local($command) = "global -gnx \"^[ \\t]*(#[ \\t]*include|include[ \\t]*\\()\"";
	open(PIPE, "$command |") || &'error("cannot fork.");
	while (<PIPE>) {
		chop;
		local($nouse, $lno, $filename, $image) = split(/\s+/, $_, 4);
		local($last, $sep);
		if ($filename =~ /\.php$/) {
			($last, $sep) = ($image =~ m![/"']([^/"']+)(["'])\)!);
		} else {
			($last, $sep) = ($image =~ m![</"]([^</"]+)([">])!);
		}
		if (!defined $includes{$last}) {
			next;
		}
		s/^[^ \t]+/$last/;
		if (!defined $included_from{$last}) {
			$included_from{$last} = "$_";
		} else {
			$included_from{$last} = "$included_from{$last}\n$_";
		}
	}
	close(PIPE);

	select($org);
	foreach $last (keys %includes) {
		if (!defined $included_from{$last}) {
			delete $includes{$last};
			next;
		}
		local($no, @incs) = split(/\n/, $includes{$last});
		if (@incs > 1) {
			local($path) = "$incdir/$no.$'HTML";
			if ($'cflag) {
				open(INCLUDE, "| gzip -c >$path") || &'error("cannot open file '$path'.");
			} else {
				open(INCLUDE, ">$path") || &'error("cannot open file '$path'.");
			}
			print INCLUDE $'html_begin, "\n";
			print INCLUDE &'set_header($last);
			print INCLUDE $'body_begin, "\n";
			print INCLUDE "<PRE>\n";
			foreach $filename (@incs) {
				$path = &'path2url($filename);
				print INCLUDE "<A HREF=../$'SRCS/$path TARGET=$target>$filename</A>\n";
			}
			print INCLUDE "</PRE>\n";
			print INCLUDE $'body_end, "\n";
			print INCLUDE $'html_end, "\n";
			close(INCLUDE);
			$'file_count++;
			# '' means that information already written to file.
			$includes{$last} = $no;
		}
		local(@refs) = split(/\n/, $included_from{$last});
		if (@refs == 1) {
			local($nouse, $lno, $filename) = split(/\s+/, $refs[0]);
			$included_from{$last} = "$lno $filename";
		} else {
			local($path) = "$dist/$'INCREFS/$no.$'HTML";
			if ($'cflag) {
				open(INCLUDE, "| gzip -c >$path") || &'error("cannot open file '$path'.");
			} else {
				open(INCLUDE, ">$path") || &'error("cannot open file '$path'.");
			}
			print INCLUDE $'html_begin, "\n";
			print INCLUDE &'set_header($last);
			print INCLUDE $'body_begin, "\n";
			print INCLUDE &'list_begin();
			foreach $line (@refs) {
				print INCLUDE &'list_body("../$'SRCS", $line);
			}
			print INCLUDE &'list_end;
			print INCLUDE $'body_end, "\n";
			print INCLUDE $'html_end, "\n";
			close(INCLUDE);
			$'file_count++;
			$included_from{$last} = " $no " . @refs;
		}
	}
	$count;
}
#
# makesearchpart: make search part
#
#	i)	$action	action url
#	i)	$id	hidden variable
#	i)	$target	target
#	r)		html
#
sub makesearchpart {
	local($action, $id, $target) = @_;
	local($index) = '';

	if ($'Fflag) {
		$index .= "<A HREF=search.$'normal_suffix><H2>SEARCH</H2></A>\n";
	} else {
		$index .= "<H2>SEARCH</H2>\n";
	}
	if (!$target) {
		$index .= "Please input object name and select [Search]. POSIX's regular expression is allowed.<P>\n"; 
	}
	$index .= "<FORM METHOD=GET ACTION=$action";
	$index .= " TARGET=$target" if ($target);
	$index .= ">\n";
	$index .= "<INPUT NAME=pattern>\n";
	$index .= "<INPUT TYPE=hidden NAME=id VALUE=$id>\n";
	$index .= "<INPUT TYPE=submit VALUE=Search>\n";
	$index .= "<INPUT TYPE=reset VALUE=Reset><BR>\n";
	$index .= "<INPUT TYPE=radio NAME=type VALUE=definition CHECKED TITLE='Retrieve the definition place of the specified symbol.'>";
	$index .= ($target) ? "Def" : "Definition";
	$index .= "\n<INPUT TYPE=radio NAME=type VALUE=reference TITLE='Retrieve the reference place of the specified symbol.'>";
	$index .= ($target) ? "Ref" : "Reference";
	if (-f "$dbpath/GSYMS") {
		$index .= "\n<INPUT TYPE=radio NAME=type VALUE=symbol TITLE='Retrieve the place of the specified symbol is used.'>";
		$index .= ($target) ? "Sym" : "Other symbol";
	}
	$index .= "\n<INPUT TYPE=radio NAME=type VALUE=path TITLE='Look for path name which matches to the specified pattern.'>";
	$index .= ($target) ? "Path" : "Path name";
	if ($'enable_grep) {
		$index .= "\n<INPUT TYPE=radio NAME=type VALUE=grep TITLE='Retrieve lines which matches to the specified pattern.'>";
		$index .= ($target) ? "Grep" : "Grep pattern";
	}
	if ($'enable_idutils && -f "$dbpath/ID") {
		$index .= "\n<INPUT TYPE=radio NAME=type VALUE=idutils TITLE='Retrieve lines which matches to the specified pattern using idutils(1).'>";
		$index .= ($target) ? "Id" : "Id pattern";
	}
	$index .= "<BR>\n<INPUT TYPE=checkbox NAME=icase VALUE=1 TITLE='Ignore case distinctions in the pattern.'>";
	$index .= ($target) ? "Icase" : "Ignore case";
	if ($'enable_grep && $'other_files) {
		$index .= "\n<INPUT TYPE=checkbox NAME=other VALUE=1 TITLE='Files other than the source code are also retrieved.'>";
		$index .= ($target) ? "Other" : "Other files";
	}
	$index .= "\n</FORM>\n";
	$index;
}
#
# makecommonpart: make a common part for mains.html and index.html
#
#	gi)	@files
#	gi)	@defines
#
sub makecommonpart {
	local($title) = @_;
	local($index) = '';

	if ($'include_header) {
		$index .= $'include_header;
		$index .= "\n$'hr\n";
	}
	$index .= "$'title_begin$'title$'title_end\n";
	$index .= "<P ALIGN=right>\n";
	$index .= "Last updated " . &'date . "<BR>\n";
	$index .= "This hypertext was generated by <A HREF=$'www TARGET=_top TITLE='Go to the GLOBAL project page.'>GLOBAL-$'version</A>.<BR>\n";
	$index .= "</P>\n";
	$index .= "$'hr\n";
	if ($'include_caution) {
		$'include_caution =~ s/\@FILE_COUNT\@/$'file_count/;
		$'include_caution =~ s/\@WWW\@/$'www/;
		$index .= $'include_caution;
		$index .= "\n$'hr\n";
	}
	if ($'fflag) {
		$index .= &makesearchpart($'action, $'id);
		$index .= "$'hr\n";
	}
	$index .= "<H2>MAINS</H2>\n";
	local($command) = "global -nx $'main_func | sort +0 -1 +2 -3 +1n -2";
	open(PIPE, "$command |") || &'error("cannot fork.");
	$index .= &'list_begin();
	while (<PIPE>) {
		chop;
		$index .= &'list_body($'SRCS, $_);
	}
	$index .= &'list_end();
	close(PIPE);
	if ($?) { &'error("'$command' failed."); }
	$index .= "$'hr\n";
	if ($'aflag && !$'Fflag) {
		$index .= "<H2>$'title_define_index</H2>\n";
		foreach $f (@defines) {
			$index .= $f;
		}
	} else {
		$index .= "<H2><A HREF=defines.$'normal_suffix>$'title_define_index</A></H2>\n";
	}
	$index .= "$'hr\n";
	if ($'Fflag) {
		$index .= "<H2><A HREF=files.$'normal_suffix>$'title_file_index</A></H2>\n";
	} else {
		$index .= "<H2>$'title_file_index</H2>\n";
		if (!$'no_order_list) {
			$index .= "<OL>\n";
		}
		foreach $f (@files) {
			$index .= $f;
		}
		if (!$'no_order_list) {
			$index .= "</OL>\n";
		} else {
			$index .= "<BR>\n";
		}
		$index .= "$'hr\n";
	}
	$index;
}
#
# makeindex: make index file
#
#	i)	$file	file name
#	i)	$title	title of index file
#	i)	$index	common part
#
sub makeindex {
	local($file, $title, $index) = @_;

	if ($'Fflag) {
		open(FRAME, ">$file") || &'error("cannot open file '$file'.");
		print FRAME $'html_begin, "\n";
		print FRAME "<HEAD>\n<TITLE>$title</TITLE>\n";
		print FRAME "$'meta_robots\n$'meta_generator\n";
		print FRAME $'style_sheet if ($'style_sheet);
		print FRAME "</HEAD>\n";
		print FRAME "<FRAMESET COLS='200,*'>\n";
		if ($'fflag) {
			print FRAME "<FRAMESET ROWS='33%,33%,*'>\n";
			print FRAME "<FRAME NAME=search SRC=search.$'normal_suffix>\n";
		} else {
			print FRAME "<FRAMESET ROWS='50%,*'>\n";
		}
		print FRAME "<FRAME NAME=defines SRC=defines.$'normal_suffix>\n";
		print FRAME "<FRAME NAME=files SRC=files.$'normal_suffix>\n";
		print FRAME "</FRAMESET>\n";
		print FRAME "<FRAME NAME=mains SRC=mains.$'normal_suffix>\n";
		print FRAME "<NOFRAMES>\n";
		print FRAME $'body_begin, "\n";
		print FRAME $index;
		print FRAME $'body_end, "\n";
		print FRAME "</NOFRAMES>\n";
		print FRAME "</FRAMESET>\n";
		print FRAME $'html_end, "\n";
		close(FRAME);
		$'file_count++;
	} else {
		open(FILE, ">$file") || &'error("cannot open file '$file'.");
		print FILE $'html_begin, "\n";
		print FILE &'set_header($title);
		print FILE $'body_begin, "\n";
		print FILE $index;
		print FILE $'body_end, "\n";
		print FILE $'html_end, "\n";
		close(FILE);
		$'file_count++;
	}
}
#
# makemainindex: make main index
#
#	i)	$file	file name
#	i)	$index	common part
#
sub makemainindex {
	local($file, $index) = @_;

	open(INDEX, ">$file") || &'error("cannot create file '$file'.");
	print INDEX $'html_begin, "\n";
	print INDEX &'set_header($title);
	print INDEX $'body_begin, "\n";
	print INDEX $index;
	print INDEX $'body_end, "\n";
	print INDEX $'html_end, "\n";
	close(INDEX);
	$'file_count++;
}
#
# makesearchindex: make search html
#
#	i)	$file	file name
#
sub makesearchindex {
	local($file) = @_;

	open(SEARCH, ">$file") || &'error("cannot create file '$file'.");
	print SEARCH $'html_begin, "\n";
	print SEARCH &'set_header('SEARCH');
	print SEARCH $'body_begin, "\n";
	print SEARCH &makesearchpart($'action, $'id, 'mains');
	print SEARCH $'body_end, "\n";
	print SEARCH $'html_end, "\n";
	close(SEARCH);
	$'file_count++;
}
#
# makehtml: make html files
#
#	i)	total	number of files.
#
sub makehtml {
	local($dist, $total) = @_;
	local($count) = 0;
	local($findcom) = ($'other_files && !$'dynamic) ? "$'findcom --other | sort -t / +1" : $'findcom;

	open(FIND, "$findcom |") || &'error("cannot fork.");
	while (<FIND>) {
		local($notsource) = 0;
		chop;
		if (/^ /) {
			next if (!$'other_files);
			s/^ //;
			if (-B $_) {
				print STDERR "Warning: '$_' is binary file. (skipped)\n" if ($'wflag);
				next;
			}
			$notsource = 1;
		}
		$count++;
		local($path) = $_;
		$path =~ s/^\.\///;
		print STDERR " [$count/$total] converting $path\n" if ($'vflag);
		$path = &'path2url($path);
		&convert'src2html($_, "$dist/$'SRCS/$path", $notsource);
	}
	close(FIND);
	if ($?) { &'error("cannot traverse directory.($findcom)"); }
}
#=========================================================================
# CONVERT PACKAGE
#=========================================================================
package convert;
#
# src2html: convert source code into HTML
#
#	i)	$file	source file	- Read from
#	i)	$hfile	HTML file	- Write to
#	i)	$notsource 1: isn't source, 0: source.
#	gi)	%includes
#			pairs of include file and the path
#
sub src2html {
	local($file, $hfile, $notsource) = @_;
	local($ncol) = $'ncol;
	local($tabs) = $'tabs;
	local(%ctab) = ('&', '&amp;', '<', '&lt;', '>', '&gt;');
	local($isjava) = ($file =~ /\.java$/) ? 1 : 0;
	local($iscpp) = ($file =~ /\.(h|c\+\+|cc|cpp|cxx|hxx|hpp|C|H)$/) ? 1 : 0;
	local($isphp) = ($file =~ /\.(php|php3|phtml)$/) ? 1 : 0;
	local($indexlink) = ($'Fflag) ? "../files.$'normal_suffix" : "../mains.$'normal_suffix";
	local($command);

	if ($'cflag) {
		$command = "gzip -c >";
		$command .= ($'w32) ? "\"$hfile\"" : "'$hfile'";
		open(HTML, "| $command") || &'error("cannot create file '$hfile'.");
	} else {
		open(HTML, ">$hfile") || &'error("cannot create file '$hfile'.");
	}
	local($old) = select(HTML);
	#
	# load tags belonging to this file.
	#
	&anchor'load($file, $notsource);
	$command = "$'gtags --expand -$tabs ";
	$command .= ($'w32) ? "\"$file\"" : "'$file'";
	open(SRC, "$command |") || &'error("cannot fork.");
	$file =~ s/^\.\///;

	print $'html_begin, "\n";
	print &'set_header($file);
	print $'body_begin, "\n";
	#
	# print the header
	#
	print "<A NAME=TOP><H2>";
	print &fill_anchor($indexlink, $file);
	if ($'cvsweb_url) {
		print "&nbsp;<A HREF=$'cvsweb_url$file";
		print "?cvsroot=$'cvsweb_cvsroot" if ($'cvsweb_cvsroot);
		print "><FONT SIZE=-1>[CVS]</FONT></A>\n";
	}
	print "</H2>\n";
	print "$'comment_begin/* ";
	print &link_format(&anchor'getlinks(0));
	if ($'show_position) {
		print $'position_begin;
		print "[+1 $file]";
		print $'position_end;
	}
	print " */$'comment_end";
	print "\n$'hr\n";

	#
	# It is not source file.
	#
	if ($notsource) {
		print "<PRE>\n";
		while (<SRC>) {
			s/([&<>])/$ctab{$1}/ge;
			print "<A NAME=$.>";
			print;
		}
		print "</PRE>\n";
	}
	#
	# Source file.
	#
	else {
		#
		# INCLUDED FROM index.
		#
		local($basename) = ($file =~ /([^\/]+)$/);
		local($incref) = $'included_from{$basename};
		if (defined $incref) {
			local($url, $title);
			if ($incref =~ /^ (\d+) (\d+)/) {
				$url = "../$'INCREFS/$1.$'HTML";
				$title = &'show('I', -1, $2);
			} else {
				local($lno, $filename) = split(/\s+/, $incref);
				$url = &'path2url($filename) . "#$lno";
				$filename =~ s!\./!!;
				$title = &'show('I', $lno, $filename);
			}
			print "<H2><A HREF=$url TITLE='$title'>$'title_included_from</A></H2>\n";
			print "$'hr\n";
		}
		#
		# DEFINITIONS index.
		#
		local($define_index) = '';
		local($lno, $tag, $type);
		for (($lno, $tag, $type) = &anchor'first(); $lno; ($lno, $tag, $type) = &anchor'next()) {
			if ($type eq 'D') {
				$define_index .= "<LI><A HREF=#$lno";
				$define_index .= " TITLE=\"" . &'show('R',$lno,'') . "\"";
				$define_index .=  ">$tag</A>\n";
			}
		}
		if ($define_index) {
			print "<H2>$'title_define_index</H2>\n";
			print "This source file includes following definitions.\n";
			print "<OL>\n";
			print $define_index;
			print "</OL>\n";
			print "$'hr\n";
		}
		#
		# print source code
		#
		print "<PRE>\n";
		$INCOMMENT = 0;			# initial status is out of comment
		$quote = '';
		local($LNO, $TAG, $TYPE) = &anchor'first();
		while (<SRC>) {
			local($converted);
			s/\r$//;
			# make link for include file
			if (!$INCOMMENT && !$quote && /^[ \t]*(#[ \t]*include|include[ \t]*\()/) {
				local($last, $sep);
				if ($isphp) {
					($last, $sep) = ($_ =~ m![/"']([^/"']+)(["'])[ \t]*\)!);
				} else {
					($last, $sep) = ($_ =~ m![</"]([^</"]+)([">])!);
				}
				if (defined $'includes{$last}) {
					local($link);
					local($no, @incs) = split(/\n/, $'includes{$last});
					if (@incs == 1) {
						$link = &'path2url($incs[0]);
					} else {
						$link = "../$'INCS/$no.$'HTML";
					}
					# quote path name.
					$last =~ s/([\[\]\.\*\+])/\\\1/g;
					if ($sep eq '"') {
						s!"(.*$last)"!"<A HREF=$link>$1</A>"!;
					} elsif ($sep eq '\'') {
						s!'(.*$last)'!"<A HREF=$link>$1</A>"!;
					} else {
						s!<(.*$last)>!&lt;<A HREF=$link>$1</A>&gt;!;
					}
					$converted = 1;
				}
			}
			# translate '<', '>' and '&' into entity name
			if (!$converted) { s/([&<>])/$ctab{$1}/ge; }
			&protect_line();	# protect quoted char, strings and comments
			# painting source code
			s/({|})/\016$1\017/g;
			local($sharp) = s/^([ \t\004]*#[ \t\004]*($'sharp_macros))// ? $1 : '';
			if ($sharp !~ '#[ \t\004]*include') {
				if ($isjava) {
					s/\b($'java_reserved_words)\b/\022$1\023/go;
				} elsif ($iscpp) {
					s/\b($'cpp_reserved_words)\b/\022$1\023/go;
				} elsif ($isphp) {
					s/\b($'php_reserved_words)\b/\022$1\023/go;
				} else {
					s/\b($'c_reserved_words)\b/\022$1\023/go;
				}
			}
			s/^/\020$sharp\021/ if ($sharp);	# recover macro
			local($define_line) = 0;
			local(@links) = ();
			local($count) = 0;
			local($warned) = 0;

			print "<A NAME=$.>";
			for (; int($LNO) == $.; ($LNO, $TAG, $TYPE) = &anchor'next()) {
				$define_line = $LNO if ($TYPE eq 'D');
				if ($TYPE eq 'R') {
					$db = 'GTAGS';
				} elsif ($TYPE eq 'Y') {
					$db = 'GSYMS';
				} else {	# 'D', 'M' or 'T'
					$db = 'GRTAGS';
				}
				local($line) = &cache'get($db, $TAG);
				if (defined($line)) {
					local($href);
					if ($line =~ /^ (\d+) (\d+)/) {
						local($url);
						if ($'dynamic) {
							local($cgi) = ($'action =~ /^\//) ? $'action : "../$'action";
							local($type);
							if ($db eq 'GTAGS') {
								$type = 'definitions';
							} elsif ($db eq 'GRTAGS') {
								$type = 'reference';
							} else {
								$type = 'symbol';
							}
							$url = "${cgi}?pattern=$TAG&type=$type";
						} else {
							local($dir);
							if ($TYPE eq 'R') {
								$dir = $'DEFS;
							} elsif ($TYPE eq 'Y') {
								$dir = $'SYMS;
							} else {	# 'D', 'M' or 'T'
								$dir = $'REFS;
							}
							$url = "../$dir/$1.$'HTML";
						}
						$href = "<A HREF=$url";
						$href .= " TITLE=\"" . &'show($TYPE,-1,$2) . "\"";
						$href .= ">$TAG</A>";
					} else {
						local($lno, $filename) = split(/[ \t]+/, $line);
						local($url) = &'path2url($filename);
						$filename =~ s!\./!!; 
						$href = "<A HREF=../$'SRCS/$url#$lno";
						$href .= " TITLE=\"" . &'show($TYPE,$lno,$filename) . "\"";
						$href .= ">$TAG</A>";
					}
					# set tag marks and save hyperlink into @links
					if (ord($TAG) > 127) {	# for multi-byte code
						if (s/([\x00-\x7f]|^)$TAG([ \t\004]*\()/$1\005$count\005$2/ || s/([\x00-\x7f]|^)$TAG([\x00-\x7f])/$1\005$count\005$2/) {
							$count++;
							push(@links, $href);
						} else {
							if ($'wflag) {
								print STDERR "Warning: $file $LNO $TAG($TYPE) tag must exist.\n";
								$warned = 1;
							}
						}
					} else {
						if (s/\b$TAG([ \t\004]*\()/\005$count\005$1/ || s/\b$TAG\b/\005$count\005/ || s/\b_$TAG\b/_\005$count\005/)
						{
							$count++;
							push(@links, $href);
						} else {
							if ($'wflag) {
								print STDERR "Warning: $file $LNO $TAG($TYPE) tag must exist.\n";
								$warned = 1;
							}
						}
					}
				} else {
					if (($TYPE eq 'R' || $TYPE eq 'Y') && $'wflag) {
						print STDERR "Warning: $file $LNO $TAG($TYPE) found but not defined.\n";
						$warned = 1;
					}
				}
			}
			# implant links
			local($s);
			for ($count = 0; @links; $count++) {
				$s = shift @links;
				unless (s/\005$count\005/$s/) {
					if ($'wflag) {
						print STDERR "Warning: $file $LNO $TAG($TYPE) tag must exist.\n";
						$warned = 1;
					}
				}
			}
			s/\016/$'brace_begin/g;
			s/\017/$'brace_end/g;
			s/\020/$'sharp_begin/g;
			s/\021/$'sharp_end/g;
			s/\022/$'reserved_begin/g;
			s/\023/$'reserved_end/g;
			&unprotect_line();
			if ($warned && $'colorize_warned_line) {
				s/^/$'warned_line_begin/;
				s/$/$'warned_line_end/;
			}
			# make guide
			if ($define_line && $'definition_header ne 'no') {
				$guide = '';
				if ($'definition_header eq 'right') {
					$guide .= ' ' x 4;
				} elsif ($'nflag) {
					$guide .= ' ' x ($ncol + 1);
				}
				$guide .= "$'comment_begin/* ";
				$guide .= &link_format(&anchor'getlinks($define_line));
				if ($'show_position) {
					$guide .= $'position_begin;
					$guide .= "[+$define_line $file]";
					$guide .= $'position_end;
				}
				$guide .= " */$'comment_end";
			}
			# print a line
			if ($define_line && $'definition_header eq 'before') {
				print $guide;
				print "\n";
			}
			printf "%${ncol}d ", $. if ($'nflag);
			chop;
			print;
			if ($define_line && $'definition_header eq 'right') {
				print $guide;
			}
			print "\n";
			if ($define_line && $'definition_header eq 'after') {
				print $guide;
				print "\n";
			}
		}
		print "</PRE>\n";
	}
	print "$'hr\n";
	print "<A NAME=BOTTOM>\n";
	print "$'comment_begin/* ";
	print &link_format(&anchor'getlinks(-1));
	if ($'show_position) {
		print $'position_begin;
		print "[+$. $file]";
		print $'position_end;
	}
	print " */$'comment_end";
	print "\n";
	print $'body_end, "\n";
	print $'html_end, "\n";

	close(SRC);
	if ($?) { &'error("cannot open file '$file'."); }
	close(HTML);
	select($old);

}
#
# fill_anchor: fill anchor into file name
#
#	i)	$root	root or index page
#	i)	$path	path name
#	r)		hypertext file name string
#
sub fill_anchor {
	local($root, $path) = @_;
	local(@file) = split(/\//, $path);
	local(@path, $url);

	$url = "<A HREF=$root>root</A>/";
	while (@file) {
		local($unit) = shift(@file);
		if (@file == 0) {
			$url .= $unit;
			last;
		}
		push(@path, $unit);
		$url .= "<A HREF=../files/";
		$url .= &'path2url(join('/', @path));
		$url .= ">";
		$url .= $unit;
		$url .= "</A>/";
	}
	$url;
}
#
# protect_line: protect quoted strings
#
#	io)	$_	source line
#
#	\003	quoted string
#	\004	comment
#
sub protect_line {
	@quoted_strings = ();
	@comments = ();
	if ($INCOMMENT) {
		# This regular expression was drived from
		# perl FAQ 4.27 (ftp://ftp.cis.ufl.edu/pub/perl/faq/FAQ)
		if (s!^([^*]*\*+([^/*][^*]*\*+)*/)!\004!) {
			push(@comments, $1);
			$INCOMMENT = 0;
		} else {
			s/^(.*)$/\004/;
			push(@comments, $1);
		}
	} elsif ($quote) {
		if (s/^(([^$quote\\]|\\.)*$quote)/\003/) {
			push(@quoted_strings, $1);
			$quote = '';
		} else {
			s/^(.*)$/\003/;
			push(@quoted_strings, $1);
		}
	}
	#
	# PHP accept both C style comment and shell style comment.
	#
	# In PHP, string may include variables but it is too hard
	# to extract them using perl. We should rewrite htags itself
	# using other language like lex or yacc in the near future.
	#
	while ($isphp ? /(#|\/\/|\/\*|'|")/ : /(\/\/|\/\*|'|")/) {
		if ($isphp && $1 eq '#') {
			s/(#.*$)/\004/;
			push(@comments, $1);
		} elsif ($1 eq '//') {
			s/(\/\/.*$)/\004/;
			push(@comments, $1);
		} elsif ($1 eq '/*') {
			# This regular expression was drived from
			# perl FAQ 4.27 (ftp://ftp.cis.ufl.edu/pub/perl/faq/FAQ)
			if (s!(/\*[^*]*\*+([^/*][^*]*\*+)*/)!\004!) {
				push(@comments, $1);
			} else {
				s/(\/\*.*)$/\004/;
				push(@comments, $1);
				$INCOMMENT = 1;
			}
		} else {
			$quote = $1;
			if (s/($quote([^$quote\\]|\\.)*$quote)/\003/) {
				push(@quoted_strings, $1);
				$quote = '';
			} else {
				s/($quote.*)$/\003/;
				push(@quoted_strings, $1);
				#
				# Accept the single quoted string which
				# consists of two or more lines for PHP
				# support.
				#
				# $quote = '' if ($quote eq "'");
			}
		}
	}
}
#
# unprotect_line: recover quoted strings
#
#	i)	$_	source line
#
sub unprotect_line {
	local($s);

	while (@comments) {
		$s = shift @comments;
		# nested tag can be occured but no problem.
		s/\004/$'comment_begin$s$'comment_end/;
	}
	while (@quoted_strings) {
		$s = shift @quoted_strings;
		s/\003/$s/;
	}
}
#
# link_format: format hyperlinks.
#
#	i)	(previous, next, first, last, top, bottom)
#
sub link_format {
	local(@tag) = @_;
	local(@label) = ($'icon_list) ? @'anchor_comment : @'anchor_label;
	local(@icons) = @'anchor_icons;
	local($line);

	for $n (0 .. $#label) {
		if ($n == 6) {
			$line .=  "<A HREF=../mains.$'normal_suffix>";
		} elsif ($n == 7) {
			$line .=  "<A HREF=../help.$'normal_suffix>";
		} elsif ($tag[$n]) {
			$line .=  "<A HREF=#$tag[$n]>";
		}
		if ($'icon_list) {
			$icon = ($tag[$n] || $n > 5) ? "$icons[$n]" : "n_$icons[$n]";
			$line .= "<IMG SRC=../icons/$icon ALT=\[$label[$n]\] $'icon_spec>";
		} else {
			$line .=  "\[$label[$n]\]";
		}
		$line .=  "</A>" if ($n > 5 || $tag[$n]);
	}
	$line;
}

#=========================================================================
# ANCHOR PACKAGE
#=========================================================================
package anchor;
#
# load: load anchors belonging to specified file.
#
#	i)	$file	source file
#	i)	$notsource 1: isn't source, 0: source.
#	go)	FIRST	first definition
#	go)	LAST	last definition
#
sub load {
	local($file, $notsource) = @_;

	@ANCHORS = ();
	$FIRST = $LAST = 0;

	if ($notsource) {
		return;
	}

	local(@keys);
	foreach $db (&'get_taglist()) {
		local($option) = &'get_option($db);
		local($pipein) = "global -fn$option ";
		$pipein .= ($'w32) ? "\"$file\"" : "'$file'";
		open(PIPE, "$pipein |") || &'error("cannot fork.");
		while (<PIPE>) {
			local($tag, $lno, $filename, $image) = split(/\s+/, $_, 4);
			local($type);
			if ($db eq 'GTAGS') {
				if ($image =~ /^#[ \t]*(define|undef)/) {
					$type = 'M';
				} elsif ($image =~ /^[ \t]*typedef/) {
					$type = 'T';
				} else {
					$type = 'D';
				}
			} elsif ($db eq 'GRTAGS') {
				$type = 'R';
			} else {
				$type = 'Y';
			}
			push(@keys, int($lno));
			push(@ANCHORS, "$lno$type$tag");
		}
		close(PIPE);
		if ($?) { &'error("'$pipein' failed."); }
	}
	sub compare { $keys[$a] <=> $keys[$b]; }
	@ANCHORS = @ANCHORS[sort compare 0 .. $#keys];
	local($c);
	for ($c = 0; $c < @ANCHORS; $c++) {
		local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$c], 2);
		if ($type eq 'D') {
			$FIRST = $lno;
			last;
		}
	}
	for ($c = $#ANCHORS; $c >= 0; $c--) {
		local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$c], 2);
		if ($type eq 'D') {
			$LAST = $lno;
			last;
		}
	}
}
#
# first: get first anchor
#
sub first {
	$CURRENT = 0;
	local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$CURRENT], 2);
	$CURRENTDEF = $CURRENT if ($type eq 'D');

	($lno, $tag, $type);
}
#
# next: get next anchor
#
sub next {
	if (++$CURRENT > $#ANCHORS) {
		return ('', '', '');
	}
	local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$CURRENT], 2);
	$CURRENTDEF = $CURRENT if ($type eq 'D');

	($lno, $tag, $type);
}
#
# getlinks: get links
#
#	i)	linenumber	>= 1: line number
#				0: header, -1: tailer
#	gi)	@ANCHORS tag table in current file
#	r)		(previous, next, first, last, top, bottom)
#
sub getlinks {
	local($linenumber) = @_;
	local($prev, $next, $first, $last, $top, $bottom);

	$prev = $next = $first = $last = $top = $bottom = 0;
	if ($linenumber >= 1) {
		local($c, $p, $n);
		if ($CURRENTDEF == 0) {
			for ($c = 0; $c <= $#ANCHORS; $c++) {
				local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$c], 2);
				if ($lno == $linenumber && $type eq 'D') {
					last;
				}
			}
			$CURRENTDEF = $c;
		} else {
			for ($c = $CURRENTDEF; $c >= 0; $c--) {
				local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$c], 2);
				if ($lno == $linenumber && $type eq 'D') {
					last;
				}
			}
		}
		$p = $n = $c;
		while (--$p >= 0) {
			local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$p], 2);
			if ($type eq 'D') {
				$prev = $lno;
				last;
			}
		}
		while (++$n <= $#ANCHORS) {
			local($lno, $type, $tag) = split(/(\D)/, $ANCHORS[$n], 2);
			if ($type eq 'D') {
				$next = $lno;
				last;
			}
		}
	}
	$first = $FIRST if ($FIRST > 0 && $linenumber != $FIRST);
	$last  = $LAST if ($LAST > 0 && $linenumber != $LAST);
	$top = 'TOP' if ($linenumber != 0);
	$bottom = 'BOTTOM' if ($linenumber != -1);
	if ($FIRST > 0 && $FIRST == $LAST) {
		$last  = '' if ($linenumber == 0);
		$first = '' if ($linenumber == -1);
	}

	($prev, $next, $first, $last, $top, $bottom);
}

#=========================================================================
# CACHE PACKAGE
#=========================================================================
package cache;
#
# open: open tag cache
#
#	i)	size	cache size
#			   -1: all cache
#			    0: no cache
#			other: sized cache
#
sub open {
	unless ($'use_cache_file) {
		return;
	}
	$GTAGS  = "$'tmp/htagd$$";
	dbmopen(%GTAGS, $GTAGS, 0600) || &'error("cannot make cache file '$GTAGS'.");
	$GRTAGS = "$'tmp/htagr$$";
	dbmopen(%GRTAGS, $GRTAGS, 0600) || &'error("cannot make cache file '$GRTAGS'.");
	if ($'symbol) {
		$GSYMS  = "$'tmp/htagy$$";
		dbmopen(%GSYMS, $GSYMS, 0600) || &'error("cannot make cache file '$GSYMS'.");
	}
}
#
# put: put tag into cache
#
#	i)	$db	database name
#	i)	$tag	tag name
#	i)	$line	tag line
#
sub put {
	local($db, $tag, $line) = @_;
	if ($db eq 'GTAGS') {
		$GTAGS{$tag} = $line;
	} elsif ($db eq 'GRTAGS') {
		$GRTAGS{$tag} = $line;
	} else {
		$GSYMS{$tag} = $line;
	}
}
#
# get: get tag from cache
#
#	i)	$db	database name
#	i)	$tag	tag name
#	r)		tag line
#
sub get {
	local($db, $tag) = @_;
	if ($db eq 'GTAGS') {
		return $GTAGS{$tag};
	} elsif ($db eq 'GRTAGS') {
		return $GRTAGS{$tag};
	} else {
		return $GSYMS{$tag};
	}
}
#
# close: close cache
#
sub close {
	unless ($'use_cache_file) {
		return;
	}
	if ($GTAGS) {
		dbmclose(%GTAGS);
		unlink("$GTAGS", "$GTAGS.db", "$GTAGS.pag", "$GTAGS.dir");
	}
	if ($GRTAGS) {
		dbmclose(%GRTAGS);
		unlink("$GRTAGS", "$GRTAGS.db", "$GRTAGS.pag", "$GRTAGS.dir");
	}
	if ($GSYMS) {
		dbmclose(%GSYMS);
		unlink("$GSYMS", "$GSYMS.db", "$GSYMS.pag", "$GSYMS.dir");
	}
}
