#!/usr/bin/perl
# $Id: chalow,v 1.1 2007-10-19 22:07:25+09 tatsuoyamashita Exp tatsuoyamashita $
#
# chalow - CHAngeLog On the Web - convert ChangeLog to HTML files
#
# This is free software with ABSOLUTELY NO WARRANTY.
# ̵̵ݾڡ (see http://nais.to/~yto/doc/zb/0002.html)
#
# chalow ۡڡ: http://chalow.org/
use strict;
use Getopt::Long;
use POSIX qw(strftime ceil);
use Time::Local;		# for 
use HTML::Template;
use ChangeLogReader;

my $version = '1.0';

# ߻γ
my $what_time_is_it_now = strftime "%Y-%m-%d %H:%M", localtime;
my $dcdate = strftime "%Y-%m-%dT%H:%M:%S+09:00", localtime;
my ($current_ym) = ($what_time_is_it_now =~ /^(\d+-\d+)/); # 

### 桼 obsolete

# ʬ home page URL --- ѻͽꡣƥץ졼Ȥľܽˤ
my $home_page_url = "http://chalow.org/";
# ʬΥۡࡼڡθƤ̾ --- ѻͽꡣƱ
my $home_page_name = "chalow home page";


### 桼
## ǥե (桼ե̾ꤵƤʤȤ)
# ̾
my $changelog_name = "ChangeLog";
# ưʸִ
my $auto_replace = '
s!(<blockquote>)!</p>$1<p>!g;
s!(</blockquote>)!</p>$1<p>!g;
';
# CSS ե
my $css_file;
# RSSե̾
my $rss_filename = "cl.rdf";
# RSS˺ǶᲿʬɽ뤫(0ξ $opt_topn Ʊ)
my $rss_topn = 0;
# ǥåڡ(index.html)ǺǶᲿʬɽ뤫
my $opt_topn = 5;
# դθ(Mon, Tue, ...)ɽ뤫 (1:yes or 0:no)
my $show_day_of_week = 1;
# ڡǡդ߽ (դ) ɽ뤫 (1:yes or 0:no)
my $reverse_order_days = 0;

# ǥåڡΥƥץ졼
my $index_page_template = << "___INDEX_PAGE_TEMPLATE"
<html lang="ja"><head>
<meta http-equiv="Content-Type" content="text/html;charset=EUC-JP">
<TMPL_IF name=css_file>
 <link rel=stylesheet href="<TMPL_VAR name=css_file>" media=all>
</TMPL_IF>
<link rel="alternate" type="application/rss+xml" title="RSS"
 href="<TMPL_VAR name=rss_file>">
<title><TMPL_VAR name=cl_name></title>
</head><body>
<a href="<TMPL_VAR name=rss_file>">RSS</a>
<h1><a href="index.html"><TMPL_VAR name=cl_name></a></h1>
<p class="calendar"><TMPL_VAR name=ym> / <TMPL_VAR name=day_list></p>
<p>last update: <TMPL_VAR name=lastupdate></p>
<p class="calendar"><TMPL_VAR name=month_page_list></p>
<p>recent <TMPL_VAR name=ndays> days</p>
<TMPL_LOOP name=entries><TMPL_VAR name=content></TMPL_LOOP>
<TMPL_VAR name=signature>
</div></body></html>
___INDEX_PAGE_TEMPLATE
    ;

# ڡΥƥץ졼
my $month_page_template = << "___MONTH_PAGE_TEMPLATE"
<html lang="ja"><head>
<meta http-equiv="Content-Type" content="text/html;charset=EUC-JP">
<TMPL_IF name=css_file>
 <link rel=stylesheet href="<TMPL_VAR name=css_file>" media=all>
</TMPL_IF>
<link rel="alternate" type="application/rss+xml" title="RSS"
 href="<TMPL_VAR name=rss_file>">
<title><TMPL_VAR name=cl_name> / <TMPL_VAR name=ym></title>
</head><body>
<TMPL_IF name=back><a href="<TMPL_VAR name=back>.html">Prev Month</a></TMPL_IF>
<TMPL_IF name=next> / <a href="<TMPL_VAR name=next>.html">Next Month</a></TMPL_IF>
<h1><a href="index.html"><TMPL_VAR name=cl_name></a> <TMPL_VAR name=ym></h1>
<p class="calendar"><TMPL_VAR name=day_list></p>
<p class="calendar"><TMPL_VAR name=month_page_list></p>
<TMPL_LOOP name=entries><TMPL_VAR name=content></TMPL_LOOP>
<p>last update: <TMPL_VAR name=lastupdate></p>
<TMPL_VAR name=signature>
</div></body></html>
___MONTH_PAGE_TEMPLATE
    ;

# ڡΥƥץ졼
my $day_page_template = << "___DAY_PAGE_TEMPLATE"
<html lang="ja"><head>
<meta http-equiv="Content-Type" content="text/html;charset=EUC-JP">
<TMPL_IF name=css_file>
 <link rel=stylesheet href="<TMPL_VAR name=css_file>" media=all>
</TMPL_IF>
<link rel="alternate" type="application/rss+xml" title="RSS"
 href="<TMPL_VAR name=rss_file>">
<title><TMPL_VAR name=cl_name> / <TMPL_VAR name=ymd></title>
</head><body>
<TMPL_IF name=back><a href="<TMPL_VAR name=back>.html">Prev Day</a></TMPL_IF>
<TMPL_IF name=next> / <a href="<TMPL_VAR name=next>.html">Next Day</a></TMPL_IF>
<h1><a href="index.html"><TMPL_VAR name=cl_name></a></h1>
<TMPL_VAR name=content> 
<p class="calendar"><a href="<TMPL_VAR name=ym>.html"><TMPL_VAR name=ym></a>
 / <TMPL_VAR name=day_list></p>
<p class="calendar"><TMPL_VAR name=month_page_list></p>
<p>last update: <TMPL_VAR name=lastupdate></p>
<TMPL_VAR name=signature>
</div></body></html>
___DAY_PAGE_TEMPLATE
    ;

# ƥڡΥƥץ졼
my $item_page_template = << "___PAGE_TEMPLATE"
<html lang="ja"><head>
<meta http-equiv="Content-Type" content="text/html;charset=EUC-JP">
<TMPL_IF name=css_file>
 <link rel=stylesheet href="<TMPL_VAR name=css_file>" media=all>
</TMPL_IF>
<link rel="alternate" type="application/rss+xml" title="RSS"
 href="<TMPL_VAR name=rss_file>">
<title><TMPL_VAR name=header_text></title>
</head><body>
<TMPL_IF name=back><a href="<TMPL_VAR name=back>.html">Prev</a></TMPL_IF>
<TMPL_IF name=next> / <a href="<TMPL_VAR name=next>.html">Next</a></TMPL_IF>
/ <a href="index.html"><TMPL_VAR name=cl_name></a>
<h1><TMPL_VAR name=header><TMPL_VAR name=cat></h1>
<div class="day">
<a href="<TMPL_VAR name=ymd>.html"><TMPL_VAR name=ymd></a>
<div class="body">
<!-- start:<TMPL_VAR name=ymdi> -->
<div class="section">
<p><TMPL_VAR name=content></p>
<TMPL_IF name=referrer>
 <div class="referer"><span>Referrer (Inside): 
 <TMPL_VAR name=referrer></span></div>
