#!/usr/bin/perl

# --------------------------------------
# テキストカウンタ（CGI+JavaScript）
$ver = 'ffCow v.1.09';
# 2001/12/30
# (C)2000 Fortunefield
# http://www.gem.hi-ho.ne.jp/fortunefield/
# --------------------------------------

# ======================================
# 定数群
# --------------------------------------
$datafile = "ffcow.dat";                # データファイル名

$lockkey = 0;                           # ロック機能（0=no, 1=flock, 2=rename）
$lockfile = "ffcow.lock";               # ロックファイル名

$nocountkey = 1;                        # 重複カウント防止機能（0=no, 1=yes）

$fig_total = "Total Access: %04d";                    # 累計表示
$fig_today = " Today: %03d";            # 日計表示（今日）
$fig_yeste = " Yesterday: %03d";        # 日計表示（昨日）

$ENV{'TZ'} = 'JST-9';                   # 時間帯（JST-9=日本時間）

# ======================================
# 手続き
# --------------------------------------
if ($ENV{'QUERY_STRING'} eq 'check') { &check; }
&decode;
$lockfile2 = "$lockfile"."2";

&lock;

open(IN, "$datafile") || &error("Open Error: $datafile");
@data = <IN>;
close(IN);

$mday = (localtime(time))[3];
$addr = $ENV{'REMOTE_ADDR'};
foreach (@data) {
  ($total, $today, $yeste, $lastmday, $lastaddr, $page) = split(/<>/);
  if ($in{'pg'} eq $page) { last; }
  $total = 0; $today = 0; $yeste = 0;
}

$flag = 0;
if ($nocountkey) {
  if ($mday eq $lastmday && $addr eq $lastaddr) { $flag = 1; }
}

if ($flag == 0) {
  $total++;
  if ($mday eq $lastmday) { $today++; }
  else { $yeste = $today; $today = 1; }

  @new = ();
  push(@new, "$total<>$today<>$yeste<>$mday<>$addr<>$in{'pg'}<>\n");
  foreach (@data) {
    if ($in{'pg'} ne (split(/<>/))[5]) { push(@new, $_); }
  }

  open(OUT, ">$datafile") || &error("Write Error: $datafile");
  print OUT @new;
  close(OUT);
}

&unlock;

$prn_total = sprintf($fig_total, $total);
$prn_today = sprintf($fig_today, $today);
$prn_yeste = sprintf($fig_yeste, $yeste);

&header;

if ($in{'prn'}) {
  print <<"JS";
  var prn = $in{'prn'};
  var str = "";
  if (prn >= 1) {
    str += "$prn_total";
  }
  if (prn == 2) {
    str += "$prn_today";
    str += "$prn_yeste";
  }
  document.write(str);
JS
} else {
  print <<"JS";
  function ffcow() {
    var a = new Array("$prn_total", "$prn_today", "$prn_yeste");
    return a;
  }
JS
}

exit;

# ======================================
# 関数群
# --------------------------------------
# パラメータをデコード
sub decode {
  local($query, @params, $param, $key, $val);
  $query = $ENV{'QUERY_STRING'};
  @params = split(/&/, $query);
  foreach $param (@params) {
    ($key, $val) = split(/=/, $param);
    $in{$key} = $val;
  }
}

# --------------------------------------
# JavaScript形式ヘッダ出力
sub header {
  print "Content-type: text/javascript\n\n";
}

# --------------------------------------
# ロック
sub lock {
  if ($lockkey == 1) {
    open(LOCK, "$lockfile");
    eval { flock(LOCK, 2); };
  } elsif ($lockkey == 2) {
    if (-e $lockfile2) {
      if (time - (stat($lockfile2))[9] > 300) { rename($lockfile2, $lockfile); }
    }
    local($retry) = 10;
    while (!rename($lockfile, $lockfile2)) {
      if (--$retry <= 0) { &error("Lock is busy"); }
      sleep(1);
    }
  }
}

# --------------------------------------
# ロック解除
sub unlock {
  if ($lockkey == 1) {
    close(LOCK);
  } elsif ($lockkey == 2) {
    rename($lockfile2, $lockfile);
  }
}

# --------------------------------------
# エラー処理
sub error {
  &unlock;
  &header;
  print "document.write(\"$_[0]\");\n";
  exit;
}

# --------------------------------------
# チェック
sub check {
  print "Content-type: text/html\n\n";
  print "<HTML><HEAD><TITLE>$ver</TITLE></HEAD><BODY>$ver<UL>\n";
  local($p1, $p2) = ('NG', 'NG');
  if (-e $datafile) { $p1 = 'OK'; }
  if (-r $datafile && -w $datafile) { $p2 = 'OK'; }
  print "<LI>\$datafile: $datafile -- path=$p1 permission=$p2\n";

  $p1 = $p2 = 'NG';
  if ($lockkey) {
    if (-e $lockfile) { $p1 = 'OK'; }
    if (-r $lockfile) { $p2 = 'OK'; }
    print "<LI>\$lockfile: $lockfile -- path=$p1 permission=$p2\n";
  } else { print "<LI>\$lockfile: $lockfile -- OFF\n"; }

  if ($lockkey == 1 && $p1 eq 'OK' && $p2 eq 'OK') {
    open(LOCK, "$lockfile");
    eval { flock(LOCK, 2); };
    if ($@) { print "<LI>\$lockkey: $lockkey -- NG\n"; }
    close(LOCK);
  }

  print "</UL></BODY></HTML>";
  exit;
}
