A long time ago

In the early 90s I was learning DOS and Unix. One thing I really liked about Unix was the concept of “symbolic links”. It meant you could install programs in their own directories and symlink the executable to somewhere in your $PATH. DOS couldn’t do that. So you ended up with horrendously long path names. And DOS had a 120 character limit. Ugh.

So I wrote a TSR, called “exelink” which kludged it. I used it for years until I gave up on DOS and became a Unix person. Even sold a copy to “PC Plus” for a cover disk.

Annoyingly I lost the code. Random searches of the internet didn’t find anything useful. Except a random search, today, found a usenet posting where I mentioned that I’d uploaded it to SIMTEL20. Huh. And that was enough to find it!

And, heh, here’s the README file…

IMPORTANT NOTE:  Needs DOS 3.0 or greater
#include <std_disclaimer.h>
All the code in this package is my own work.  No responsibility will be
taken for loss of data or damage caused by running this program.  This
program has been tested and I use it myself, so if you do come across
any problems then let me know!
The program can be freely distributed.  There are no restrictions on use.
Just keep my name on it please!
The program is "postcardware" - send me a postcard if you like :-)
A big problem with Hard discs is that they can store so much data!
This isn't as silly as it sounds; if you have four or five applications
on your disc (maybe Pascal, C, Assembler, Word Processor, Norton etc)
and wish to keep some sort of organisation do your disc then your PATH
variable gets a little large.  Until you reach the dreaded 127
character limit.  Although programs exist that enable you to get up to
255 characters in the PATH, this is a bit long and unwieldy, and can
make you computer spend too much time skipping around directories just
to find the program you want.  I had this problem and decided to find a
better solution, and EXELINK is it (well I think its better!)
What EXELINK does
NOTE: EXELINK will not work with .BAT files since the command shell
interprets them internally and doesn't call the DOS 'exec' routines.
Only routines that call 'exec' (eg .EXE and .COM files, Overlays?)
When you execute a command, MS-DOS needs to find where the file is that
you are trying to run.  It first looks in the current directory, then
in the first directory on the PATH, then the next, then the next...
until it finds what you wanted.
eg if you have your path set up as
then typing the command 'nu'  (for norton utilities) will involve
looking for
which it will eventually find.  Any files in any of these directories
which are not executable will slow down the searching...
Of course an easy way to speed up access to NU would be to put it at
the front of the PATH, at the expense of some other program!
EXELINK sets aside directory which you include on your PATH (for speed
you put it at the beginning) and this contains a set of files which
appear to DOS to be executable.  Instead of being run though, EXELINK
reads the contents of this file and gets the filename of the REAL
program from there.  Since the link directory is at the beginning of
the PATH and there are only executables it will find the link file very
In the example above, you could now have the following setup:
and searching would be
     c:\links\NU.???  <- found!  Open the file, read its contents and
Less searching is done, executables are found quicker, PATH is shorter
and less disk head movement is used.
But what is this I hear?  You can do this by creating a BATch files which
calls the real program?  Almost true, but there are a  few problems with
batch files:
 (1) There is difficulty passing an unknown number of parameters.  A batch
     file such as
     @c:\app\wp %1 %2 %3 %4 %5
     can be taken as meaning that is passes exactly five parameters, some
     of which are NULL (GEM programs can suffer from this problem)
 (2) It only works from the DOS prompt - a program such as MAKE is
     unable to use BATch files unless you specifically call COMMAND.COM
     which is slower and takes more memory.
 (3) It is an interpreted file.  DOS opens the BATch file, reads
     a line.  If it executes an external program, closes the BATch
     file, executes the command, opens the BATch file, etc.  Lots of
     disc accessing...
The only real alternative would be to write a specialised Pascal or C
program which just executed the real version with all the parameters
passed on.  This will work in all cases, but has the problem that you
need to compile a new link program for each new executable you want
linked, and even the simplest compiled program takes about 2.5k -
wasting 4k of disc space!
example in Turbo C 2.01:
main(int argc,char *argv[], char **envp)
Which would then need compiling, and even in the TINY memory model
takes over 3k!
Using EXELINK you need to create a 1 line ASCII file which you can do
with the COPY command.
How EXELINK works
EXELINK is a Terminate and Stay Resident (TSR) program.  While resident
it takes an astounding 400 bytes of memory!  The only vector it
attaches to is INT 21h and any call that is not Function 4Bh (exec) is
passed directly onto the original handler.  To cut down on resident size
it frees the environment block passes to it by DOS, and relocates itself
over the PSP, which is no longer needed once the program has gone resident.
If the call is an 'exec' then the pathname of the program to be called
is worked out.  If this program is in the EXELINK directory (by default
C:\LINKS) then the file is opened for reading and the contents of the
file (up to 127 characters) are read in.  A little processing is done
to convert this to an ASCIIZ string and then the original routine
continues with this new name.  All registers are preserved through this
except for DS:DX which point to the filenames so any options passed to
'exec' are preserved.  Also, as far as the called application is concerned,
it was run by typing the full pathname of the program, so that programs that
use the command line (eg WordPerfect) to find the directory it is running
in work properly.
EXELINK makes use of an internal DOS function:  INT 21h Function 60h -
This is only available on MS-DOS 3.0 onwards, and I am not sure if this is
a fully documented call.
EXELINK has been tested with:
     PC-DOS 3.20
     vanilla MS-DOS 3.30
     Atari PC2 specific MS-DOS 3.21
     Tri-Gem MS-DOS 3.30
     OEM MS-DOS 5.0
     4DOS v3.01, v3.02, v3.02a, v4.0, v4.01 (a good COMMAND.COM replacement)
     Windows 3.0, 3.1
     DesqView 386 v2.3, v2.4
     Various applications.