</TMPL_IF>
<p><a href="<TMPL_VAR name=ymdi>.html">permlink</a></p>
</div>
<!-- end:<TMPL_VAR name=ymdi> -->
</div></div>
<!--<p>last update: <TMPL_VAR name=lastupdate></p>-->
<TMPL_VAR name=signature>
</div></body></html>
___PAGE_TEMPLATE
    ;

# ƥڡΥƥץ졼
my $cat_page_template = << "TMPL"
<html lang="ja"><head>
<meta http-equiv="Content-Type" content="text/html;charset=EUC-JP">
<TMPL_IF name=css_file>
 <link rel=stylesheet href="<TMPL_VAR name=css_file>" media=all>
</TMPL_IF>
<link rel="alternate" type="application/rss+xml" title="RSS"
 href="<TMPL_VAR name=rss_file>">
<title><TMPL_VAR name=cat_name> / <TMPL_VAR name=cl_name></title>
</head><body>
<TMPL_IF name=page_list><TMPL_VAR name=page_list></TMPL_IF>
<h1><TMPL_VAR name=cat_name> -
 <a href="index.html"><TMPL_VAR name=cl_name></a></h1>
<div>
<TMPL_LOOP name=entries>
 <div class="day"><h2><span class="date"><TMPL_VAR name=eh></span></h2>
 <div class="body"><TMPL_VAR name=cont></div></div>
</TMPL_LOOP>
<p>last update: <TMPL_VAR name=lastupdate></p>
<TMPL_VAR name=signature>
</div></body></html>
TMPL
    ;

# item Υƥץ졼
my $item_template = << "EACHITEM"
<!-- start:<TMPL_VAR name=ymdi> -->
<div class="section">
<p><TMPL_VAR name=header><TMPL_VAR name=cat><TMPL_VAR name=content></p>
<TMPL_IF name=referrer>
 <div class="referer"><span>Referrer (Inside): 
 <TMPL_VAR name=referrer></span></div>
</TMPL_IF>
</div>
<!-- end:<TMPL_VAR name=ymdi> -->
EACHITEM
    ;

# entry (date) Υƥץ졼
my $entry_template = << "DAYENTRY"
<div class="day">
<h2><span class="date"><TMPL_VAR name=header></span></h2>
<div class="body">
<TMPL_IF name=message_top><TMPL_VAR name=message_top></TMPL_IF>
<TMPL_IF name=same_date><div class="calendar"><TMPL_VAR name=same_date></div>
</TMPL_IF>
<TMPL_VAR name=content>
<TMPL_IF name=referrer>
 <div class="referer"><span>Referrer (Inside): 
 <TMPL_VAR name=referrer></span></div>
</TMPL_IF>
<TMPL_IF name=message_bottom><TMPL_VAR name=message_bottom></TMPL_IF>
</div>
</div>
DAYENTRY
    ;

# RSSեΥƥץ졼
my $rss_template = << "RDFSTR"
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
 xmlns="http://purl.org/rss/1.0/"
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:admin="http://webns.net/mvcb/"
 xml:lang="ja">
<channel rdf:about="<TMPL_VAR name=clog_url_pref><TMPL_VAR name=rss_file>">
 <title><TMPL_VAR name=changelog_name></title>
 <link><TMPL_VAR name=clog_url></link>
 <description><TMPL_VAR name=changelog_description></description>
 <dc:language>ja</dc:language>
 <dc:date><TMPL_VAR name=dcdate></dc:date>
 <admin:generatorAgent rdf:resource="<TMPL_VAR name=generatorAgent>"/>
 <items>
 <rdf:Seq><TMPL_LOOP name=items>
  <rdf:li rdf:resource="<TMPL_VAR name=permlink>"/></TMPL_LOOP>
 </rdf:Seq>
 </items>
</channel>
<TMPL_LOOP name=items>
<item rdf:about="<TMPL_VAR name=permlink>">
 <title><TMPL_VAR name=itemheader></title>
 <link><TMPL_VAR name=permlink></link>
 <description>
  <TMPL_VAR name=itemcontent>
 </description>
 <dc:creator><TMPL_VAR name=itemauthor></dc:creator>
 <dc:date><TMPL_VAR name=item_dcdate></dc:date>
 <content:encoded>
  <![CDATA[<TMPL_VAR name=itemcontentencoded>]]>
 </content:encoded>
</item>
</TMPL_LOOP>
</rdf:RDF>
RDFSTR
	;

# ɽȤѵ ('>' or '|') ä (1:YES, 0:NO)
my $remove_quote_mark = 0;

# հ򥫥ɽˤ뤫 (1:YES, 0:NO)
my $calendar_style = 0;

# ƥإåΥեޥåȤɤ뤫
# (0:"* HOGE:", 1:"* HOGE", 2:"HOGE:",3:"HOGE")
my $item_header_style = 0;
# item header  h3 Ȥ (1:YES, 0:NO) - tDiary ȤθߴΤ
my $use_h3_for_item_header = 0;
# item header Ƭε˥󥫡Ĥ뤫 (1:YES, 0:NO)
my $use_item_anchor = 1;
# item header Ƭελ
# ΥƬ(֥ȥιƬ)롢Ѥ
# 󥫡ʸꤷޤʤ<span class="panchor">_</span>פ
# ꤹȡơޤˤäƤϼưŪ˲󥫡Ĥ褦ˤʤ
# (tDiary  skel/conf.rhtml )
my $item_header_mark = '<span class="sanchor">*</span>';

# ¾ǯƱ () ؤΥ󥯤ĥ뤫 (1:YES, 0:NO)
my $same_date_jump = 1;
# # ƥƥ˵Ҽ̾ɽ뤫 (1:YES, 0:NO)
# my $show_author_name = 0;

# RSS Ϥ뤫 (1:YES, 0:NO)
my $output_rss = 1;
#  for RSS : : "Τ줳졣"
my $changelog_description = "";
# ChangeLog  URL ( URL 򶯤侩) - RSS ɬ
#my $clog_url = "http://chalow.net/";
my $clog_url = "./";

# ѥե (cl.itemlist) 뤫 (1:YES, 0:NO)
my $output_itemlist = 1;
# Ф (JavaScript ե) ǽϤ
my $latest_titles_num = 10;

# Ȥ˥ڡ뤫 (0:NO, 1:YES) --- obsolete
my $day_page_mode = 0;
# ڡñ̡Ǿڡñ (0:, 1:, 2:ƥ)
my $page_mode = 0;

# ƥڡ뤫 (0:NO, 1:YES)
my $output_cat_pages = 1;
# ƥڡΥȥξ
# ($output_cat_pages = 1 ΤȤΤͭ)
my $cat_page_entry_max = 10;
# ƥitemɽΤCGIꤹʥƥ̾ %%CAT%% ֤
# ($output_cat_pages = 0 ΤȤΤͭ)
my $cat_page_cgi = "clsearch.cgi?cat=%%CAT%%";
#my $cat_page_cgi = "";

# եκǽ˽ФƤ<!-- ReplaceOnce -->פ֤ʸ
my $replace_once = "";

# UTF8 mode (0:OFF, 1:ON)
my $utf8_mode = 0;

