For Programmers: Free Programming Magazines  


Home > Archive > Tcl > November 2006 > how to universally source files









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author how to universally source files
comp.lang.tcl

2006-11-27, 4:10 am

[TCL]
if {[string length [info procs {IS_LIST}]] == 0} then source
../cgi_globals.tcl
[/TCL]

I want to write this in such a way so that I can test on both Windows
and UNIX. How do I do that; it gives me "./cgl_globals.tcl: No such
file or directory" error in Windows but works in UNIX, but if I do
this:

if {[string length [info procs {IS_LIST}]] == 0} then source [file
join /cgi_globals.tcl]

Then I get the following error in both:

"/cgi_globals.tcl: No such file or directory"

So how do I write this to work in both UNIX and Windows? The file
"cgi_globals.tcl" exists in the same directory as the script using this
line.

Thanks
Phil

Aric Bills

2006-11-27, 4:10 am

Your working directory is not necessarily the directory from which your
script was sourced; by default, it will be the directory where your Tcl
binary lives.

The command [info script] will provide the filename of the current
script if it's executed during the source operation. That means that
you have to put it either outside of a proc, or inside of a proc that
gets called by some code that lives outside of a proc. Probably the
easiest thing to do is to put something like this near the beginning of
your script:

set script_dir [file dirname [info script]]

This creates a global variable. Then, when you need it:

source [file join $::script_dir cgi_globals.tcl]

suchenwi

2006-11-27, 4:10 am

The directory of the current script can be retrieved with [info script]
while it's being sourced (not later) So you could write:

if {[info procs IS_LIST] eq ""} {source [info
script]/../cgi_globals.tcl}

Note however where braces are needed, and where not.

comp.lang.tcl schrieb:

> [TCL]
> if {[string length [info procs {IS_LIST}]] == 0} then source
> ./cgi_globals.tcl
> [/TCL]
>
> I want to write this in such a way so that I can test on both Windows
> and UNIX. How do I do that; it gives me "./cgl_globals.tcl: No such
> file or directory" error in Windows but works in UNIX, but if I do
> this:
>
> if {[string length [info procs {IS_LIST}]] == 0} then source [file
> join /cgi_globals.tcl]
>
> Then I get the following error in both:
>
> "/cgi_globals.tcl: No such file or directory"
>
> So how do I write this to work in both UNIX and Windows? The file
> "cgi_globals.tcl" exists in the same directory as the script using this
> line.
>
> Thanks
> Phil


comp.lang.tcl

2006-11-27, 8:03 am


suchenwi wrote:
> The directory of the current script can be retrieved with [info script]
> while it's being sourced (not later) So you could write:
>
> if {[info procs IS_LIST] eq ""} {source [info
> script]/../cgi_globals.tcl}
>
> Note however where braces are needed, and where not.


Sorry I tried what you suggested and I kept getting syntax errors until
I tried:

if {[string length [info procs {IS_LIST}]] == 0} { source [info
script]/../cgi_globals.tcl }

But that produced the following error:

couldn't read file "/../tcl_string_tools.tcl": no such file or
directory

So it appears [info script] is null!

Phil

[color=darkred]
>
> comp.lang.tcl schrieb:
>

comp.lang.tcl

2006-11-27, 8:03 am


Aric Bills wrote:
> Your working directory is not necessarily the directory from which your
> script was sourced; by default, it will be the directory where your Tcl
> binary lives.
>
> The command [info script] will provide the filename of the current
> script if it's executed during the source operation. That means that
> you have to put it either outside of a proc, or inside of a proc that
> gets called by some code that lives outside of a proc. Probably the


Sorry but that's not the case here. Proc CALCULATE_XML_EXPDATE in
xml_procs.tcl will be calling cgi_globals.tcl, a TCL script in the same
directory as xml_procs.tcl, and will also call tcl_string_tools.tcl,
another TCL script in the same directory as xml_procs.tcl.

Sorry, but the procs are all calling each other and a global variable
library, all in the same directory.

