Copy Link
Add to Bookmark
Report
QBNews Volume 1 Number 5
Volume 1, Number 5 December 1, 1990
**************************************************
* *
* QBNews *
* *
* International QuickBASIC Electronic *
* Newsleter *
* *
* Dedicated to promoting QuickBASIC around *
* the world *
* *
**************************************************
The QBNews is an electronic newsletter published by Clearware
Computing. It can be freely distributed providing NO CHARGE is charged
for distribution. The QBNews is copyrighted in full by Clearware
Computing. The authors hold the copyright to their individual
articles. All program code appearing in QBNews is released into the
public domain. You may do what you wish with the code except
copyright it. QBNews must be distributed whole and unmodified.
You can write The QBNews at:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Copyright (c) 1990 by Clearware Computing.
The QBNews Page i
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
T A B L E O F C O N T E N T S
1. From the Editor's Desk
And the winner is . . . ...................................... 1
2. Beginners Corner
Common Questions about QuickBASIC by Tom Hanlin .............. 2
How to use Libraries in QuickBASIC by Tom Hanlin ............. 4
3. Advertisement
Crescent Software, 32 Seventy Acres, West Redding, CT 06896 . 6
4. Swap Shop
Graphics and text screen dumps by Alan J. Fridlund, Ph.D. .... 7
Saving and loading .PCX files for EGA screen 9 by Greg Harder 9
Getting the .PCX palette info by Dwain Goforth ............... 11
DBase III file viewer by David Perry ......................... 11
A Quick Basic archive file viewer by Dick Dennison ........... 12
5. Who ya gonna call? CALL INTERRUPT
Format Floppy Disks with QB by Cornel Huth .................. 12
6. Power Programming
Scenic Views by way of the Video Map by Larry Stone .......... 14
Self-Cloning Exe's Revisted by Ronny Ong ..................... 18
7. Engineers Corner
GPIB Instrument control from IOTech by Dave Cleary ........... 20
8. New and Noteworthy
GEOGRAF Level One from GEOCOMP Corporation ................... 24
9. And I Heard it Through the Grapevine
Exerpts from the QUIK_BAS echo ............................... 25
10. EOF
Receiving The QBNews ......................................... 36
Advertising in The QBNews .................................... 37
Submitting Articles to The QBNews ............................ 37
The QBNews Page ii
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
F r o m t h e E d i t o r ' s D e s k
----------------------------------------------------------------------
And the winner is . . .
The winner of the QBNews Reader Contest was Bruce Guthrie of
Silver Spring, MD. I'd like to say congratulations to Bruce and I
would like to thank all those who entered. I was disappointed with the
quantity of entries, but not with the quality. I received entries from
all over the U.S. and Canada plus three other continents. It makes me
happy to see that all the hard work the authors put into their
articles is appreciated.
This marks the last issue of volume one. I have decided to commit
to one more year of putting out the QBNews, so I am going to be
offering subscriptions for volume two. I don't have the time to
process disk orders as they come in, so volume two will only be
available on disk by buying a whole subscription. Details of this can
be found in the back of the newsletter. Of course, the QBNews will
still be distributed free through BBS's.
As always, the QBNews is looking for new authors. I find that
most of the submissions I receive are a result of direct requests to
the author from me. I am running out of people I can coerce (er ... I
mean ask) to write articles. Please support the QBNews by contributing
your time and effort into writing articles. Details on submitting
articles can be found in the back of the newsletter.
Dave Cleary
The QBNews Page 1
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
B e g i n n e r s C o r n e r
----------------------------------------------------------------------
Common Questions about QuickBASIC by Tom Hanlin
After spending much time on CompuServe, BIX, the FidoNet QuickBASIC
echo and other national BASIC forums, I've noticed that there is a lot
of repetition. People ask the same questions, time after time. They
must be good questions! Here is a compilation of a few of the more
common questions.
Question: How can I disable Control-Break?
Answer: Programs compiled with QuickBASIC or BASCOM usually don't have
to worry about this. Control-Break is disabled unless you compile
with the /D (debug) option. In the event that you are doing something
that QuickBASIC doesn't completely control, like printing to the
screen via DOS functions, this protection no longer holds. In that
case, you may be able to disable Break by getting DOS to check for it
less frequently. Use the command BREAK OFF from a batch file, or
execute it from BASIC like so: SHELL "COMMAND BREAK OFF"
Question: How can I get the error level from a SHELLed program? How
can I get my program to return an error level?
Answer: You can't. More accurately, you can only do it with assembly
language routines.
Question: How can I get a directory listing into an array?
Answer: Most BASIC libraries can do this for you. Another way to do
this is to put the directory listing into a file by SHELL "COMMAND DIR
*.* >DIRLIST.TXT" and then read the file into an array. Yet another
alternative is to use the FILES statement on a non-displayed screen
page (if you have a CGA, EGA or VGA) or in invisible colors (say,
black on black), then get the results off the screen with the SCREEN
function.
Question: How can I see if a file exists?
Answer: Most BASIC libraries can do this for you. Or, you can use the
directory approach given above. Yet another way to do it is to try to
open the file for input:
ON ERROR GOTO NotFound
OPEN File$ FOR INPUT AS #1
CLOSE #1
Found = -1
Done:
RETURN
The QBNews Page 2
Volume 1, Number 5 December 1, 1990
NotFound:
Found = 0
RESUME Done
Question: I'm running out of string space. What can I do?
Answer: If you have arrays, try moving them outside of the string
space area. Either use REDIM to dimension 'em or use the REM $DYNAMIC
metacommand. If this doesn't help enough, use fixed-length strings,
which are stored outside the regular string area. Still not enough
room? Well, you can buy Microsoft's BASCOM 7.0 "Professional
Development System", which will set you back about $300.
Question: I'd like to constantly display the time. What do I do?
Answer: That's also available in libraries (gee, aren't libraries
great?!). You can do it yourself using an approach like this:
ON TIMER(1) GOSUB DisplayTime
TIMER ON
' your program goes here
DisplayTime:
OldRow = CSRLIN
OldCol = POS(0)
LOCATE 25, 70
PRINT TIME$;
LOCATE OldRow, OldCol
RETURN
Question: I need to know how many days lie in between two dates. How
do I do it?
Answer: As usual... this is something you can get in a library from
your local BBS. Try QB4BAS. It's quite possible to do it in BASIC,
but I can never remember the proper formulae... you need to account
for leap years and leap centuries, so it isn't as straightforward as
you might guess.
Question: How can I use ANSI display codes?
Answer: You need to go through DOS display functions for that to work.
Use this: OPEN "CON" FOR OUTPUT AS #1 This makes the DOS display
functions available as file (device) number one. You can print to it
using normal file statements: PRINT #1, CHR$(27); "[2J"; The above
statement will clear the screen if an ANSI driver is installed. See
your DOS manual for information on the available ANSI codes. You can
also get this information from your friendly local BBS.
The QBNews Page 3
Volume 1, Number 5 December 1, 1990
How to use Libraries in QuickBASIC by Tom Hanlin
So you've never used a library before and you want to know what
gives?
A library is a collection of routines, whether written in BASIC,
assembly language, or some other language altogether. It provides a
convenient way to allow different programs to use the same sets of
standard or special-purpose routines (subprograms or functions, in
BASIC parlance).
There are two forms of libraries for QuickBASIC. The form with
the extension ".LIB" is for use with LINK, for creating stand-alone
programs which do not require the QuickBASIC environment. This sort
of library can be made or manipulated using the LIB utility provided
with QuickBASIC. The form of library with the extension ".QLB" is for
use in the QuickBASIC environment. It is created with LINK and
(unfortunately) can't be manipulated at all.
To use a QLB library, you specify the /L parameter when starting
up QB:
QB /L BASWIZ
You can optionally include the name of your program before the /L
switch.
To use a LIB library, you specify the name of the library when
you LINK your program. Either let LINK prompt you for the library or
type something like this:
BC program/O; (or whatever)
LINK program/EX,,NUL,BASWIZ
If you are in the QuickBASIC environment and direct the compiler
to produce an .EXE file, it will automatically link the library for
you if you started up QB with the /L option.
Suppose you have more than one library that you wish to use?
Well, provided that you have both of the libraries in .LIB form, this
presents no problem. To create a combined .LIB library, use the LIB
utility to extract all of the .OBJ files from one .LIB and add them to
the other one. You can convert the new combined library to .QLB form
by using a special LINK syntax:
LINK combined.LIB/Q,,NUL,BQLB45
The last two digits of "BQLBxx" represent the version of the
compiler that you have. It doesn't necessarily match the formal
version number, though, so you might just want to use DIR and see what
the name of the file really is. BQLBxx.LIB is one of the files that
comes with QuickBASIC.
If you experience a LINK error, make sure that you're using the
The QBNews Page 4
Volume 1, Number 5 December 1, 1990
current version of LINK. I've heard from many people who turn out to
have the wrong version of LINK in their PATH somewhere... when LINK
starts up, it will display its version number on the screen. The
version should be around 3.69 as of QuickBASIC 4.5. You must use the
LINK that came with QuickBASIC-- the one that comes with Quick C is
incompatible and the one that came with BASCOM 6.0 (the one with two
periods in the version number) has a few bugs.
All clear? No?! Check your QuickBASIC manual for more
information!
**********************************************************************
Tom Hanlin is the author of the ADVBAS and BASWIZ shareware
libraries, among others. He can be reached through the QUIK_BAS echo
on Fidonet or in care of this newsletter.
**********************************************************************
The QBNews Page 5
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
A d v e r t i s e m e n t
----------------------------------------------------------------------
STAR PROGRAMMERS REACH FOR THE MOON!
Crescent Software publishes the highest quality support products
available for use with QuickBASIC and BASIC 7 PDS. We offer twelve
different libraries, and all are extremely easy to use. Our software
has received outstanding reviews in all of the major computer
publications, including PC Magazine, Byte, Dr. Dobb's Journal, PC
Resource, and too many others to mention here. Our two most popular
products are described briefly below. Please call or write for more
information. We offer tools for screen design, graphics, scientific
applications, and more. All Crescent Software products come with full
commented source code, and require no royalty payments when added to
your own programs. Free technical support is included.
QuickPak Professional ($169) is the most comprehensive collection of
QuickBASIC tools ever developed. It features more than 450 routines
you can add to your own programs, a beautifully typeset manual in an
IBM-style D-ring binder, and 120 demonstration programs. Included are
routines for searching and sorting any type of array, DOS services for
extremely fast file access, sophisticated pull-down and vertical menus
with integrated mouse support, and fast video routines that work in
the 25-, 43-, or 50-line EGA and VGA text modes. Also included are a
real word processor you can add to your programs, a graphics-mode
screen print routine that supports all BASIC video modes, routines to
read and write Lotus 1-2-3 .WKS files, an assembly language tutorial,
and much more. This is our most popular library, and it offers a
wealth of functionality and educational value. Fully commented BASIC
and assembler source is included. QuickPak Professional requires
QuickBASIC 4.0 or later, or BASIC 7 PDS (the PDS version costs $199).
P.D.Q. ($129) is a replacement for the BCOM libraries that come with
QuickBASIC, and it lets you write programs in BASIC that are smaller
and more efficient than any other high-level language. P.D.Q. also
lets you easily create TSR programs and interrupt handlers. Minimum
tasks can be written in 1K. P.D.Q. programs are much smaller than an
equivalent written in C, and are as little as one-tenth the size of a
QuickBASIC counterpart. Of course, they are also very fast. Numerous
sample BASIC applications are provided, including a TSR screen capture
program, a pop-up calculator, work-alike copies of several Norton
Utilities, and much more. Because we also include the complete
library source code, examining P.D.Q. is an excellent way to learn
about BASIC's internal workings. Please note that P.D.Q. is a subset
of Microsoft BASIC, and does not support floating point math. A
communications toolbox is available separately for $79. P.D.Q.
requires QuickBASIC 4.0 or later, or BASIC 7.x PDS.
Please add $6 per order for 2nd day UPS shipping in the US.
Crescent Software, 32 Seventy Acres, West Redding, CT 06896
Phone: 203-438-5300, FAX: 203-431-4626, CompuServe 72657,3070
The QBNews Page 6
----------------------------------------------------------------------
S w a p S h o p
----------------------------------------------------------------------
'Graphics and text screen dumps by Alan J. Fridlund, Ph.D.
DEFINT A-Z
SUB DumpScr (DisplayType, PrinterType$) STATIC
'Subroutine DumpScr.
'Alan J. Fridlund, Ph.D., April-August, 1988.
'Adapted from routine by Charles Petzold in PC Magazine,
'Vol 6, No 2, Jan 27, 1987.
'QuickBasic 4.0 Graphics or Text Screen Dumps to:
' Epson (EPS), IBM Proprinter (IBM), or HP LaserJet (HP) printers.
'Dumps graphics screens in landscape (sideways) mode.
'DisplayType:
' 0 = CGA 200x640 pixel mode (SCREEN 2).
' 1 = EGA 200x640 pixel mode (SCREEN 8).
' 2 = EGA 350x640 pixel mode (SCREEN 9).
' 3 = VGA 480x640 pixel mode (SCREEN 11 or 12).
' 4 = Text screens for all display types.
'PrinterType$:
' "EPS" = Epson-compatible dot matrix printer.
' "IBM" = IBM Proprinter-compatible printer.
' "HPL" = Hewlett-Packard LaserJet printer w/ 75 dpi graphics.
IF DisplayType = 0 OR DisplayType = 1 THEN BottomPixel = 199: NTAB = 8
IF DisplayType = 2 THEN BottomPixel = 349: NTAB = 12
IF DisplayType = 3 THEN BottomPixel = 479: NTAB = 0
Esc$ = CHR$(27)
IF DisplayType = 4 THEN
WIDTH LPRINT 80
LPRINT STRING$(9, 13) 'Center dump on page.
FOR ROW = 1 TO 25
FOR COL = 1 TO 80
KIN$ = INKEY$: IF KIN$ = Esc$ THEN GOTO GraphEnd'Esc terminates.
CHARACTER = SCREEN(ROW, COL)
CHAR$ = "-" 'Substitute for unprintable chars.
IF CHARACTER > 31 AND CHARACTER < 126 THEN
CHAR$ = CHR$(CHARACTER)
END IF
LPRINT CHAR$;
NEXT
NEXT
END IF
IF DisplayType < 4 AND (PrinterType$ = "EPS" OR PrinterType$ = "IBM")_
THEN
The QBNews Page 7
Volume 1, Number 5 December 1, 1990
WIDTH LPRINT 255
LPRINT Esc$ + "@": LPRINT STRING$(5, 13)'Reset printer, center graph.
PIXEL400$ = Esc$ + CHR$(75) + CHR$(144) + CHR$(1)'400 pixels perline.
PIXEL350$ = Esc$ + CHR$(75) + CHR$(94) + CHR$(1)'350 pixels per line.
PIXEL480$ = Esc$ + CHR$(75) + CHR$(224) + CHR$(1)'480 pixels perline.
IF DisplayType < 2 THEN NPIXEL$ = PIXEL400$'CGA pixels doubleprinted.
IF DisplayType = 2 THEN NPIXEL$ = PIXEL350$
IF DisplayType = 3 THEN NPIXEL$ = PIXEL480$
NormSp$ = Esc$ + CHR$(65) + CHR$(12) 'Normal line spacing.
NarrSp$ = Esc$ + CHR$(65) + CHR$(8)'Narrow line spacing for graphics.
IF PrinterType$ = "IBM" THEN
NormSp$ = NormSp$ + Esc$ + CHR$(50)
NarrSp$ = NarrSp$ + Esc$ + CHR$(50)
END IF
LPRINT NarrSp$
FOR COL = 0 TO 639 STEP 8
LPRINT TAB(NTAB);
LPRINT NPIXEL$;
FOR ROW = BottomPixel TO 0 STEP -1
KIN$ = INKEY$: IF KIN$ = Esc$ THEN GOTO GraphEnd
BYTE = 0
FOR PIXEL = 0 TO 7
IF POINT(COL + PIXEL, ROW) > 0 THEN
BYTE = BYTE OR 2 ^ (7 - PIXEL)
END IF
NEXT
LPRINT CHR$(BYTE);
IF DisplayType < 2 THEN LPRINT CHR$(BYTE);
NEXT 'CGA/lowres EGA pixels
LPRINT 'are double-printed.
NEXT
LPRINT NormSp$;
END IF
IF DisplayType < 4 AND PrinterType$ = "HPL" THEN
WIDTH LPRINT 255
IF DisplayType < 2 THEN NPIXEL$ = Esc$ + "*p400x300Y"'Center cursor.
IF DisplayType = 2 THEN NPIXEL$ = Esc$ + "*p510x300Y"
IF DisplayType = 3 THEN NPIXEL$ = Esc$ + "*p240x300Y"
NPIXEL$ = NPIXEL$ + Esc$ + "*t75R" + Esc$ + "*r1A"'Start 75 dpi mode
LPRINT NPIXEL$
IF DisplayType < 2 THEN NPIXEL$ = Esc$ + "*b50W" 'Expect xxW pixels.
IF DisplayType = 2 THEN NPIXEL$ = Esc$ + "*b44W"
IF DisplayType = 3 THEN NPIXEL$ = Esc$ + "*b60W"
FOR COL = 0 TO 639
KIN$ = INKEY$: IF KIN$ = Esc$ THEN GOTO GraphEnd
LPRINT NPIXEL$;
FOR ROW = BottomPixel TO 0 STEP -8
IF DisplayType < 2 THEN 'Separate point into 2 bytes
HIBYTE = 0: LOBYTE = 0 ' for CGA/low-res EGA modes.
FOR PIXEL = 0 TO 7
IF POINT(COL, ROW - PIXEL) > 0 THEN
IF PIXEL <= 3 THEN
The QBNews Page 8
Volume 1, Number 5 December 1, 1990
LOBYTE = LOBYTE OR 2 ^ ((3 - PIXEL) * 2) OR _
2 ^ ((4 - PIXEL) * 2 - 1)
END IF
IF PIXEL >= 4 THEN
HIBYTE = HIBYTE OR 2 ^ ((7 - PIXEL) * 2) OR _
2 ^ ((8 - PIXEL) * 2 - 1)
END IF
END IF
NEXT
BYT$ = CHR$(LOBYTE) + CHR$(HIBYTE)
LPRINT BYT$;
END IF
IF DisplayType >= 2 THEN
LOBYTE = 0
FOR PIXEL = 0 TO 7
IF POINT(COL, ROW - PIXEL) > 0 THEN
LOBYTE = LOBYTE OR 2 ^ (7 - PIXEL)
END IF
NEXT
LPRINT CHR$(LOBYTE);
END IF
NEXT
NEXT
LPRINT Esc$; "*rB"; Esc$; "E" 'Return to text mode.
END IF
GraphEnd:
LPRINT CHR$(12); 'Page eject.
SOUND 1000, 1 'Signal termination.
WIDTH LPRINT 80
END SUB
----------------------------------------------------------------------
'PCX SAVE & PCX LOAD FOR EGA SCREEN 9 (640 x 350, 16 COLOR)
'BY G.C.HARDER, RE-ENGINEERED FROM C SOURCE IN
' "FRACTAL PROGRAMMING IN C"
DEFINT A-Z
DECLARE SUB PCXSAVE (File$, Pal.Array%())
DECLARE SUB PCXLOAD (File$, Pal.Array%())
SCREEN 9, , 0
DIM Pal.Array%(15)
FOR I% = 0 TO 15: READ Pal.Array%(I%): NEXT
FOR A = 10 TO 360 STEP 10
X = 320 + 48 * 2 * COS(A * .017453)
Y = 175 + 40 * 1.75 * SIN(A * .017453)
CIRCLE (X, Y), 120, RND * 15 + 1
NEXT
PCXSAVE "DEMO.PCX", Pal.Array%()
CLS
PCXLOAD "DEMO.PCX", Pal.Array%()
'default Palette Colors
DATA 0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63
'----------------------------------------------------------------
The QBNews Page 9
Volume 1, Number 5 December 1, 1990
SUB PCXLOAD (File$, Pal.Array%()) STATIC
SCREEN 9, , 0: OPEN File$ FOR BINARY AS #1: SEEK #1, 17
DIM Byte AS STRING * 1
FOR I% = 0 TO 15
GET #1, , Byte: Red% = ASC(Byte) / 85
GET #1, , Byte: Green% = ASC(Byte) / 85
GET #1, , Byte: Blue% = ASC(Byte) / 85
Red% = ((Red% AND 1) * 32) OR ((Red% AND 2) * 2)
Green% = ((Green% AND 1) * 16) OR (Green% AND 2)
Blue% = ((Blue% AND 1) * 8) OR ((Blue% AND 2) \ 2)
Hue% = Red% OR Green% OR Blue%: Pal.Array%(I%) = Hue%
NEXT
PALETTE USING Pal.Array%(0): SEEK #1, 129: DEF SEG = &HA000
FOR K% = 0 TO 349
Addr% = 80 * K%: Line.end% = Addr% + 80: J% = 1
DO WHILE J% <= 4
B% = J%
IF J% = 3 THEN B% = 4
IF J% = 4 THEN B% = 8
OUT &H3C4, 2: OUT &H3C5, B%
GET #1, , Byte: Byte.1% = ASC(Byte)
IF (Byte.1% AND 192) <> 192 THEN
POKE Addr%, Byte.1%: Addr% = Addr% + 1
IF Addr% >= Line.end% THEN Addr% = 80 * K%: J% = J% + 1
ELSE
Byte.1% = Byte.1% AND 63
GET #1, , Byte: Byte.2% = ASC(Byte)
FOR M% = 1 TO Byte.1%
B% = J%
IF J% = 3 THEN B% = 4
IF J% = 4 THEN B% = 8
OUT &H3C4, 2: OUT &H3C5, B%: POKE Addr%, Byte.2%
Addr% = Addr% + 1
IF Addr% >= Line.end% THEN Addr% = 80 * K%: J% = J% + 1
NEXT
END IF
LOOP
NEXT
OUT &H3C4, 2: OUT &H3C5, &HF: DEF SEG : CLOSE #1
END SUB
'PCX SAVE ROUTINE
'---------------------------------------------------------------------
SUB PCXSAVE (File$, Pal.Array%()) STATIC
OPEN File$ FOR BINARY AS #1
A$ = CHR$(10) + CHR$(5) + CHR$(1) + CHR$(1): PUT #1, , A$
A% = 0: PUT #1, , A%: PUT #1, , A%: A% = 639: PUT #1, , A%
A% = 349: PUT #1, , A%: A% = 640: PUT #1, , A%: A% = 350: PUT #1, , A%
FOR I% = 0 TO 15
Red% = (((Pal.Array%(I%) AND 32) \ 32) OR _
((Pal.Array%(I%) AND 4) \ 2)) * 85
Green% = (((Pal.Array%(I%) AND 16) \ 16) OR _
(Pal.Array%(I%) AND 2)) * 85
Blue% = (((Pal.Array%(I%) AND 8) \ 8) OR _
The QBNews Page 10
Volume 1, Number 5 December 1, 1990
((Pal.Array%(I%) AND 1) * 2)) * 85
A$ = CHR$(Red%) + CHR$(Green%) + CHR$(Blue%): PUT #1, , A$
NEXT
A$ = CHR$(0) + CHR$(4): PUT #1, , A$: A% = 80: PUT #1, , A%
A% = 0: PUT #1, , A%: A% = 0
FOR I% = 70 TO 127 STEP 2
PUT #1, , A%
NEXT I%
DEF SEG = &HA000
FOR K% = 0 TO 349
SCREEN 9, , 0: Add1% = 80 * K%: Number% = 1: J% = 0
OUT &H3CE, 4: OUT &H3CF, 0: OUT &H3CE, 5: OUT &H3CF, 0
Old% = PEEK(Add1%): Add2% = 1
FOR I% = 1 TO 320
IF I% = 320 THEN
IF Old% <> 1 THEN New% = 1 ELSE New% = 0
ELSE
IF Add2% = 80 THEN J% = J% + 1: Add2% = 0
OUT &H3CE, 4: OUT &H3CF, J%: OUT &H3CE, 5: OUT &H3CF, 0
New% = PEEK(Add1% + Add2%)
END IF
IF New% = Old% AND Number% < 63 THEN
Number% = Number% + 1
ELSE
Num.Out% = (Number% OR 192)
IF (Number% <> 1) OR ((Old% AND 192) = 192) THEN
A$ = CHR$(Num.Out%): PUT #1, , A$
END IF
A$ = CHR$(Old%): PUT #1, , A$: Old% = New%: Number% = 1
END IF
Add2% = Add2% + 1
NEXT
PSET (0, K%), 13: PSET (639, K%), 13
NEXT
OUT &H3CE, 4: OUT &H3CF, 0: DEF SEG : CLOSE #1
END SUB
----------------------------------------------------------------------
'Getting the .PCX palette info by Dwain Goforth
DIM ByteStr AS STRING * 1 'color data is in bytes
OPEN filename$ FOR BINARY AS #1 ' open the PCX file
SEEK #1, 17 'position to start of palette info
FOR k = 0 TO 15
GET #1, , ByteStr 'get the red byte for color k
red = ASC(ByteStr) * 64 \ 256
GET #1, , ByteStr 'get the green byte for color k
green = ASC(ByteStr) * 64 \ 256
GET #1, , ByteStr
blue = ASC(ByteStr) * 64 \ 256 'get the blue byte for color k
PALETTE k, 65536 * blue + 256 * green + red 'now set palette k
NEXT k
----------------------------------------------------------------------
The QBNews Page 11
Volume 1, Number 5 December 1, 1990
'+==============================================+
'| DB.BAS 1/25/88 |
'| David Perry |
'| QuickBASIC 4.0 Source |
'| Compile: BC DB /O/D |
'| Link: LINK /EX DB; |
'| Opens dBASE III .DBF and .DBT files |
'| Reads and displays structure .DBF file |
'| Then reads and displays data to include |
'| up to first 4000 bytes of memo fields |
'| This can be redirected to file or printer |
'| by typing DB FILENAME.DBF>FILEDAT or |
'| DB FILENAME.DBF>PRN |
'| Respects flag for deleted records (may |
'| be modified--see source below) |
'| This is a simple basis for building QB |
'| programs which require reading .DBF files |
'+==============================================+
[EDITOR'S NOTE]
Because of the complexity of this program, it can be found in
the file DB.BAS.
----------------------------------------------------------------------
ZV.BAS : A Quick Basic archive file viewer for MS-DOS machines
author : Dick Dennison [74270,3636] 914-374-3903 3/12/24 24 hrs
supports: ZIP, LZH, ARC, PAK, ZOO archive formats
[EDITOR'S NOTE]
Due to the complexity of the code, the source code can be found in the
file ZV.ZIP.
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
W h o y a g o n n a c a l l ? C A L L I N T E R R U P T
----------------------------------------------------------------------
Format Floppy Disks with QB by Cornel Huth
You just wrote a great new program that does everything you could
possibly want it to do but one thing - format a blank disk. You could
have QB shell to DOS and run FORMAT, but what if FORMAT isn't
available? Even if it is, maybe you'd rather not shell because it
looks sloppy. Other programs can format blank disks so you ought to
be able to do it, too. Right? Well, now you can. QBFORMAT.BAS is a
plug-and-play QB4 module that will format a DOS disk with one simple
function call.
You wil need QB4 or higher and a floppy disk. The code supports
360K drives for XTs and 360K and 1.2M drives for ATs. 720K and 1.44M
3.5- inch drives should format just fine on ATs but without the actual
hardware I can't verify that it does. I also can't find XT-BIOS
support documentation for the 3.5-in drives so you'll have to do the
digging and add the code if you need to support those drives on an XT.
To use the code, call the routine with the drive and media type.
Floppy drives start at 0, i.e., drive A: is 0, B: is 1 (no, your C:
hard drive is not 2, it's 128, so don't worry). The media types are
described in the source by CONST declarations. By doing the same in
the calling program the call to format a disk would be as simple as
this:
xerr% = QBFORMAT%(0, DS9)
IF xerr% THEN
errl% = xerr% \ 256
errc% = xerr% AND 255
END IF
0 is drive A:, DS9 is the media byte for a 360K floppy. The
function returns a multiplexed error code. The high byte is the level
at which the error occurred and the low byte is the BIOS error code.
See the source for more along with descriptions of the level and error
codes.
Somebody goofed when he assigned the media byte for 720K 3.5-inch
floppies. He used the same media byte as the 1.2M 5.25-inch AT
floppy. To differentiate the two, QBFORMAT expects 1.2M media byte
arguments to be positive &HF9 and 720K media byte arguments to be
negative &HF9 (-&HF9). See the source for more.
The source is all QB except for the INTERRUPTX routine. This
routine is supplied by Microsoft in the QB.LIB/QLB file and the source
is INTRPT.ASM. QB 4.00's INTRPT.ASM has 2 bugs, one so bad that it
can not be used with QBFORMAT.BAS. QB 4.00b has one bug, not so bad
that it can't be used with QBFORMAT but it does prevent the error code
from being returned properly if you call INT 25/26h (QBFORMAT calls on
BIOS INT 13h). Included with the QBFORMAT code should be the
The QBNews Page 12
Volume 1, Number 5 December 1, 1990
corrected version of INTRPT.OBJ. Hopefully the ASM source can also be
included (if space allows). Replace your INTRPT.OBJ with this one,
especially if you are using QB 4.00 (initial release).
The code speaks for itself (it does to me). If you're having
trouble understanding the code, drag out the old QB manual and piece
through the code. If the logic behind MS-DOS formatting is difficult
to follow, consult a PC BIOS book such as those by Peter Norton, Ray
Duncan (his Advanced MS-DOS), the Phoenix people or Robert Jourdain
(one alone probably won't do it). PCDOS texts usually won't cover the
BIOS to the required detail so those won't be of much help in the
format process. However, they may provide you with details of the
structure of the boot record, file allocation tables, and root
directory.
**********************************************************************
Cornel Huth is the author of various shareware and commercial
tools for use with QuickBASIC. He can be reached through this
newsletter.
**********************************************************************
[EDITOR'S NOTE]
All code and files for this article can be found in the file
QBFORMAT.ZIP. I have tested this code and found it to work on all disk
types on MY 386. You should thoroughly test this code on any machines
you plan to use. If you find any problems, I am sure Cornel would be
interested in hearing from you.
The QBNews Page 13
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
P o w e r P r o g r a m m i n g
----------------------------------------------------------------------
Scenic Views by way of the Video Map by Larry Stone
Creating an attractive set of screens for your program is, often
times, more important than WHAT your program actually does or doesn't
do. As Marshall McCluine would say, "the medium is the message".
Packaging is everything when selling to the public. After all,
how much research, development, and skill went into the "growing" of
America's favorite pet, the "pet rock"? None. However, plenty of
resources were involved in packaging and promoting it so that the con-
sumer would buy it.
Computer software is packaged twice. The first packaging is the
box itself and is more important for selling games or Vapor-Ware. The
next type of packaging is within the software itself. It is the bells
and whistles, the pizzazz; the sizzle along with the steak. It is what
turns dull, boring, productive software into productive software that
is exciting and fun to use. Our bell and whistle stop will be, where
else - the monitor. To navigate the monitor, we will need a good map,
a video map. Understanding and playing with the video map is the key
to many a bell and a whistle.
The video map holds text mode screens in a simple and redundant
fashion. It is this simplicity and redundancy that allows us to create
dazzling windows that implode, slide, push and pop into view. The map
is an area of memory that can be considered a grid holding character
and color information inside of alternating cells. If we designate a
capital "C" to represent "character" and "A" for "color Attribute", we
could depict the map as:
012345... ...159
CACACACACACACACACACACACACACACACACACACACACACACACACACACACACACA
CACACACACACACACACACACACACACACACACACACACACACACACACACACACACACA
CACACACACACACACACACACACACACACACACACACACACACACACACACACACACACA
Each column contains either character data or color data but not
both. Each "CA" pair represents data for one column-row location on a
monitor. This means that there are 80 pairs per row or, 160 pieces of
information per row. Knowing this makes accessing the map easier. If
we want to read or write to row 1, column 1 (PRINT 1, 1), we go to the
map and put our character into position "0" and our color into "1".
PRINT 1, 80 would have a map address of 158 for the character and 159
for the color. PRINT 2, 1 address would be 160 and 161. An 80x25 mode
screen is mapped from position 0 to 3999 (4000 positions). A screen
in 80x50 starts at 0 and ends at 7999 (8000 positions).
Knowing how the video map stores data makes it easy to build an
array for our windows. The easiest array to build would be an integer
array that corresponds to every element in the map. To create a one
to one array would require an array DIMensioned for 4000 elements with
The QBNews Page 14
Volume 1, Number 5 December 1, 1990
an 80x25 text screen. An array of 8000 elements would be required for
an 80x50 screen. Although these arrays make our programming very easy
due to the one to one correlation, they are, never-the-less, very in-
efficient. This is because a simple integer is a two byte word. The
video map uses one integer to hold information for each "CA" pair. The
high byte holds character information and the low byte holds the color
data. When we make an integer array DIMmed to 4000 elements, there is
4000 bytes of wasted space (each integer is a two byte word - hence,
an array DIMmed to 4000 elements uses 8000 bytes.) What we want is an
2000 elements array that houses 4000 bytes.
Because we are going for memory efficiency, and because we access
into the video map by POKEing one byte at a time, we need a translator
to move data from our arrays to the map and back. In other words,
we will need to combine bytes into integers and extract bytes from
integers. When we do so, we need a convenient method to keep track
of where we are in both the map and the array. I find that the easi-
est way to do this is to simply keep track of where we are in the map
then divide that number by two to correlate it to our position in the
array.
Fancy screen writes are, generally, accomplished by manipulating
data from our array via one or more loops and STEPping through these
loops in a manner that will write our screen in a dazzling manner. The
accompanying code (DAZZLING.BAS and DAZZDEMO.BAS) illustrates eleven
different, dazzling screen writes. Because each of these methods are
performed in two different ways (top to bottom, bottom to top and,
right to left, left to right), the effect is 22 completely different
screen routines in only three subprograms. In addition to the fancy
screen display routines, the code supplies five other useful routines.
ReadBinFile reads a disk file that was formed by a simple binary
dump of the video map. You could create your screens using TheDraw,
save your files using the "BIN" option and read them into your screen
array with ReadBinFile. An 80x25 text screen will produce a 4000 byte
BIN file. This type of file is fast to read into arrays and they are
slightly smaller than a Bsave file (4007 bytes). The two BIN files
used by my sample code, CRESCENT.BIN and SHUTTLE.BIN are re-creations
of screens used by The Crescent Software Support BBS and a modified
shuttle used by TheDraw as one of their samples. The ReadBinFile rou-
tine also does something no others of its ilk do. It can read the
screen to into a row position other than row number one. This allows
a screen that was saved in 80x25 mode to be re-positioned for higher
resolutions (80x43 or 80x50). The sample code, DAZZDEMO, creates 10
leading rows for high resolution. It then uses the StuffMess routine
to fill these leading (and trailing rows). In this manner, one screen
can be saved in a low resolution mode and expanded for high resolution
systems.
The StuffMess subprogram stuffs a message into a screen array
BEFORE it is displayed on the monitor. Pass it the message string,
the array to stuff, and the fore and background colors, and the row
and column location. DAZZDEMO.BAS uses this routine to create a second
story to the QBNews Software Library building and to expand the planet
The QBNews Page 15
Volume 1, Number 5 December 1, 1990
earth when it runs on a video system that supports screen modes 80x43
or 80x50. If you study the accompanying code,you will notice that when
StuffMess adds a second story to the QBNews Library, it uses a string
that is 800 bytes long. The call to StuffMess simply locates the Mess
string at row 1, column 1. StuffMess, in conjunction with the Curtain
routine, produces the illusion of the shuttle doors opening. This is
accomplished by filling the monitor with the bytes from the array with
the shuttle picture. Once the picture is displayed, StuffMess is used
to "redraw" that portion of the array that contains the shuttle doors.
The array is, again, sent to the monitor only, this time, it is dis-
played over the original shuttle picture with a call to the Curtain
routine. The Curtain routine redisplays the shuttle from the middle
outward. The effect is that the shuttle doors appear to open before
your very eyes!
TickPause is a simple delay that pauses in increments of 18 ticks
per second. Simply pass in the number of ticks to pause. TickPause
does NOT use BASIC's TIMER and, as consequence, does not access any of
the Floating point library. This can translate as a huge savings in
the compiled size of your exe files (DAZZLING, with it's 8 subprograms
that perform 27 routines, compiles to only 7,100 bytes or so).
GetMonitorSeg returns the starting address of the video map. If
it senses a color system, it returns &HB800. Otherwise, it returns
&HB000 as the starting address.
Shake is a slight modification of a routine originally published
at the end of 1988 by HumbleWare Custom Programming. It reprograms
the 6845 CRT controllers viewport into video RAM. The shaking screen
produced is quite radical. Don't watch it if you are prone to getting
sea sick.
Two other routines that are worth mentioning are not included in
DAZZLING.BAS but are part of the demo program, DAZZDEMO. One uses the
WIDTH statement to test and set your monitor for it's highest resolu-
tion. If your monitor is EGA or VGA, "WIDTH , 43" or "WIDTH , 50" will
force 80x43 / 80x50 screen mode. This technique uses error trapping.
If someone knows how to test for a system's capability to use 80x43 or
80x50 modes without error trapping, I sure would like to know how.
The other routine creates a continuous noise by reprogramming the
timer with a new clock rate and outputs this straight to the speaker.
This routine is one among several, useful sound routines published
in "Inside Microsoft BASIC", by the Cobb Group, July 1990. If you
don't subscribe to this magazine, this little routine should wet your
whistle.
If you compile DAZZLING.BAS as an object module, three variables
must be declared as COMMON SHARED within your main code: Monitor AS
INTEGER, ScrnEls AS INTEGER, and MaxLine AS INTEGER. To simplify your
coding and to assure that the COMMON SHARED blocks will be the same,
the code includes DAZZLING.BI which contains the declarations for the
routines and COMMON SHARED blocks required. If you compile DAZZLING
for use with your other code, REM $INCLUDE: 'DAZZLING.BI' immediately
The QBNews Page 16
Volume 1, Number 5 December 1, 1990
after your last DECLARE and prior to your COMMON SHARED statement. Or,
you could modify DAZZLING.BI and re-compile as your needs dictate.
Follow the instructions at the top of DAZZLING.BAS and DAZZDEMO.BAS
for linking and compiling into a stand alone program.
One final note. The fancy screen routines used by DAZZLING.BAS
use the POKE command. On older CGA systems, using a POKE to the sys-
tem's monitor may cause snow because these old CGA systems cannot
handle the direct screen activity during re-trace.
**********************************************************************
Larry Stone is President of LSRGroup and is involved in writing
software for marine and aquatic research, as well as, data acquisition
software systems. He has also authored various shareware programs such
as "SERVICES", a file, directory, disk and archive manager rated a
trophy by the "PUBLIC BRAND SOFTWARE" shareware catalog. Larry can be
reached at LSRGroup, P.O. Box 5715, Charleston, OR 97420, or in care
of this newsletter or, contact him via The Empire Builder BBS 1:356/0
1:356/1 1:356/4 (14400 Baud), (503) 888-4121.
**********************************************************************
[EDITOR'S NOTE]
All code for this article can be found in the file DAZZLING.ZIP.
The QBNews Page 17
Volume 1, Number 5 December 1, 1990
Self-Cloning Exe's Revisted by Ronny Ong
In Volume 1, Number 3 of QBNews, Larry Stone presented "How to
Make a Self-Cloning Exe in QuickBASIC." In his sample code, you
needed to define a value for MyProg$, the filename of the EXE that
would be accessing itself. Larry did not go into the considerations
involved in defining MyProg$. This article will.
You could simply hard-code a filename into the program, but that
would prevent users from renaming it, an inconvenience. The program
could ask users for its own filename, making the program look
unnecessarily dumb. You would also have the headache of getting and
validating input, and handling all the possible errors like invalid
filenames and valid filenames which are simply wrong, i.e. not the
true name of the program.
And then there is the drive/path specification. You certainly
cannot hard-code that. You might get away with forcing users to keep
the program in a certain directory, but not on a certain drive. There
are too many different hardware configurations in today's PC world.
Think you can leave off the drive/path and let DOS look in the default
drive/path? Think again:
(1) What if the program is located in the DOS PATH? It can get
loaded even if it is not in the default drive/path, but the OPEN
statement will not find it (unless users just happen to use DPATH or
APPEND and just happen to specify the same drive/path as in PATH).
(2) What if the program gets executed through PC Magazine's RUN.COM
utility, which searches all directories on a drive regardless of PATH?
(3) What if users execute the program from a different drive/path by
specifying the drive/path of the program along with the filename?
Fortunately, there is a way to avoid all these problems.
The sample program contained in FILESPEC.BAS demonstrates how
programs written in QuickBASIC Version 4 or higher and compiled and
linked to an EXE file can find out the complete drive, path, filename,
and .EXE extension the program was loaded as. This information is
stored in memory when DOS loads a program through its "EXEC" function.
The underlying approach can be applied to COM or EXE files in any
language.
When incorporating this technique into your self-cloning
programs, you should get to the OPEN statement immediately if
possible, in case users try to execute your program from diskette and
then remove the diskette. If you can put this code and your I/O to
the EXE up front, the disk activity will look like it is part of DOS's
loading of your program.
Hard-coding may look like an easy way out when compared to the
code above, but if your program is good enough to deserve a self-
cloning feature, then it deserves the flexibility of this approach.
The QBNews Page 18
Volume 1, Number 5 December 1, 1990
**********************************************************************
Ronny Ong is a mainframe systems engineer. He can be reached at
P.O. Box 260796, Plano, TX 75026-0796.
**********************************************************************
[EDITOR'S NOTE]
All code and files for this article can be found in the file
FILESPEC.ZIP.
The QBNews Page 19
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
E n g i n e e r s C o r n e r
----------------------------------------------------------------------
GPIB Instrument control from IOTech by Dave Cleary
This is the start of a new column that I hope gets some support
from all you readers. Engineer's Corner is a column that will cater to
all the Scientists and Engineers out there that use QuickBASIC. I feel
that the QuickBASIC environment makes the PC an invaluable tool to
perform our everyday tasks that just can't be done with a package "off
the self". I started using QuickBASIC 2.0 to produce some automated
testing stations. Although this can be done in other languages, BASIC,
in general, is best suited for this purpose. I am going to discuss the
software I use that allows me to control GPIB instruments from
QuickBASIC programs.
The software is called DRVR488 and is sold by IOTech. I buy the
software bundled with IOTech's GP488B interface board, but you can buy
the software separately. The DRVR488 software should be compatible
with interface boards based on the NEC uPD7210 GPIB controller chip.
The software is a TSR you load before you start your QuickBASIC
program. It takes less than 50k when resident. DRVR488 installs itself
as a device so DOS 3.0 or later is required. If you need to control
more than one board, alternate drivers are provided that allow you to
have four boards in your PC. I currently use version 2.4 of this
software, but there may be later versions available.
To load the TSR, the typical command line may look like this:
DRVR488 /I /D1 /A&H02E1 /B21 /F8 /TCRLFEOI /ECRLF /SC <\DEVCONF1.DAT
The install program handles most of the switches for you, but I
want to tell you about one in particular. the /SC <[filename] switch
allows you to load a text file that contains information about the
devices you are going to be using. Mine looks like this:
CONFIG /TICRLFEOI /TOLF /NPTS500 01
CONFIG /TCRLFEOI /NANZ3561 06
CONFIG /TICRLFEOI /TOCRLFEOI /NDVM8840 02
CONFIG /TCRLFEOI /NCNTR5334 03
CONFIG /TCRLFEOI /NCNTR5335 10
CONFIG /TCRLFEOI /NCNTR5370 04
CONFIG /TCRLF /NDVM3600 05
CONFIG /TEOI /NSCP2431 07
This tells DRVR488 information about specific devices at specific
addresses. For instance, I have a Fluke 8840 DVM located at address 2.
The DVM expects certain terminator characters on input and output of
GPIB commands. This is specified by the /TI and /TO switches. Best of
all, the /N switch allows your to specify a name in place of the
address. Instead of issuing a command like this:
PRINT #2, "REMOTE 02"
The QBNews Page 20
Volume 1, Number 5 December 1, 1990
I can issue this:
PRINT #2, "REMOTE DVM8840"
Both commands do exactly the same thing.
After the TSR is loaded, your QuickBASIC programs can now access
GPIB devices. The first thing your QB program needs to do is to open
two files. One of these is for input while the other is for output. My
GPIB initialization routine looks like this:
'=====================================================================
' IEEE BUS INITIALIZATION SUB
'=====================================================================
'*********************************************************************
' JUL 1989- VERSION 1.0: Initial Release
'
' IeeebusInit(TimeOut)
' Timeout= Bus Timeout
'
'*********************************************************************
DEFINT A-Z
ErrSub:
IF ERR = 76 THEN
CLS
PRINT "DRVR488 SOFTWARE NOT INITIALIZED! Program Terminating."
END
ELSE
CLS
PRINT " Undefined Error # "; ERR; ". Program Terminating."
END
END IF
SUB IeeebusInit (TimeOut)
ON ERROR GOTO ErrSub
OPEN "\DEV\IEEEOUT" FOR OUTPUT AS #2
OPEN "\DEV\IEEEIN" FOR INPUT AS #3
Rst:
IOCTL #2, "BREAK"
PRINT #2, "RESET"
PRINT #2, "STATUS"
INPUT #3, A$
A$ = RIGHT$(A$, 2)
IF A$ <> "OK" THEN GOTO Rst
PRINT #2, "ERROR OFF"
PRINT #2, "TIMEOUT"; STR$(TimeOut)
The QBNews Page 21
Volume 1, Number 5 December 1, 1990
ON ERROR GOTO 0
END SUB
IEEEIN and IEEEOUT are devices that the TSR installs and are
accessed through DOS 3.0's DEV. After I open the files, I reset the
controller board by issuing BREAK and RESET commands. I then issue a
STATUS command and input a response from the controller board. The
board responds with a string that contains various info with the last
two characters OK. You are now ready to communicate with your devices.
I started using this software back in the days of QB2. At that
time, I received a "pre-release" version that didn't have pretty docs
and was at version 1.0. This software was a big improvement over what
was available for GPIB control back then. While it may seem outdated
compared to the GUI software that is available now for GPIB control,
it offered a very easy way to control GPIB devices that was similar in
syntax to dedicated HP controllers running HP BASIC. This is still
true today and it allows you to look at examples from instrument
manuals and easily translate them into the appropriate QuickBASIC
commands.
For instance, the programming manual for the HP 5334A counter
gives this example for initializing the 5334 using an HP-85
controller:
10 CLEAR 'Clear controller
20 CLEAR 703 'Clear device at address 3
30 OUTPUT 703 ;"ID" 'Issue ID command to device at address 3
40 ENTER 703 ;A$ 'Read 5334 "ID" response into A$
50 PRINT A$ 'Print A$
60 OUTPUT 703 ;"IN" 'Set 5334 to initialized state
70 END 'All done
To do the same thing with QuickBASIC and DRVR488, you would do
this:
PRINT #2, "CLEAR"
PRINT #2, "CLEAR CNTR5334" 'You could use 03, but I prefer this
PRINT #2, "OUTPUT CNTR5334; ID"
PRINT #2, "ENTER CNTR5334" 'This puts the counter into TALK mode
INPUT #3, A$
PRINT A$
PRINT
#2, "OUTPUT CNTR5334; IN"
END
As you can see, the syntax is very similar to the examples in the
HP manuals. This article is not meant to be a review of the DRVR488
software, but is just my experiences using this decent product. Like I
said before, there are now a lot of alternatives available for GPIB
instrumentation control that weren't available when I first started
using this product, but I am completely satisfied with it.
For information about this and other IOTech products, you can
The QBNews Page 22
Volume 1, Number 5 December 1, 1990
call or write IOTech at:
IOTech, Inc.
25971 Cannon Rd.
Cleveland, OH 44146
(216) 439-4091
**********************************************************************
Dave Cleary is an electronics engineer for Vectron Laboratories
in Norwalk, CT. Besides putting together the QBNews, he is also the
author of Crescent Software's PDQComm. He can be reached in care of
this newsletter.
**********************************************************************
The QBNews Page 23
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
N e w a n d N o t e w o r t h y
----------------------------------------------------------------------
GEOGRAF Level One from GEOCOMP Corporation
GEOCOMP announces the release of GEOGRAF Level One. GEOGRAF Level One
enables programmers to add customized graphics to their application
programs, without having to develop complex graphics device drivers
for each device they wish to support. The device independence of
GEOGRAF Level One allows users to output their graphics to virtually
any output device. GEOGRAF Level One is priced at $149.
GEOCOMP Corporation
66 Commonwealth Ave.
Concord, MA 01742
(800)822-2669
If you have a product you would like to announce in New and
Noteworthy, send a 5 or 6 line paragraph to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
The QBNews Page 24
Volume 1, Number 5 December 1, 1990
----------------------------------------------------------------------
A n d I H e a r d i t T h r o u g h t h e G r a p e v i n e
----------------------------------------------------------------------
Exerpts from the QUIK_BAS echo
=====================================================================
Integers between 32K and 64K
=====================================================================
From: Larry Stone
To: Mike Welch
Subject: Boy, do I feel dumb
MW> In the QBQUIRKS file by MicroHelp (a freely distributed text file
MW> with tons of neato QB tidbits), there's the statement:
MW> "Converting large numbers to integers"
MW> "A common technique to stuff a large number (between 32767
MW> and 65536) into a BASIC integer is:
MW> number! = 50000
MW> number% = VAL("&H" + HEX$(number!))
MW> However, QB's VAL() function is quite sluggish. The
MW> following technique produces the same result, and runs
MW> approximately 20-30% faster, depending upon the compiler:
MW> number! = 50000
MW> number% = CVI(CHR$(number! MOD 256) + CHR$(number! \ 256))
MW> Hmmm. Well, I want the book on these "common techniques." I've
MW> beat my head against the wall trying to find a way to speed up
MW> long integer processing...when the range was just a few
MW> thousand > 32767. Gee. I know hex numbers will be 'smaller,' but
MW> why didn't I think...
The above technique is slow because of the use of single precission
number (forcing the use of the floating point library). In the
latest issue of the BUG Newsletter from MicroHelp, they suggest an
alternative:
BigNum& = 65000 'A big number between 0 and 65535
Intg% = BigNum& + 65536 * (BigNum& > 32767)
The above will allow your exe to shrink by 10K+ (assuming no other
floating point is used) and executes 47 times faster than the code
you listed.
If you use either of the above posted techniques, you will discover
that the resultant number is a signed, negative number for any number
between 32767 and 65536. With this in mind, I tried the following:
number& = 65000
IF number& > 32767 THEN intg% = number& - 65536 ELSE intg% = number&
The QBNews Page 25
Volume 1, Number 5 December 1, 1990
Along the same vein, when an asm routine passes back a large integer,
QB will see it as a negative. To convert the negative to a number in
the 32K - 64K range,
IF intg% < 0 then number& = intg% + 65536 ELSE number& = intg%
This code is somewhat faster again because there is no multiplication
used.
=====================================================================
From: Tom Hanlin
To: Mike Welch
Subject: Re: Boy, do I feel dumb
You can use that unsigned integer trick in QuickBASIC-- it won't
work for PRINTing the numbers, calculations, or anything, but it can
be a neat way of saving memory during file storage or in arrays. Just
convert the number to a LONG integer when you want to use it:
L& = CVL(MKI$(UnsignedInt%) + STRING$(2, 0))
The same trick works the other way, too:
IF L& < 65536 THEN UnsignedInt% = CVI(LEFT$(MKL$(L&), 2)) ELSE error
I don't -think- this brings in the floating point libraries... it
shouldn't, but the BASIC runtimes are so tangled,anything is possible!
Actually, it would be a good idea to check that L& >= 0 too, on the
long --> int conversion. Either case would indicate an overflow.
=====================================================================
From: Mike Welch
To: Tom Hanlin
Subject: Re: Boy, do I feel dumb
Long integers& themselves do not require floating point, but I'm not
sure about the CVI function...think it does!
=====================================================================
Delay Loops
=====================================================================
From: Doug Wilson @ 965/9
To: Tim Downey
Subject: Re: PowerBASIC
On August 14, Tim Downey writes to Mike Welch (but intends for Henry
Piper -- go figure...):
> Here's a little routine that does away with most of the overhead
> (nearly 3k) of the SLEEP function:
> SUB Delay (t%)
> StopTime& = (TIMER + t%) MOD 86400
> DO
> z$ = INKEY$
> IF INT(TIMER) >= StopTime& THEN EXIT DO
The QBNews Page 26
Volume 1, Number 5 December 1, 1990
> LOOP UNTIL z$ <> ""
> END SUB
> Note the MOD 86400. That takes care of the midnight rollover
> problem. Works like a champ for me.
You are on the right track, but if you specify a delay which
takes you beyond midnight, the MOD 86400 sets StopTime& to a value
less than the current value of TIMER and your IF-THEN statement kicks
you out of the loop immediately. (I verified this by resetting my
system clock to a few seconds before midnight before running the
routine.)
I posted a solution to this quite a few months ago. Darned if I
remember how I did it then, but modifying your code:
SUB Delay (t%)
StopTime& = TIMER + t%
DO
IF LEN(INKEY$) THEN EXIT DO
LOOP UNTIL (StopTime& - TIMER) MOD 86400 <= 0
END SUB
This way, StopTime& is always larger than TIMER while in your delay.
If you cross over midnight and TIMER drops back to zero, the MOD 86400
takes care of it. Also, there is no need to convert TIMER to an
integer. Decimal fractions work just fine, and since the thrust
was to get to smaller code than the SLEEP function, why throw in
an extra function? (This is also useful for folks using earlier
QB versions since SLEEP was not introduced until QB4.5.)
I tested this by resetting my system clock to a few seconds before
midnight also and it "works like a champ". (Where have I heard that
before? <grin>)
You'll also notice I reorganized slightly to make the main function
a delay loop rather than a key test loop. It seemed to make more
sense to have the delay be the controlling factor in the loop, with
the key press just being a way to exit the loop on an exception basis.
This is strictly personal preference, either way would work.
======================================================================
From: Larry Westhaver
To: Tom Hanlin
Subject: Re: REM $INCLUDE
Tom, thanks for chiming in about the 'recurring timer
question'. I've seen so many wierd approaches to creating a
timeout within a program that my head spins from the sheer
numbers... You beat me to the punch on this one.
The QBNews Page 27
Volume 1, Number 5 December 1, 1990
For some odd reason most folks want to base their timeouts on
some calculated time in the future (an offset of x minutes from
the present time). It really makes more sense to treat BASIC's
TIME$ string or TIMER value as a 'metronome'.
Who cares about the actual time when all you want to do is
pause for some number of seconds or clock ticks? I've used the
method you alluded to many times.
I usually approach the problem something like this:
SecondsToPause% = 10
DO
IF CurrentTIME$ <> TIME$ THEN
TickCount% = TickCount% + 1
CurrentTIME$ = TIME$
END IF
LOOP UNTIL TickCount% > SecondsToPause%
I can think of many variations on this theme, each having it's
own advantages. Sometimes I use the most active byte of the BIOS
master clock count as a metronome when I need higher resolution
than that offered by TIME$.
Anyway, my point is this: Do I care if my TIME$ string has done
a midnight rollover? Not a bit... I'm just tapping out the
seconds to the rythm of TIME$.
Larry Westhaver
PS. I realize that this is like preaching to the converted but I just
wanted to throw in my 2 cents :-)
======================================================================
From: Tom Hanlin
To: Tim Kilgore
Subject: Re: REM $INCLUDE
SUB Delay(xxx)
xxy = xxx
DO
t = TIMER
WHILE t = TIMER
WEND
xxy = xxy - 1
LOOP WHILE xxy
END SUB
Sorry if it's sloppy, my online time is out!
======================================================================
Binary Numbers
======================================================================
From: Richard Randles
The QBNews Page 28
Volume 1, Number 5 December 1, 1990
To: Brian Wasserman
Subject: Re: Binary to Numbers
* Reply on a message originally to All
BW> I understand how to convert Binary to Integers, and Integers back
BW> to Binary, but I am lost when it comes to negative numbers. Can
BW> you tell me how to convert a binary number to a negative integer?
BW> How about a negative integer to a Binary number?
To change a positive number into a negative number, you do a two's
compliment, that is, invert all bits (change 0's to 1's and 1's to
0's), then add 1.
To convert 17 decimal to -17: 00000000 00010001
Invert all bits: 11111111 11101110
Add 1: 11111111 11101111
You follow the same procedure to convert negatives to positives.
======================================================================
From: Louis Siadous
To: Spencer Wood
Subject: Binary To Decimal
Sorry to correct you Spencer but binary to decimal is as follows:
Bit 7 6 5 4 3 2 1 0
Value 128 64 32 16 8 4 2 1
Even is you can't remember those you can just do a 2^<bit> to get the
decimal value of a particular bit. In other words 2^0 = 1, 2^1 = 2.
You are correct that for integers BASIC uses the leftmost bit 15 or
31, integer or long integer, set on (1) to indicate a negative number.
Hope this clears it up.
Louis
======================================================================
From: Donn Bly
To: Brett Emery
Subject: 16-bit Numbers
on <Aug 30 09:03> Brett Emery (1:159/500) writes (to All):
BE> I would like to know how to convert a 16-bit (2 byte) number into
BE> binary 1's & 0's. The number is the result from a call
BE> interruptx but each bit stands for something else. So I need to
BE> know how to get each piece of info out of that number - 16-bit to
BE> binary. Thanks to All that reply - Brett Emery.
Lets see...
L% = <Integer>
X$ = ""
FOR I% = 15 TO 0 STEP -1
The QBNews Page 29
Volume 1, Number 5 December 1, 1990
IF L% AND (2 ^ I%) THEN X$ = X$ + "1" ELSE X$ = X$ + "0"
NEXT
PRINT X$
This code should make X$ contain the binary representation of the
integer L%.
======================================================================
From: Donn Bly
To: Larry Stone
Subject: 16-bit Numbers
on <Sep 01 17:48> Larry Stone (1:129/34) writes (to Donn Bly):
LS> Nice code, Donn. About the best I've ever seen for direct
LS> conversions.
LS> One question. At 07:02am, I'm only good for fishing. How did you
LS> do it? Lots of coffee?
Thank you. I gave up on coffee before work -- agrivates my ulcers.
I got up early that morning, and firured that I would read a few
messages before going to work.
LS> is easily modified for 32 bit numbers. Also, looking at it, I
LS> see how almost
LS> the same code could be employed to convert the string back to an
LS> integer.
LS> L% = 0
LS> FOR I% = 0 TO 15
LS> IF (VAL(X$) AND (2 ^ I%)) = 2 ^ I% THEN L% = L% + (2 ^ I%)
LS> NEXT
LS> Is this what you do?
No.
X$ = "1001"
Accum& = 0
FOR I% = 1 TO LEN(X$)
Accum& = Accum& * 2
IF MID$(X$, I%, 1) = "1" THEN Accum& = Accum& + 1
NEXT
PRINT Accum&
This code handles variable length "binary" strings. It can also be
easily modified to handle any base number. BTW, your line of code:
LS> IF (VAL(X$) AND (2 ^ I%)) = 2 ^ I% THEN L% = L% + (2 ^ I%)
can be optimized:
IF (VAL(X$) AND (2^I%)) THEN L% = L% + 2 ^ I%
The QBNews Page 30
Volume 1, Number 5 December 1, 1990
No need to do those extra 16 calculations, and the comparisons should
be a wee bit faster. ;-) However, your code give you what I think are
your desired results. X$ should contain a series of ones and zeros,
and I don't think that you really want to take the VAL() of it.
======================================================================
From: Cornel Huth
To: Louis Siadous
Subject: DEC 2 BIN (simply)
I've seen a couple of convert to binary routines
lately but they seem to need the power function.
Since I do a lot of work in assembly, and the
power function per se is not at all needed for
decimal to binary fformatting I decided to hop
into QB and punch a routine that does the conversion
without using the ^ operator in BASIC...let's UL it:
DEFINT A-Z
'routine to convert base 10 to base 2
hibit = 7 'number of significant bits - 1
test = 240 'decimal number to convert
FOR i = 0 TO hibit
q = test \ 2
IF q THEN r = test MOD (q * 2) ELSE r = test
IF r THEN b2$ = "1" + b2$ ELSE b2$ = "0" + b2$
test = q
NEXT
PRINT b2$
b2$ = ""
That's it. Binary to decimal conversion is left to the
reader (don't you just hate that?).
chh
======================================================================
From: Richard Randles
To: Donn Bly
Subject: Re: 16-bit Numbers
Here's a way that's a little faster. I just compared the two on a
386SX and got these results. Times shown are for looping through each
method 1000 times.
Using 2 ^ n Using b + b
and x$ + x$ and Mid$(x$
----------- ------------
Environment 59.48 sec 1.82 sec
Compiled 57.45 sec .39 sec
L% = <integer>
x$ = "0000000000000000"
The QBNews Page 31
Volume 1, Number 5 December 1, 1990
Byte& = 1
FOR i% = 16 TO 1 STEP -1
IF L% AND Byte& THEN MID$(x$, i%, 1) = "1"
Byte& = Byte& + Byte&
NEXT i%
If more speed is needed, add
Pointer& = SADD(x$) - 1
before the FOR and change the IF line to
IF L% AND Byte& then POKE Pointer& + i%, 49
======================================================================
From: Donn Bly
To: Richard Randles
Subject: Re: 16-bit Numbers
on <Sep 09 11:03> Richard Randles (1:157/98.1) writes (to Donn Bly):
RR> Here's a way that's a little faster. I just compared the two on
I do something similiar at work. I have a program that converts a
two-dimentional array (32 x n) that contains flag bits into long
integers for storage. If I can remember it, I will bring in the code
and post it tomorrow.
RR> Byte& = Byte& + Byte&
Here is something that I haven't benchmarked to see which is faster,
the above or B = B * 2. The optimizer should turn them into the same
code...
RR> Pointer& = SADD(x$) - 1
RR> before the FOR and change the IF line to
RR> IF L% AND Byte& then POKE Pointer& + i%, 49
I wouldn't. I never trust SADD beyond a single line of code.
======================================================================
Colors
======================================================================
From: Larry Stone
To: Dan Davidson Msg #153, 29-Sep-90
Subject: monochrome display toggles
> I use QuickBASIC 4.5, with a monochrome monitor. I can use bright,
> underlined, flashing or reverse display in setting up my DOS prompt,
> but haven't found out how to do those things with QuickBASIC.
Monochrome COLOR commands:
COLOR Description
***** ***********
7, 0 Normal white on black
15, 0 Intense white on black
The QBNews Page 32
Volume 1, Number 5 December 1, 1990
0, 7 Inverse video
1, 0 Underlined white on black
9, 0 Intense underlined white on black
23, 0 Flashing white on black
31, 0 Flashing intense white on black
17, 0 Flashing underlined white on black
25, 0 Flashing intense underlined white on black
Not all monochrome display adapters will handle all of the above
listed colors.
BTW, monochrome attributes are either normal, intense, or underlined,
or, a combination thereof. Underlined is produced with the forground
color attribute *blue*. To calculate intense, add 8 to the attribute,
ie, intense white is 7 + 8 = 15, intense underlined is intense blue or
1 + 8 = 9. To calculate flashing, add 16 to the forground color, ie,
intense flashing white is 15 + 16 = 31. Inverse video cannot be
underlined nor intense.
COLOR 7, 0: PRINT "This is normal"
COLOR 1, 0: PRINT "Underlined"
COLOR 9, 0: PRINT "Intense underline"
COLOR 23, 0: PRINT "Flashing"
COLOR 25, 0: PRINT "Intense flashing"
======================================================================
BSAVE/BLOAD
======================================================================
From: Larry Westhaver
To: Tim Kilgore
Subject: Binary files
Tim, the 7 byte header that QuickBASIC tacks onto the front of any
BSAVE contains some information that QuickBASIC needs to BLOAD
the file *if* you choose to use the syntax: BLOAD "filename"
without the offset parameter. Have you ever wondered how BLOAD
knows where in memory the image came from?
Anyway, here's the skinny...
Byte #1 - Always an ASCII 253 (identifies the file as BSAVE/BLOAD)
Byte #2 - Low byte of segment where image originated
Byte #3 - High byte of segment where image originated
Byte #4 - Low byte of offset into segment where file originated
Byte #5 - High byte of offset into segment where file originated
Byte #6 - Low Byte of image length
Byte #7 - High byte of image length
So, to interpret the header...
'define BSAVE file header
TYPE HeaderStruc
BSaveID AS STRING * 1 'ID always ASCII 253 (byte)
SegByte AS INTEGER 'Segment of data origin (word)
The QBNews Page 33
Volume 1, Number 5 December 1, 1990
OffByte AS INTEGER 'Offset of data origin (word)
LenByte AS INTEGER 'Length of data (word)
END TYPE
'allocate memory for BSAVE file header structure
DIM Header AS HeaderStruc
'open a BSAVE file
OPEN "E:\GDP\SCREENS\XMAS.80C" FOR BINARY AS #1 LEN = LEN(Header)
GET #1, 1, Header
CLOSE #1
CLS
'ID byte
PRINT " BSAVE file ID byte:"; ASC(Header.BSaveID)
'segment of origin
PRINT "BSAVE'd from Segment: "; HEX$(Header.SegByte)
'offset of origin
PRINT " BSAVE'd from Offset: "; HEX$(Header.OffByte)
'length of data
PRINT "Length of BSAVE data:"; Header.LenByte
I hope this helps, I uncovered these facts in 1985 when I wrote
GDPEdit (a screen design tool that I sell mail order through
Komputerwerk Inc., one of the first QuickBASIC add-on library
marketers)
Larry
======================================================================
Do It with Booleans
======================================================================
From: Tom Hanlin
To: All
Subject: Booleans
A little bit <!> on Booleans, since it appears they're not as well
known as they might be...
uickBASIC allows any conditional expression to be converted to a
Boolean value. In other words, you can say something like:
A = (B <> 0)
...in which case, A will be zero if B is zero, or -1 if B is not zero.
The parentheses are important.
As far as BASIC is concerned, "true" is any nonzero value. Given a
conditional of the type above, "true" will always evaluate to -1,
however. This is because QuickBASIC treats its Boolean operations
like the equivalent arithmetic operations: NOT -1 is 0, NOT 0 is -1;
however, NOT 1 won't give you 0, but rather something like -2, which
is also "true"... explanation? The numbers are treated as a sequence
The QBNews Page 34
Volume 1, Number 5 December 1, 1990
of bits: zero is 0000,0000, and negative one is 1111,1111. Any
Boolean-type operation is essentially equivalent to a math operation
in QuickBASIC, operating on all of the bits in the numbers concerned.
I'm not sure I'm making sense to y'all here, but so it goes...
This equivalence is a bit dangerous but mostly useful. It allows you
to make an integer into a Boolean value, essentially. You can do
things like:
IF PrinterSelected THEN LPRINT St$ ELE PRINT St$
More on this later, I'm running out of time right now. Booleans
(named after George Boole, who invented such math... incidentally,
he was delighted when he discovered 'em. He was a pure theoretical
mathematician and was pleased to come up with something that [he
thought] would never have any practical application! In truth, it's
fundamental to computers, valuable in symbolic logic and philosophy,
and very, very practical for many things!)
[EDITOR'S NOTE]
The purpose of this conference is to discuss Microsoft
QuickBASIC and related applications and utilities. SysOps looking
for a GroupMail or EchoMail link into QUIK_BAS should contact
Fidonet node 107/323 or call 1-201-247-8252. People wishing to read
QUIK_BAS can do so by calling The Crescent Software Support BBS at
1-203-426-5958.
The QBNews Page 35
----------------------------------------------------------------------
E O F
----------------------------------------------------------------------
Receiving The QBNews
The QBNews is distributed mainly through BBS systems around the
world. Some of the networks it gets distributed through are SDS
(Software Distribution System), PDN (Programmers Distribution
Network), and SDN (Shareware Distribution Network). Ask the sysop of
your local board about these networks to see if there is a node in
your area.
The QBNews can also be found on CompuServe in the MSLang
(Microsoft Language) forum. It can be found in file area 1 or 2 of
that forum. Just search for the keyword QBNEWS. The QBNews will also
be available on PC-Link. I send them to Steve Craver, who is the BASIC
Programming Forum Host on PC-LINK and he will make them available. I
would appreciate anybody who could upload The QBNews to other services
such as GENIE since I don't have access to these.
I have also set up a high speed distribution network for people
who would like to download The QBNews at 9600 baud. The following
boards allow first time callers download privileges also. They are:
Name Sysop Location Number Node #
---------------------------------------------------------------------
Treasure Island Don Dawson Danbury, CT 203-791-8532 1:141/730
Gulf Coast BBS Jim Brewer New PortRichey,FL 813-856-7926 1:3619/20
221B Baker St. James Young Panama City,FL 904-871-6536 1:3608/1
EMC/80 Jim Harre St. Louis, MO 314-843-0001 1:100/555
Empire Builder Bob Fetherson Charleston, OR 503-888-4121 1:356/4
Finally, you can download The QBNews from these vendors BBS's:
The Crescent Software Support BBS 203-426-5958
The Microhelp BUG BBS 404-552-0567
404-594-9625
You do not have to be a customer of these vendors in order to download
The QBNews, but the Microhelp BBS only allows non-members 15 minutes
of time per call.
If you would like to receive The QBNews on disk, I am now
offering a subscription for volume 2 next year. If you subscribe, you
will receive a disk with all the issue from volume 1, plus you will
The QBNews Page 36
Volume 1, Number 5 December 1, 1990
receive 4 disks next year as each of the 4 issues of volume 2 come
out. I have decided against offering individual disks as I don't have
the time to administer that. The cost of a subscription is as follows:
Base Price for Volume 2: $15.00
Additional charge for 3.5" disks: $5.00
Additional charge for international: $5.00
The base price includes 5.25" 360k disks. Send a check or money
order in U.S. funds to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Please be sure to specify what archive format you want. The
QBNews normally uses PKZip as it's archiver.
----------------------------------------------------------------------
Advertising in The QBNews
The QBNews now offers an outstanding opportunity to advertise
your products to Microsoft QuickBASIC users. For about the same price
a "classified" ad goes for in Dr. Dobbs Journal or Computer Language,
you receive a full page ad in The QBNews. There is also another
important difference. While these magazines cater to C programmers
because they feel "professionals" wouldn't use anything else, The
QBNews is especially for QuickBASIC programmers. To see an example of
the type of ad you will receive, see the Crescent Software ad earlier
in the newsletter.
You get a 50 line by 70 column ad for $300. If you are interested
in placing an ad in a future QBNews, send a check along with the ad
(Ascii text on disk preferred) to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
----------------------------------------------------------------------
Submitting Articles to The QBNews
The QBNews relies on it's readers to submit articles. If you are
interested in submitting an article, please send a disk of Ascii text
of no more than 70 characters per line to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Articles can also be submitted via E-Mail. Send them via Compuserve to
76510,1725 or via FidoNet to 1:141/777. I can be reached at the above
addresses as well as on Prodigy as HSRW18A.
The QBNews Page 37