# Read More mode (0:OFF, 1:ON)
my $readmore_mode = 1;
# Read More tag
my $readmore_tag = "====";

### chalow ڤΤ HTML ΰֲ˥󥯤ɽ롣Ǥоäʤǡ
my $signature = qq(<p class="footer">Powered by 
<a href="http://chalow.org/">chalow</a></p>);

### ޥɥ饤
Getopt::Long::Configure('bundling');
my ($opt_topn_tmp, $outputdir, $quiet_mode, $opt_css_file, $debug_mode,
    $update_by_size, $conf_file, $stop_date);
my $gor = GetOptions('n|top-n=n'   => \$opt_topn_tmp,
		     'o|output-dir=s'   => \$outputdir,
		     'c|configure-file=s' => \$conf_file,
		     's|stop-date=s' => \$stop_date,
		     'u|update-by-size' => \$update_by_size,
		     'C|css=s' => \$opt_css_file,
		     'q|quiet' => \$quiet_mode,
		     '8|utf8' => \$utf8_mode,
		     'd|debug' => \$debug_mode);

if (@ARGV == 0 or $gor == 0) {
    print << "USAGE";
usage: chalow [options] <file> [file]...
    -n, --top-n=NUM             write NUM days to "index.html"
    -o, --output-dir=DIR        directory to output
    -c, --configure-file=FILE   configure file
    -s, --stop-date=DATE        date to stop processing
    -u, --update-by-size        overwrite only if sizes are different
    -C, --css=FILE              css file
    -q, --quiet                 quiet mode
    -8, --utf8                  utf8 mode
    -d, --debug                 debug mode
USAGE
    ;
    exit;
}

# 桼եɤ߹ (ե̾ꤵƤȤΤ)
if ($conf_file ne "") {
    open(CONF, $conf_file) or die "Can't open $conf_file : $!\n";
    binmode(CONF);
    my $conf = join('', <CONF>);
#    $conf = Jcode->new($conf)->euc; # del 050412
    eval $conf;
    die qq(error in "$conf_file" (obsolete variable?): $@\n) if ($@);
}

$outputdir = "." if (not defined $outputdir);

# 桼եꥳޥɥ饤ͥ褹
$opt_topn = $opt_topn_tmp if (defined $opt_topn_tmp);
$css_file = $opt_css_file if (defined $opt_css_file);

# : ʸäΤͤˤ롣ǿͤȤդ
# ˻Ȥ顣
$stop_date =~ s/-//g;

my $latest_item_list;
my $category_list;

my $clog_url_pref = $clog_url;
$clog_url_pref =~ s!/[^/]+html?$!/!;
$clog_url_pref .= "/" unless ($clog_url_pref =~ m!/$!);
# SPEC:   $clog_url                 $clog_url_pref
# http://chalow.net/           -> http://chalow.net/
# http://chalow.net/index.html -> http://chalow.net/
# http://chalow.net            -> http://chalow.net/

my %month_page;			# ̤Υڡ
my %category_item;		# ƥ̥ڡ item
my %inside_ref;			# ե󥯤ˤե顼

#my %all_entries;                # hash for all ChangeLog entries
# {XXXX-XX-XX}{"eh"} - Entry header
# {XXXX-XX-XX}{1,2,3,...}{"ho"} - Item header (original text)
# {XXXX-XX-XX}{1,2,3,...}{"co"} - Item content (original text)
# {XXXX-XX-XX}{1,2,3,...}{"cat"} - Category (array)
# {XXXX-XX-XX}{1,2,3,...}{"a"} - Author
# {XXXX-XX-XX}{"message-top"} - Pragma item
# {XXXX-XX-XX}{"message-bottom"} - Pragma item
# {XXXX-XX-XX}{curid} - Item ID manager
# {XXXX-XX-XX}{1,2,3,...}{"h"} - ƥإå
# {XXXX-XX-XX}{1,2,3,...}{"c"} - ̣

my $cl = ChangeLogReader->new(stop_date => $stop_date);

for my $fname (@ARGV) {
    print "reading \"$fname\"\n" if (!defined $quiet_mode);
    $cl->store_changelog_file($fname);
}

print "done.\nconverting\n" if (!defined $quiet_mode);

foreach my $ymd (reverse sort keys %{$cl->{all}}) {
    parse_entry($ymd, \%{$cl->{all}->{$ymd}});
}

print "done.\n" if (!defined $quiet_mode);

# ̰Ƥ
my $month_page_list = make_month_page_list($cl->{STAT}->{ym}); 

# հƤ
my $current_day_list = make_day_list_str($current_ym);

### (1)
write_rss_file() if ($output_rss); # RSS ե
write_itemlist_file() if ($output_itemlist); # ѥե(itemlist) 
write_latest_item_list_file();	# Ƕ
write_category_list_file();	# ƥ

### HTML ΤΥ롼
foreach my $ymd (sort keys %{$cl->{all}}) {
    my $e = $cl->{all}->{$ymd};
    my @items;
    foreach my $i (sort {$b <=> $a} keys %{$e}) {
	next if ($i !~ /^\d/);
	push @items, make_item_html($e, $ymd, $i);
    }
    my ($y, $m, $d) = ($ymd =~ /^(\d{4})-(\d\d)-(\d\d)$/);
    $month_page{"$y-$m"}{$ymd}{str} = make_entry_html($e, $ymd, \@items);
}

### (2) HTML եν
write_index_page();
write_month_page();
write_day_page() if ($day_page_mode or $page_mode >= 1);
write_item_page() if ($page_mode == 2);
write_category_page() if ($output_cat_pages);

print "done.\n" if (!defined $quiet_mode);

exit;


### ȥѡƳǼ
sub parse_entry {
    my ($ymd, $ent) = @_;
    for (my $i = $ent->{curid}; $i >= 1; $i--) {
	my $c = $ent->{$i}->{co};
	$c =~ s/^\s*\n//g if ($use_h3_for_item_header == 1);
	$ent->{$i}{h} = okikae($ent->{$i}{ho}, $ymd, $i);
	$ent->{$i}{c} = okikae($c, $ymd, $i);
    }
}


### ʸ֤
sub okikae {
    local ($_) = shift;	
    my ($ymd, $i) = @_;		# ˻Ȥ뤫?

    escape_string(\$_);

    # ե󥯾γǼ - parse_entry ˤäescape˹Ԥʤ
    # 褤ȻפäΤǤ˰ư(5.1.19)
    while (/\[((\d\d\d\d-\d\d)-\d\d(-\d+)?)\]/g) {
	$inside_ref{$1}{"$ymd-$i"}++;
    }

    s/&/&amp;/go;
    s/\]>/\]&gt;/go;
#    s/>/&gt;/go;		# >  &.. ˤʤȡURL ȤѤΥޥå
#    s/"/&quot;/go;		# ";
    ### "<" ֤롣
    s|<(/?[a-z!]+)|&lt;$1|gio;
