[net.micro.pc] You can get argv[0] in DOS 3.x

morearty@cory.Berkeley.EDU (Mike Morearty) (10/06/86)

I just discovered an undocumented feature of the more recent
versions of DOS: it is at last possible to obtain argv[0].

I discovered this because I was surprised to read in the DOS 3.2
manual that XCOPY.EXE behaves differently if you rename it as
MCOPY.EXE.  So I disassembled it, and found the following method
to determine the name of the program that is being run.

As you probably know, in all versions of DOS from 2.0 on, there
is an environment area in memory with strings that can be created
with the SET command, such as "set PATH=\".  The segment of this
environment area is stored as a word at offset 2Ch into the
Program Segment Prefix.  If, for example, the word at address 2Ch
is 1000, then the environment area begins at offset 1000:0000.

This environment area consists of null-terminated strings of the
form "NAME=value" (with NAME all upper case), followed by a null
byte.  If the next byte is also a null, then that marks the end
of the environment area.  (Thus, if the very first byte in the
environment area is a null, there are no strings present.)

Now, the good stuff: in DOS 3.1 and 3.2, and possibly in 3.0 (I
haven't been able to test it), this environment area is followed
by the complete path and filename of the program that has been
invoked.  Here is the exact format (#x indicates a byte with
value x):

     NAME=value#0        ;one or more null-terminated strings
     #0                  ;the terminating null byte
     #1                  ;followed by a byte with value one
     #0                  ;followed by another null byte
     C:\PAS\ENV.COM#0    ;argv[0], null-terminated

Note the following changes from older versions of DOS:

1.   There are always TWO null bytes at the end of the
     environment area.  In older versions, there may have been
     only one null byte if there were no environment strings
     present.

2.   The environment area is immediately followed by a 1 and then
     a 0.  If this is not present, assume that argv[0] is not
     present either.

Note that the drive specifier and/or certain subdirectory names
in the path may be lower case, and there may be "." and/or ".."
entries in the path, depending on the line that the user typed to
invoke the program.  Some examples follow, assuming that the user
is in the directory C:\DIR, and there is a program in that
directory called PROGRAM.COM:

     User typed               argv[0] contains
     ----------               ----------------
     program                  C:\DIR\PROGRAM.COM
     PROGRAM                  C:\DIR\PROGRAM.COM
     .\program                C:\DIR\.\PROGRAM.COM
     \dir\program             C:\dir\PROGRAM.COM
     c:program                c:\DIR\PROGRAM.COM
     program.exe              C:\DIR\PROGRAM.COM

Here is a sample program written in Turbo Pascal (version 3.x),
to display argv[0].

=================================================================

{
  Argv0.pas - Display argv[0], in other words, the path and filename
              that invoked this program.  Works under DOS 3.1 and 3.2,
              and possibly 3.0.
}

program Argv0;

var
  env: integer absolute cseg:$2C;       (* segment of environment *)
  cp:  integer;                         (* pointer into environment segment *)
  r: record                             (* record of registers *)
       ax,bx,cx,dx,bp,si,di,ds,es,flags: integer;
     end;

begin
  r.ax := $3000;
  MsDos(r);                             (* get DOS version number *)
  if (lo(r.ax) <> 3) or (hi(r.ax) > $20) then begin
    writeln('Needs DOS 3.0, 3.1, or 3.2');
    halt;
  end;

  cp := 0;                              (* point to beginning of segment *)

  (* find the end of the environment space, e.g., where two nulls are
     found in a row. *)
  while (memw[env:cp] <> 0) do begin
    cp := cp + 1;
  end;
  cp := cp + 2;                         (* move past the two nulls *)

  (* If this version of DOS has argv[0], then the two nulls are
     immediately followed by an ASCII 1 and then another null. *)
  if (memw[env:cp] <> 1) then begin
    writeln('Invalid memory format');
  end else begin
    cp := cp + 2;                       (* move past the 1 and the 0 *)
    while mem[env:cp] <> 0 do begin     (* argv[0] is null-terminated *)
      write(chr(mem[env:cp]));
      cp := cp+1;
    end;
  end;
end.

                                   -- Mike Morearty

smdev@csustan.UUCP (Scott Hazen Mueller) (10/06/86)

In article <> morearty@cory.Berkeley.EDU (Mike Morearty) writes:
<I just discovered an undocumented feature of the more recent
<versions of DOS: it is at last possible to obtain argv[0].
<...environment...complete path and filename of the program
<
<     NAME=value#0        ;one or more null-terminated strings
<     #0                  ;the terminating null byte
<     #1                  ;followed by a byte with value one

I'm not absolutely certain, but I believe that this can have values other than
one.  I think that it is actually argc.

<     #0                  ;followed by another null byte
<     C:\PAS\ENV.COM#0    ;argv[0], null-terminated

The entire command line _might_ be copied here.  Again, I don't remember
exactly.

<                                   -- Mike Morearty
                  \scott

-- 
Scott Hazen Mueller                         lll-crg.arpa!csustan!smdev
City of Turlock                             work:  (209) 668-5590 -or- 5628
901 South Walnut Avenue                     home:  (209) 527-1203
Turlock, CA 95380                           <Insert pithy saying here...>

johnl@ima.UUCP (John R. Levine) (10/07/86)

In article <468@zen.BERKELEY.EDU> morearty@cory.Berkeley.EDU (Mike Morearty) writes:
>I just discovered an undocumented feature of the more recent
>versions of DOS: it is at last possible to obtain argv[0].
>...

You can indeed get the name under which the program was invoked, but you could
have saved yourself a lot of effort by reading the DOS 3.x technical reference,
in the section on the EXEC call, in which the feature is documented.
-- 
John R. Levine, Javelin Software Corp., Cambridge MA +1 617 494 1400
{ ihnp4 | decvax | cbosgd | harvard | yale }!ima!johnl, Levine@YALE.EDU
The opinions expressed herein are solely those of a 12-year-old hacker
who has broken into my account and not those of any person or organization.

hamilton@uiucuxc.CSO.UIUC.EDU (10/14/86)

morearty@cory.Berkeley.EDU sez:
>I just discovered an undocumented feature of the more recent
>versions of DOS: it is at last possible to obtain argv[0].

ummm, this WAS documented, in my dos 3.0 technical reference manual.

	wayne hamilton
	U of Il and US Army Corps of Engineers CERL
UUCP:	{ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!hamilton
ARPA:	hamilton%uiucuxc@a.cs.uiuc.edu	USMail:	Box 476, Urbana, IL 61801
CSNET:	hamilton%uiucuxc@uiuc.csnet	Phone:	(217)333-8703
CIS:    [73047,544]			PLink: w hamilton