#!/usr/bin/env ruby
# -*- ruby -*-
#
# Copyright (c) 2000-2001 Akinori MUSHA
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

RCS_ID = %q$Idaemons: /home/cvs/pkgtools/portcvsweb,v 1.3 2001/08/18 13:43:21 knu Exp $
RCS_REVISION = RCS_ID.split[2]
MYNAME = File.basename($0)

BROWSER = ENV['BROWSER'] || 'lynx'

CVSWEB_URI = {
  'FreeBSD' => 'http://www.FreeBSD.org/cgi/cvsweb.cgi/',
  'NetBSD' => 'http://cvsweb.netbsd.org/bsdweb.cgi/',
  'OpenBSD' => 'http://www.openbsd.org/cgi-bin/cvsweb/',
}

CVSTAGS = CVSWEB_URI.keys

CVSTAG_RE = /\$(#{CVSTAGS.join('|')}):\s+(\S+),v\s*(\d[\d.]*)/

MAKEFILE = 'Makefile'

if ARGV.empty?
  $file = nil
else
  $file = ARGV[0].chomp('/')

  if File.directory?($file)
    Dir.chdir($file)
    $file = nil
  else
    dir, $file = File.split($file)
    Dir.chdir(dir)
  end
end

if $file && !File.file?($file)
  STDERR.puts MYNAME + ': file not found.'
  exit 1
end

def check_cvs
  File.directory?('CVS') or return

  open('CVS/Repository') do |f|
    $path = File.join(f.gets.chomp, $file || '')
  end rescue nil

  open('CVS/Root') do |f|
    $tag = guess_tag(f.gets)
  end rescue nil

  if $file
    open('CVS/Entries') do |f|
      f.each do |line|
	ary = line.split('/')

	if ary[1] == $file
	  $anchor = '#rev' + ary[2]
	  break
	end
      end
    end rescue nil
  end
end

def check_makefile(subdir = nil)
  ret = check_file(MAKEFILE)

  if $path
    if subdir
      $path = File.join(File.dirname($path), subdir, $file || '')
    else
      $path = File.join(File.dirname($path), $file || '')
    end

    $anchor = nil if $file.nil?
  end

  ret
end

def check_file(file, set_anchor = false)
  open(file) do |f|
    f.each do |line|
      if CVSTAG_RE =~ line
	$tag = $1
	$anchor = '#rev' + $3 if set_anchor

	if $path.nil?
	  case $tag
	  when 'FreeBSD'
	    $path = $2
	  when 'NetBSD'
	    if %r:/([^/]+/[^/]+)$: =~ Dir.pwd
	      $path = File.join('pkgsrc', $1, file)
	    end
	  when 'OpenBSD'
	    category = `make -V CATEGORIES`.split[0]
	    if %r"/(#{Regexp.quote(category)}(?:/[^/]+){1,3})$" =~ Dir.pwd
	      $path = File.join('ports', $1, file)
	    end
	  end
	  break
	end
      end
    end

    return true
  end rescue false
end

def guess_tag(hint)
  hint = hint.downcase	# dup

  CVSTAGS.each do |name|
    if hint.include?(name.downcase)
      return name
    end
  end

  nil
end

$tag = nil
$path = nil
$anchor = nil

check_cvs()

if $file
  if $tag.nil? || $path.nil?
    check_file($file, true) || check_makefile
  end
else
  check_makefile
end

if $path.nil?
  dir, rel = File.split(Dir.pwd)

  until dir == '/'
    Dir.chdir(dir)
    check_makefile(rel) and break

    dir, last = File.split(dir)

    rel = File.join(last, rel)
  end

  if $path.nil?
    STDERR.puts MYNAME + ': CVS tag not found.'
    exit 2
  end
end

if $tag.nil?
  $tag = guess_tag(Dir.pwd) || guess_tag(`uname`) || 'FreeBSD'
end

uri = CVSWEB_URI[$tag] + $path + ($anchor || '')

BROWSER.split(':').each do |s|
  s.strip!

  next if s.empty?

  s << ' %s' unless s.include?('%s')

  exec format(s, uri) rescue nil
end

STDERR.puts 'No browser is available - please define BROWSER.'
