Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to the board
Thread view  Mix view  Order
bencollver

Homepage

28.02.2026, 00:52
 

save & restore environment (Developers)

I ran into a situation in SvarDOS where the EDR-DOS command interpreter was creating duplicate environment variables. For example, when i ran the SET command, i might see multiple PATH= variables in its output. I believe it was related to running out of space in the environment. The way i worked around this problem was by increasing the size of the environment, and also by running COMMAND /C instead of CALL to run helper .bat files. With COMMAND /C the original environment is restored when the helper .bat file completes.

I found myself wishing for a utility to back up and restore the environment. As an exercise, i wrote a couple of AWK scripts to do it.

mkenvset.awk

# Usage: awk -f mkenvset.awk >envset.bat
# Run envset.bat to restore all environment variables
BEGIN {
    for (k in ENVIRON) {
        printf "SET %s=%s\n", k, ENVIRON[k]
    }
}


mkenvdel.awk

# Usage: awk -f mkenvdel.awk >envdel.bat
# Run envdel.bat to delete all environment variables
BEGIN {
    for (k in ENVIRON) {
        printf "SET %s=\n", k
    }
}


I imagine using them like so:

awk -f mkenvset.awk >envset.bat
call helper.bat
awk -f mkenvdel.awk >envdel.bat
call envdel.bat
call envset.bat


This would effectively restore the original environment without using a COMMAND /C sub-shell.

What do you think? Is it a bad idea? Why?

Rugxulo

Homepage

Usono,
28.02.2026, 03:18

@ bencollver

save & restore environment

> awk -f mkenvset.awk >envset.bat
> call helper.bat
> awk -f mkenvdel.awk >envdel.bat
> call envdel.bat
> call envset.bat

>
> This would effectively restore the original environment without using a
> COMMAND /C sub-shell.
>
> What do you think? Is it a bad idea? Why?

4DOS and NT's CMD both have "SETLOCAL". So if you don't need any vars to persist, try that.

If you insist on this way (presumably to run on older shells), I'd suggest putting it in a single .BAT like "SAVEENV.BAT [on | off]". The AWK scripts are small enough to be in-place, but even an embedded AWK script (or ten) is easy to use.

bencollver

Homepage

28.02.2026, 04:26

@ Rugxulo

save & restore environment

> 4DOS and NT's CMD both have "SETLOCAL". So if you don't need any vars to
> persist, try that.

Thanks for that information. 4DOS is really "where it's at" isn't it?

> If you insist on this way (presumably to run on older shells), I'd suggest
> putting it in a single .BAT like "SAVEENV.BAT [on | off]". The AWK scripts
> are small enough to be in-place, but even an embedded AWK script (or ten)
> is easy to use.

Here's an attempt at SAVEENV.BAT:

@echo off

if x%1 == xon goto save
if x%1 == xoff goto restore
goto usage

:usage
echo SAVEENV.BAT ON
echo This saves the environment.
echo.
echo SAVEENV.BAT OFF
echo This restores the saved environment.
echo.
goto the_end

:save

echo BEGIN{ >%TEMP%\envset.awk
echo print "@echo off" >>%TEMP%\envset.awk
echo for(k in ENVIRON){printf "SET %%s=%%s\n",k,ENVIRON[k]} >>%TEMP%\envset.awk
echo } >>%TEMP%\envset.awk

awk -f %TEMP%\envset.awk >%TEMP%\envset.bat

goto the_end

:restore

echo BEGIN{ >%TEMP%\envdel.awk
echo print "@echo off" >>%TEMP%\envdel.awk
echo for(k in ENVIRON){printf "SET %%s=\n",k} >>%TEMP%\envdel.awk
echo } >>%TEMP%\envdel.awk

awk -f %TEMP%\envdel.awk >%TEMP%\envdel.bat

call %TEMP%\envdel.bat
call %TEMP%\envset.bat

goto the_end

:the_end

boeckmann

Aachen, Germany,
28.02.2026, 10:23

@ bencollver

save & restore environment

> I ran into a situation in SvarDOS where the EDR-DOS command interpreter [...]

Is it really the EDR command.com or SvarCOM, the default SvarDOS command interpreter?

bencollver

Homepage

28.02.2026, 15:20

@ boeckmann

save & restore environment

> > I ran into a situation in SvarDOS where the EDR-DOS command interpreter
> [...]
>
> Is it really the EDR command.com or SvarCOM, the default SvarDOS command
> interpreter?

It was really EDR command.com, and here's how i reproduced it:

Downloaded and extracted the TCC sources:

    C:\>curl -O gopher://tilde.pink/9/~bencollver/files/dos386/devel/tcc/src.zip
   
    C:\>unzip src.zip


Verify shell

    C:\>ver
   
    Enhanced DR-DOS based on Caldera OpenDOS 7.01
    Copyright (c) 1976, 1997 Caldera, Inc. All rights reserved.
    Patches to original OpenDOS source code Copyright (c) 2002-2011 Udo Kuhnt
   
    C:\>command.com /? | find "DOS"
    Enhanced DR-DOS based on Caldera OpenDOS 7.01
    Patches to original OpenDOS source code Copyright (c) 2002-2011 Udo Kuhnt
   
    C:\>find "SHELL=" config.sys
    ---------------- CONFIG.SYS
    SHELL=C:\COMMAND.COM C:\ /E:2048 /P


Configure Watcom build environment

    C:\>cd watcom
   
    C:\WATCOM>owsetenv
    Open Watcom Build Environment
   
    C:\WATCOM>cd ..


Configure HX

    C:\>set DPMILDR=136
   
    C:\>set HDPMI=32
   
    C:\>path %PATH%;C:\HX\BIN
   
    C:\>hxldr32
    HXLdr32 V1.13 Installed. Win32 console apps may possibly run now in DOS


Edit TCC win32\mkall.bat
Change one line.
OLD: set CALL=\command.com /c
NEW: set CALL=call

    C:\>cd src\win32
   
    C:\SRC\WIN32>oed mkall.bat
    1921
    /set CALL=\\command.com/s/.*/set CALL=call/p
    set CALL=call
    w
    1910
    q


Compile TCC
Takes a while for the script to complete or fail.

    C:\SRC\WIN32>mkall.bat

Verify duplicate variables in environment

    C:\SRC\WIN32>set | find "D="
    CD=C:\SRC\WIN32
    D=-dTCC_TARGET_PE -dTCC_TARGET_I386
    D=-DTCC_TARGET_PE -DTCC_TARGET_I386
    D=-DTCC_TARGET_PE -DTCC_TARGET_I386

    C:\>

boeckmann

Aachen, Germany,
28.02.2026, 19:26

@ bencollver

save & restore environment

