set XesDef(info:date)         {23MAR99}
set XesDef(info:version)      {v5_21}
set XesDef(info:rcs)          {q20}
set XesDef(info:comp_date)    {Tue_Mar_23_18:49:09_MET_1999}
set XesDef(info:comp_uid)     {fornari}
set XesDef(info:cc_comp_name) {gcc 2.8.1}
set XesDef(info:machine)      {PCi586}
set XesDef(info:system)       {Linux}
set XesDef(info:protection)   {education}

catch {wm withdraw .}


proc DisplayMsg {msg kind} {
    global tcl_platform
    switch $kind {
	trace {
	    set prefix "\#\#\# "
	}
	error {
	    set prefix "*** "
	}
	help {
	    set prefix ""
	}
    }
    puts stderr $prefix$msg
}
proc Trace {msg} {
    DisplayMsg $msg trace
}
proc Help {} {
    global HELP
    DisplayMsg $HELP help
    Exit 0
}
proc Error {msg {exit 1}} {
    DisplayMsg $msg error
    if { $exit } {
	Exit 1
    }
}

proc Exec {cmd {exit 1}} {
    global errorCode
    Trace $cmd
    if {[catch "exec $cmd" result]} {
	if {$errorCode != "NONE"} {
	    Error $result $exit
	} else {
	    puts stderr $result
	}
    }
}

proc Exit {status} {
    catch {
	if {[winfo exist .xesdialog]} {
	    .xesdialog.ok configure -command "exit $status"
	    tkwait window .xesdialog
	}
    }
    exit $status
}

proc XesInfo {} {
    global XesDef
    XesVersion 0
    puts stderr "         released: $XesDef(info:date)"
    puts stderr "         rcs name: $XesDef(info:rcs)"
    puts stderr "      compiled on: $XesDef(info:machine)/$XesDef(info:system)"
    puts stderr "             with: $XesDef(info:cc_comp_name)"
    puts stderr "             date: $XesDef(info:comp_date)"
    puts stderr "               by: $XesDef(info:comp_uid)"
    exit 0
}

proc XesVersion { {exit 1} } {
    global XesDef
    puts -nonewline stderr "--- xes "
    XesAccess 0
    if { $exit } {
	exit 0
    }
}

proc XesAccess { {exit 1}} {
    global XesDef
    puts stderr "$XesDef(info:protection) version $XesDef(info:version)"
    if { $exit } {
	exit 0
    }
}

#========
# Common
#========
#-------------------------------------
# Compiler to use. See also -cc option
#-------------------------------------
if {[catch {set CC $env(CC)}]} {
  set CC cc
}

