[comp.lang.pascal] Modifying the DOS environment with TP

mjensen@ccwf.cc.utexas.edu (Marc S. Jensen) (01/28/91)

I'm working on a DOS shell program, for no particular reason other than I
want to, and have a problem: While I can use GetEnv, EnvCount, etc., to
read the DOS environment variables, I can't find a way of changing those
same variables.
I thought I could get around this by using somoething like
	
	exec('COMMAND.COM','/C SET <VAR>=<VALUE>')

but this won't work, I guess because the new values are zapped when the
exec statement is done executing...

Any suggestions?

		-Marc

P.S. - I'm using TP5.5, 'cause I don't like Borland's new, fake looks-like-
a-mac-in-text-mode interface, even if it would be nice to edit more than 
one file at a time...



-- 

Marc Jensen
mjensen@ccwf.cc.utexas.edu
University of Texas at Austin
-----
"Never attribute to malice that which is adequately explained by stupidity!"

ts@uwasa.fi (Timo Salmi) (01/28/91)

In article <43263@ut-emx.uucp> mjensen@ccwf.cc.utexas.edu (Marc S. Jensen) writes:
>I'm working on a DOS shell program, for no particular reason other than I
>want to, and have a problem: While I can use GetEnv, EnvCount, etc., to
>read the DOS environment variables, I can't find a way of changing those
>same variables.
>I thought I could get around this by using somoething like
>	
>	exec('COMMAND.COM','/C SET <VAR>=<VALUE>')
>
>but this won't work, I guess because the new values are zapped when the
>exec statement is done executing...
:

You are right.  This is not the solution.  You have to deal with the
PSP to change the environment, which is an advanced subject.  Some
Turbo Pascal books have material on this, perhaps Michael Tischer's
Turbo Pascal Internals?  Perhaps someone will have an exaple.

...................................................................
Prof. Timo Salmi        
Moderating at garbo.uwasa.fi anonymous ftp archives 128.214.12.37
School of Business Studies, University of Vaasa, SF-65101, Finland
Internet: ts@chyde.uwasa.fi Funet: gado::salmi Bitnet: salmi@finfun

jeroenk@cnps.philips.nl (Jeroen Kessels) (01/30/91)

In article <43263@ut-emx.uucp> mjensen@ccwf.cc.utexas.edu (Marc S. Jensen) writes:
>I'm working on a DOS shell program, for no particular reason other than I
>want to, and have a problem: While I can use GetEnv, EnvCount, etc., to
>read the DOS environment variables, I can't find a way of changing those
>same variables.
>I thought I could get around this by using somoething like
>	
>	exec('COMMAND.COM','/C SET <VAR>=<VALUE>')
>
>but this won't work, I guess because the new values are zapped when the
>exec statement is done executing...


unit environm;                                                   { version 1.0 }


(******************************************************** 1990 J.C. Kessels ****
Change DOS environment settings.


J.C. Kessels
Philips de Goedelaan 7
5615 PN  Eindhoven
Netherlands
*******************************************************************************)




Interface
function SetEnv(name, value : string) : boolean;




Implementation