Is it the EDR command version from the SvarDOS package (this comes from https://github.com/SvarDOS/edrdos )?

The code involved should be:

https://github.com/SvarDOS/edrdos/blob/cd65cc5e671...05ff2531099dddc348/command/comint.c#L1647-L1661

The intended logic is like this: delete environment variable if it already exists, then append the variable with the changed content at the end of the environment. If "D" occurs multiple times, this logic somehow fails.

Rugxulo

Homepage

Usono,
01.03.2026, 00:24

@ bencollver

save & restore environment

> > 4DOS and NT's CMD both have "SETLOCAL". So if you don't need any vars to
> > persist, try that.
>
> Thanks for that information. 4DOS is really "where it's at" isn't it?

Yes and no. It's brilliant, but I always avoided it to write "portable" scripts. But it does make some things easier. (Honestly, it no worse than relying on a POSIX shell!)

> > If you insist on this way (presumably to run on older shells), I'd
> suggest
> > putting it in a single .BAT like "SAVEENV.BAT [on | off]". The AWK
> scripts
> > are small enough to be in-place, but even an embedded AWK script (or
> ten)
> > is easy to use.
>
> Here's an attempt at SAVEENV.BAT:

Here's an old example of mine that may give you ideas: invnas97.bat

bencollver

Homepage

01.03.2026, 15:12

@ boeckmann

save & restore environment

> Is it the EDR command version from the SvarDOS package (this comes from
> https://github.com/SvarDOS/edrdos )?

Here's what i am using:

https://github.com/SvarDOS/edrdos/releases/tag/v20250427

bencollver

Homepage

08.03.2026, 00:45

@ boeckmann

save & restore environment

I reduced it to a test case.
COMMAND.COM is from EDR DOS 20250427
CMD701.COM is from Caldera OpenDOS 7.01

C:\>type test.bat
SET D=-dTCC_TARGET_PE -dTCC_TARGET_I386
SET D=-DTCC_TARGET_PE -DTCC_TARGET_I386
SET

C:\>command.com /c test.bat
OS=DRDOS
VER=7
COMSPEC=C:\COMMAND.COM
TEMP=C:\TEMP
NLSPATH=C:\SVARDOS\NLS
WATTCP.CFG=C:\SVARDOS
PATH=C:\SVARDOS;C:\CWSDPMI;C:\UNZIP32;C:\V8POWER;C:\WHICH
PROMPT=$P$G
LANG=EN
DOS32A=/QUIET
D=-dTCC_TARGET_PE -dTCC_TARGET_I386
D=-DTCC_TARGET_PE -DTCC_TARGET_I386

C:\>cmd701.com /c test.bat
OS=DRDOS
VER=7
COMSPEC=C:\COMMAND.COM
TEMP=C:\TEMP
NLSPATH=C:\SVARDOS\NLS
WATTCP.CFG=C:\SVARDOS
PATH=C:\SVARDOS;C:\CWSDPMI;C:\UNZIP32;C:\V8POWER;C:\WHICH
PROMPT=$P$G
LANG=EN
DOS32A=/QUIET
D=-DTCC_TARGET_PE -DTCC_TARGET_I386


If i run the script in DEBUG.COM, it gives a 3rd version of the output:

C:\>debug command.com /c test.bat
- g
OS=DRDOS
VER=7
COMSPEC=C:\COMMAND.COM
TEMP=C:\TEMP
NLSPATH=C:\SVARDOS\NLS
WATTCP.CFG=C:\SVARDOS
PATH=C:\SVARDOS;C:\CWSDPMI;C:\UNZIP32;C:\V8POWER;C:\WHICH
PROMPT=$P$G
LANG=EN
DOS32A=/QUIET
D=-dTCC_TARGET_PE -dTCC_TARGET_I386

Program terminated normally (0000)
-


This discouraged me because i was hoping to use DEBUG.COM to trace what was happening within COMMAND.COM.

Oddly, if i edit test.bat and change the variable name, then i can no longer reproduce the problem even on EDR DOS COMMAND.COM. It creates a duplicate environment variable named D, but will not produce one named A, B, C, E, or even DD.

p.s.

I compared OpenDOS 7.01 COMMAND.COM with EDR DOS 20250427.

command\csup.asm get_key has only one difference.
So far as i can tell, it should work the same.

--- old-getkey.asm      2026-03-07 14:40:31.343231149 -0800
+++ new-getkey.asm      2026-03-07 14:40:54.172230574 -0800
@@ -8,7 +8,7 @@
        push ds
        pop es                          ; Calculate the length of the
        mov     di,04[bp]               ; key by scaning the string for
-       mov     al,0                    ; a zero byte.
+       xor     al,al                   ; a zero byte.
        mov     cx,-1
        repnz   scasb
        neg     cx                      ; CX is the length of the sting + 2


command\csup.asm env_del has only one difference.
So far as i can tell, it should work the same.

--- old-envdel.txt      2026-03-07 14:10:03.196277219 -0800
+++ new-envdel.txt      2026-03-07 14:10:24.636276679 -0800
@@ -28,7 +28,7 @@
 env_d15:
        lodsb
        stosb                           ; Copy through AL checking for the end
-       or      al,al
+       test    al,al
        jnz     env_d15                 ; of the environment after each
        jmps    env_d10                 ; end of string.
 env_d20:



After converting the spacing
command\comint.c cmd_set has a couple of differences,
after converting to ANSI C and fixing the indentation.

--- old-cmdset.txt      2026-03-07 14:01:29.396290167 -0800
+++ new-cmdset.txt      2026-03-07 13:42:03.099319559 -0800
@@ -46,8 +46,6 @@
       syntax();             /* or the '=' is missing return */
       return;
    } /* a syntax error.                */
-       
-   s++;
 
 #if 0
        /* msdos doesn't do this */
@@ -67,7 +65,9 @@
       crlfflg = YES;
       return;
    }
