[ Tech stuff | NT | Perl on NT ]

#### In which it is revealed that IIS appears to have a rather broken idea of what the current working director (cwd) actually is

Note that this problem has gone away with IIS4. Please don't take that as an endorsement of IIS4 - Rich

When running Perl applications under IIS, I found that they do not seem to know what the CWD (Current Working Directory) is, and appear to think that it is c:\Perl, or wherever you have Perl installed. After digging a while, I found that it is the web server's responsibility to set this environment variable, and Perl reads it from the environment. Thus, we can safely say that it is Microsoft's fault.

In looking for a lookaround, the best thing that I came up with was, of course, installing Apache. But, failing that, you can add the following code to the top of your Perl CGI programs:

BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_}

Of course, when I posted that code to a mailing list, people found that it worked, but was entirely illegible, and they really wanted to know what it did. Here's the complete text from a note that I posted to the HWG-Servers mailing list:

I wrote the following ghastly code ...

> > BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_}

> > ($here=$0)=~s![\\/][^\\/]+$!!; And Steve very reasonably asked ... > ...I was wondering if you would mind taking the time to > decompose these two little gems for me. (Regex's are definitely the > most powerful and yet confusing programming constructs I've run across, > with the possible exception of APL.) OK, first ... BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_} BEGIN{} is a piece of code that will be executed before anything else in the script. In general, Perl executes stuff in the order that it appears in the code - being very imprecise there. There are some exceptions to this, like BEGIN blocks and "use" statements, and some other stuff. BEGIN ensures that the usual ordering is ignored and this statement gets done before other stuff. This is important in this case, because any "use" statements are likely to fail if this code is not executed first, as you will see in a minute. ($_ = $0) That little bit there takes the value of$0 and puts it
in the variable $_$0 is the name of the script that is
currently running.  More accurately, it is the first
agrument that was presented to the perl interpreter,
which is always the name of the script, in the CGI environment.

$_ is the "default" variable, which is a pretty powerful thing all by itself, but is probably a topic for another time. I stuck it in another variable, since modifying$0 can have some wierd results, and, potentially, you
may actually want to know what $0 was, so I really don't want to modify it. OK, now the ugly part. ($_=$0)=~s![\\/][^\\/]+$!!

You already know what ($_=$0) means.

=~ means, simply put, perform the following regular expression
on.  OK, so it means more than that, and terms like "bind to"
are used, but take that's what it really means.

Now, the s/// operator is pretty cool (this may seem like a side
track - hang on).  Syntax like s/foo/bar/ replaces the sub-string
"foo" with the sub-string "bar" in a string.  Occasionally,
however, your s/// statement might contain references to the
character "/", as in our case.  When this happens, you have to
"escape" the /, so that the s/// operator does not get confused
between the /'s that occur in the operator, and the ones that
are actually part of your string.  (Escaping involves putting
a \ in front of the offending character.)  Another convenient
way around this is that you can use other characters instead of
the /, such as !, so that the s/// operator becomes the s!!!
operator.  This is what I have done in my code.

In my s/// operator, we have the follwing:

s![\\/][^\\/]+$!! Think of it in two parts - the "search" part, and the "replace" part. Consult the s/foo/bar/ example above for a more concrete example. In this example, the "search" part is [\\/][^//\]+$
and the replace part is "" - that is, it is empty.  Let's do the
easy part first.  If we match the "search" part (whatever it ends
up meaning) we'll replace it with "" (nothing).  That is, we'll
just delete that part.  That's not too bad.

OK, now the "search" part, one piece at a time.

[\\/][^//\]+$[] is a character class, and that means that I want to match any of the characters that appear in there. In my character class are two characters. \ and / Remember what I said about escaping characters? Well, every time you have a \ character, you have to escape it, or Perl thinky that you are using it to escape something else. So, [\\/] means I want to match one character that is either \ or /. The second character class is [^\\/]. The ^ means not, and I am trying to match a character that is NOT \ or /. The + means more than one. The$ means "occurring at the end of the string.

OK, so, to translate that into something that makes more sense,
I am starting with the name of the script that is running, which
is something like

c:\foo\bar\baz\script.pl

And I am matching everything at the END that starts with a \ (or
a /, for systems that use that slash istead of the other one) followed
by one or more non-slash characters, and removing it.

In this case, that would leave is with  c:\foo\bar\baz  , which is
the "current directory", as desired.

Note that this will also work with systems that use the / slash,
since the regular expression does not care which slash I am using.

Finally, "push @INC, $_" takes that variable that I just created, and stuffs it onto @INC, which is the array containing Perl's search path. If, after this point, I try to "use" or "require" a file, it is going to look in the currentl directory. Actually, on looking back, it makes more sense to unshift$INC, $_ since that will make it look in the current directory _first_ rather than last. But then, the line is 3 characters longer! The second statement above, upon careful examination, is the same line of code, except that I put the value into the variable$here, and just keep it around for reference.

Hopefully, that was reasonably clear.  Regular Expressions are
the most powerful thing that is in Perl.  It allows you to do
a page and a half of explanation in one line.

If you really want to know more about this, you need to get
Mastering Regular Expressions from O'Reilly & Assoc, by
Jeff Friedl   Wonderful book.

--
##################################################
#  Rich Bowen                                    #
#  Web Services Engineer - DataBeam Corporation  #
#  rbowen@databeam.com                           #
##################################################