I tried using [info script] in that setting and [info script] turned
out null

Phil


> easiest thing to do is to put something like this near the beginning of
> your script:
>
> set script_dir [file dirname [info script]]
>
> This creates a global variable. Then, when you need it:
>
> source [file join $::script_dir cgi_globals.tcl]


Uwe Klein

2006-11-27, 8:03 am

comp.lang.tcl wrote:
> suchenwi wrote:
>
>
>
> Sorry I tried what you suggested and I kept getting syntax errors until
> I tried:
>
> if {[string length [info procs {IS_LIST}]] == 0} { source [info
> script]/../cgi_globals.tcl }
>
> But that produced the following error:
>
> couldn't read file "/../tcl_string_tools.tcl": no such file or
> directory
>
> So it appears [info script] is null!


sure, you are typing at the tclsh prompt?
and you are using way too much "/".
take a cortical pause.

however and beware of wrapping:
# this may be empty:
set script [ info script ] ; puts "script:\"$script\""

# get the path element
set path [ file dirname $script ] , puts "path:\"$path\"

# your scripts name was :
set myscript myscript.tcl

# build a proper filename according to the platform rules on names:
set myscriptfullpathandname [ file join $path $myscript ] ; put full:\"$myscriptfullpathandname\""

source $myscriptfullpathandname

uwe
Aric Bills

2006-11-27, 8:03 am

[info script] only works while the script is running through the source
command. Procs don't generally get evaluated during that process, but
global code does. So it follows that you must call [info script] in
the global scope of your script rather than from inside a proc*.

The following script illustrates effective use of [info script]:

# begin script

set script_dir [file dirname [info script]]

proc script_dir_contents {} {
variable script_dir
return [glob [file join $script_dir *]]
}

# end script

