Magic with BASIC in Batch Files |

Let us assume that you spend a lot of time at the DOS prompt.
Either your PC is old and slow, or you have a ~~DOS-capable~~ ~~hand-held~~
device, or you prefer to perform ~~file-maintenance~~ tasks in a DOS window,
~~or —~~ heaven ~~forbid —~~ you simply love DOS. Anyone who
programs in BASIC should fall into one of these categories.

Creating your own program is great, but having to load the BASIC interpreter in order to execute the code might not be so great. If all that you desire is some sort of little utility that performs a short task, then the hassle might not be worth it. If you cannot compile your code, or you need to limit the file sizes, then your options are limited. Also, there is no way to supply command-line instructions to the BASIC interpreter. What can you do?

One solution is the batch file. It is possible to run GW-BASIC, load and
execute a program with parameters supplied at the DOS prompt, close down BASIC,
delete temporary files, and return control to the DOS ~~prompt —~~ all within
a fraction of a second, and with all internal activity transparent to the
user! Moreover, it's ~~easy —~~ and fun.

Here is one way to accomplish the mission:

- Create a batch file to input any desired parameters and store them in a temporary file.
- Write a BASIC program that performs the desired task. It also will need to open and read the parameter file, and know what to do with the data.
- Have the batch file delete the temporary files, then exit.

Let's try a simple example. Either you are studying probability in
school, or you play a lot of fancy keno tickets. So you have occasion to
calculate the combinations of **N** things, taken **R**
at a time. (Example: if you have 5 marbles of different colors, how many
~~2-color~~ combination are there?) The objective is to be able to enter
something such as ~~COMBO 14 5~~ at the DOS prompt,
and have the answer printed on the screen. Here is a workable batch file:

:COMBO.BAT (combinations of N things R at a time)

@echo off

set f=c:\temp\parm

echo %1 > %f%

echo %2 >> %f%

gwbasic c:\prgmfile\combo

del %f%

set f=

This page is not intended as a tutorial on batch-file protocols, as that information can be found on a batzillion other pages; nevertheless, I will explain briefly:

- Yes, I have used a colon, rather than "rem," to start a title line.
Big deal. It doesn't hurt anything to create a label that never is
used as one, and it's much
~~cleaner-looking.~~If it makes you feel better, use a~~double-colon;~~such lines are ignored by DOS. In any case, I hate seeing the word "rem" cluttering my listings; so I never use it to comment anything. REM does have one useful function, though, as we shall see later. - Variable f is set equal to the path of the output file. This is not required, but it cleans up some subsequent lines.
- %1 and %2 are the command-line parameters supplied by the user.
- The echo command is DOS's way of sending data somewhere.
- The first redirect symbol (>) means "to" or "into"; it creates a new file with the specified name, even if it already exists.
- The second redirect (>>) means "append to the file", so the second number is added to existing data, starting on a new line.
- BASIC is run, and C:\PRGMFILE\COMBO.BAS is loaded and executed.
- Finally, the temporary file and environment variable are erased, and the process is complete.

Now, let's create COMBO.BAS:

10 '---[ Combo = combinations of N things R at a time]--- |

11 ' |

20 OPEN "i",1,"C:\TEMP\PARM" |

30 INPUT$ #1,N$: N=VAL(N$) |

40 INPUT$ #1,R$: R=VAL(R$) |

49 ' |

50 COMBO=N |

60 FOR J=2 TO R |

70 COMBO=COMBO*(N+1-J)/J |

80 NEXT J |

89 ' |

90 PRINT "Combinations:" COMBO |

99 SYSTEM |

Place this file in the directory indicated in the batch file, and you are
ready to test your new system. At the DOS prompt, enter
~~COMBO 8 3~~, with one or more spaces between the
parameters, and almost instantaneously the text
~~Combinations: 56~~ is output to the screen.
Surely enough, 8 items can be selected 3 at a time in 56 unique ways. It works!

Observe, however, that the input must make sense. Should you enter
something other than integers,the result will be nonsensical. Garbage in,
garbage out. ~~Error-trapping~~ of input always is desirable,
and we'll do some of that in the next exercise.

This routine can easily be augmented to include calculations for Permutations and Factorials. I have done that in a file available for downloading (see end of page).

This next project is admittedly an esoteric one. If you are comfortable
with BASIC and not with batch files, then you might prefer to stick with the
method just covered. However, those interested in ~~batch-file~~ programming
will find this method more interesting.

