Passing INI Variables To Scripts


Thu, 21 Sep 2000 10:41:49 -0400 (EDT)
Date: Thu, 21 Sep 2000 10:41:49 -0400 (EDT)
 

You wrote to me:

>
My problem is how to catch the inifile name when a script is executed or
is that an automatic thing when you use emcsh.
<

It's automatic. tkemc.tcl, and any subscripts it spawns with "exec
$scriptdir/$file -- -ini $EMC_INIFILE &", can refer to the global
variable $EMC_INIFILE and see the .ini file name. Details below.

>
If yes, can this also be done for iosh?
<

It can be done, and I just did it using the same procedure I describe
below. I'll push up the new version of iosh.cc to SourceForge in a bit.
See the details below if you want to do this one-liner yourself.

>
I assume that since this is emcsh that you can use something like this
command

emc_ini CYCLE_TIME DISPLAY

in the script and get the correct one that is being used in the EMC
controller.
<

Yes, this works in both the top-level script tkemc.tcl, and any
subscripts that are passed "-ini $EMC_INIFILE" as an argument.

Details:

When you run "tkemc.tcl -- -ini ray.ini", what happens is this:

1. The Unix shell that you are running, like bash or csh, notes that
while the file has the executable bit set, it's not an ELF-format binary
executable and can't be passed directly to the Unix loader. As a second
try, it opens the file and see this:

#!/bin/sh
# the next line restarts using emcsh \
exec plat/linux_2_2_14/bin/emcsh "$0" "$@"

Your shell reads through the well-known comment token #!, sees that it's
an sh script, and passes control to /bin/sh. Your shell implicitly
passes its command line to /bin/sh.

2. /bin/sh is now running, and its args are the same as what you typed
on your shell's command line. sh steps over the comments and runs the
first non-commented statement,

exec plat/linux_2_2_14/bin/emcsh "$0" "$@"

which is what the guy who wrote the sh program (me, originally) wants to
happen. In this case, it's to execute emcsh with the command line
arguments. The $0 and $@ args expand to the name of the program ($0 =
"tkemc.tcl") and all the subsequent args ($@ = "-- -ini ray.ini").

3. emcsh is now running, and its args are the same as what you typed on
your shell's command line, having been passed once implicitly by your
shell to /bin/sh, and once again explicitly as args to the exec call to
emcsh. This is effectively what would have happened if we started with
this at your shell: "plat/linux_2_2_14/bin/emcsh tkemc.tcl -- -ini
ray.ini".

4. In the C++ code for emcsh.cc, you'll see that it calls the function
emcGetArgs() just after main() runs. This function is defined in
emc/src/emcnml/emcargs.cc. It looks for things like "-ini",
"-queryhost", and "-host". In our case, it finds "-ini", looks at the
next arg, and if it's there, it sets the EMC global variable EMC_INIFILE
to that next arg. So, the effect here is that EMC_INIFILE, a C-language
global variable defined in emc/src/emcnml/emcglb.c and linked into the
emcsh binary, has been set to "ray.ini".

5. Now, main() calls Tk_Main(argc, argv, Tcl_AppInit) and passes argc,
argv, and the function Tcl_AppInit. Tk_Main() processes some of the
command line args itself, gives up when it sees the "--" separator, and
calls Tcl_AppInit(). The "--" separator is needed since otherwise
Tk_Main() would see "-ini ray.ini", which is not a valid argument to
Tcl/Tk proper, and complain. Tcl_AppInit() then does this:

// set app-specific global variables
Tcl_SetVar(interp, "EMC_INIFILE", EMC_INIFILE, TCL_GLOBAL_ONLY);

This sets a global variable accessible to Tcl/Tk scripts, "EMC_INIFILE",
to the C-language global variable EMC_INIFILE. Otherwise it would be
inaccessible. There are a bunch of other C-language globals (the rest of
them in emc/src/emcnml/emcglb.c, like EMC_TASK_CYCLE_TIME, and whatever
else in linked into the emcsh binary) that aren't accessible to your
Tcl/Tk code unless they're explicitly exported via Tcl_SetVar().

6. When you refer to $EMC_INIFILE in the Tcl/Tk code, it's simply
"ray.ini".

7. You can do the same thing for iosh.cc, that is, just add this to
Tcl_AppInit():

// set app-specific global variables
Tcl_SetVar(interp, "EMC_INIFILE", EMC_INIFILE, TCL_GLOBAL_ONLY);

Since iosh is linked with libemc.a, it gets the global EMC_INIFILE and
all the rest, so it can export them to its scripts.

Note that most of the EMC globals are set by .ini file variables, so
they don't need to be exported like EMC_INIFILE since they can be
obtained via the "emc_ini <variable> <section>" syntax in the script.
EMC_INIFILE was the exception. Like the chicken and egg, you can't get
this from "emc_ini" since not only is it not an entry in the .ini file
(like [EMC] NMLFILE), even if it were, you'd need to know it to find out
which .ini file contains its definition.

--Fred