In this script, the global variable $script_dir gets populated when the
script is sourced. At some point after the script is sourced, the user
can call [script_dir_contents], which will work correctly (as long as
the global variable hasn't been tampered with).

Hope that clarifies things.

Aric

* Actually you can call [info script] from within a proc, but only if
that proc is only called during the source operation.

Bryan Oakley

2006-11-27, 8:03 am

Uwe Klein wrote:
> comp.lang.tcl wrote:
>
>
> sure, you are typing at the tclsh prompt?


No, he is running from within a web server. It could be that there is no
notion of "script" in his situation since he's working with tcl embedded
within a web page.

My guess is, his web server provides an environment variable and/or proc
that returns the path to a directory where scripts should reside.
suchenwi

2006-11-27, 8:03 am

Like I wrote, [info script] has a non-null content only during source
time. If you call it in a proc that is called later, it will return "".
But usually, if script a.tcl depends on b.tcl (in the same directory),
it makes sense to include the following line in a.tcl, outside a proc,
i.e. for immediate execution:
source [info script]/../b.tcl

Using [file dirname] and [file join] was recommended since Tcl 7.6 or
8.0. But "/" as path separator works fine in Windows and Unix/Linux/Mac
OS X; the only exception was old Mac (9 and before) where "/" was a
legal character in directory or file names. When you don't need your
script to run on old Mac, the simpler /../ method is fully sufficient.

Neil Madden

2006-11-27, 8:03 am

Bryan Oakley wrote:
> Uwe Klein wrote:

The error messages does not match the code posted -- a different file is
being sourced. Are you sure that [info script] is null, or is there in
fact a separate bug inside cgi_globals.tcl itself?
[color=darkred]
>
> No, he is running from within a web server. It could be that there is no
> notion of "script" in his situation since he's working with tcl embedded
> within a web page.
>
> My guess is, his web server provides an environment variable and/or proc
> that returns the path to a directory where scripts should reside.


If he's working within a CGI environment, then he likely wants:

set script_dir [file dirname $::env(SCRIPT_FILENAME)]
if {[llength [info procs IS_LIST]] == 0} {
source [file join $script_dir .. cgi_globals.tcl]
}

-- Neil


Bryan Oakley

2006-11-27, 7:05 pm

Neil Madden wrote:
> Bryan Oakley wrote:
>
> If he's working within a CGI environment, then he likely wants:
>
> set script_dir [file dirname $::env(SCRIPT_FILENAME)]
> if {[llength [info procs IS_LIST]] == 0} {
> source [file join $script_dir .. cgi_globals.tcl]
> }
>


I don't think he's CGI either. It's either a version of Vignette's
product that still usesTcl, or it's some other web server. Some of his
examples have been bracketed with [TCL] ... [/TCL].
comp.lang.tcl

2006-11-27, 7:05 pm


suchenwi wrote:
> Like I wrote, [info script] has a non-null content only during source
> time. If you call it in a proc that is called later, it will return "".
> But usually, if script a.tcl depends on b.tcl (in the same directory),
> it makes sense to include the following line in a.tcl, outside a proc,
> i.e. for immediate execution:
> source [info script]/../b.tcl
>
> Using [file dirname] and [file join] was recommended since Tcl 7.6 or
> 8.0. But "/" as path separator works fine in Windows and Unix/Linux/Mac
> OS X; the only exception was old Mac (9 and before) where "/" was a
> legal character in directory or file names. When you don't need your
> script to run on old Mac, the simpler /../ method is fully sufficient.


Sorry I tried this too, to no avail

source [file join [file dirname [info script]] tcl_string_tools.tcl]

returned:

"./tcl_string_tools.tcl: No such file or directory"

AND I tried

source [info script]/../tcl_string_tools.tcl

returned:

"/../tcl_string_tools.tcl: No such file or directory"

In both cases [info script] was null

Phil

comp.lang.tcl

2006-11-27, 7:05 pm


Bryan Oakley wrote:
> Uwe Klein wrote:
>
> No, he is running from within a web server. It could be that there is no
> notion of "script" in his situation since he's working with tcl embedded
> within a web page.



No sorry but in this case you're both wrong, and both right. On the
remote UNIX (HP-UX) platform it is running as TCL CGI within /cgi-bin;
on my Windows box at home I simply use Wish and open up a console via
Wish to test my TCL scripts.

The only way I could get it to work is to manually source in each TCL
script so far, I can never get [info script] to populate, making my
testing almost impossible.

I have no way of ever knowing that I am sourcing correctly
cross-platform.

Phil


>
> My guess is, his web server provides an environment variable and/or proc
> that returns the path to a directory where scripts should reside.


Bryan Oakley

2006-11-27, 7:05 pm

comp.lang.tcl wrote:
> Bryan Oakley wrote:
>
>
> No sorry but in this case you're both wrong, and both right. On the
> remote UNIX (HP-UX) platform it is running as TCL CGI within /cgi-bin;
> on my Windows box at home I simply use Wish and open up a console via
> Wish to test my TCL scripts.
>
> The only way I could get it to work is to manually source in each TCL
> script so far, I can never get [info script] to populate, making my
> testing almost impossible.


If you are running interactively, of course [info script] will return
null. After all, you aren't running a script.

If this is the case, the solution is simple. Simply cd to where your
scripts are, then "source cgi_globals.tcl" will work. Likewise in your
CGI environment, do a cd to where the scripts are and everything will
work. If you put your scripts in the working directory of your CGI
script you won't have to cd anywhere.

> I have no way of ever knowing that I am sourcing correctly
> cross-platform.


If you are doing "source /path/to/some/file" you are "sourcing correctly
cross-platform". There are no issues with cross-platform use of source.

I think you are misunderstanding the problem. This isn't really a "cross
platform" issue or a "source" issue. The problem is, you don't know
where to find your scripts, and you are placing your scripts in
different locations on different machines. Since we can't guess where
you put your scripts, we're having a hard time helping you.

Another solution, if you don't want to change to the proper directory,
is to create a proc that returns the fully qualified path to a file. You
can then put logic in that script to do whatever cross-platform thing
you need to do.

For example:

proc findTheFile {filename} {
global runningInCGI
if {![info exists runningInCGI] || $runningInCGI} {
return [file join [pwd] $filename]
} else {
return [file join /my/files/are/here $filename]
}
}

The only trick, then, is to figure out how to define $runningInCGI. By
default, if you don't set it the code will assume you are running CGI.
In your interactive session you can simply do "set runningInCGI 0".
There are probably a dozen different ways you could initialize
runningInCGI.

Once you implement the above, you can then use source like this:

source [findTheFile cgi_globals.tcl]

comp.lang.tcl

2006-11-27, 7:05 pm


Bryan Oakley wrote:
> comp.lang.tcl wrote:
>
> If you are running interactively, of course [info script] will return
> null. After all, you aren't running a script.
>
> If this is the case, the solution is simple. Simply cd to where your
> scripts are, then "source cgi_globals.tcl" will work. Likewise in your
> CGI environment, do a cd to where the scripts are and everything will
> work. If you put your scripts in the working directory of your CGI
> script you won't have to cd anywhere.
>
>
> If you are doing "source /path/to/some/file" you are "sourcing correctly
> cross-platform". There are no issues with cross-platform use of source.
>
> I think you are misunderstanding the problem. This isn't really a "cross
> platform" issue or a "source" issue. The problem is, you don't know
> where to find your scripts, and you are placing your scripts in
> different locations on different machines. Since we can't guess where
> you put your scripts, we're having a hard time helping you.


No I'm not putting the files in different locations; they are in the
exact same locations on different machines:

Windows:

C:\Program Files\live_sites_files_temp\cgi-bin

UNIX

/home/ppowell/web/cgi-bin

The problem seems to be that I use Wish to test my TCL scripts and I am
not calling them as you guys would, using a web server along with
optional application server to do the work to define [info script]; I
don't have the ability to do that on my machine as of yet (I used to
have apache on there to run locally, but I cannot have a web server on
my machine because here in Virginia it's illegal to be running a web
server on your machine if you are also using a residential cable
provider. Wacked.); thus, I am stuck with having to use some sort of
utility like Wish which apparently doesn't interpret [info script]
since no script is actually running, thus, again, I can't verify that
my code is universally correct (other than you guys telling me it is),
hence, my original rant.


