Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the sum of 2 numbers in original DOS?

Tags:

batch-file

dos

I wanted to relive the nostalgia of good old dos.
I've been testing a few batch commands but I've noticed /a isn't usable in dos.
Is there another method I can use to add two variables without including /a?

@echo off
::this is how I would originally add two numbers
set /p number1=
set /p number2=
set /a "number1=number1+number2"
echo %number1%
pause >nul
exit

dos states "invalid switch. - /a" when I run this program.

like image 559
Zennik99 Avatar asked Jan 12 '19 06:01

Zennik99


2 Answers

It's a bit more tricky than using set /a, but it can be solved with MS-DOS 6.22.

One part is to write a function to add single digits and one function that can add multiple digits.

The main problem is to split a number into single digits, because MS-DOS doesn't support string manipulation.
But it exists a tiny flaw in the FOR-Loop handling, / splits a text into three parts.

for %%a in (`abcdef/ghijklmno`) do echo %%a

Outputs

abcdef
g
hijklmno

With this trick a number can be split into single digits

split.bat

@echo off
for %%P in (/%1.) do if %%P==: goto %1

set _idx=
set _remain=%2
set _splitRev=
set _splitRev_comma=

:loop

set _loop=1

for %%a in (/%_remain%) do call %0 :split %1 %%a
if NOT "%_remain%"=="" goto :loop
set %1=%_splitRev%
set %1_comma=%_splitRev_comma%

REM Clear temp vars
FOR %%v in (_remain _idx _loop _splitRev _splitRev_comma) do set %%v=
goto :eof

:split
if %_loop%%==2 goto :split_2
set _loop=2
set _remain=
set _splitRev=%3%_splitRev%
set _splitRev_comma=%3,%_splitRev_comma%
goto :eof

:split_2
set _remain=%3
goto :eof

:eof

And the add.bat looks like

@echo off
for %%P in (/%1.) do if %%P==: goto %1

call split _valueRev1 %1
call split _valueRev2 %2

set _result=
set _carry=
for %%d in (%_valueRev1_comma%,0,0,0,0,0) do call %0 :getDig1 %%d


REM Remove leading zeros
:zeroLoop
for %%z in (/%_result%) do set _remain=%%z
if not %_result%==0%_remain% goto :finish
set _result=%_remain%
goto :zeroLoop

:finish
echo %1+%2=%_result%

REM Clear temp vars
FOR %%v in (_result _carry _len _digit1 _digit2 _remain _valueRev1 _valueRev1_comma _valueRev2 _valueRev2_comma) do set %%v=
goto :eof

:getDig1
set _digit1=%2
set _digit2=
for %%d in (/%_valueRev2%0) do call %0 :getDig2 %%d

set _len=%_carry%
call %0 :lenAddDigit %_digit1%
call %0 :lenAddDigit %_digit2%
call %0 :len2val
set _result=%_val%%_result%
goto :eof

:getDig2
if not "%_digit2%"==" set _valueRev2=%2
if "%_digit2%"=="" set _digit2=%2
goto :eof

:lenAddDigit
if %2==1 set _len=%_len%#
if %2==2 set _len=%_len%##
if %2==3 set _len=%_len%###
if %2==4 set _len=%_len%####
if %2==5 set _len=%_len%#####
if %2==6 set _len=%_len%######
if %2==7 set _len=%_len%#######
if %2==8 set _len=%_len%########
if %2==9 set _len=%_len%#########
goto :eof

:len2val
set _carry=
set _val=
if %_len%.==. set _val=0
if %_len%.==. goto :eof
if %_len%==# set _val=1
if %_len%==## set _val=2
if %_len%==### set _val=3
if %_len%==#### set _val=4
if %_len%==##### set _val=5
if %_len%==###### set _val=6
if %_len%==####### set _val=7
if %_len%==######## set _val=8
if %_len%==######### set _val=9
if NOT "%_val%"=="" goto :eof
set _carry=#

if %_len%==########## set _val=0
if %_len%==########### set _val=1
if %_len%==############ set _val=2
if %_len%==############# set _val=3
if %_len%==############## set _val=4
if %_len%==############### set _val=5
if %_len%==################ set _val=6
if %_len%==################# set _val=7
if %_len%==################## set _val=8
if %_len%==################### set _val=9
goto :eof

:eof

Tested successfully on a MS-DOS 6.22 (VMWare)

#Limitations of MS-DOS 6.22

  1. IF doesn't support ELSE

    Workaround:

     IF %1==b echo It is equal
     IF NOT %1==b echo It isn't equal
    
  2. Only goto can jump to a label, CALL can only start another batch.

    Workaround:

    Put something like this into the first line of your batch

     FOR %%P in (/%1) do IF %%P==: goto %1
     ...
     REM This calls the current batch file and jumps to a label
     CALL %0 :myLabel arg1
     ...
     :myLabel
     echo arg1=%2
     echo Action1
     echo Action2
     goto :eof
    
  3. No code blocks, like

     FOR %%a in (1 2 3 ) do ( 
       set concat=%%a
       echo %concat%
     )
    

    Workaround:

     FOR %%a in (1 2 3 ) do CALL %0 :myFunc %%a
    
  4. No indirect expansion of variables

    Workaround:

     set var=content
     set indirect=var
      > temp$$$.bat echo set result=%%%indirect%%%
     call temp$$$.bat
     echo result=%result%
    
like image 98
jeb Avatar answered Oct 05 '22 04:10

jeb


If you're trying to do this from actual DOS (and not Windows's emulation from the 32-bit era), it's simply not possible, unless you manually handle each possible pair of numbers you could have as input (which grows unmanageable when you go above the single-digits).

This was always a large deficiency in DOS's batch files, which was usually remedied by calling small scripts in actual scripting languages (such as BASIC), often being written out by the same .bat file that called them. This, of course, requires having an interpreter for your language of choice.

like image 40
aaaaaa123456789 Avatar answered Oct 05 '22 02:10

aaaaaa123456789