#    s|<(/?[a-z]+)|&lt;$1|gio;	#  (<!-- -->) ΤϤ
    # ޥΥҥ: <s></s> Ĥ 
    # s|<(/?[a-rt-z]+)|&lt;$1|gi; <b> Ĥ 
    # s|<(/?[ac-z]+)|&lt;$1|gi; ( = <br> ʤɤĤ)

    ### Read More ###
    s!^$readmore_tag$(.*)$!<div class="readmore">$1</div>!sm;

    ### ʸȿʿHiki εˡѡ
    s!'''(.+?)'''!<strong>$1</strong>!gms;
    s!''(.+?)''!<em>$1</em>!gms;
    s!==(\S.+?)==!<s>$1</s>!gms;
    s!^\-{4}!<hr>!gms;

    ### URLHiki εˡѡ
    s!\[\[(.+?)\s*\|\s*(.+?)\]\]!get_link_str($1, $2)!gmse;

    ### ɽHiki εˡѡ
    s!(^(\|\|[^\n]+\n)+)!'<table><tr>'.
	(join("<tr>", (map {join('<td>', split(/\|\|/ ,$_))} split(/\n/, $1))))
	    .'</table>'!gsme;

    ###  (quote): ">>"  "<<" ǰϤ
    s!^>>\n!<blockquote>!gm;
    s!^<<\n!</blockquote>!gm;

    ###  (quote): "| ..."  "> ..."
    if ($remove_quote_mark == 1) {
	my $a;
	s!((^((\||>)[^\n]*)\n)+)!'<blockquote>'.($a = $1,
	    $a =~ s{^(\||>)\s?}{}gm, $a).'</blockquote>'!gme;
    } else {
	s!((^((\||>)[^\n]*)\n)+)!<blockquote>$1</blockquote>!gmx;
    }

    ### դǻȥ
    # date ref : [YYYY-MM-DD]
    $_ = datestr2anchor($_);

    ### URLɽ href 
    # URL : http://....
    # ɽ http://www.din.or.jp/~ohzaki/perl.htm#httpURL ꡣ
    # ХååѤURLǤβԤб 021025
    #my $URLCHARS = "[-_.!~*'()a-zA-Z0-9;/?:@&=+,%\#\$]";
    my $URLCHARS = "[-_.!~*'a-zA-Z0-9;/?:@&=+,%\#\$]";
    my $URLDELIM = "\\\\\\n *";
    s{(?<![\"\=|])((s?https?|ftp)://($URLCHARS+)($URLDELIM($URLCHARS+))*)}
    {'<a href="'.join('', split(/$URLDELIM/, $1)).'">'.
	 join('', split(/\\/, $1)).'</a>'}gem; #")};

    ### ƬΥڡ &nbsp; ֤롣
    s!^( +)!{"&nbsp;" x length($1)}!gme;
    s!^(</?blockquote>)( +)!{"$1" . ("&nbsp;" x length($2))}!gme;

    ### ưʸִŬ
    eval $auto_replace;

    # ƹԤι <br> դ
    # memo: Τ pre ǰϤǤv0.23 ᤿
#print "1[$_]\n";
    s!$!<br>!gsm;
    s!<br>$!!;
#print "2[$_]\n";

    unescape_string(\$_);	# ץ饰ƤӽФԤʤ

    s!</pre><br>!</pre>!g;	# ad hoc

    return $_;
}


### ƥHTMLѴ
sub make_item_html {
    my ($e, $ymd, $i) = @_;

    ### item header
    my $ih = make_item_header_html($e->{$i}{h}, $ymd."-".$i);

    ### ƥ
    my $catstr = make_cat_link_html($e->{$i}{cat});

    ### ե󥯤ˤե顼
    my @inside_refs = get_inside_ref("$ymd-$i");
    
    ### item δþ
    my $item_url = datestr2url("$ymd-$i");
    my $item_ymdi = $ymd."-".$i; 
    (my $item_id = $ymd.$i) =~ s/-//g; # Ex. "200309241"
    
    ### item Ȥ߾夲
    my $t = HTML::Template->new(scalarref => \$item_template,
				die_on_bad_params => 0);
    my $ccc = $e->{$i}{c};
    if ($page_mode == 2 and $readmore_mode) {
	if ($ccc =~ s!(<div class="readmore">.*</div>)$!!sm) {
	    my $readmore_str = $1;
	    $t->param(readmore => $readmore_str);
	}
    }
    $t->param(content => $ccc);
    $t->param(header => $ih);
    $t->param(cat => $catstr);
    $t->param(author => $e->{$i}{a});
    $t->param(referrer => join(" ", @inside_refs));
    $t->param(id => $item_id);
    $t->param(ymdi => $item_ymdi);
    $t->param(url => $item_url);
    $t->param(rss_file => $rss_filename); # 050821
    my $this_item = $t->output();

    if ($output_cat_pages == 1) { # ƥ̥ڡФȤν
	my $ent_h = make_entry_header_html($e->{eh}, $ymd);
	foreach (@{$e->{$i}{cat}}) {
	    # ƥ̥ڡ --stop-date Τ
	    push @{$category_item{$_}}, {eh=>$ent_h, cont=>$this_item};
	}
    }
    return $this_item;
}


### ȥHTMLѴ
sub make_entry_html {
    my ($e, $ymd, $itemsp) = @_;

    ### entry header
    my $ent_h = make_entry_header_html($e->{eh}, $ymd);

    my ($y, $m, $d) = ($ymd =~ /^(\d{4})-(\d\d)-(\d\d)$/);

    ### ¾ǯƱ () ؤΥ󥯤ĥ
    my @same_dates;
    if ($same_date_jump == 1) {
	if (defined $cl->{STAT}->{md}{"$m-$d"}) {
	    my @ys = sort keys %{$cl->{STAT}->{md}{"$m-$d"}};
	    @same_dates = map {"<a href=\"".datestr2url("$_-$m-$d").
				   "\">$_</a>"} grep {$_ != $y} @ys;
	}
    }

    ### ե󥯤ˤե顼
    my @inside_refs = get_inside_ref("$ymd");

    ### entry δþ
    my $entry_url = datestr2url($ymd);
    my $entry_ymd = $ymd;
#    my $entry_id = $ymd; $entry_id =~ s/-//g; # Ex. "20030924"
    (my $entry_id = $ymd) =~ s/-//g; # Ex. "20030924"

    ### ȥȤ߾夲
    my $t = HTML::Template->new(scalarref => \$entry_template,
				die_on_bad_params => 0);
    $t->param(header => $ent_h);
    $t->param(message_top => $e->{"message-top"});
    $t->param(message_bottom => $e->{"message-bottom"});
    $t->param(referrer => join(" ", @inside_refs));
    $t->param(same_date => join(" ", @same_dates));
    $t->param(id => $entry_id);
    $t->param(ymd => $entry_ymd);
    $t->param(url => $entry_url);
    $t->param(rss_file => $rss_filename); # 050821
    $t->param(content => @{[join('', @{$itemsp})]});
    return $t->output();
}


### ƥ̥ڡ(ex: cat_life.html)롣
sub write_category_page {
    my @cat_list = keys %category_item;

    foreach my $catname (@cat_list) {

        my @ents = sort {$b->{eh} cmp $a->{eh}} @{$category_item{$catname}};

        my $n = $cat_page_entry_max;
        my $num_of_old_pages = int(@ents / $n);

        my @fnames;
        for (my $i = 0; $i <= $num_of_old_pages; $i++) {
            $fnames[$i] = get_category_filename($catname);
            my $suffix = ($i == 0) ? "" : "-".($i+1);
            $fnames[$i] =~ s/\.html$/$suffix.html/;
        }

        for (my $i = 0; $i <= $num_of_old_pages; $i++) {

            ### ڡȤ߾夲
            my $t = HTML::Template->new(scalarref => \$cat_page_template,
                                        loop_context_vars => 1,
                                        die_on_bad_params => 0);
            $t->param(cl_name => $changelog_name);
            $t->param(css_file => $css_file);
            $t->param(lastupdate => $what_time_is_it_now);
            $t->param(signature => $signature);

            $t->param(cat_name => $catname);
            $t->param(ym => $current_ym);
            $t->param(day_list => $current_day_list);
            $t->param(latest_item_list => $latest_item_list);
            $t->param(category_list => $category_list);
	    $t->param(rss_file => $rss_filename); # 050821
            $t->param(entries => [grep /^.+$/, @ents[$i*$n...($i+1)*$n-1]]);

            my @page_list;
            my $back_page_url;
            my $next_page_url;
            if ($num_of_old_pages > 0) {
                for (my $j = 0; $j <= $num_of_old_pages; $j++) {
                    $page_list[$j] = ($i == $j) ? $j+1 : 
                        qq(<a href="$fnames[$j]">@{[$j+1]}</a>);
                    $back_page_url = $fnames[$j] if ($j == $i - 1);
                    $next_page_url = $fnames[$j] if ($j == $i + 1);
                }
            }

            $t->param(page_list => join(" ",@page_list));
            $t->param(first_page => $fnames[0]);
            $t->param(back => $back_page_url);
            $t->param(next => $next_page_url);
            $t->param(page_id => $i + 1);
            $t->param(page_num => $num_of_old_pages + 1);

            my $ostr = $t->output();

            ### ե˽
            output_to_file("$outputdir/".$fnames[$i], \$ostr);
        }
    }
}


### ƥڡ(ex: 2001-01-01-1.html)롣
sub write_item_page {
    my @day_list = reverse sort keys %{$cl->{all}};

    for (my $idx = 0; $idx < @day_list; $idx++) {
	my ($ymd, $ym) = ($day_list[$idx] =~ /^((\d+-\d+)-\d+)/);
	my $ent = $cl->{all}->{$ymd};

	for (my $i = $ent->{curid}; $i >= 1; $i--) {
	    my $item = $ent->{$i};
	    my $ymdi = "$ymd-$i";

	    ### ƥ
	    my $catstr = make_cat_link_html($ent->{$i}{cat});

	    ### ե󥯤ˤե顼
	    my @inside_refs = get_inside_ref("$ymdi");

	    ### item δþ
	    my $item_url = datestr2url("$ymdi");
	    my $item_ymdi = $ymdi; 
	    my $item_id = $ymdi; $item_id =~ s/-//g; # Ex. "200309241"

	    # Υڡ
	    my $ymdi_before;
	    my $ymdi_after;
	    if ($i > 1) {
		$ymdi_before = $ymd."-".($i-1);
	    } elsif ($idx < @day_list - 1) {
		my $day_b = $day_list[$idx + 1];
		$ymdi_before = $day_b."-".$cl->{all}->{$day_b}{curid};
	    }
	    if ($i != $ent->{curid}) {
		$ymdi_after = $ymd."-".($i+1);
	    } elsif ($idx > 0) {
		my $day_a = $day_list[$idx - 1];
		$ymdi_after = $day_a."-1";
	    }

	    ### ڡȤ߾夲
	    my $t = HTML::Template->new(scalarref => \$item_page_template,
					loop_context_vars => 1,
					die_on_bad_params => 0);

	    $t->param(cl_name => $changelog_name);
	    $t->param(css_file => $css_file);
	    $t->param(lastupdate => $what_time_is_it_now);
	    $t->param(signature => $signature);

	    $t->param(ymd => $ymd);
	    $t->param(ym => $ym);

	    $t->param(month_page_list => $month_page_list);
	    $t->param(latest_item_list => $latest_item_list);
	    $t->param(category_list => $category_list);
	    $t->param(back => $ymdi_before);
	    $t->param(next => $ymdi_after);

	    my $ccc = $item->{c}; $ccc =~ s!^<br>!!g;# ad hoc
	    $t->param(content => $ccc);
	    $t->param(header_text => $item->{ho});
	    $t->param(header => $item->{h});
	    $t->param(cat => $catstr);
	    $t->param(author => $item->{a});
	    $t->param(referrer => join(" ", @inside_refs));
	    $t->param(id => $item_id); # 200101011
	    $t->param(ymdi => $item_ymdi); # 2001-01-01-1
	    $t->param(url => $item_url); # 2001-01-01-1.html
	    $t->param(rss_file => $rss_filename); # 050821
	    
	    my $ostr = $t->output();

	    ### ե˽
	    output_to_file("$outputdir/$ymdi.html", \$ostr);
	}
    }
}


### ڡ(ex: 2001-01-01.html)롣
sub write_day_page {
    return if ($day_page_template eq ""); # tmplʤʤ(5.1.19)

    my @day_list = reverse sort keys %{$cl->{all}};

    for (my $idx = 0; $idx < @day_list; $idx++) {

	my ($ymd, $ym) = ($day_list[$idx] =~ /^((\d+-\d+)-\d+)/);

	# ڡ
	my $day_before = $day_list[$idx + 1] if ($idx < @day_list - 1);
	my $day_after = $day_list[$idx - 1] if ($idx > 0);

	# ؤΥ (հ)
	my $day_list = make_day_list_str($ym);

	### ڡȤ߾夲
	my $t = HTML::Template->new(scalarref => \$day_page_template,
				    loop_context_vars => 1,
				    die_on_bad_params => 0);
	$t->param(cl_name => $changelog_name);
	$t->param(css_file => $css_file);
	$t->param(lastupdate => $what_time_is_it_now);
	$t->param(signature => $signature);

	$t->param(ymd => $ymd);
	$t->param(ym => $ym);
	$t->param(day_list => $day_list);
	$t->param(month_page_list => $month_page_list);
	$t->param(latest_item_list => $latest_item_list);
	$t->param(category_list => $category_list);
	$t->param(rss_file => $rss_filename); # 050821
	$t->param(back => $day_before);
	$t->param(next => $day_after);
	$t->param(content => $month_page{$ym}{$ymd}{str});

	my $ostr = $t->output();

	### ե˽
	output_to_file("$outputdir/$ymd.html", \$ostr);
    }
}


### ڡ(ex: 2001-01.html)롣
sub write_month_page {
    return if ($month_page_template eq ""); # tmplʤʤ(5.1.19)

    my @month_list = reverse sort keys %month_page;
    for (my $idx = 0; $idx < @month_list; $idx++) {
	my $ym = $month_list[$idx];

	# η
	my $m_before = $month_list[$idx + 1] if ($idx < @month_list - 1);
	my $m_after = $month_list[$idx - 1] if ($idx > 0);

	# ե󥯰
	my $day_list = make_day_list_str($ym);

	### Υȥ
	my @cont;
	if ($reverse_order_days) { # ߽: դοΤ (v0.11 Ʊ)
	    @cont = reverse sort keys %{$month_page{$ym}};
	} else {		# : դθŤΤ
	    @cont = sort keys %{$month_page{$ym}};
	}
	my @contlist = map {{content => $month_page{$ym}{$_}{str}}} @cont;

	### ڡȤ߾夲
	my $t = HTML::Template->new(scalarref => \$month_page_template,
				    loop_context_vars => 1,
				    die_on_bad_params => 0);
	$t->param(cl_name => $changelog_name);
	$t->param(css_file => $css_file);
	$t->param(lastupdate => $what_time_is_it_now);
	$t->param(signature => $signature);

	$t->param(ym => $ym);
	$t->param(day_list => $day_list);
	$t->param(month_page_list => $month_page_list);
	$t->param(latest_item_list => $latest_item_list);
	$t->param(category_list => $category_list);
	$t->param(rss_file => $rss_filename); # 050821
	$t->param(back => $m_before);
	$t->param(next => $m_after);
	$t->param(entries => \@contlist);

	my $ostr = $t->output();

	output_to_file("$outputdir/$ym.html", \$ostr);
    }
}


### ǥåڡ(index.html)
sub write_index_page {
    ### Ƕβǥåڡ˺ܤ뤿ν
    my @recent = (reverse sort keys %{$cl->{all}})[0..$opt_topn];

    my @top_n_entries;

    for (my $i = 0; $i < $opt_topn and $recent[$i]; $i++) {
	my $ymd = $recent[$i];
	my ($ym, $d) = ($ymd =~ /^(\d{4}-\d\d)-(\d\d)$/);
#	$top_n_str .= $month_page{$ym}{$ymd}{str};
	push @top_n_entries, {content => $month_page{$ym}{$ymd}{str}};
    }
    my ($ymd, $ym, $d) = ($recent[0] =~ /^((\d{4}-\d\d)-(\d\d))$/);

    # ե󥯰
    my $day_list = make_day_list_str($ym);

    ### ڡȤ߾夲
    my $t = HTML::Template->new(scalarref => \$index_page_template,
				loop_context_vars => 1,
				die_on_bad_params => 0);
    $t->param(cl_name => $changelog_name);
    $t->param(css_file => $css_file);
    $t->param(lastupdate => $what_time_is_it_now);
    $t->param(signature => $signature);

    $t->param(ymd => $ymd);	# ǿȥ
    $t->param(ym => $ym);	# ǿȥη
    $t->param(ndays => $opt_topn);
    $t->param(day_list => $day_list);
    $t->param(month_page_list => $month_page_list);
    $t->param(latest_item_list => $latest_item_list);
    $t->param(category_list => $category_list);
    $t->param(rss_file => $rss_filename); # 050821
    $t->param(entries => \@top_n_entries);

    my $ostr = $t->output();

    output_to_file("$outputdir/index.html", \$ostr);
}


### ̰
sub make_month_page_list {
    my ($month_page) = @_;
    my @month_list = sort keys %{$month_page};
    my ($start_year) = ($month_list[0] =~ /^(\d\d\d\d)/);
    my ($end_year) = ($month_list[$#month_list] =~ /^(\d\d\d\d)/);
    my $month_page_list = "";
    for (my $y = $end_year; $y >= $start_year; $y--) { # year loop
	$month_page_list .= "$y : ";
	for (my $m = 1; $m <= 12; $m++) { # month loop	
	    my $m0 = sprintf "%02d", $m;
	    if (defined $month_page->{"$y-$m0"}) {
		$month_page_list .= "<a href=\"$y-$m0.html\">$m0</a> ";
	    } else {
		$month_page_list .= "$m0 ";
	    }
	}
	$month_page_list .= "<br>\n";
    }
    return $month_page_list;
}


### ե󥯰 - ʸ֤
sub make_day_list_str {	
    my ($ym) = @_;
    if ($calendar_style == 1) {
	return make_calendar_table($ym, make_day_list($ym));
    } else {
	return join(" ", @{make_day_list($ym)});
    }
}

# ե󥯰 - ꥹȤؤΥݥ󥿤֤
my %daylist;
sub make_day_list {	
    my ($ym) = @_;
    my $lday = get_last_day_of_month($ym);
    return $daylist{$ym} if (defined $daylist{$ym}); # cache
    for (my $d = 1; $d <= $lday; $d++) {
	my $day = ($d < 10) ? "0".$d : $d;
	if (defined $cl->{all}->{$ym."-".$day}) {
	    my $day_url = datestr2url($ym."-".$day);
	    push @{$daylist{$ym}}, qq(<a href="$day_url">$day</a>);
	} else {
	    push @{$daylist{$ym}}, $day;
	}
    }
    return $daylist{$ym};
}

# հ - 
sub make_calendar_table {
    my ($ym, $dlistp) = @_;
    my ($y, $m) = split("-", $ym);
    my $offset = (localtime timelocal(0, 0, 0, 1, $m - 1, $y))[6];
    
    my $week = 0;
    my @cal;
    for (my $i = 0; $i < 42; $i++) {
	my $day = ($i < $offset) ? " " : $dlistp->[$i - $offset];
	last if (not $day);
	$day =~ s/^0//;
	$day =~ s/>0([1-9])</>$1</;
	$cal[$week] .= qq(<td align="center">$day</td>);
	$week++ if (($i + 1) % 7 == 0);
    }

    my @wn = ("S", "M", "T", "W", "T", "F", "S");
#    my @wn = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");

    my $rv = << "CAL"
<table>
<caption><a href="$ym.html">$ym</a></caption>
<tr>
@{[join "", map {qq(<th align="center">$_</th>)} @wn]}
</tr>
@{[join "", map {"<tr>$_</tr>"} @cal]}
</table>
CAL
    ;

    return $rv;
}


### anchor, img ʸ
sub get_link_str {
    my ($a, $b) = @_;
    if ($a =~ /\.(jpg|jpeg|png|gif)$/i) { # [[http://nais.to/|image/nais.jpg]]
	return qq(<a href="$b"><img src="$a" alt=""></a>);
    } elsif ($b =~ /\.(jpg|jpeg|png|gif)$/i) { # [[|image/sp.jpg]]
	return qq(<img src="$b" alt="$a">);
    } else {			# [[ȥåץڡ|http://nais.to/]]
	return qq(<a href="$b">$a</a>);
    }
}


### ǯϤȤϤؿ since 021001
# RETURN VALUES
#     the text name of the day of the week.  Mon, Tue, Wed, ...
# EXAMPLES
#     get_day_of_week(1, 12, 2002), get_day_of_week("2002-12-01")
sub get_day_of_week {
    my ($d, $m, $y) = @_;
    ($y, $m, $d) = split("-", $d) unless (defined $m);
    my $WEEKDAY = (localtime timelocal(0, 0, 0, $d, $m - 1, $y))[6];
    return ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")[$WEEKDAY];
}


### ǯϤȤηκǽϤؿ since 030105
# EXAMPLES
#     get_last_day_of_month(12, 2002), get_last_day_of_month("2002-12")
sub get_last_day_of_month {
    my ($m, $y) = @_;
    ($y, $m) = split("-", $m) unless (defined $y);
    return (31, ((($y % 4 == 0) and ($y % 100)) or ($y % 400 == 0)) ? 29 : 28,
	    31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[$m - 1];
}


### RSS եϤ
sub write_rss_file {
    my $rdfseq;
    my $rdfitem;
    my $ctr = ($rss_topn > 0) ? $rss_topn : (($opt_topn > 7) ? 7 : $opt_topn);

    my @items;

    foreach my $ymd (sort {$b cmp $a} keys %{$cl->{all}}) {
	$ctr--;
	last if ($ctr < 0);
	my $e = $cl->{all}->{$ymd};
	foreach my $i (sort {$b <=> $a} keys %$e) {
	    next if ($i !~ /^\d/);

	    my $permlink = $clog_url_pref.datestr2url($ymd."-".$i);
	    my ($ym) = ($ymd =~ /^(\d{4}-\d\d)-\d\d/);

	    my $coen = $e->{$i}{c};
	    $coen =~ s!<a href="(\d.+?)"!<a href="$clog_url_pref$1"!g;
	    $coen =~ s!<img src="([^h].+?)"!<img src="$clog_url_pref$1"!g;

	    my $cont = $e->{$i}{c};
	    $cont = html2xmlstr($cont);
	    if ($cont =~ s/^(([\x00-\x7F]|[\x80-\xFF]{2}){300}).+$/$1/sm) {
		$cont =~ s/&[^;]*$//g; # &gt...$ XMLѡ顼
		$cont .= "...";
	    }

	    my $item_dcdate = # ($dcdate =~ /^$ymd/) ? $dcdate : 
		$ymd."T23:59:59+09:00";

	    push @items, {
		permlink => $permlink,
		itemheader => html2xmlstr($e->{$i}{h}),
		itemauthor => $e->{$i}{a}, 
		itemcontent => $cont,
		itemcontentencoded => $coen,
		item_dcdate => $item_dcdate
	    };
	}
    }
    my $t = HTML::Template->new(scalarref => \$rss_template,
				die_on_bad_params => 0, gloval_vars => 1);
    $t->param(items => \@items);
    $t->param(changelog_name => $changelog_name);
    $t->param(dcdate => $dcdate);
    $t->param(changelog_description => $changelog_description);
    $t->param(clog_url => $clog_url);
    $t->param(clog_url_pref => $clog_url_pref);
    $t->param(rss_file => $rss_filename); # 050821
    $t->param(generatoragent=>"http://chalow.org/?v=$version");
    my $ostr = $t->output();
    to_utf8_cl(\$ostr) if (not $utf8_mode);
    output_to_file("$outputdir/$rss_filename", \$ostr);
}


sub html2xmlstr {
    local ($_) = @_;
    s/&nbsp;/ /g;
    s|<img.+?alt="(.*?)".*?>|[$1]|gosm;
    s/[\t\n]//g;
    s/[\x00-\x1f]+/ /g;
    s/\s\s+/ /g;
    s|<[^<>]+?>||gosm;
    s/&lt;/</go;
    s/&/&amp;/go; s/>/&gt;/go; s/</&lt;/go; s/\"/&quot;/go; # "ĤΣ
    return $_;
}


### JavaScript feed եϤ
sub write_latest_item_list_file {

    ### Ƕε
    my @lines;
    my $date;
    my $ctr = $latest_titles_num;
    foreach my $ymd (sort {$b cmp $a} keys %{$cl->{all}}) {
	$ctr--;
	last if ($ctr < 0);
	my $e = $cl->{all}->{$ymd};
	foreach my $i (sort {$b <=> $a} keys %$e) {
	    next if ($i !~ /^\d/);
	    my ($ym) = ($ymd =~ /^(\d{4}-\d\d)-\d\d/);
	    my $c = $e->{$i}{h};
            $c =~ s/[\t\n]//g;
	    $c =~ s/\s\s+/ /g;
	    $c =~ s/\s*$//;
            $c =~ s/<.+?>//g;
	    $c =~ s/^\*\s+//;
#	    $c =~ s/\'/&\#x27;/g;

	    if ($date ne $ymd) {
		push @lines, "<a href=\"".
		    $clog_url_pref.datestr2url("$ymd")."\">$ymd</a><br>";
		$date = $ymd;
	    }
	    push @lines, "- <a href=\"".
		$clog_url_pref.datestr2url("$ymd-$i")."\">$c</a><br>";
	}
    }

    my $ostr = join("\n", map {s/\'/&\#x27;/g; "document.writeln('".$_."');"}
		    @lines);
    output_to_file("$outputdir/cl.js", \$ostr);

    $latest_item_list = join("\n", @lines);

}


sub write_category_list_file {
    ### ƥ
#    return if ($output_cat_pages == 0 or $cat_page_cgi eq "");
#    return if ($output_cat_pages == 0);

    my @lines = ();
    foreach my $cat (sort keys %{$cl->{CAT}}) {
	my $n = $cl->{CAT}->{$cat};
	my $url;
	if ($output_cat_pages) {
	    $url = get_category_filename($cat);
	    $url = $clog_url_pref.$url;
	} else {
	    $url = $cat_page_cgi;
	    $url =~ s/%%CAT%%/urlencode($cat)/ge;
	    $url = $clog_url_pref.$url if ($url !~ /^http/);
	}
	push @lines, "- <a href=\"$url\">$cat</a> ($n)<br>";
    }

    my $ostr = join("\n", map {s/\'/&\#x27;/g; "document.writeln('".$_."');"}
		 @lines);

    $category_list = join("\n", @lines);
    if ($output_cat_pages == 1) {
	output_to_file("$outputdir/cl-cat.js", \$ostr);
    }
}


### ѥեϤ
# clsearch.cgi ѤΥե
sub write_itemlist_file {
    my $ostr;
    foreach my $ymd (sort {$b cmp $a} keys %{$cl->{all}}) {
	my $e = $cl->{all}->{$ymd};
	foreach my $i (sort {$b <=> $a} keys %$e) {
	    next if ($i !~ /^\d/);
	    my ($ym) = ($ymd =~ /^(\d{4}-\d\d)-\d\d/);
	    my $h = $e->{$i}{h}.
		((defined $e->{$i}{"cat"}) ?
		 join('', map {"[$_]"} @{$e->{$i}{"cat"}}) : "");
	    my $c = $h."\x01".$e->{$i}{c};
	    $c =~ s|<img.+?alt="(.*?)".*?>|[$1]|gosm;
            $c =~ s/[\t\n]//g;
	    $c =~ s/&nbsp;/ /g;
	    $c =~ s/\s\s+/ /g;
            $c =~ s/<.+?>//g;
	    $c =~ s/\x01/\t/;	# Ķ ad hoc
	    $ostr .= datestr2anchor("[$ymd-$i]")."\t$c\n";
	}
    }

    if (-e "$outputdir/cl.itemlist" and $stop_date != 0) { # ʬ
	open(F, "$outputdir/cl.itemlist") or die;
	my $flag = 0;
	while (<F>) {
	    if ($flag == 0) {
		(/\[(\d+)-(\d+)-(\d+)-/);
		my $cdate = $1 * 10000 + $2 * 100 + $3;
		$flag = 1 if ($stop_date > $cdate);
	    }
	    $ostr .= $_ if ($flag);
	}
	close F;
	print "update ";
    }

    output_to_file("$outputdir/cl.itemlist", \$ostr);
}


### դǻȥ
sub datestr2anchor {
    my ($d) = @_;
    if ($page_mode == 2) {	# ƥ⡼
	$d =~ s!\[(\d{4}-\d\d-\d\d(-\d+)?)\]!<a href="$1.html">[$1]</a>!g;
    } elsif ($day_page_mode or $page_mode == 1) { # ⡼
	$d =~ s!\[((\d{4}-\d\d-\d\d)(-\d+)?)\]!<a href="$2.html#$1">[$1]</a>!g;
    } else {			# ⡼
	$d =~ s!\[((\d{4}-\d\d)-\d\d(-\d+)?)\]!<a href="$2.html#$1">[$1]</a>!g;
    }
    return $d;
}

sub datestr2url {
    my ($d) = @_;
    if ($page_mode == 2) {	# ƥ⡼
	$d =~ s!(\d{4}-\d\d-\d\d(-\d+)?)!$1.html!;
    } elsif ($day_page_mode or $page_mode ==1) { # ⡼
	unless ($d =~ s!((\d{4}-\d\d-\d\d)-\d+)!$2.html\#$1!) {
	    $d =~ s!(\d{4}-\d\d-\d\d)!$1.html!;
	}
    } else {			# ⡼
	$d =~ s!((\d{4}-\d\d)-\d\d(-\d+)?)!$2.html#$1!;
    }
    return $d;
}


### ʸ֤Ū򤷡
my $num_of_escaped_string;
my %escaped_string;
my $num_of_escaped_src;
my %escaped_src;
my $num_of_escaped_plugin;
my %escaped_plugin;

sub escape_string {
    my ($strp) = @_;

    ### HTML  - ʸ󤽤Τޤ
    my $btag = '_HTML_START_\n'; # ϥޡ
    my $atag = '_HTML_END_\n'; # λޡ
    $num_of_escaped_string = 0;
    $$strp =~ s!$btag(.*?)$atag!
	$escaped_string{++$num_of_escaped_string} = $1,
	sprintf("\x5\x13%d\x3", $num_of_escaped_string)!gsmxe;
    $$strp =~ s!\[(literal|sic|esc)\](.*?)\[/\1\]!
	$escaped_string{++$num_of_escaped_string} = $2,
	sprintf("\x5\x13%d\x3", $num_of_escaped_string)!gsmxe;

    ###  - "&"  "<" ʤɤִ pre դ
    $num_of_escaped_src = 0;
    $$strp =~ s!\[src\](.*?)\[/src\]!
	$escaped_src{++$num_of_escaped_src} = $1,
	$escaped_src{$num_of_escaped_src} =~ s/&/&amp;/g,
	$escaped_src{$num_of_escaped_src} =~ s/</&lt;/g,
	$escaped_src{$num_of_escaped_src} =~ s/>/&gt;/g,
	sprintf("\x6\x13%d\x3", $num_of_escaped_src)!gsmxe;

    ### ץ饰󥨥
    $num_of_escaped_plugin = 0;
    $$strp =~ s!{{(.*?)}}!
	$escaped_plugin{++$num_of_escaped_plugin} = $1,
	sprintf("\x7\x13%d\x3", $num_of_escaped_plugin)!gsmxe;
}

sub unescape_string {
    my ($strp) = @_;

    ### ץ饰󥢥󥨥 - ¹ԡ
    $$strp =~ s|\x7\x13(\d+)\x3|eval($escaped_plugin{$1})|ge;
    ### 󥨥 - pre ɲ
    #$$strp =~ s|\x6\x13(\d+)\x3|<pre>$escaped_src{$1}</pre>|g;
    $$strp =~ s|\x6\x13(\d+)\x3|</p><pre>$escaped_src{$1}</pre><p>|g;
    ### HTML 󥨥
    $$strp =~ s|\x5\x13(\d+)\x3|$escaped_string{$1}|g;
}


### inside referrer Υ󥯺
sub get_inside_ref {
    my ($id) = @_;
    if (defined $inside_ref{"$id"}) {
        return map {datestr2anchor("[".$_."]")} 
	(sort {$b cmp $a} keys %{$inside_ref{"$id"}});
    }
    return ();
}


### ƥڡΥե̾
sub get_category_filename {
    my ($cn) = @_;
    to_utf8_cl(\$cn) if (not $utf8_mode and $cn =~ /[\x80-\xff]/);
    $cn =~ s/([^0-9a-z_-])/unpack('H2', $1)/gei;
    $cn =~ tr/A-Z/a-z/;
    return "cat_$cn.html";
}


### ȥإå
sub make_entry_header_html {
    my ($eh, $ymd) = @_;
    if ($show_day_of_week == 1) { ### դθɤ뤫?
	# (Mon, Tue, ...)ɲ: "2000-10-19" --> "2000-10-19 Thu"
	$eh .= " ".get_day_of_week($ymd);
    }
    return qq(<a name="$ymd" href="@{[datestr2url($ymd)]}">$eh</a>);
}


### ƥإå
sub make_item_header_html {
    my ($ih, $ymdi) = @_;
    # ­
    my $ihb = "";
    if ($item_header_style == 0 or $item_header_style == 1) {
	$ihb = $item_header_mark;
	if ($use_item_anchor == 1) {
	    my $day_url = datestr2url($ymdi);
	    $ihb = qq(<a name="$ymdi" href="$day_url">$ihb</a>);
	}
	$ihb .= " ";
    }

    # ǰϤ
    $ih = qq($ihb<span class="clitemheader">$ih</span>);
    # ­
    if ($item_header_style == 0 or $item_header_style == 2) {
	$ih .= ":";
    }
    return $ih;
}


### make category link(anchor) string for item header
sub make_cat_link_html {
    my ($catp) = @_;
    my $catstr;
    if (defined $catp) {
	if ($output_cat_pages) {
	    $catstr = 
		join("", map 
		     {"[<a href=\"".get_category_filename($_)."\">$_</a>]"}
		     @$catp);
	} elsif ($cat_page_cgi eq "") {
	    $catstr = join("", map {"[".$_."]"} @$catp);
	} else {
	    $catstr = 
		join("", map 
		     {my $tmp = $cat_page_cgi;
		      $tmp =~ s/%%CAT%%/urlencode($_)/ge;
		      "[<a href=\"$tmp\">$_</a>]"}
		     @$catp);
	}
	
    }
    return $catstr;
}    


### ꤵ줿եʸ
sub output_to_file {
    my ($fname, $contp) = @_;
    $$contp =~ s/<!-- ReplaceOnce -->/$replace_once/;

    if ($update_by_size == 1 and -s $fname == length($$contp)) {
	return;
    }

    if ($utf8_mode) {		# ad hoc 050821
	$$contp =~ s/;charset=EUC-JP">/;charset=UTF-8">/;
    }

    print "output to \"$fname\"\n" if (!defined $quiet_mode);
    open(F, "> $fname") || die "$fname: $!\n";
    binmode(F);
    print F $$contp;
    close(F);
}

### URL ENCODE
sub urlencode {
    local ($_) = @_;
    s/([^ \n\.\*\-_A-Z0-9])/sprintf("%%%02lX",unpack("C",$1))/gie;
    s/ /+/g;
    return $_;
}

### modularized for i18n
# delete content of this func, 
# if you use utf8 file and don't use Jcode.
sub to_utf8_cl {
    my ($sp) = @_;
    use Jcode;
    $$sp = Jcode->new($$sp)->utf8;
}