>
> Another solution, if you don't want to change to the proper directory,
> is to create a proc that returns the fully qualified path to a file. You
> can then put logic in that script to do whatever cross-platform thing
> you need to do.
>
> For example:
>
> proc findTheFile {filename} {
> global runningInCGI
> if {![info exists runningInCGI] || $runningInCGI} {
> return [file join [pwd] $filename]
> } else {
> return [file join /my/files/are/here $filename]
> }
> }
>
> The only trick, then, is to figure out how to define $runningInCGI. By
> default, if you don't set it the code will assume you are running CGI.
> In your interactive session you can simply do "set runningInCGI 0".
> There are probably a dozen different ways you could initialize
> runningInCGI.
>
> Once you implement the above, you can then use source like this:
>
> source [findTheFile cgi_globals.tcl]


Actually, that's a great proc, but it would be pointless to implement,
because I would have to **source** that as well, considering that my
TCL CGI scripts pull up various *.tcl proc library TCL scripts (like
"xml_procs.tcl", "url_procs.tcl", "tcl_string_tools.tcl", etc.)
according to need, thus, this proc may or may not be available, and
even were it to be available, it would only be found in one of the TCL
procs which would have to be sourced in were it to be needed by, well,
another TCL proc.

Makes sense?

Bryan Oakley

2006-11-27, 7:05 pm

comp.lang.tcl wrote:
> Bryan Oakley wrote:
>
> No I'm not putting the files in different locations; they are in the
> exact same locations on different machines:
>
> Windows:
>
> C:\Program Files\live_sites_files_temp\cgi-bin
>
> UNIX
>
> /home/ppowell/web/cgi-bin
>


<rubs eyes>

