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