#!../tclsh
# -*- tcl -*-
# emulation of md5sum build with blob, blobX, tcl
#
# md5sum [-b] [-v] [-c [file]] [file ...]
#
# -b :: read files as binary /no effect here
# -v :: verbose, print filenames during check
# -c :: check hashvalues, file contains them + filenames.
#       no file: read from stdin
#
# no check, no files: generate hashvalue of stdin
# no check, files:    read files, generate hashvalues
#
package require BlobX

proc usage {args} {
    puts {
	usage: md5sum

	md5sum -h		this help
	md5sum			generate hash of stdin
	md5sum file...		generate hash of specified files
	md5sum [-v] -c		check hash, read filenames from stdin
	md5sum [-v] -c file	check hash, read filenames from file

	-v == produce more verbose output during the checks
    }
    exit 0
}

lappend auto_path $env(TCL_POOL)

set verbose 0
set check   stdin

# -- hashvalue checking
proc checkhash {} {
    global verbose check
    if {"stdin" != "$check"} {
	if {[catch {set check [open $check r]} msg]} {
	    puts "couldn't access $check: $msg"
	    exit -1
	}
    }

    puts "performing md5 check of hashvalues for files in package"

    blob create fmem
    blob create fhash
    set failures 0
    set files    0
    set missing  0

    while {[gets $check line] > 0} {
	set hashhex [lindex $line 0]
	set file    [lindex $line 1]

	if {[catch {set fh [open $file r]} msg]} {
	    puts "$file inaccessible, check skipped: $msg"
	    incr missing
	    # skip check
	} else {
	    incr files
	    if {$verbose} {puts -nonewline "checking ... "; flush stdout}

	    fconfigure $fh -translation binary
	    fmem set file $fh
	    close $fh

	    md5 fhash blob fmem
	    set newhash [string tolower [fhash string -hex]]

	    if {0 != [string compare $hashhex $newhash]} {
		if {$verbose} {
		    puts "failed \[$newhash -- $hashhex] for $file"
		} else {
		    puts "checking ... failed \[$newhash -- $hashhex] for $file"
		}
		flush stdout
		incr failures
	    } else {
		if {$verbose} {puts "ok: $file"; flush stdout}
	    }
	}
    }

    puts "md5 check failed for $failures files out of $files"
    puts "missing $missing files out of $files"

    rename fmem  {}
    rename fhash {}
}

# -- hashvalue generation
proc genhash {} {
    global argc argv
    if {$argc == 0} {
	# hash stdin
	fconfigure stdin -translation binary
	[blob create stdin] set file stdin
	puts "[string tolower [[md5 stdin blob stdin] string -hex]]"
    } else {
	blob create fmem
	blob create fhash
	while {[set file [lshift argv]] != {}} {
	    if {[catch {set fh [open $file r]} msg]} {
		puts stderr "$file inaccessible, no hash generated: $msg"
	    } else {
		fconfigure $fh -translation binary
		fmem set file $fh;	close $fh
		puts "[string tolower [[md5 fhash blob fmem] string -hex]]\t$file"
	    }
	}
	rename fhash {}
	rename fmem  {}
    }
}



# -- main section --
# defined regocnized options.
set   opt(_) {}
unset opt(_)

getoptDefine opt b  no       obinary
getoptDefine opt v  no       overbose
getoptDefine opt c  optional ocheck
getoptDefine opt h  no       usage

set docheck 0

proc obinary  {opt} {}
proc overbose {opt} {
    global verbose
    set    verbose 1
}
proc ocheck {opt arg} {
    global  check docheck
    if {{} != $arg} {set check $arg}
    set docheck 1
}

# process options.
getopt       opt

if {$docheck} {
    checkhash
} else {
    genhash
}

exit 0
