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? ) 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^ 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 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% = 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 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% = 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 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