proc Cmdputsd { text } {
    global DEBUG
    if { !$DEBUG } { return }
    puts $text\n
    set DEBUGFOUT [open c:/tmp/kk_gid.err a]
    puts $DEBUGFOUT $text\n
    close $DEBUGFOUT
}

proc CmdErrorAndQuit { text } {
    CmdErrorNoQuit $text
    exit 2
}

if { [info command bgerror] == "" } {
    proc bgerror { text } {
	CmdErrorAndQuit $text
    }
}

proc OutputInProgramErrorFile { txt } {
    global ProgramErrorFile

    if { $ProgramErrorFile != "" } {
	catch {
	    set fout [open $ProgramErrorFile a]
	    puts $fout $txt
	    close $fout
	    Cmdputsd "filled $ProgramErrorFile"
	}
    }
}

proc CmdErrorNoQuit { text } {
    global NumLine DEBUG ProgramErrorFile

    if { $DEBUG } {
	set DEBUGFOUT [open /temp/kk.err a]
    }

    if { !$NumLine } {
	if { [info command wm] != "" } {
	    wm withdraw .
	    tk_messageBox -icon error -title [_ "error in .bat file"] -type ok \
		    -message "$text"
	} elseif { $DEBUG } {
	    puts $text\n
	    puts $DEBUGFOUT $text\n
	} else {
	    puts $text\n
	}
	OutputInProgramErrorFile "error in .bat file: \n$text\n"
    } else {
	if { [info command wm] != "" } {
	    wm withdraw .
	    tk_messageBox -icon error -title [_ "error in .bat file"] -type ok \
		    -message "line: $NumLine.- $text"
	} elseif { $DEBUG } {
	    puts "line: $NumLine.- $text\n"
	    puts $DEBUGFOUT "line: $NumLine.- $text\n"
	} else {
	    puts "line: $NumLine.- $text\n"
	}
	OutputInProgramErrorFile "error in .bat file: \nline: $NumLine.- $text\n"
    }
    if { $DEBUG } {
	close $DEBUGFOUT
    }
}

proc CmdWarnWin {text} {
    global NumLine
    tk_messageBox -icon error -title [_ "error in .bat file"] -type ok \
	    -message "line: $NumLine.- $text"
}

proc CmdEraseElement { inum } {
    global line linelen

   for { set i [expr $inum+1] } { $i < $linelen } { incr i } {
	set iprev [expr $i-1]
	set line($iprev) $line($i)
    }
    incr linelen -1
}

proc CmdCommandExecuter { inum fbat } {
    global errorCode arv0 env
    global line linelen ProgramErrorFile
    global param

    set retval ""
    set cmdinum $line($inum)
    switch -- [string tolower $line($inum)] {
	rem {
	    if { [info exists line([expr $inum+1])] && [info exists line([expr $inum+2])] && \
		    [string tolower $line([expr $inum+1])] == "errorfile:" } {
		set ProgramErrorFile [file join $line([expr $inum+2])]
		Cmdputsd ProgramErrorFile=$ProgramErrorFile
	    }
	    # nothing
	}
	cd - chdir {
	    set dir ""
	    incr inum
	    if { $inum < $linelen } {
		set dir $line($inum)
	    }
	    if { [catch {
		regsub -all {\\} $dir {/} dir
		set dir [lindex $dir 0]
		cd $dir
	    } ] } {
		CmdErrorAndQuit "error: trying to change directory to '$dir'"
	    }
	}
	del - delete - erase {
	    incr inum
	    for { set i $inum } { $i < $linelen } { incr i } {
		set file $line($i)
		if { [string match /* $file] } { continue }
		catch {
		    regsub -all {\\} $file {/} file
		    set file [lindex $file 0]
		    file delete $file
		}
	    }
	}
	copy {
	    incr inum
	    set file1 ""
	    set file2 ""
	    set filestoadd ""
	    set addnextfile 0
	    for { set i $inum } { $i < $linelen } { incr i } {
		set file $line($i)
		if { [string match /* $file] } { continue }
		regsub -all {\\} $file {/} file
		set file [lindex $file 0]
		if { $file == "+" } {
		    set addnextfile 1
		} elseif { $addnextfile } {
		    lappend filestoadd $file
		    set addnextfile 0
		} elseif { $file1 == "" } { 
		    set file1 $file
		} elseif { $file2 == "" }  {
		    set file2 $file
		} else {
		    CmdErrorAndQuit "error in copy func"
		}
	    }
	    if { $file2 == "" } {
		CmdErrorAndQuit "error in copy func (2)"
	    }
	    catch {
		#file copy -force $file1 $file2
		if {  [file tail $file1] == "*.*" } {
                    #change "c:/a/b/*.*" by "c:/a/b/*" (wild card MSDos style)
	            set file1 [file rootname $file1]
                }	
		set order "file copy -force [glob $file1] $file2"
		eval $order
		if { $filestoadd != "" } {
		    set fout [open $file2 a]
		    foreach i $filestoadd {
			set fin [open $i r]
			puts -nonewline $fout [read $fin]
			close $fin
		    }
		    close $fout
		}
	    }
	}
	ren - rename - move {
	    if { [expr $linelen-$inum] != 3 } {
		CmdErrorAndQuit "error: $line($inum) needs two arguments"
	    }
	    incr inum
	    set file1 ""
	    set file2 ""
	    for { set i $inum } { $i < $linelen } { incr i } {
		set file $line($i)
		if { [string match /* $file] } { continue }
		regsub -all {\\} $file {/} file
		set file [lindex $file 0]
		if { $file1 == "" } { 
		    set file1 $file
		} else {
		    set file2 $file
		    break
		}
	    }
	    catch {
		file rename $file1 $file2
	    }
	}
	md - mkdir {
	    incr inum
	    for { set i $inum } { $i < $linelen } { incr i } {
		set file $line($i)
		if { [string match /* $file] } { continue }
		regsub -all {\\} $file {/} file
		set file [lindex $file 0]
		catch {
		    file mkdir $line($i)
		}
	    }
	}
	set {
	    incr inum
	    set execline ""
	    for { set i $inum } { $i < $linelen } { incr i } {
		append execline $line($i)
		if { $inum < [expr $linelen-1] } { 
		    append execline " "
		}
	    }
	    if { [regexp {^[ ]*$} $execline] } { break }
	    set var ""
	    set value ""
	    if { [regexp {([^=]*)=(.*)} $execline {} var value] } {
		if { $var != "" } {
                    set var [string trim $var " \""]
                    set value [string trim $value " \""]
		    set env($var) $value
		}
	    }

	}
	echo - @echo {
	    incr inum
	    if { [expr $linelen-$inum] == 1 && ( [string tolower $line($inum)] == "on" || \
		    [string tolower $line($inum)] == "off") } {
	    } else {
		set type ""
		for { set i [expr $linelen-1] } { $i >= $inum } { incr i -1} {
		    set item $line($i)
		    if { ![regexp {^[\"]} $item] } {
			if { [string match *>* $item] } {
			    regexp {^([^>]*)(>>?)(.*)} $item {} before sign after
			    set ifile [expr $i+1]
			    if { $before == "" } {
				CmdEraseElement $i
				incr ifile -1
			    } else {
				set line($i) $before
			    }
			    if { $after == "" } {
				if { $ifile == $linelen } {
				    CmdErrorAndQuit [_ "error: in echo command after > or >> need filename"]
				}
				set after $line($ifile)
				CmdEraseElement $ifile
			    }
			    if { $type == "" } {
				if { $sign == ">" } {
				    set type w
				} else {
				    set type a
				}
				set file $after
			    }
			}
		    }
		}
		if { $type == "" } {
		    for { set i $inum } { $i < $linelen } { incr i } {
			puts -nonewline $line($i)
			if { $inum < [expr $linelen-1] } { 
			    puts -nonewline " " 
			} else { puts "" }
		    }
		} else {
		    regsub -all {\\} $file {/} file
		    set file [lindex $file 0]
		    if { [catch { set fout [open $file $type] } err] } {
			CmdErrorAndQuit "error ($err): trying to echo to file '$file'"
		    }
		    for { set i $inum } { $i < $linelen } { incr i } {
			puts -nonewline $fout $line($i)
			if { $inum < [expr $linelen-1] } { 
			    puts -nonewline $fout " " 
			} else { puts $fout "" }
		    }
		    close $fout
		}
	    }
	}
	"if" {
	    incr inum
	    set negate 0
	    if { [string tolower $line($inum)] == "not" } {
		set negate 1
		incr inum
	    }
	    set val 0
	    set ifpos [string tolower $line($inum)]
	    if { [regexp {^([^ ]+)[ ]*==[ ]*([^ ]+)} $ifpos {} caden1 caden2] } {
		set val [expr [string compare $caden1 $caden2] == 0]
                incr inum
	    } elseif { $line([expr $inum+1]) == "=="  } {
		set caden1 $ifpos
		if { [expr $inum+1] >= $linelen } {
		    CmdErrorAndQuit "error: expression 'if c1 == c2' not correct"
		}
		set caden2 [string tolower $line([expr $inum+2])]
		set val [expr [string compare $caden1 $caden2] == 0]
                set inum [expr $inum+3]
	    } elseif { $ifpos == "errorlevel" } {
		incr inum
		set number $line($inum)
		if { [catch { expr int($number) }] } {
		    CmdErrorAndQuit "error: after 'if errorlevel' one number is needed"
		}
		set errorlevel 0
		if { [lindex $errorCode 0] == "CHILDSTATUS" } { 
		    set errorlevel [lindex $errorCode 2]
		}
		set val [expr $errorlevel>=$number]
		incr inum
	    } elseif { $ifpos == "exist" } {
		incr inum
		set file $line($inum)
		regsub -all {\\} $file {/} file
		set file [lindex $file 0]
		set val [file exists $file]
		incr inum
	    } else {
		CmdErrorAndQuit "Unknown condition for 'if' command: '$ifpos'"
	    }
	    if { $negate } { set val [expr !$val] }
	    if { $val } {
		set retval [CmdCommandExecuter $inum $fbat]
	    }
	}
	call {
	    incr inum
	    set errorCode NONE
	    set execline ""
	    for { set i $inum } { $i < $linelen } { incr i } {
		append execline $line($i)
		if { $inum < [expr $linelen-1] } { 
		    append execline " "
		}
	    }
	    regsub -all {\\} $execline {\\\\} execline
	    global RunningProcess
	    set RunningProcess running
	    if { [catch { set pid [eval exec $execline &] } errorchar] } {
  		if { [lindex $errorCode 0] != "CHILDSTATUS" } {
  		    CmdErrorAndQuit "error: $errorchar "
  		}
	    }
	    while 1 {
		if { $RunningProcess == "" } {
		    kill $pid
		    vwait forever
		}
		if { ![isalive $pid] } { break }
		after 200
		update
	    }
	    unset RunningProcess
	}
	goto {
	    incr inum
	    return $line($inum)
	}

	type {
	    incr inum	  
	    set file ""
	    set type ""
	    for { set i [expr $linelen-1] } { $i >= $inum } { incr i -1} {
		set item $line($i)
		if { ![regexp {^[\"]} $item] } {
		    if { [string match *>* $item] } {
			regexp {^([^>]*)(>>?)(.*)} $item {} before sign after
			set ifile [expr $i+1]
			if { $before == "" } {
			    CmdEraseElement $i
			    incr ifile -1
			} else {
			    set line($i) $before
			}
			if { $after == "" } {
			    if { $ifile == $linelen } {
				CmdErrorAndQuit [_ "error: in %s command after > or >> need filename" $cmdinum]
			    }
			    set after $line($ifile)
			    CmdEraseElement $ifile
			}
			if { $type == "" } {
			    if { $sign == ">" } {
				set type w
			    } else {
				set type a
			    }
			    set file $after
			}
		    }
		}
	    }
            if { $type != "" } {
               if { $file != "" } {
		   regsub -all {\\} $file {/} file
		   set file [lindex $file 0]
		   set filesource $line($inum)
		   regsub -all {\\} $filesource {/} filesource
		   set filesource [lindex $filesource 0]
		   if { ![file exists $filesource]  } {
		       CmdErrorAndQuit [_ "Error: in %1\$s command, source file %2\$s not exist" $cmdinum $filesource]
		   } else {
		       if { $type == "w" || ![file exists $file] } {
			   file copy -force $filesource $file
		       } elseif {  $type == "a" } {
			   set fout [open $file a]
			   set fin [open $filesource r]
			   puts -nonewline $fout [read $fin]
			   close $fin
			   close $fout
		       }
		   }
	       } else {
		   CmdErrorAndQuit [_ "error: in %s command after > or >> need filename" $cmdinum]
	       }
	    }
	}
	
	shift {
	    incr inum
	    set i 1
	    while { [info exists param($i)] } {
		set param([expr $i-1]) $param($i)
		incr i
	    }
	    unset param([expr $i-1])
	}
	tcl {
	    set script ""
	    incr inum
	    for {} { $inum < $linelen } { incr inum } {
		append script " $line($inum)"
	    }
	    append script \n[read $fbat]
	    set err [catch { uplevel \#0 $script } errstring]
	    if { $err } {
		OutputInProgramErrorFile "error in .bat file: \n$errstring\n"
	    }
	    return ""
	}
	default {
	    set errorCode NONE
	    set execline ""
	    for { set i $inum } { $i < $linelen } { incr i } {
		append execline $line($i)
		if { $inum < [expr $linelen-1] } { 
		    append execline " "
		}
	    }
	    regsub -all {\\} $execline {\\\\} execline
	    global RunningProcess
	    set RunningProcess running
	    
	    Cmdputsd execline=--$execline--
	    
	    if { [catch { set pid [eval exec $execline &] } errorchar] } {
  		if { [lindex $errorCode 0] != "CHILDSTATUS" } {
  		    CmdErrorAndQuit "error: $errorchar "
  		}
	    }
	    while 1 {
		if { $RunningProcess == "" } {
		    Cmdputsd "Before killing..."
		    kill $pid
		    Cmdputsd "after killing"
		    vwait forever
		}
		if { ![isalive $pid] } { break }
		after 100
		update
	    }
	    Cmdputsd "after finishing"
	    unset RunningProcess
	}
    }
    return $retval
}

proc CmdReadAndExecute { fbat } {
    global NumLine rargc rargv
    global line linelen
    global env
    global param

    for { set i 0 } { $i < $rargc } { incr i } {
	set param($i) [lindex $rargv $i]
	catch { set param($i) [file native [file attributes $param($i) -shortname]] } aa
    }
    catch { unset labels }
    while { ![eof $fbat] } {
	gets $fbat aa
	Cmdputsd "executing:   $aa"
	incr NumLine
	if { [regexp {^[ ]*$} $aa] } { continue }
	if { [regexp {^[ ]*:[ ]*([^ ]+)} $aa {} label] } {
	    set label [string tolower $label]
	    set labels($label) [tell $fbat]
	    continue
	}

	set word ""
	set linelen 0
	catch { unset line }
	set thereisspace 0
	set openpar 0
	for { set i 0 } { $i < [string length $aa] } { incr i } {
	    set l [string index $aa $i]
	    if { $l == "\"" } {
		if { $openpar } {
		    append word "\""
		    set line($linelen) $word
		    incr linelen
		    set word ""
		    set thereisspace 0
		    set openpar 0
		} elseif { $word == "" } {
		    set openpar 1
		    set word "\""
		} else {
		    append word "\""
		}
	    } elseif { !$openpar && ($l == " " || $l == "\t" || \
		    ($l == "+" && [regexp -nocase {copy} $aa] ) \
		    ) } {
		if { $word != "" } {
		    if { $thereisspace && [string index $word 0] != "\"" } {
			set word "\"$word"
		    }
		    set last [expr [string length $word]-1]
		    if { $thereisspace && [string index $word $last] != "\"" } {
			append word "\""
		    }
		    set line($linelen) $word
		    incr linelen
		    set word ""
		    set thereisspace 0
		}
		if { $l == "+" } {
		    set line($linelen) +
		    incr linelen
		}
	    } else {
		if { $l == "%" } {
		    incr i
		    set l [string index $aa $i]
		    switch -- $l {
			0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
			    if { [info exists param($l)] } {
				if { [llength $param($l)] > 1 } { set thereisspace 1 }
				append word $param($l)
			    }
			}
			default {
			    if { [regexp {^([a-zA-Z_0-9]+)%} [string range $aa $i end] {} varname] } {
				if { [info exists env($varname)] } {
				    if { [llength $env($varname)] > 1 } { set thereisspace 1 }
				    append word $env($varname)
				    incr i [string length $varname]
				} else {  
                                    if { [string tolower $line(0)] == "rem" } {
                                      incr i -1
                                      set comment [string range $aa $i end]
                                      append word $comment
				      incr i [string length $comment]
                                    } else {
			                CmdErrorAndQuit "Error: variable '$varname' not known"
                                    }
				}
			    } else {
				incr i -1
			    }
			}
		    }
		} else {
		    append word $l
		}
	    }
	}
	if { $word != "" } {
	    if { $thereisspace && [string index $word 0] != "\"" } {
		set word "\"$word"
	    }
	    set last [expr [string length $word]-1]
	    if { $thereisspace && [string index $word $last] != "\"" } {
		append word "\""
	    }
	    set line($linelen) $word
	    incr linelen
	}
	set retval [CmdCommandExecuter 0 $fbat]
	if { $retval != "" } {
	    set retval [string tolower $retval]
            if { $retval == ":eof" } { break }
	    if { [info exists labels($retval)] } {
		fseek $fbat $labels($retval)
	    } else {
		while { ![eof $fbat] } {
		    gets $fbat aa
		    incr NumLine
		    set label ""
		    if { [regexp {^[ ]*:[ ]*([^ ]+)} $aa {} label] } {
			set label [string tolower $label]
			set labels($label) [tell $fbat]
		    }
		    if { $retval == $label } { break }
		}
		if { $retval != $label } {
		    CmdErrorAndQuit "error: label for goto not found '$retval'"
		}
	    }
	}
    }
}

if { [info command wm] != "" } {
	    wm withdraw .
}

set NumLine 0
set errorCode NONE
set DEBUG 0
set ProgramErrorFile ""

Cmdputsd encoding=[encoding system]
Cmdputsd argv0=$argv0
set i 1
foreach j $argv {
    Cmdputsd "argv $i=$j"
    incr i
}


if { $argc < 4 } {
    CmdErrorAndQuit [_ "error; usage: %s file.bat basename projectdirectory problemtypedirectory " $argv0]
}

proc CmdExitReal {} {
    Cmdputsd "exit real"
    exit
}

proc Exit { args } {
    global RunningProcess

    Cmdputsd "exiting..."
    if { [info exists RunningProcess] } {
	set RunningProcess {}
    }
    after 400 CmdExitReal
    return "goodbye"
}

load tcldde12.dll dde
dde servername [pid]


set rargc 0
set rargv ""
for { set i 0 } { $i < $argc } { incr i } {
    if { ![regexp {^/[a-zA-Z]$} [lindex $argv $i]] } {
	incr rargc
	lappend rargv [lindex $argv $i]
    }
}


set file [lindex $rargv 0]

if { [catch {
    set fbat [open $file r]
}] }  {
    CmdErrorAndQuit "error: file $file does not exist"
}

#set rargv [lrange $argv 1 end]

CmdReadAndExecute $fbat
CmdExitReal