if {[catch {set ESTEREL $env(ESTEREL)}]} {
    Error "ESTEREL environment variable is undefined"
}
if { $tcl_platform(platform) == "windows" } {
    # in case of Cygwin, transform //drive into drive:
    regsub {^//([a-zA-Z])} $ESTEREL {\1:} ESTEREL
}

# Some defaults.
if {[catch {set XES_LIBRARY_PATH $env(XES_LIBRARY_PATH)}]} {
    set XES_LIBRARY_PATH [file join $ESTEREL lib]
}


#-------------------------------------------------
# sourcing of Xes compilation specific definitions
#-------------------------------------------------
set XesDef(libxes) [file join $XES_LIBRARY_PATH libxes.a]

set xesdef [file join $XES_LIBRARY_PATH xes/xes.def]
if { ! [file exists $xesdef] } {
    set xesdef [file join $XES_LIBRARY_PATH xes.def]
    if { ! [file exists $xesdef] } {
	Error "Cannot find xes.def"
    }
}
if {[catch {source $xesdef} err]} {
    Error $err
}


#------------------------------------------------------
# Librairies needed to build the final executable. This
# may be system dependent. Set the LIBS variable
#------------------------------------------------------
switch $tcl_platform(platform) {
    unix {
	set XesDef(libraries) $XesDef(libraries:$tcl_platform(os))
    }
    windows {
	set XesDef(libraries) $XesDef(libraries:windows)
    }
    default {
	Exit 1
    }
}

#===============================================================
#	       DO NOT CHANGE FROM HERE
#===============================================================

set USAGE {
Usage: xes [-help] [-info] [-version] [-access]
       xes [options] object_files [-o simulator[.exe]]
       xes [options] simulator.exe
}
set HELP {
Usage: xes [-help] [-info] [-version] [-access]
       xes [options] object_files [-o simulator[.exe]]
       xes simulator.exe

The object_files argument is a list of object files, one of them
being the result of the C-compilation of a C-code generated by the 
Esterel compiler. In this case, the xes script links the object files 
with the libxes.a library, runs the a.out produced simulator, and 
then removes it when finished.
The .o suffixes of object files are  optional.
If invoked with the -o option, the xes command don't execute the
the a.out executable but rename it with its argument and adds if needed
a .exe suffix. 

One can also give only one file argument to  xes which is an
already linked simulator, with sufix .exe. In that case, the 
simulator is immediately executed in the suitable environment.

Options for both the xes script or the generated executable simulators:
   -help                - Help, but how did you get it?
   -display             - Next argument is the display to use
   -name                - Next argument is the name to use for application
   -geometry            - Next argument is the initial geometry for window
   -D                   - Next argument is the directory of Esterel programs
   -script              - Next argument is the name of a user Tcl script
   -ns                  - Set xes in no-source  mode
   -np                  - Set xes in no-parse  mode
   -ki                  - Set xes in keep inputs mode
   -hl                  - Allow high or low default for inputs
   -version             - Display xes current version number
   -info                - Display xes characteristics
   -access              - Display xes access rights

Specific options of the xes script:
  -o name               - Keep executable with name "name" and don't exec
  -cc compiler_name     - Compiler to use for linking; default "cc"

A minimal use of esterel and xes is:
  esterel -simul foo.strl
  cc -c foo.c
  xes foo.o
where foo.strl is supposed to be a correct Esterel program.

Alternatively, here is another example:
xes foo -o foo		;# Links foo.o and keeps foo.exe
xes foo.exe		;# Execute foo.exe

}
# command line options
set OPTIONS {}
# list of object file to link
set OBJLIST   ""
# name of the temporary executable
if { $tcl_platform(platform) == "windows" } {
    set EXEC xes[pid].exe
} else {
    set EXEC /tmp/xes[pid].exe
}
# -keep option
set KEEP 0



# No arguments == need help !
if {$argc == 0} {
    Help
}

set info_opt ""

#-----------
# Parse args
#-----------
set argc 0
while { [set arg [lindex $argv $argc]] != ""} {
    switch -glob -- $arg {
	-help {
	    Help
	}


	-o {
	    # option -o has 1 arguments
	    
	    set KEEP 1 
	    set arg [lindex $argv [incr argc]]
	    if { $arg == "" || [string match -* $arg] } {
		Error "missing argument"
	    }
            set KEEP_NAME $arg
	    if { [file extension $KEEP_NAME] != ".exe" } {
		append KEEP_NAME ".exe"
	    }
	}

	-cc {
	    # cc option has 1 argument
	    set arg [lindex $argv [incr argc]]
	    if { $arg == "" || [string match -* $arg] } {
		Error "missing argument"
	    }
	    set XesDef(linker:unix) $arg

	}	    

	-si -
	-ki -
	-np -
	-ns -
	-hl -
	-info - 
	-version -
	-access {
	    # si, ns, np, ki, hl, info, version, and access
	    # options  have no following argument
	    lappend OPTIONS $arg 
	    # see below OBJLIST = ""
	    switch -- $arg {
		-info -
		-version -
		-access {
		    if { $info_opt == "" } {
			set info_opt $arg
		    }
		}
	    }
	}

	-D -
	-display -
        -name -
	-script {
	    # D, us options have 1 following argument
	    set opt $arg
	    lappend OPTIONS $OPTIONS $opt
	    set arg [lindex $argv [incr argc]]
	    if { $arg == "" || [string match -* $arg] } {
		Error "$opt: missing argument"
	    }
	    lappend OPTIONS $arg 
	}

	-* {
	    Error "$arg :  bad option"
	}

	default {
	    lappend OBJLIST $arg
	}
    }
    incr argc
}

# Check for immediate execution
if {[llength $OBJLIST] == 1 && [string match *.exe $OBJLIST] } {
    Trace "Immediate Xes execution: $OBJLIST $OPTIONS"
    if { $tcl_platform(platform) == "windows" } {
	set exec [file join $ESTEREL bin/[lindex [file split $OBJLIST] end]]
	file copy $OBJLIST $exec 
	Exec [concat $exec $OPTIONS] 0
	file delete $exec
    } else {
	if { [file pathtype $OBJLIST ] == "relative" } {
	    set OBJLIST [file join . $OBJLIST]
	}
	Exec [concat $OBJLIST $OPTIONS] 0
    }
    Exit 0
}

# Need link: check for object list
set obj_ext $XesDef(object:$tcl_platform(platform))

if { "$OBJLIST" == "" } {
    switch -- $info_opt {
	-info XesInfo
	-version XesVersion
	-access XesAccess
	default {
	    puts stderr $USAGE
	    Exit 1
	}
    }
}

foreach object $OBJLIST {
    if { [file extension $object] == ""} {
	append object $obj_ext
    }
    lappend NEWLIST $object
}
# Static link
Trace "--- Linking ... "
set os $tcl_platform(platform) ; # just for readability
Exec [concat \
	  $XesDef(linker:$os) \
	  $XesDef(linker:options:$os) \
	  $XesDef(linker:out:$os)$EXEC \
	  $NEWLIST \
	  $XesDef(libxes) \
	  $XesDef(tcltk:$os) \
	  $XesDef(libraries)]
Trace "--- Done"

# Exec program and remove or keep it
if { $KEEP == 0  } {
    if { $tcl_platform(platform) == "windows" } {
	set exec [file join $ESTEREL bin/[file tail $EXEC]]
	file copy $EXEC $exec 
	Exec [concat $exec $OPTIONS] 0
	file delete -force -- $exec
    } else {
	Exec [concat $EXEC $OPTIONS] 0
    }
    file delete -force -- $EXEC
} else {
    file rename -force -- $EXEC $KEEP_NAME
    Trace "Executable simulator is kept in: $KEEP_NAME"
}
Exit 0

