It must have been a millennium ago that I've tried to change the environment of the current DOS session by means of a program. The problem is: that program runs within its own DOS shell, so it has to operate on its parent environment. It takes a walk, starting at the DOS Info Block, all along the chain of Memory Control Blocks, to find the location of that parent environment. Once I had found out how to do this, my need for manipulating environment variables had vanished. I'll give you the Turbo Pascal code below, but I guess there are at least two better ways to do the trick:
Create a batch file that: (a) calls a Python script (or whatever) that generates a temporay batch file containing the appropriate SET commands; (b) calls the temporary batch file (the SET commands are executed in the current shell); and (c) removes the temporary batch file.
Create a Python script that writes something like "VAR1=val1\nVAR2=val2\nVAR3=val3\n" to STDOUT. Use it this way in your batch file:
for /f "delims=|" %%X in ('callYourPythonScript') do set %%Xet voilà: variables VAR1, VAR2 and VAR3 have been given a value.
And here goes the Pascal code (you may need a Dutch dictionary and a Pascal programming book) of a program that just reports memory locations. It still seems to work under Windows XP, be it reporting we're running DOS 5.00. This is only a first beginning, there's a lot of low level programming to do in order to manipulate the selected environment. And as the pointer structure may seem correct, I'm not so sure if the environment model of 1994 still holds these days...
program MCBKETEN;
uses dos, HexConv;
{----------------------------------------------------------------------------}
{ Programma: MCBKETEN.EXE }
{ Broncode : MCBKETEN.PAS }
{ Doel : Tocht langs de MCB's met rapportage }
{ Datum : 11 januari 1994 }
{ Auteur : Meindert Meindertsma }
{ Versie : 1.00 }
{----------------------------------------------------------------------------}
type
MCB_Ptr = ^MCB;
{ MCB_PtrPtr = ^MCB_Ptr; vervallen wegens DOS 2.11 -- zie verderop }
MCB = record
Signatuur : char;
Eigenaar : word;
Paragrafen : word;
Gereserveerd : array[1..3] of byte;
Naam : array[1..8] of char;
end;
BlokPtr = ^BlokRec;
BlokRec = record
Vorige : BlokPtr;
DitSegment,
Paragrafen : word;
Signatuur : string[6];
Eigenaar,
Omgeving : word;
Functie : String4;
Oorsprong,
Pijl : char;
KorteNaam : string[8];
LangeNaam : string;
Volgende : BlokPtr;
end;
PSP_Ptr = ^PSP;
PSP = record
Vulsel1 : array[1..44] of byte;
Omgeving : word;
Vulsel2 : array[47..256] of byte;
end;
var
Zone : string[5];
ProgGevonden,
EindeKeten,
Dos3punt2 : boolean;
Regs : registers;
ActMCB : MCB_Ptr;
EersteSchakel, Schakel,
LaatsteSchakel : BlokPtr;
ActPSP : PSP_Ptr;
EersteProg,
Meester, Ouder,
TerugkeerSegment,
TerugkeerOffset,
TerugkeerSegment2,
OuderSegment : word;
Specificatie : string[8];
ReleaseNummer : string[2];
i : byte;
{----------------------------------------------------------------------------}
{ PROCEDURES EN FUNCTIES }
{----------------------------------------------------------------------------}
function Coda (Omgeving : word; Paragrafen : word) : string;
var
i : longint;
Vorige, Deze : char;
Streng : string;
begin
i := 0;
Deze := #0;
repeat
Vorige := Deze;
Deze := char (ptr (Omgeving, i)^);
inc (i);
until ((Vorige = #0) and (Deze = #0)) or (i div 10ドル>= Paragrafen);
if (i + 3) div 10ドル < Paragrafen then begin
Vorige := char (ptr (Omgeving, i)^);
inc (i);
Deze := char (ptr (Omgeving, i)^);
inc (i);
if (Vorige = #01) and (Deze = #0) then begin
Streng := '';
Deze := char (ptr (Omgeving, i)^);
inc (i);
while (Deze <> #0) and (i div 10ドル < Paragrafen) do begin
Streng := Streng + Deze;
Deze := char (ptr (Omgeving, i)^);
inc (i);
end;
Coda := Streng;
end
else Coda := '';
end
else Coda := '';
end {Coda};
{----------------------------------------------------------------------------}
{ HOOFDPROGRAMMA }
{----------------------------------------------------------------------------}
BEGIN
{----- Initiatie -----}
Zone := 'Lower';
ProgGevonden := FALSE;
EindeKeten := FALSE;
Dos3punt2 := (dosversion>= 1403ドル) and (dosversion <= 1ドルD03);
Meester := 0000ドル;
Ouder := 0000ドル;
Specificatie[0] := #8;
str (hi (dosversion) : 2, ReleaseNummer);
if ReleaseNummer[1] = ' ' then ReleaseNummer[1] := '0';
{----- Pointer naar eerste MCB ophalen ------}
Regs.AH := 52ドル; { functie 52ドル geeft adres van DOS Info Block in ES:BX }
msdos (Regs);
{ ActMCB := MCB_PtrPtr (ptr (Regs.ES, Regs.BX - 4))^; NIET onder DOS 2.11 }
ActMCB := ptr (word (ptr (Regs.ES, Regs.BX - 2)^), 0000ドル);
{----- MCB-keten doorlopen -----}
new (EersteSchakel);
EersteSchakel^.Vorige := nil;
Schakel := EersteSchakel;
repeat
with Schakel^ do begin
DitSegment := seg (ActMCB^);
Paragrafen := ActMCB^.Paragrafen;
if DitSegment + Paragrafen>= $A000 then
Zone := 'Upper';
Signatuur := Zone + ActMCB^.Signatuur;
Eigenaar := ActMCB^.Eigenaar;
ActPSP := ptr (Eigenaar, 0);
if not ProgGevonden then EersteProg := DitSegment + 1;
if Eigenaar>= EersteProg
then Omgeving := ActPSP^.Omgeving
else Omgeving := 0;
if DitSegment + 1 = Eigenaar then begin
ProgGevonden := TRUE;
Functie := 'Prog';
KorteNaam[0] := #0;
while (ActMCB^.Naam[ ord (KorteNaam[0]) + 1 ] <> #0) and
(KorteNaam[0] < #8) do
begin
inc (KorteNaam[0]);
KorteNaam[ ord (KorteNaam[0]) ] :=
ActMCB^.Naam[ ord (KorteNaam[0]) ];
end;
if Eigenaar = prefixseg then begin
TerugkeerSegment := word (ptr (prefixseg, 000ドルC)^);
TerugkeerOffset := word (ptr (prefixseg, 000ドルA)^);
LangeNaam := '-----> Terminate Vector = ' +
WordHex (TerugkeerSegment) + ':' +
WordHex (TerugkeerOffset ) ;
end
else
LangeNaam := '';
end {if ÆProgØ}
else begin
if Eigenaar = 0008ドル then begin
if ActMCB^.Naam[1] = 'S' then
case ActMCB^.Naam[2] of
'D' : Functie := 'SysD';
'C' : Functie := 'SysP';
else Functie := 'Data';
end {case}
else Functie := 'Data';
KorteNaam := '';
LangeNaam := '';
end {if Eigenaar = 0008ドル}
else begin
if DitSegment + 1 = Omgeving then begin
Functie := 'Env ';
LangeNaam := Coda (Omgeving, Paragrafen);
if EersteProg = Eigenaar then Meester := Omgeving;
end {if ÆEnvØ}
else begin
move (ptr (DitSegment + 1, 0)^, Specificatie[1], 8);
if (Specificatie = 'PATH=' + #0 + 'CO') or
(Specificatie = 'COMSPEC=' ) or
(Specificatie = 'OS=DRDOS' ) then
begin
Functie := 'Env' + chr (39);
LangeNaam := Coda (DitSegment + 1, Paragrafen);
if (EersteProg = Eigenaar) and
(Meester = 0000ドル )
then
Meester := DitSegment + 1;
end
else begin
if Eigenaar = 0
then Functie := 'Free'
else Functie := 'Data';
LangeNaam := '';
if (EersteProg = Eigenaar) and
(Meester = 0000ドル )
then
Meester := DitSegment + 1;
end;
end {else: not ÆEnvØ};
KorteNaam := '';
end {else: Eigenaar <> 0008ドル};
end {else: not ÆProgØ};
{----- KorteNaam redigeren -----}
for i := 1 to length (KorteNaam) do
if KorteNaam[i] < #32 then KorteNaam[i] := '.';
KorteNaam := KorteNaam + ' ';
{----- Oorsprong vaststellen -----}
if EersteProg = Eigenaar
then Oorsprong := '*'
else Oorsprong := ' ';
{----- Actueel proces (uitgaande Pijl) vaststellen -----}
if Eigenaar = prefixseg
then Pijl := '>'
else Pijl := ' ';
end {with Schakel^};
{----- MCB-opeenvolging onderzoeken / schakelverloop vaststellen -----}
if (Zone = 'Upper') and (ActMCB^.Signatuur = 'Z') then begin
Schakel^.Volgende := nil;
EindeKeten := TRUE;
end
else begin
ActMCB := ptr (seg (ActMCB^) + ActMCB^.Paragrafen + 1, 0);
if ((ActMCB^.Signatuur <> 'M') and (ActMCB^.Signatuur <> 'Z')) or
($FFFF - ActMCB^.Paragrafen < seg (ActMCB^) )
then begin
Schakel^.Volgende := nil;
EindeKeten := TRUE;
end
else begin
new (LaatsteSchakel);
Schakel^.Volgende := LaatsteSchakel;
LaatsteSchakel^.Vorige := Schakel;
Schakel := LaatsteSchakel;
end {else: (ÆMØ or ÆZØ) and Æteveel_ParagrafenØ};
end {else: ÆLowerØ or not ÆZØ};
until EindeKeten;
{----- Terugtocht -----}
while Schakel <> nil do with Schakel^ do begin
{----- Ouder-proces vaststellen -----}
TerugkeerSegment2 := TerugkeerSegment + (TerugkeerOffset div 10ドル);
if (DitSegment <= TerugkeerSegment2) and
(DitSegment + Paragrafen>= TerugkeerSegment2)
then
OuderSegment := Eigenaar;
{----- Meester-omgeving markeren -----}
if DitSegment + 1 = Meester then Oorsprong := 'M';
{----- Schakel-verloop -----}
Schakel := Schakel^.Vorige;
end {while Schakel <> nil};
{----- Rapportage -----}
writeln ('Chain of Memory Control Blocks in DOS version ',
lo (dosversion), '.', ReleaseNummer, ':');
writeln;
writeln ('MCB@ #Par Signat PSP@ Env@ Type !! Name File');
writeln ('---- ---- ------ ---- ---- ---- -- -------- ',
'-----------------------------------');
Schakel := EersteSchakel;
while Schakel <> nil do with Schakel^ do begin
{----- Ouder-omgeving vaststellen -----}
if Eigenaar = OuderSegment then begin
if not Dos3punt2 then begin
if (Functie = 'Env ') then begin
Ouder := DitSegment + 1;
Pijl := 'Û';
end
else
Pijl := '<';
end {if not Dos3punt2}
else begin
if ((Functie = 'Env' + chr (39)) or (Functie = 'Data')) and
(Ouder = 0000ドル)
then begin
Ouder := DitSegment + 1;
Pijl := 'Û';
end
else
Pijl := '<';
end {else: Dos3punt2};
end {with Schakel^};
{----- Keten-weergave -----}
writeln (WordHex (DitSegment) , ' ',
WordHex (Paragrafen) , ' ',
Signatuur , ' ',
WordHex (Eigenaar) , ' ',
WordHex (Omgeving) , ' ',
Functie , ' ',
Oorsprong, Pijl , ' ',
KorteNaam , ' ',
LangeNaam );
{----- Schakel-verloop -----}
Schakel := Schakel^.Volgende;
end {while Schakel <> nil};
{----- Afsluiting rapportage -----}
writeln;
write ('* = First command interpreter at ');
if ProgGevonden
then writeln (WordHex (EersteProg), ':0000')
else writeln ('?');
write ('M = Master environment at ');
if Meester> 0000ドル
then writeln (WordHex (Meester), ':0000')
else writeln ('?');
write ('< = Parent proces at ');
writeln (WordHex (OuderSegment), ':0000');
write ('Û = Parent environment at ');
if Ouder> 0000ドル
then writeln (WordHex (Ouder), ':0000')
else writeln ('?');
writeln ('> = Current proces at ',
WordHex (prefixseg), ':0000');
writeln (' returns to ',
WordHex (TerugkeerSegment), ':', WordHex (TerugkeerOffset));
END.
(Above ASCII 127, there may be some ASCII/ANSI translation issues in this presentation.)