Dear Rony,

Thank you for your very detailed post. You will have to pardon the
belatedness of my reply: I wanted to do some research and perform some
tests, to be able to reply to your mail as extensively as it deserves.

I see that you have attempted to tackle the problem by comparing the
behaviour of the command line processors under Windows and under the
Unices. I'm not completely sure this is a good starting point. For some
aspects of the problem, accepting that this is the right comparison will
amount, in some senses that I'll be slowly detailing below, to begging the
question.

In particular, I'm not certain that we can so readily compare Rexx programs
and the behaviour of *executables*. Rexx programs *are*, of course,
executables. But, at the same time, Rexx programs are also *program
source *(this
is of course also true of all interpreted languages). Therefore, although
we can probably learn and profitably borrow concepts and ideas from the
executable program paradigm, we will also likely be able to learn and
profitably borrow from the program source paradigm. The most likely is that
when we'll have ended our investigation, we will come with a solution which
takes some elements from (say) the behaviour of the command line
interpreters, and some other elements from the behaviour of certain static
language compilers, like gcc, or cl, and still, maybe, some other elements
from the behaviour of more dynamic, i.e., interpreted, languages.

Let's recapitulate. Please bear with me for a while. I think we'll gain a
lot if we take an ample perspective and allow ourselves a high degree of
abstraction. We'll descend into the necessary details later.

*Definitions*. A *Search Order Algorithm* (SOA) is a procedure with the
following arguments.

   - A *filename*. This can be specified as name.ext, or it can also
   include a (possibly relative) path specification (e.g, some/path/name.ext
   ).

   - An ordered collection of ordered collections of (possibly only
   partially specified) *directories* (or *paths*). One or more of these
   directories can be *distinguished*, and constitute a fallback choice
   when a *directory exception* is applied (see below).

   A *super-path* is created by an order-preserving union of all the
   ordered collections.

   - Another ordered collection of ordered collections of (possibly
empty) *file
   extensions*.

   A *super-list of extensions* is created by an order-preserving union of
   all the ordered collections.

The *goal *of the procedure is to locate and return the first file that
matches the *filename*, resides in one of the *directories* and has one of
the specified *extensions*.

The search algorithm can be *extension-first* or *directory-first*. An
*extension-first* algorithm searches for a file in all directories using
the first of the extensions supplied; if not found, the search is initiated
again, in all directories, with the second extension supplied, and so on. A
*directory-first* algorithm first searches all extensions in the first
supplied directory; if not found, it searches all extensions in the second
supplied directory, and so on.

In pseudo-code,

Do dir Over directories *-- Directory-first search algorithm*
  Do ext Over extensions
     file = Check(dir, filename, ext)
     If file \== "" Then Return file
  End
End


and

Do ext Over extensions *-- Extension-first search algorithm*
  Do dir Over directories
     file = Check(dir, filename, ext)
     If file \== "" Then Return file
  End
End


Every SOA algorithm can specify a procedure for *directory exceptions*, and
another procedure for *extension exceptions*. The *directory exceptions*
procedure can indicate that, instead of searching in all directories, the
search will be limited to a designated subset of these same directories. The
*extension exception* procedure can limit the search to a designated subset
of the extensions, or require that the search is performed using no
extension at all.

A Search Order Algorithm is completely determined by its parameters, by the
exception subalgorithms, if any, and by the fact that the search has to be
performed extension- or directory-first.

[*End of definition*]

*Example 1. ooRexx*

The ooRexx SOA is an *extension-first* SOA. The super-path is conceptually
created as follows (assume the union method is order preserving)
[rexxref 7.2.1.1]:

Parse source . . myself
mydir = Left(myself,Pos(.File~separator,myself)-1)
directories = (mydir, ".")~ -     -- "same" directory and current directory
  union( appDefinedPath )~ -      -- The EXTERNAL_CALL_PATH parameter
  union( Value("REXX_PATH",,"ENVIRONMENT")~makeArray(.File~pathSeparator)
)~ -
  union( Value("PATH",,"ENVIRONMENT")~makeArray(.File~pathSeparator) ) -


The super-list of extensions is conceptually created as follows:

If REQUIRES_CALL Then extensions = .Array~of(".cls")
Else extensions = .Array~new
Parse source . . myself
myname = Substr(myself,Pos(.File~separator,myself)+1)
Parse Value myname~reverse With txe"."eman
If eman \== "", txe \== "" Then extensions = extensions~union(
"."txe~reverse )
extensions = extensions~union( appDefinedExtensions )  -- The
EXTERNAL_CALL_EXTENSIONS
parameter
extensions = extensions~union( ".REX" )
If \Windows Then extensions = extensions~union( ".rex" )
extensions = extensions~union( "" )


The directory exception algorithm currently returns .true when

filename[1] == "~" | filename[1] == "/" | filename[1,2] = "./" |
filename[1,3] == "../"


for the Unices, and

filename[1] == "\" | filename[2] == ":" | filename[1,2] = ".\" |
filename[1,3] == "..\"


for Windows, and then the search is limited to the distinguished directory,
".", i.e., to the current directory. The extension exception algorithm
returns .true when the filename part of the file specification has a dot (
".") in it.

Please note that the directory exception algorithm is *undocumented*, while
the extension exception algorithm is *documented *("If the routine name
contains at least
one period, then this routine is extension qualified" - rexxref 7.2.1.1).

*Note: a bug in the Windows version of ooRexx. *The current implementation
of the Windows extension exception algorithm, the boolean
SysFileSystem::hasExtension function, incorrectly searches for "/" (instead
of "\") as the path separator, so that the results of the function are, in
some cases, incorrect. Please note that this an error that is difficult to
trigger, since the algorithm runs backwards, examining all the characters
in the full file specification, and returns .true (i.e., "has an
extension"), if a dot is first found, and .false (i.e., "there is no file
extension") if a separator is found, or when the string is exhausted. Files
with a true extension will correctly return .true, and files with no
extension will return .false (because the string will be exhausted, not
because a path separator has been found, but who cares?)... unless one or
more of the directories in the path contain a dot, e.g., in cases like
"my.dir\file", or, of course, also "..\filename" (I've reported this bug in
SourceForge [ticket 187o <https://sourceforge.net/p/oorexx/bugs/1870/>]).

*Example 2. Regina Rexx*

The Regina Rexx SOA is a *directory-first* SOA. The super-path is
conceptually formed as follows [regina.pdf 1.4.2]:

directories = Value("REGINA_MACROS",,"ENVIRONMENT")~makeArray(
.File~pathSeparator
)
directories = directories~union( "." )
directories = directories~union( Value("PATH",,"
ENVIRONMENT")~makeArray(.File~pathSeparator) )


The super-list of extensions is built as follows (to simplify, we will
assume that REGINA_SUFFIXES is separated by commas, contains no blanks, and
that all the extensions have their leading dot):

extensions = .Array~of("")
extensions =  extensions ~union( Value("REGINA_SUFFIXES",,"
ENVIRONMENT")~makeArray(",") )
extensions =  extensions ~union( (".rexx",".rex",".cmd",".rx") )


The *directory exception* algorithm for Regina is very simple: when

filename~contains( .File~separator )


the search will be limited to the current directory. The *extension
exception* algorithm reads as follows "If a known file extension is part of
the file name only this file is searched", but I've not had the time to
find out what this actually means.

*Example 3. The concept of the "same" directory in C/C++ compilers*

The concept of the "same" directory in C is *recursive* and, in the general
case, may refer not to a single directory, but to a whole stack of
directories

"*The preprocessor searches for include files in this order: In the same
directory as the file that contains the #include statement. In the
directories of the currently opened include files, in the reverse order in
which they were opened. The search begins in the directory of the parent
include file and continues upward through the directories of any
grandparent include files [...]*" (source
<https://learn.microsoft.com/en-us/cpp/preprocessor/hash-include-directive-c-cpp?view=msvc-170>
).


*Example 4. Extension-first, or directory-first*

REXXSAA
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/external-search-order-in-rexxsaa-for-os2.md>
and OBJREXX
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/external-search-order-in-objrexx-for-os2.md>
for OS/2, and ooRexx
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/external-search-order-in-oorexx.md>
use *extension-first* SOAs. Regina Rexx
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/external-search-order-in-regina.md>
and the Windows CLI
<https://learn.microsoft.com/en-us/previous-versions//cc723564(v=technet.10)#command-search-sequence>
(CMD)
use *directory-first* SOAs.

*Excursus: same and current, CALL and ::REQUIRES*

In some contexts, the notion of the *same* directory does not make sense.
For example, in a Windows command prompt, where there is no source file to
begin with. In other contexts, it's the notion of the *current* directory
that is not applicable. For example, when one compiles a C program, the
current directory at the moment of compilation is normally irrelevant and
often completely unrelated to the compilation at hand. Although one can, of
course, force the compiler to explore the current directory (for example,
by using the "-I." compiler option) if one so desires.

The *definition* of the ::REQUIRES directive states that "The program
*programname* is called as an external routine with no arguments"
[rexxref 3.7], but this should not allow us to forget that *the ontology of
::REQUIRES and the ontology of CALL are, indeed, not quite equivalent*.

::REQUIRES speaks of *source files*, of referencing blocks of code which
constitute libraries we want to use. The natural logic for ::REQUIRES is
the logic of source files, where the *same* directory has great relevance,
while the *current* directory should, in practice, be almost always
irrelevant.

CALL, on the other hand, is a more dynamic statement. One can find cases
where it's natural to refer to the same directory, and other cases where
referring to the current directory (or to some other directory specified in
an environment variable like PATH) is more natural.

The semantics of CALL can be dynamically patched, by altering the current
directory, the environment variables, or both.

The semantics of a ::REQUIRES directive is determined and cannot be patched.

This is extremely unfortunate: since the directory exception algorithm is
undocumented, the semantics of ::REQUIRES will appear to a programmer as
(1) erratic, and (2) too dependent on an extraneous notion, like the
current directory.

*A test program*

Now we can rely on the above definitions and start to test different
implementations of Rexx (and maybe other products, like certain compilers
or interpreters), to try to deepen our understanding of the problem at
hand. I've written a version-independent test program that runs under
various interpreters and operating systems, namely:

*Operating systems:*

   - OS/2 (Arca Noae 5.0.7).
   - Windows (Windows 11 Pro).
   - Linux (Ubuntu 22.04.01 LTS).

*Interpreters:*

   - IBM REXXSAA for OS/2 ("REXXSAA 4.00 3 Feb 1999,").
   - IBM Object REXX for OS/2 ("OBJREXX 6.00 18 May 1999")
   - Regina Rexx for Windows, Linux and OS/2 ("REXX-Regina_3.9.5(MT) 5.00
   25 Jun 2022")
   - ooRexx for Windows and Linux (" REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23
   Dec 2022")

The test program, sotest.rex, uses the following directory structure:

(*Root* directory. Normally, "sotest")
   |
   +---> sotest.rex (The test initiator program. Calls
./subdir/dotdotsame/same/same.rex)
   |
   +---> *subdir* (Dummy directory, for future expansion)
           |
           +---> *dotdotsame* (The parent of the "same"or caller directorY)
           |       |
           |       +---> dotdotsame.rex (Returns "dotdotsame")
           |       |
           |       +---> *same* (The "same" or caller directory)
           |               |
           |               +---> same.rex (The program in the "same" or
           |               |               caller directory. Returns "same")
           |               +---> main.rex (The main program)
           |               |
           |               +---> *lib*
           |                       |
           |                       +---> samelib.rex (Returns "samelib")
           |
           +---> *dotdotcurr* (The parent of the current directory)
           |       |
           |       +---> dotdotcurr.rex (Returns "dotdotcurr")
           |       |
           |       +---> *curr* (The current directory)
           |               |
           |               +---> curr.rex (The program in the current
           |               |               directory. Returns "curr")
           |               +---> oorexxextensions (Extensionless. Returns
           |               |               "directory")
           |               +---> reginaextensions.rex (Returns
           |               |               "directory")
           |               +---> *lib*
           |                       |
           |                       +---> currlib.rex (Returns "currlib")
           |
           +---> *dotdotpath*
                   |
                   +---> dotdotpath.rex (Returns "dotdotpath")
                   |
                   +---> *path*
                           |
                           +---> path.rex (The program in the path
                           |               directory. Returns "path")
                           +---> oorexxextensions.rex (Returns
                           |               "extension")
                           +---> reginaextensions.rexx (Returns
                           |               "extension")
                           +---> *lib*
                                   |
                                   +---> pathlib.rex (Returns "pathlib")

The main program, sotest.rex, immediately calls main.rex, located in the
subdir/dotdotsame/same subdirectory, which then proceeds to test all kind
of CALL statements: starting with "normal" calls, and following by more
"pathological" ones. This allows us to know and tabulate the behaviour of
the different interpreters.

You can have a look at some test results here:

   - Object Rexx for OS/2
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/os2.objrexx.results.txt>
   .
   - Regina Rexx for OS/2
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/os2.regina.results.txt>
   .
   - Classic Rexx for OS/2 (REXXSAA)
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/os2.rexxsaa.results.txt>
   .
   - ooRexx for Ubuntu
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/ubuntu.oorexx.results.txt>
   .
   - Regina for Ubuntu
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/ubuntu.regina.results.txt>
   .
   - ooRexx for Windows, with the hasDirectory bug
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/windows-bug.oorexx.results.txt>
   .
   - ooRexx for Windows, without the hasDirectory bug
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/windows-nobug.oorexx.results.txt>
   .
   - Regina for Windows
   
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/windows.regina.results.txt>
   .

The results of each run of the test program are themselves a Rexx routine
that returns a stem; this facilitates enormously the comparison of results,
their aggregation and tabulation, etc. You can browse a preliminary
interpretation of the results here
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/OS2(REXXSAA,OBJREXX,Regina),Windows(ooRexx,Regina),Ubuntu(ooRexx,Regina).md>;
I've copied the main results below, and I'll comment briefly on them.

*The concept of the "same" directory*

The concept of the "same" (or caller's directory) is *exclusive to ooRexx*.
REXXSAA or OBJREXX for OS/2 don't have such a concept, and Regina doesn't,
either.

On the other hand, it's a concept which is very frequent when dealing with
compilers. The Microsoft C/C++ compiler, for example, searches, by
default and in the first place, in the same directory (source
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/include-directive-in-visual-studio.md>
).

*Comment*. *There is nothing "natural" or "Rexx-like" in the idea of a
"same" directory. Most of the predecessors of ooRexx don't even have such
an idea. My personal impression is that the concept of a "same" directory
is a very welcome addition and improvement to the external search order
algorithms in Rexx, but that the exact definition and behaviour of this
"same" directory is more nuanced and subtle than one could think at first,
and that it should be better delimited and defined. That's, after all, what
we are trying here.*

*See also*: the above discussion about the same and the current directory.

*Note: a bug in the OS/2 REXXSAA interpreter*

The definition of the external search order for the OS/2
REXXSAA interpreter states that "REXX functions in the current directory,
with the current extension" will be searched, but this doesn't seem to work
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/documents/external-search-order-in-rexxsaa-for-os2.md>.
We will refer to this behaviour of the REXXSAA interpreter as *the SAA bug*.

*The similarity of all classic Rexx interpreters*

Interestingly, all the classic Rexx, or non-object oriented, interpreters
behave identically, regardless of the operating system (i.e., OS/2, Windows
or Linux) and the interpreter variant (REXXSAA, Regina), and modulo the SAA
bug. Regina is explicit about its directory exception algorithm, as we have
seen above: only the current directory is searched when the file
specification contains a path delimiter. REXXSAA gives the same results as
Regina, so that the exception algorithm must be similar. This allows us to
group, in the results, all the non-object oriented interpreters in a single
column, for comparison.

*"Normal" calls*

In the first tests, we try calling routines located in the same, current
and path directories (0 means "fail", and 1 means "pass"). REXXSAA, Object
Rexx and Regina do not have the notion of the "same" directory; all the
other CALL tests pass.

+-----------------+-----+-----+-----+
| Call            | CLA | OBJ | OOR | CLA: CLAssic rexx interpreters, i.e.,
REXXSAA and Regina
+-----------------+-----+-----+-----+
| same.rex        |  0  |  0  |  1  | OBJ: IBM OBJect Rexx for OS/2
| curr.rex        |  1  |  1  |  1  |
| path.rex        |  1  |  1  |  1  | OOR: OORexx
+-----------------+-----+-----+-----+


*Downward-relative calls*

Regina can't handle PATH-based downward-relative calls, because of its
directory exception algorithm, and REXXSAA behaves similarly.

+-----------------+-----+-----+-----+
| Call            | CLA | OBJ | OOR |
+-----------------+-----+-----+-----+
| lib/samelib.rex |  0  |  0  |  1  |
| lib/currlib.rex |  1  |  1  |  1  |
| lib/pathlib.rex |  0  |  1  |  1  |
+-----------------+-----+-----+-----+



*Dot-relative calls*

+-----------------+-----+-----+-----+
| Call            | CLA | OBJ | OOR |
+-----------------+-----+-----+-----+
| ./samelib.rex   |  0  |  0  |  0  |
| ./currlib.rex   |  1  |  1  |  1  |
| ./pathlib.rex   |  0  |  1  |  0  |
+-----------------+-----+-----+-----+


Dot-relative call tests produce a matrix which is almost identical to the
downward-relative calls; modulo the SAA bug
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/OS2(REXXSAA%2COBJREXX%2CRegina)%2CWindows(ooRexx%2CRegina)%2CUbuntu(ooRexx%2CRegina).md#the-saa-bug>,
the "CLA" group (i.e., REXXSAA and Regina) exhibit the same behaviour (they
only search in the current directory). The only test result matrix
difference appears when the ooRexx interpreter is being tested: the ooRexx
directory exception algorithm skips "./file", and does not search the same
directory or thePATH.It's interesting to note that OBJREXX *does* search in
thePATHin this case.

*Upward-relative calls*

+-----------------+-----+-----+-----+
| Call            | CLA | OBJ | OOR |
+-----------------+-----+-----+-----+
| ../samelib.rex  |  0  |  0  |  0  |
| ../currlib.rex  |  1  |  1  |  1  |
| ../pathlib.rex  |  0  |  1  |  0  |
+-----------------+-----+-----+-----+


Dot-relative call tests produce a matrix which is almost identical to the
downward-relative calls, and completely identical to the dot-relative
calls; modulo the SAA bug
<https://github.com/RexxLA/rexx-repository/blob/master/ARB/standards/work-in-progress/search-order/tests/results/OS2(REXXSAA%2COBJREXX%2CRegina)%2CWindows(ooRexx%2CRegina)%2CUbuntu(ooRexx%2CRegina).md#the-saa-bug>,
the "CLA" group (i.e., REXXSAA and Regina) exhibit the same behaviour (they
only search in the current directory). The only test result matrix
difference appears when the ooRexx interpreter is being tested: the ooRexx
directory exception algorithm skips "../file", and does not search the same
directory or the PATH. It's interesting to note that OBJREXX *does* search
in the PATH in this case.

*Upward-relative calls, with a trick*

+------------------------+-----+-----+-----+
| Call                   | CLA | OBJ | OOR |
+------------------------+-----+-----+-----+
| lib/../../samelib.rex  |  0  |  0  |  1  |
| lib/../../currlib.rex  |  1  |  1  |  1  |
| lib/../../pathlib.rex  |  0  |  1  |  1  |
+------------------------+-----+-----+-----+


The trick (go downwards first and then upwards twice) helps ooRexx to pass
the tests, because ooRexx triggers the directory exception algorithm by
inspecting *the first characters* of the filename only, but does not help
with the "CLA" group (i.e., REXXSAA and Regina), because they search for a
path separator *in the whole filename* (confirmed for Regina and true for
REXXSAA according to reverse engineering).

*Other tests*

The other tests refer to more obscure, Windows- and OS/2-only variants of
CALL, and will not be discussed here.

Missatge de Rony G. Flatscher <rony.flatsc...@wu.ac.at> del dia dc., 8 de
febr. 2023 a les 14:08:

> Dear Josep Maria,
>
> again thank you very much for your thorough write up!
>

I'll finish my reply by interspersing some random comments.

> Having had a little bit more time and researching the Internet for
> resources that explain/document in a brief, but professional manner the
> terms and definitions that get used in this thread as this makes it better
> researchable for others (e.g. I know that Windows by default will consult
> the current directory when searching for executables, whereas in Unix
> *usually* this is not the case such that one must add the current
> directory symbolized as the dot '.' to the PATH).
>
> Here two resources which may help for this discussion:
>
>    - PATH (variable): <https://en.wikipedia.org/wiki/PATH_(variable)>
>    <https://en.wikipedia.org/wiki/PATH_(variable)>
>    - Path (computing): <https://en.wikipedia.org/wiki/Path_(computing)>
>    <https://en.wikipedia.org/wiki/Path_(computing)>
>
> When I see the same word used for two different, but related, concepts,
well... :)


> Ad resolving Rexx programs, here a few terms that get used further down:
>
>    1. srcDir: the source directory of the Rexx program that currently
>    gets run (one can get at it by extracting the path2pgm's location from
>    'parse source . . path2pgm'
>    2. currDir: the current working directory in which the Rexx program
>    executes
>
> The current directory can be changed while a program executes, and
therefore there's no such thing as a place where the program executes.


>
>    1. pathDir: the directories listed on the PATH environment variable
>
>    2. relativePath: any path that does not start with the root directory,
>    which therefore gets resolved relative to currDir
>
> It's a little more complicated than that. "D:path\file.ext", for example,
is relative, but relative to the current directory *of the D: drive*. In
Windows, each drive has its own directory. Furthermore, and in general
terms, thinking that a relative path has to be resolved relative to the
current directory amounts to begging the question. I.e., it *assumes* that
we are adopting a perspective identical to the current behaviour of the
ooRexx interpreter, instead of adopting a more general perspective, to be
able to carry on our investigation, and determine later whether the idea of
a current directory is "natural", or "convenient", or, more in general,
which place will we be asigning to this concept. As we have previously
seen, there are search order contexts where the idea of a current directory
does not apply, contexts where the "natural" meaning of a relative
directory specification is the "same", or some other directory, and so on.


>
>    1. absolutePath: any path that starts out with the root directory,
>    which therefore locates exactly the desired executable
>
> An obviousness: there is more than one root under Windows and OS/2.


>
>    1.
>    2. unqualifiedExecutable: the name of an executable without path
>    information
>    3. relativeExecutables: the name of an executable with relative path
>    information, i.e. relativePath
>    4. absoluteExecutables: the fully qualified name of any executable,
>    i.e. absolutePath
>
> Searching for executables via the operating system:
>
>    - Unix-like:
>    - unqualifiedExecutables: get searched along the pathDir (PATH) in the
>       order supplied, if not found an error gets raised
>       - relativeExecutables: the supplied information gets appended to
>       currDir (current working directory) and denotes the exact location of 
> the
>       executable, no further searches are undertaken and if not found an error
>       gets raised
>       - absoluteExecutables: denotes the exact location of the
>       executable, no further searches are undertaken and if not found an error
>       gets raised
>
>       - Windows:
>       - unqualifiedExecutables:
>       - first the current working directory gets searched for it and if
>          not found
>          - search along the pathDir (PATH) in the order supplied, if not
>          found an error gets raised
>          - relativeExecutables: the supplied information gets appended to
>       currDir (current working directory) and denotes the exact location of 
> the
>       executable, no further searches are undertaken and if not found an error
>       gets raised
>
> It's quite more complicated. Firstly, you have the case of drive-relative
filenames, i.e. D:path/file.ext, where you can have several current
directories, one for each drive. Second, a directory specified in the path
can itself be relative. The clearer example of that is ".". You can add "."
to the path under Unix, and get the same effect that under Windows, where
the presence of "." in the path is implicitly assumed. Or you can add ".."
to the path. In general terms, you can add a relative path to the PATH
variable: then this path gets first prepended to the filename, and the
result is again resolved against the current directory (double-relative
resolution).

>
>    -
>       - absoluteExecutables: denotes the exact location of the
>       executable, no further searches are undertaken and if not found an error
>       gets raised
>
> So the resolution of executables is the same on Unix and Windows except
> for Windows first searching currDir (the current working directory) in the
> case of unqualifiedExecutables.
>
The Windows world is a real nightmare. You have to add (1) several roots,
which include (1.a) different drives (A:, B:, C:, etc.), and (1.b) UNC
names, like \\server\share\path\name.ext. Each drive has a current
directory. Then you have very strange concoctions, like filenames starting
with "\\?\" (source
<https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#win32-file-namespaces>),
sometimes used to overcome the MAX_PATH limitations. Then there is still
another prefix, "\\.\", to refer to Win32 devices. And so on. As I said, a
real nightmare.


> Conclusion #1: if relativeExecutables get searched and are not found
> relative to the current working directory, then no further search takes
> place and an error gets raised! This is how the operating systems behave,
> no matter whether using a shell/terminal or system services.
>
Again, it's much more complicated. Under Windows, you have to take into
account the value of the PATHEXT environment variable *to locate an
executable*. To locate a DLL, other environment variables are used. Java
programs use CLASSPATH, not PATH. ooRexx programs use REXX_PATH, in
addition to PATH. Regina programs use REGINA_MACROS, in addition to PATH.
ooRexx, when called programmatically, can specify an EXTERNAL_CALL_PATH
that supplies an additional path. Similarly, there is
a EXTERNAL_CALL_EXTENSIONS parameter, to specify additional extensions. And
so on and on :)


>
> Conclusion #2: if non-operating system software behaves differently then
> the operating system then this is the responsibility of that software and
> needs to be documented. E.g. the observation that a compiler like gcc will
> use the paths in some environment variables in a different manner (e.g.
> using the value of the INCLUDE environment variable for locating c/cpp
> include files), does not define/determine/change how PATH should get used
> for locating unqualifiedExecutables.
>
>
> Conclusion #3: if a Rexx CALL, that causes an external search, or an
> ooRexx ::requires directive (the first time encountered will cause a CALL
> of the denoted external file) get executed then the following rules
> (should) apply:
>
>    - Rexx programs that are unqualifiedExecutables:
>    - srcDir gets searched first and if not found
>       - the operating system search for unqualifiedExecutables gets
>       carried out next and if not found an error gets raised
>       - Rexx programs that are relativeExecutables: the supplied
>    information gets appended to currDir (current working directory) and
>    denotes the exact location of the Rexx program, no further searches are
>    undertaken and if not found an error gets raised
>    - Rexx programs that are absoluteExecutables: denotes the exact
>    location of the Rexx program, no further searches are undertaken and if not
>    found an error gets raised
>
> Given these findings and conclusions it is probably a misconception of
> expecting Rexx/ooRexx to behave like gcc (when employing the INCLUDE
> environment variable directories), rather than like operating systems
> resolve PATH.
>
That is the point where I get the impression that you're begging the
question <https://en.wikipedia.org/wiki/Begging_the_question>. I've argued
above in some detail why I think that we can't adhere too quickly to the
command-line or executable paradigm. The comparison with gcc is not to say
that ooRexx should work as gcc does, but to point out that it's not
unthinkable that ooRexx worked as I mentioned.

After all, Object Rexx for OS/2 does work as I mentioned. It searches
"..\program.rex" against the current directory and against the PATH. Hey,
it even searches against the same directory, if one puts it first in the
path.

Why and how has ooRexx, which after all is an evolution of Object Rexx,
*lost* this capability? After all, losing a capability is a sad thing; it's
better and easier not to use something that is offered to you than not
being able to use it because there is a limitation.

I can't reply to this question, but we can always guess. The Unix version
of the interpreter has a routine, SysFileSystem::canonicalizeName, in whose
description we read "*Process a file name to add the current working
directory or the home directory, as needed, then remove all of the . and ..
elements*". There's no corresponding routine for Windows: all the work is
left to the SearchPath Windows API. But this API chokes on the "..\" and
".\" cases: see Erich's comment on bug ticket no. 1865
<https://sourceforge.net/p/oorexx/bugs/1865/>: "*this is a restriction of
the SearchPath Windows API. **It doesn't support searching for a filename
with a leading .\ or ..\*".

*My personal opinion* is that we should not be using this API. Not at all,
since it doesn't work as expected. As expected by Erich, as expected by you
yourself. As expected by me. As expected by anybody who reads the
documentation in detail. As expected by any user of IBM Object Rexx for
OS/2, which does not have this limitation. Hey, half of the work is already
done, one only has to clone and adapt SysFileSystem::canonicalizeName from
the Unixlike world.

But this is only my opinion. I hope that the rest of the information that I
have presented here helps to contribute to foster the debate.

Best regards,

  Josep Maria



>
> In the case of Rexx/ooRexx the documentation defines for
> unqualifiedExecutables to first search srcDir and then pathDir. (Probably
> it needs to be improved w.r.t. to the above as currently one can observe
> quite some confusion even among long-time users while discussing this
> issue.)
>
> Would that be applicable for your case as well?
> Best regards
>
> ---rony
>
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to