We must have different definitions for the word "exact". They aren't
even close! One is in a subdirectory named "cgi-bin" in a subdirectory
named "web" of your home directory. The other is in a subdirectory named
"cgi-bin" in a temporary (?) folder in the system folder named
"C:/Program Files".

The solution, though, is likely quite simple. Assuming you are starting
wish or tclsh from a command line, on your windows box, *before starting
wish* do the following:

cd "c:/Program Files/live_sites_files_temp/cgi-bin"

If instead you are starting wish by double-clicking on an icon,
right-click on the icon, select "properties" from the pull-down menu,
then change the "start in:" property to be "c:\program
files\live_sites_files_temp\cgi-bin"
Darren New

2006-11-27, 7:05 pm

suchenwi wrote:
> source [info script]/../b.tcl


Since [info script] doesn't return a directory, I don't think this will
actually work as written, will it? I mean, /a/b/c.txt/../d.txt isn't a
valid path on Unix *or* Windows.

--
Darren New / San Diego, CA, USA (PST)
Scruffitarianism - Where T-shirt, jeans,
and a three-day beard are "Sunday Best."
comp.lang.tcl

2006-11-27, 7:05 pm


Bryan Oakley wrote:
> comp.lang.tcl wrote:
>
> <rubs eyes>
>
> We must have different definitions for the word "exact". They aren't
> even close! One is in a subdirectory named "cgi-bin" in a subdirectory
> named "web" of your home directory. The other is in a subdirectory named
> "cgi-bin" in a temporary (?) folder in the system folder named
> "C:/Program Files".


You're right, we do. On my Windows box the scripts are in a folder
called "cgi-bin"; on the remote UNIX box the scripts are in a folder
called "cgi-bin". The paths are different, of course, but the folder
name is identical and thus the file placements are identically found in
the same identically-named folder called "cgi-bin"

> The solution, though, is likely quite simple. Assuming you are starting
> wish or tclsh from a command line, on your windows box, *before starting
> wish* do the following:
>
> cd "c:/Program Files/live_sites_files_temp/cgi-bin"
>
> If instead you are starting wish by double-clicking on an icon,
> right-click on the icon, select "properties" from the pull-down menu,
> then change the "start in:" property to be "c:\program
> files\live_sites_files_temp\cgi-bin"


It's the latter but I'll remember the property trick, thanx!

Darren New

2006-11-27, 7:05 pm

comp.lang.tcl wrote:
> It's the latter but I'll remember the property trick, thanx!


The basic problem is that you're using relative file names, and in one
case your current working directory is correct and in the other case it
isn't correct.

That's what you need to fix, by either using full path names or by
cd'ing to the right directory first.

--
Darren New / San Diego, CA, USA (PST)
Scruffitarianism - Where T-shirt, jeans,
and a three-day beard are "Sunday Best."
Cameron Laird

2006-11-27, 7:05 pm

In article <1164644514.033404.29220@n67g2000cwd.googlegroups.com>,
comp.lang.tcl <phillip.s.powell@gmail.com> wrote:
Bryan Oakley

2006-11-27, 10:02 pm

Cameron Laird wrote:
>
> I'm quite curious about the illegality of Web service
> in Virginia; while it's been a year since I was there,
> I certainly ran Web servers in cable-equipped buildings,
> and was planning to do so again.


My guess is, his broadband terms of service prohibit "running a web
server", the spirit of which is to not run it on an open port and chew
up a bunch of bandwidth. I can't imagine a scenario where it would be
illegal to run one on a port only open to the local machine (though,
this wouldn't be the first time I was surprised by the practices of a
cable monopoly).

I would harbor a guess that it's perfectly safe and legal, and possibly
wise, for Phil to try and run the same web server on his machine locally
as he is running elsewhere. He seems quite befuddled by the differences
between running a script via wish and via a web server.
comp.lang.tcl

2006-11-27, 10:02 pm