Known incompatibilities:
     MKS Tools 3.1c version of the Korn-Shell.
       I have had a lot of problems with the Korn Shell, from TSR's to
       bog-standard applications.  I am unsure as to why this shell fails
       to work with EXELINK since it seems to support INT21/AX=60h
       I have not tested with later versions of MKS tools.
     Turbo C exec() call.
       Turbo C seems to try to open the executable and read the header
       contents to determine the file type.  Of course, these files are
       ASCII and so TurboC returns "Invalid exec type" :-(
       This also affects Borland C++ 3.1 (the Run Time Library Sources
       show why Borland do this - to enable exec() to overlay better)
     Windows 3.0, 3.1.
       I think Windows also tries to open the file to determine
       if a file is a DOS or a Windows executable.  I am not sure.
       However,  EXELINK works happily inside a DOS window.
     DesqView 386.
       It appears that DesqView has its own exec() replacement, and so
       each window that you wish to use EXELINK in must have its own
       copy of EXELINK loaded.  Once this has happened, it works happily
       inside that window.
     Word Perfect for Windows 5.1
       Word Perfect seems to search the PATH to find where your windows
       system resides, so it knows where to put the INI GRP DLL files.
       If WIN.COM is in the links directory then WP4W assumes this is where
       windows lives!  Silly Word Perfect.....before installing this program
       you should modify your PATH so that it has the real windows directory
       at the front.  This is only needed to work around the install problem,
       and is not needed at runtime.
    Most problems appear to boil down to the program trying to open the
    executable as a file to determine its type.  In Windows this is only
    a problem at the menu level (normally!) and creating an icon
    pointing to the real program is no major problem.  With DesqView
    creating an "Open Program" item pointing to the real program solves the
    problem as well, with a special "DOS" shell running exelink when that is
    I had debated with the idea of extending exelink so that the open() call
    is also linked, but decided against this for various reasons, mainly
    that I would also need to trap filesize() and other related calls to
    maintain consistency, which would make exelink too large and unwieldly.
    Finally there would also need to be a way to deactivate exelink so that
    the link file could be editted!
What if the link points to a non-existent file?
   With 4DOS if you have an link pointing to a non-existent file then 4DOS
   will give the error: Invalid path "link_name".  The name it gives is
   the file in the LINK directory, so you can TYPE this file and find out
   why it doesn't work.  Under command.com 3.3 the error you get reads
   "EXE failure".  Under command.com 5.0 the error is:
   Cannot Execute "link_name".
1) Put EXELINK.COM in a directory on your PATH
2) Add the line
   to your autoexec.bat file.  It is recommended that this is one of the
   first TSR's loaded so that the links are active as soon as possible.
   Then either reboot to run the new autoexec sequence, or run EXELINK
   by hand to be able to use it now.  EXELINK will load high with no problem
   (at least it does with QEMM).
3) Put the link directory at the beginning of your path
4) create the link directory.
5) create all the links needed.  Remember, a link file is just an ASCII
   file which contains the filename of the program you really want run.
Helpful Hints
Applications called via EXELINK can live on any disk accessible by DOS.
There may be problems with 'join' and 'assign'.  The function INT21/AX=60h
used to test whether the called program is in the link directory returns the
filename as if there were no join's or assign's.  Your milage may vary.
Using 4DOS a nice utility that goes well is a small alias:
     alias addlink `for %add in (%&) echo %@full[%add]
            > c:\links\%@name[%add].%@ext[%add]`
[all on the same line of course!]
Alternatively you could create ADDLINK.BTM which performs the same
thing.  Then you could do something like
     cdd c:\app\turbop
     addlink *.com *.exe
which would create links for all .exe and .com files in the turbop
directory, enabling you to remove c:\app\turbop from the PATH.
If you have 'noclobber' set (setdos /n1) then any link that already exists
will not be overwritten.
Under MS-DOS command.com you could do the following:
create a file addlink.bat containing
     echo %1\%2 > c:\links\%2
Then you could do
     cd \app\turbop
     for %a in (*.com *.exe) do addlink c:\app\turbop %a
WARNING:  This method would erase any old link of the same name, as would
the 4DOS version without 'noclobber' set.
The link files are PURE ASCII and can be edited using any editor
from Edlin upwards.  The first character with a code of 32 or less counts
as the end of the string, so a ^Z or CR or LF are all ways of ending the
link file.   Up to 127 characters are allowed in the filename
on one line.  Anything longer than that will be truncated.  Filenames
must be FULLY QUALIFIED.  ie  they must be of the form drive:\path\file.ext
If they are not, then the command executed will be relative to the current