The goal is to create a system that extracts the prime factors of an integer. That will be more fun than calculating combinations. However, unlike COMBO, the BASIC program will be created within the batch file itself! The procedure is somewhat more complicated, but it results in a cleaner setup in that there is no BASIC program to store. Here is our simple algorithm:

- An integer X is divided by 2 as many times as possible, then by the successive odd numbers.
- The procedure continues until either X is reduced to a value of 1, wherein factoring will be complete, or the square root of X is reached by the divisor, indicating that X is prime.
- Output will list the prime factors, plus any exponents greater than 1.

In the most efficient setup, the divisors would be the successive primes, but that really isn't necessary for our purposes. You will find that factoring integers up to 11 or 12 digits runs plenty fast even with this minimal structure, and without being compiled. The crux of our algorithm:

{ N is the number to be factored. X is set equal to N. D is the divisor. E is the exponent }

300 WHILE X>=D^2 AND X>1 |

310 D=D+1-(D<>2): E=0 |

320 IF X/D=INT(X/D) THEN X=X/D: E=E+1: GOTO 320 |

330 IF E THEN F$=F$+""+STR$(D) |

340 IF E>1 THEN F$=F$+"^"+RIGHT$(STR$(E),LEN(STR$(E))-1) |

350 WEND |

399 ' |

400 IF X<>N AND X<>1 THEN F$=F$+""+STR$(X) |

410 IF X<>N THEN PRINT "Prime factors:" F$ |

420 IF X=N THEN PRINT TAB(3); N; "is prime." |

430 END |

Before writing the batch file, let us establish another couple of useful protocols. Let's decide to name all temporary files as "$----"; that way, they always will be recognizable as such. Let's also plan always to put them in the directory C:\TEMP (or whatever you prefer). It also is useful to include a Help screen in the batch file, lest the user forget what the program does or how the input should be structured.

But first, there are a couple of snags to overcome. The BASIC '>' and
'<' symbols cannot be used as text within a batch file, unless they are enclosed
in quotes. Also, the crummy ~~DOS-equivalent~~ featured in
Windows XP chokes on (that is, ignores) the carat '^' symbol, unless it also is inside
quotes. Earlier versions of Windows didn't have this problem; eventually, Microsoft
will succeed in eliminating the Windows ~~command-prompt~~ entirely,
which will force us DOS lovers to set up a ~~dual-boot~~ system with DOS ~~6.22~~
or Windows 98. Perhaps you already have done that; it's easy enough.

Meanwhile, it will be necessary to code exponential functions and certain relational
expressions in other ways. An expression such as ~~D^2~~ can be written as
~~D*D,~~ so we will do that (larger or fractional exponents also could be
accommodated by the use of LOG and EXP). Relational expressions can be converted
to something workable by judicious use of the ~~absolute-value~~ construct.

While we're at it, let's include a little Help screen. Here is a working batch file:

:FACTORS.BAT (extracts prime factors)

@echo off

if %1!==! goto Help

set f=c:\temp\$factors.bas

echo 1 defdbl a-z: n=%1: x=n: color 14,1:
? > %f%

echo 2 while x-d*d = abs(x-d*d): e=0: if d=2
then d=3 else d=d+2 >> %f%

echo 3 if x/d = int(x/d) then x=x/d: e=e+1: goto 3
>> %f%

echo 4 if e then ? d;: if e-2 =
abs(e-2) then ? "^" E; >> %f%

echo 5 wend: ? x;: if x=n then ? "is prime." >>
%f%

echo 6 system >> %f%

gwbasic.exe %f%

del %f%

set f=

goto End

:Help

echo.

echo Usage: FACTORS positive integer (15-digit max)

echo.

:End

Explanation:

- The extra spacing in the program code is solely for readability on this page. Ideally, all redundant spaces would be eliminated. Combining program statements on lines saves time for both DOS and BASIC.
- Testing for existence of a parameter (%1) directs control to the Help section when none was entered.
- The temporary program will be $FACTORS.BAS.
- DEFDBL eliminates the need to flag variables as X#, Y#, etc.
- 1. N is the integer to be factored, and a nice yellow-on-blue output is selected.
- 1. The smaller the program, the faster it will load. GW-BASIC expands any '?' character to 'PRINT' as it loads the file.
- 2. '>=' cannot be used; substituting 'X-D*D = ABS(X-D*D)' guarantees that X > D^2.
- 2. The exponent is initialized at 0.
- 3. X is tested for divisibility by D, and the exponent E is incremented.
This line combines the BASIC lines 340 and 350. The program runs
**much**faster this way. I separated them in the BASIC listing only for readability. - 4. The expression 'E-2 = ABS(E-2)' fails if E<2. Showing an exponent of 1 would be redundant.
- 5. 'IF X=N' determines whether any divisions have been made.