function SetEnv(name, value : string) : boolean;
{ Change variable "name" in the DOS environment into "value", like with the SET
  command in DOS. If "value" is empty, then remove the variable from the
  environment. Return TRUE if everything OK, return FALSE if there is not
  enough environment space available or if the "name" is bad (no name). }
{ Note: "name" is always translated into uppercase, and may not contain spaces,
  zero's or equal-signs. }
{ Note: The change is invisible from the running program. Every program
  receives a copy of the environment of it's parent. SetEnv changes the
  "master" environment, owned by DOS. The "current" environment cannot be
  changed, because there is "just enough" memory allocated to it. }
{ Note: The "master" environment has a default size of 160 bytes, which can be
  changed by using the "/e:nnnnn" setting with COMMAND.COM. }
{ Example:
     if SetEnv('PATH','c:\system;c:\turbop\system')
       then writeln('Path changed.')
       else writeln('Error: environment full.');                               }
type
  Environment = array[0..65534] of char;                  { Environment array. }
var
  PSP : word;                      { Program Segment Prefix address (segment). }
  EnvSeg : word;                       { Address of the environment (segment). }
  EnvEnd : word;                            { End of the environment (offset). }
  EnvEntryBegin : word;             { Begin of the environment entry (offset). }
  EnvEntryEnd : word;                 { End of the environment entry (offset). }
  EnvSize : word;                           { Size of the environment (bytes). }
  Env : record case integer of                            { Only used by MOVE. }
    0 : (p : ^Environment);                       { Access to the environment. }
    1 : (ofs, seg : word);       { Access to the pointer's offset and segment. }
    end;
  NameIndex : word;                                     { Index into the name. }
begin
SetEnv := false;                                               { Assume error. }

{ Zero, space or equal-sign are not allowed in the name. }
NameIndex := 1;
while NameIndex < length(name) do
  begin
  if (name[NameIndex] = #0) or (name[NameIndex] = ' ') or
     (name[NameIndex] = '=') then
    name := copy(name,1,NameIndex-1);
  inc(NameIndex);
  end;
if length(name) = 0 then exit;                        { Exit if name is empty. }
for NameIndex := 1 to length(name) do                     { Name to uppercase. }
  name[NameIndex] := upcase(name[NameIndex]);
name := name + '=';                              { Add equal-sign to the name. }

{ Locate the DOS environment by walking through the chain of PSP's ("Program
  Segment Prefix"). DOS is the latest PSP in the chain. The "previous-PSP"
  pointer is stored at $16 in the current PSP. The "previous-PSP" value in the
  DOS-PSP points to itself. }
PSP := PrefixSeg;
while PSP <> memw[PSP:$16] do PSP := memw[PSP:$16];

{ Get the address of the environment. This is stored as a segment-address. }
EnvSeg := memw[PSP:$2C];

{ Get the maximum environment size. This is stored as a number of paragraphs. }
EnvSize := memw[memw[PSP:$2C]-1:3] shl 4;

{ Find the actual end of the environment. The environment is constructed out of
  a number of zero-terminated strings. The last string is empty. }
EnvEnd := 0;
while mem[EnvSeg:EnvEnd] <> 0 do
  begin
  while mem[EnvSeg:EnvEnd] <> 0 do inc(EnvEnd);
  inc(EnvEnd);
  end;

{ Find the begin and the end of the environment entry for variable "name". }
EnvEntryEnd := 0;
repeat
  EnvEntryBegin := EnvEntryEnd;   { Store the begin of this environment entry. }
  NameIndex := 1;              { Compare the name with this environment entry. }
  while (NameIndex <= length(name)) and
        (name[NameIndex] = chr(mem[EnvSeg:EnvEntryEnd])) do
    begin
    inc(NameIndex);
    inc(EnvEntryEnd);
    end;
  { Skip to the end of this entry, which is the begin of the next entry. }
  while (EnvEntryEnd < EnvEnd) and (mem[EnvSeg:EnvEntryEnd] <> 0) do
    inc(EnvEntryEnd);
  if EnvEntryEnd < EnvEnd then inc(EnvEntryEnd);
until (NameIndex > length(name)) or (EnvEntryEnd >= EnvEnd);
if NameIndex <= length(name) then EnvEntryBegin := EnvEnd;

{ If there is not enough environment space available, then exit. }
if (EnvEnd - EnvEntryEnd + EnvEntryBegin + length(name) + length(value)
   >= EnvSize) and (length(value) > 0) then exit;

{ Delete the environment entry. }
Env.seg := EnvSeg;                                 { Setup the "Env" variable. }
Env.ofs := 0;
if EnvEntryBegin < EnvEntryEnd then                                  { Delete. }
  move(Env.p^[EnvEntryEnd],Env.p^[EnvEntryBegin],EnvEnd-EnvEntryEnd+1);
EnvEnd := EnvEnd - EnvEntryEnd + EnvEntryBegin;               { Update EnvEnd. }

{ If value is empty, then exit. The entry has been removed from the
  environment. }
SetEnv := true;                                                    { No error. }
if length(value) = 0 then exit;

{ Add entry to the top of the environment. }
for NameIndex := 1 to length(name) do                              { Add name. }
  begin
  mem[EnvSeg:EnvEnd] := ord(name[NameIndex]);
  inc(EnvEnd);
  end;
for NameIndex := 1 to length(value) do                            { Add value. }
  begin
  mem[EnvSeg:EnvEnd] := ord(value[NameIndex]);
  inc(EnvEnd);
  end;
mem[EnvSeg:EnvEnd] := 0;                             { Add zero, end of entry. }
inc(EnvEnd);
mem[EnvSeg:EnvEnd] := 0;                       { Add zero, end of environment. }
end;




begin
end.
-- 
Jeroen C. Kessels
Software Engineer, Philips C&P-LSS
VA-25, P.O. Box 218, 5600 MD Eindhoven, The Netherlands
Usenet = jeroenk@cnps.philips.nl