Bryan Oakley wrote:
> Cameron Laird wrote:
>
> My guess is, his broadband terms of service prohibit "running a web
> server", the spirit of which is to not run it on an open port and chew
> up a bunch of bandwidth. I can't imagine a scenario where it would be
> illegal to run one on a port only open to the local machine (though,
> this wouldn't be the first time I was surprised by the practices of a
> cable monopoly).
>


Yep we have Cox here as our sole cable provider in our area of
Virginia.

Per these links

http://episteme.arstechnica.com/eve...36/m/5540962155

and

http://support.cox.com/sdccommon/as...1c-8cd5579e132a

Port 80 is blocked (I used to have apache on my machine and pointed it
to port 8080, until that got blocked and then to 8081, until my machine
caught some nasty viruses and I had to uninstall apache altogether.

Basically you could, in theory, use a different port, but Cox makes it
clear that you're not supposed to and will make sure, in the long run,
that you don't (again, port 8080 was blocked, so I figured I wasn't
going to have much love trying any other port until I got caught too
many times, and where I live now I do not own the Cox cable Internet
account, so I have no say in what I can and cannot do even moreso now)

> I would harbor a guess that it's perfectly safe and legal, and possibly
> wise, for Phil to try and run the same web server on his machine locally
> as he is running elsewhere. He seems quite befuddled by the differences
> between running a script via wish and via a web server.


I would think the difference is that running a script via Wish is to do
TCL-based evaluation on a TCL script whereas running a script via web
server would infer that there is some means of TCL interpretation via
applications that are called by the web server in order to process the
information and spawn an HTML-based browser-packaged return text for
client-based browser processing.

Phil

Bryan Oakley

2006-11-27, 10:02 pm

comp.lang.tcl wrote:
> Bryan Oakley wrote:
>
> Yep we have Cox here as our sole cable provider in our area of
> Virginia.
>
> Per these links
>
> http://episteme.arstechnica.com/eve...36/m/5540962155
>
> and
>
> http://support.cox.com/sdccommon/as...1c-8cd5579e132a
>
> Port 80 is blocked (I used to have apache on my machine and pointed it
> to port 8080, until that got blocked and then to 8081, until my machine
> caught some nasty viruses and I had to uninstall apache altogether.


The port blocking only affects incoming and outgoing connections. If the
web server and the browser are on the same machine (or even the same
subnet) cox can block all the ports they want and you'll be fine.

I used to have cox and had at any one time two or three web servers
running on my lan. My wireless router had one, my ipcop box had one,
sometimes my mac or windows box would have one depending on what I was
doing. Whatever cox did had no effect on my own internal lan.

Of course, do whatever makes you feel comfortable.

comp.lang.tcl

2006-11-27, 10:02 pm


Bryan Oakley wrote:
> comp.lang.tcl wrote:
>
> The port blocking only affects incoming and outgoing connections. If the
> web server and the browser are on the same machine (or even the same
> subnet) cox can block all the ports they want and you'll be fine.
>
> I used to have cox and had at any one time two or three web servers
> running on my lan. My wireless router had one, my ipcop box had one,
> sometimes my mac or windows box would have one depending on what I was
> doing. Whatever cox did had no effect on my own internal lan.
>
> Of course, do whatever makes you feel comfortable.


This is true that if I plan to use my machine as a development server,
any blocking by Cox is rather moot, considering that I have no plans
for outgoing streaming anyway. I'll think about it though.

Thanx for the suggestion though regarding Wish, I'll keep that in mind
in the future

Phil

Cameron Laird

2006-11-27, 10:02 pm

In article <1164657676.376673.139480@h54g2000cwb.googlegroups.com>,
comp.lang.tcl <phillip.s.powell@gmail.com> wrote:
suchenwi

2006-11-28, 8:04 am


Darren New schrieb:

> Michael A. Cleverly wrote:
>
> Funky. I'm not sure that is a good idea. :-)


I think it is - consistent simplicity :^) $foo/.. being the directory
of $foo, no matter whether it's a directory or a file...
Consider also VFS paths where files can be virtual directories - "to
Tcl".

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com