I did promise some error-trapping capability, so let us finish up by
restricting user input to as appropriate number. ~~GW-BASIC~~
~~double-precision~~ stores 17 digits, but will print only 16.
My testing has shown that this routine fails on certain ~~16-digit~~
numbers, so let us arbitrarily limit the size to 15 digits. Also,
negative numbers and ~~non-integers~~ are unacceptable. Here is an
updated program, which will catch most errors:

:FACTORS.BAT (extracts prime factors)

@echo off

if %1!==! goto Help

set d=c:\temp\

set f=$factors.bas

echo 1 on error goto 10: if not %1-2 =
abs(%1-2) goto 10 > %f%

echo 2 if not %1 = int(%1) goto 10 >> %f%

echo 3 z=log(1E+15): if not z-log(%1) = abs(z-log(%1)) goto 10
>> %f%

echo 4 defdbl a-z: n=%1: x=n: color 14,1:
? > %f%

echo 5 while x-d*d = abs(x-d*d): e=0: if d=2 then
d=3 else d=d+2 >> %f%

echo 6 if x/d = int(x/d) then x=x/d: e=e+1: goto 6 >>
%f%

echo 7 if e then ? d;: if e-2 = abs(e-2)
then ? "^" E; >> %f%

echo 8 wend: ? x;: if x=n then ? "%1 is prime."
>> %f%

echo 9 system >> %f%

echo 10 shell "rem > %d%$err":
system >> %f%

gwbasic.exe %f%

if not exist %d%$err goto Cleanup

:Help

echo.

echo Usage: FACTORS positive integer (15-digit max)

echo.

:Cleanup

if exist %d%$*.* del %d%$*.*

set f=

set d=

Explanation:

- 1 An ON ERROR statement is useful in any program, as a way of
trapping unanticipated errors. The
~~'%1-2 = abs(%1-2)'~~guarantees that N is greater than 1. - 2 '%1 = int(%1) fails if N is not an integer.
- 3 Having decided that 10^15-1 is the largest permissible integer. Execution is terminated if the logarithm of N is greater than that of the maximum, indicating that N is too large.
- In BASIC, these three conditions could have been trapped easily by a
statement such as,
~~'IF N<1 OR N >= 10^15 OR N <> INT(N)';~~The restrictions on usage of "<" and ">" necessitated creative measures. - 10 If any error is detected, line 10 creates the file $ERR as a way
of telling DOS that an error was encountered. The usage of REM here is
an undocumented method for creating a file of zero length. We don't
care what's in the
~~file —~~merely that it exists. - After BASIC quits, the batch file checks for the presence of $ERR. If it is there, the Help screen is printed.

So there you have it. At the command prompt, enter ~~
FACTOR 16790123457~~, and up pops a listing of the three prime components:
~~3 ^ 2 17 ^ 3 379721~~.

Try it again: ~~FACTOR 16790123473.~~ This runs
somewhat slower, then produces the message: ~~16790123473
is prime~~.

It's all a matter of total loops. The more lower-numbered factors, the faster
the process will be completed. Should you try
~~FACTOR 167901234579971~~, it will run for a lot longer time,
because that number also is prime. Each extra digit potentially increases the
runtime by a factor of 5. This particular calculation requires 12 seconds on my PC,
even when compiled. But anything up to 13 digits spits out a solution immediately.

I include two other utilities that you might find useful:

– MATH.BAT –

Do you miss the ability to actually calculate something from the
DOS prompt? Now you can. Virtually any math problem that BASIC can
understand may be entered at the DOS prompt. For example, enter
~~MATH 380 +16*LOG(27/4) -9.5~~; the screen will clear,
then will display both the problem and its solution:
~~380 +16*LOG(27/4) -9.5 = 372.4096~~

Enter MATH by itself for
a listing of all the available functions, plus a couple of extras, such as using
P=pi and R=radians. But remember the legacy of XP; the carat '^' cannot be
used. To calculate, for example, 3^4.5, enter ~~
MATH EXP(LOG(3)*4.5)~~. The answer will be displayed:
140.2961.

– AMORT.BAT –

With this one, you simply enter an amount to finance, interest rate, and term, and it will display the monthly charge on the principal.

*Download:***Batches.zip**
All four batch files