-   if ( (*s-- = c) != 0 ) {     /* Add the definition to the end*/
+   *s++ = c;
+
+   if ( *s != 0 ) { /* Add the definition to the end*/
       /* of the environment if the new*/
       if ( env_ins( key ) ) {   /* definition is not NULL      */
          printf( MSG_ENVFULL ); /* check for an error.         */



The asm PROC get_key begins with:

1E push ds
07 pop es
?? mov di,04[bp]
?? xor al,al


COMMAND.COM is 63601 bytes large (F871)

    C:\>debug command.com /c test.bat
    -s 100 l F871 1E 07
    1954:20D2
    1954:22B3
    1954:242D
    1954:2440
    1954:3D2A
    1954:2E26
    1954:408B
    1954:40A1
    1954:40E3
    1954:4109
    1954:4140
    1954:4156
    1954:42A9
    1954:446A
    1954:B262


Unassembling these offsets, only one matches the PROC get_key signature.

    -u 1954:3D2A
    1954:3D2A 1E                PUSH    DS
    1954:3D2B 07                POP     ES
    1954:3D2C 8B7E04            MOV     DI,[BP+04]
    1954:3D2F 32C0              XOR     AL,AL
    1954:3D31 B9FFFF            MOV     CX,FFFF
    1954:3D34 F2AE              REPNE   SCASB
    1954:3D36 F7D9              NEG     CX
    1954:3D38 83E902            SUB     CX,+02
    1954:3D3B 8BD1              MOV     DX,CX
    1954:3D3D 33C0              XOR     AX,AX
    1954:3D3F 8EC3              MOV     ES,BX
    1954:3D41 33FF              XOR     DI,DI
    1954:3D43 57                PUSH    DI
    1954:3D44 8BCA              MOV     CS,DX
    1954:3D46 8B7604            MOV     SI,[BP+04]
    1954:3D49 F3A6              REPE    CMPSB

jadoxa

Homepage E-mail

Queensland, Australia,
08.03.2026, 01:39

@ bencollver

save & restore environment

> COMMAND.COM is from EDR DOS 20250427

This is failing because it is not getting the key, it is getting the prefix of the key.

C:\>type test.bat
set d11=d11
set d12=d12
set d13=d13
set D1=d1
set D1=D1
set

C:\>command.com /c set | tail -1
COMSPEC=J:\COMMAND.COM

C:\>command.com /c test.bat | tail -4
COMSPEC=J:\COMMAND.COM
D13=D13
D1=d1
D1=D1


(COMSPEC is J: because I'm actually running this in MSDOS Player in Win10.)

When it gets the key it doesn't check there's an equals after it, hence the key will match any other variable that starts with it.

bencollver

Homepage

08.03.2026, 02:05

@ jadoxa

save & restore environment

> > COMMAND.COM is from EDR DOS 20250427
>
> This is failing because it is not getting the key, it is getting the prefix
> of the key.
> ...
> When it gets the key it doesn't check there's an equals after it, hence the
> key will match any other variable that starts with it.

Thanks!

Maybe that was what the removed s++; line was for:

to include the = (equal sign) in the key.

boeckmann

Aachen, Germany,
08.03.2026, 22:23

@ bencollver

save & restore environment

> > > COMMAND.COM is from EDR DOS 20250427
> >
> > This is failing because it is not getting the key, it is getting the
> prefix
> > of the key.
> > ...
> > When it gets the key it doesn't check there's an equals after it, hence
> the
> > key will match any other variable that starts with it.
>
> Thanks!
>
> Maybe that was what the removed s++; line was for:
>
> to include the = (equal sign) in the key.

Yes, get_key does not check for '='. The following seems to fix it (includes the = as part of the key for deletion.


diff --git a/command/comint.c b/command/comint.c
index 5068153..2d785c1 100644
--- a/command/comint.c
+++ b/command/comint.c
@@ -1641,6 +1641,7 @@ GLOBAL VOID CDECL cmd_set( BYTE *s )
        }
 #endif
 
+   s++;                        /* skip over = (include in key name) */
    c = *s;                     /* Save Character               */
    *s = '\0';                  /* terminate keyword            */
    strupr( key );              /* make keyword upper case       */
@@ -1649,7 +1650,7 @@ GLOBAL VOID CDECL cmd_set( BYTE *s )
       crlfflg = YES;
       return;
    }
-   *s++ = c;
+   *s = c;    /* recover first character of value */
 
    if ( *s != 0 ) { /* Add the definition to the end*/
       /* of the environment if the new*/

boeckmann

Aachen, Germany,
09.03.2026, 17:15

@ boeckmann

save & restore environment

Fixed by https://github.com/SvarDOS/edrdos/commit/579ab148df4d6af82752155137e0cad6a31b1a34

bencollver

Homepage

09.03.2026, 20:09

@ boeckmann

save & restore environment

> Fixed by
> https://github.com/SvarDOS/edrdos/commit/579ab148df4d6af82752155137e0cad6a31b1a34

Thanks! I verified that it fixed the problem on my end.

https://github.com/SvarDOS/edrdos/actions/runs/22862905914

Back to the board
Thread view  Mix view  Order
23234 Postings in 2190 Threads, 405 registered users (2 online)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum