home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-28 | 61.6 KB | 1,643 lines |
- The PowerBASIC Wizard's Library
- =-----------------------------=
- Version 1.2
-
- PBWIZ Copyright (c) 1991-1992 Thomas G. Hanlin III
-
-
-
- This is PBWiz, a library of assembly language and BASIC
- routines for use with PowerBASIC version 2.x. Full source code
- is available with registration. The PBWiz collection is
- copyrighted and may be distributed only under the following
- conditions:
-
- 1) All PBWiz files must be distributed together in original,
- unaltered form. A list of the 16 files included may be
- found in FILES.LST.
-
- 2) No files may be added to the PBWiz collection. This applies
- specifically to the practice of adding files containing BBS
- ads to archives. I find this seriously offensive.
-
- You use this library at your own risk. It has been tested by
- me on my own computer, but I will not assume any responsibility
- for any problems which PBWiz may cause you. If you do
- encounter a problem, please let me know about it, and I will do
- my best to verify and repair the error.
-
- It is expected that if you find PBWiz useful, you will register
- your copy. You may not use PBWiz routines in programs intended
- for sale unless you have registered. Registration entitles you
- to receive the latest version of PBWiz, complete with full
- source code in assembly language and BASIC. The assembly code
- is designed for the MASM 6.0 assembler and may require minor
- modifications if you wish to use it with OPTASM, TASM, or
- earlier versions of MASM.
-
- Warning: Unregistered use of PBWiz for more than 30 days may
- encourage the author to sing Gregorian chants under your
- window. Don't let this happen to you!
-
- Table of Contents page 2
-
-
-
- Synopsis and Legal Info .................................... 1
-
- Table of Contents .......................................... 2
-
- Overview ................................................... 3
-
- Archives ................................................... 4
-
- Dates and Times ............................................ 6
-
- Equipment Info ............................................. 7
-
- Extended Math ............................................. 11
-
- Graphics .................................................. 14
-
- Keyboard .................................................. 17
-
- Memory (EMS) .............................................. 21
-
- Memory (XMS) .............................................. 24
-
- Mouse Support ............................................. 26
-
- Strings ................................................... 29
-
- Text-mode Video ........................................... 32
-
- Credits ................................................... 36
-
- Overview page 3
-
-
-
- Any program that uses any of the PBWiz routines must DECLARE
- them appropriately. To make this easy, I've created a single
- file which contains all of the necessary declarations. Put
- the following line at the top of your program to use it:
-
- $INCLUDE "PBWIZ.INC"
-
- The DECLARE statements contained in this file tell PowerBASIC
- how to behave when it runs into any PBWiz routines. They
- don't actually load the routines. To do that, you must $LINK
- the appropriate units. The names of the units to $LINK are
- specified in each chapter of this manual.
-
- Each chapter covers a specific unit or pair of units. If the
- code is written in assembly language, the unit name ends in A.
- If the code is written in PowerBASIC, the unit name ends in B.
- So, for instance, the VIDEO units are called VIDEOA.OBJ and
- VIDEOB.PBU. If the code for a chapter is written entirely in
- one language, I don't bother with -A or -B suffix.
-
- Archives page 4
-
-
-
- When I started in the microcomputer industry, there was a
- small variety of file archivers, all (more or less)
- compatible. They did not provide compression, which was
- relegated to another large selection of more-or-less
- compatible utilities. Then came SEA's ARC. It was very slow,
- but it did compression as well as archiving, and included CRC
- checks so you could know whether the files were intact. It
- swept the BBS scene in short order, becoming the new
- standard. A few other archivers competed on about a level
- footing, providing only minor variances on the ARC theme. Then
- SEA decided to sue one of its more successful competitors,
- Phil Katz (PKARC). The end result was the ZIP standard... but
- in the chaos resulting from the breaking of the ARC standard,
- many other archivers came into being: ARJ, LZH, PAK, ZOO, and
- so forth.
-
- PBWiz helps resolve the confusion by providing a single set of
- routines which allow you to view the contents of archives in
- any of the above-mentioned formats: ARC, ARJ, LZH, PAK, ZIP, or
- ZOO. Only archive directories are provided at this time.
- Other formats will also be added as they arise. If you have
- details on the format of an archive that you'd like me to add,
- please send them my way. I'll do what I can to get it into
- PBWiz.
-
- This unit requires the STRING unit (discussed later) as well.
- To use it in your program, you need to include both units:
-
- $LINK "stringa.obj"
- $LINK "stringb.pbu"
- $LINK "archives.pbu"
-
- Viewing archive directories is handled in roughly the same
- fashion as you might view a DOS file directory. This makes it
- possible to treat an archive and a subdirectory in a similar
- manner.
-
- When you're looking for the first file in an archive, use the
- FindFirstA function. You must specify the archive name and a
- file name. The archive name may include a drive and path
- specification, and does not need to have the archive
- extension. If you leave off the extension, FindFirstA will use
- the first archive it comes across that matches the rest of the
- specification. Note that the archive specification may not
- contain wildcards. In contrast, the search file name may not
- contain drive or path specs, but may contain wildcards.
-
- CALL FindFirstA (Archive$, Filename$, ErrCode%)
-
- Archives page 5
-
-
-
- If there are no files to be found, or if the archive
- specification was bad, an error code will be returned. If
- there was no error, there may well be more files to be found.
- You can find each of them with FindNextA:
-
- CALL FindNextA (ErrCode%)
-
- Of course, just finding a matching file doesn't do you much
- good unless you can retrieve information about it. You can use
- any of the following routines to provide information about a
- matched file:
-
- Nam$ = GetNameA$
- Dat$ = GetDateA$
- Tim$ = GetTimeA$
- CRC$ = GetCRCA$
- StorageMethod$ = GetStoreA$
-
- CALL GetSizeA (OriginalSize&, CurrentSize&)
-
- When you're done viewing an archive, be sure to close it:
-
- CALL CloseA
-
- Let's try an example. Given that you've already written the
- $LINK line as specified on the previous page, you could see
- all of the files in an archive using a program like this:
-
- CALL FindFirstA (Archive$, "*.*", ErrCode%)
- DO UNTIL ErrCode%
- PRINT GetNameA$
- CALL FindNextA (ErrCode%)
- LOOP
- CALL FCloseA
-
- This program fragment also assumes that you have set Archive$
- to the name of an archive. It might be convenient to set it to
- the command line for testing purposes:
-
- Archive$ = UCASE$(LTRIM$(RTRIM$(COMMAND$)))
-
- Dates and Times page 6
-
-
-
- This unit allows you to validate and compare dates. It also
- provides the day of the week, given the date. Dates may not be
- before the year 1900. Date strings may be in the form
- "01/01/91" or "01-01-1991" (the delimiter is not significant
- and years may be two or four digits; two-digit years will be
- assumed to be in the 20th century).
-
- To use the routines in this unit, include the following line
- at the top of your program:
-
- $LINK "timedate.pbu"
-
- Let's start off with date validation. It's often important to
- know if a date entered into your program is a valid date.
-
- IF GoodDate%(DateSt$) THEN PRINT "The date is valid."
-
- It can also be helpful to know on which day of the week a given
- date falls.
-
- Day$ = WeekDay$(DateSt$)
-
- There are many useful things you can accomplish by turning a
- date into a number which represents that date (or vice versa).
- This allows you to compare two dates, which is important if you
- want to sort by date; find out what the date will be in a given
- number of days, or what it was some number of days ago; find
- the number of days between two dates; display a calendar; and
- so forth. This is easy to do with PBWiz:
-
- DateNr& = Date2Num&(DateSt$)
-
- DateSt$ = Num2Date$(DateNr&)
-
- The DateNr& represents the number of days since January 1,
- 1900. This is less than 65,535 for dates that go up to around
- the year 2070 or so, so you may wish to store the dates in
- compressed two-byte form if your required range of dates is not
- that large:
-
- CrunchDate% = CVI(LEFT$(MKL$(DateNr&), 2))
-
- This can be reversed simply:
-
- DateNr& = CVL(MKI$(CrunchDate%) + STRING$(2, 0))
-
- Note that dates crunched this way are only useful for storage
- purposes, since the numbers greater than 32,767 are stored as
- negative numbers due to the signed integer format BASIC uses.
- You must uncompress them before doing any comparisons or date
- calculations. Still, for a savings of 50%, it may be worth the
- hassle to convert back and forth.
-
- Equipment Info page 7
-
-
-
- The equipment unit gives you information about the computing
- environment. This includes both installed software and
- hardware. You can use the equipment information routines by
- including this line in your program:
-
- $LINK "equipmen.obj"
-
- The first function allows you to determine if an "enhanced"
- keyboard (101-key) is installed. It may not be able to figure
- out what the keyboard is on some older not-quite-clone PCs, in
- which case it will take the safe way out and report that there
- is no enhanced keyboard. This function returns -1 if there is
- an enhanced keyboard present, 0 if not.
-
- Enhanced% = KbdType%
-
- Want to know the type of processor (CPU) being used? Can do!
-
- CPU% = Processor%
-
- The results will be reported as a number which can be decoded
- as follows:
-
- 0 NEC V20
- 1 8088 or 8086
- 2 80186
- 3 80286
- 4 80386 or 80486
-
- If anyone knows how to differentiate between an 80386 and an
- 80486, please let me know. I've only seen one test which could
- do it, and it wasn't reliable.
-
- Maybe you'd like to check for a CD-ROM drive:
-
- Drives% = CDROM%
-
- This tells you how many logical drives exist, if there is a
- CD-ROM available. If not, it will return 0. Note that the
- CD-ROM installation check conflicts with the GRAPHICS.COM
- installation check for DOS 4.0, due to some screw-up at IBM or
- Microsoft. I'm not yet sure whether DOS 5.0 is similarly
- afflicted.
-
- The number of floppy drives installed is retrieved like this:
-
- Drives% = Floppies%
-
- Equipment Info page 8
-
-
-
- There may be up to four floppy drives in a system; however, the
- AT CMOS data area only directly supports two. This makes it
- easy to find out what kind of drives the first two are, but not
- the second two. Oh well, guess we'll have to settle for what
- we can get, right?
-
- CALL FloppyType (Drive1, Drive2)
-
- The results from FloppyType are returned as follows:
-
- 0 no drive
- 1 5 1/4" 360K
- 2 5 1/4" 1.2M
- 3 3 1/2" 720K
- 4 3 1/2" 1.44M
-
- Result codes of 5-7 are available, but not yet defined. One
- might guess that the 2.88M drive supported by DOS 5.0 will be
- drive type 5. Has anybody seen one of those puppies yet?
-
- New memory types sure have burgeoned over the years...
- expanded, extended, and now XMS. There are routines to check
- all of these:
-
- BaseExt& = AllExtMem& ' extended memory installed
- NowExt& = GetExtM& ' BIOS extended memory available
-
- CALL GetEMSm (TotalPages%, FreePages%) ' expanded memory
-
- CALL GetXMSm (LargestFree&, TotalFree&) ' XMS memory
-
- When you're dealing with extended memory, whether it be
- BIOS-type or using the XMS standard, the results are returned
- in kilobytes. Multiply 'em by 1024 to convert to bytes. When
- you're dealing with expanded memory (EMS), the results are in
- pages of 16,384 bytes.
-
- I might note, by the way, that Microsoft seems to have
- intentionally crippled the XMS standard. It can only support a
- maximum of 64 megabytes. This may seem like a lot now, but I
- can remember when my first PC (a Compaq portable) was the awe
- of the neighborhood with 384K RAM! A few years down the road,
- the artificial limitations of XMS are going to be a nuisance.
-
- A few more routines to get the versions of the EMS and XMS
- drivers, if any:
-
- CALL GetEMSv (MajorV%, MinorV%)
- CALL GetXMSv (MajorV%, MinorV%)
-
- These return the major and minor version numbers as two
- separate integers. For example, EMS 4.0 would return major
- version 4, minor version 0.
-
- Equipment Info page 9
-
-
-
- It's nice to know a little about the operating environment.
- With the below routines, you can find out what the DOS version
- is; what version of 4DOS, if any, is in use; and whether
- Microsoft Windows is running.
-
- CALL GetDOSv (MajorV%, MinorV%)
- CALL Get4DOSv (MajorV%, MinorV%)
- CALL WinCheck (MajorV%, MinorV%)
-
- These return results as major and minor version numbers, as
- discussed on the previous page. The Get4DOSv and WinCheck
- routines return zeroes if 4DOS and Windows, respectively, are
- not available.
-
- There are a couple of curious features of GetDOSv to keep in
- mind. If the version is 10 or higher, you're running in OS/2
- compatibility mode. DOS version 10 is actually OS/2 1.0,
- version 20 is OS/2 2.0, and so on. Secondly, if you're using
- DOS 5.0, the version reported may not be 5.0-- DOS 5.0 can be
- told to reply with a lower version number to allow some older
- software (which checks for a specific DOS version) to run
- properly.
-
- One final routine that should be of some value is the one that
- allows you to find out what kind of display is available. It
- tells you the specific adapter and whether the display is color
- or monochrome. There is one case in which it can be confused,
- however-- if the adapter is CGA, the display is assumed to be
- color, since there is no way for the computer to know any
- differently. So, although this routine provides a good idea of
- what is available, it would be a good idea to provide an option
- to tell the program that a monochrome display is attached.
- Microsoft normally uses "/B" for this purpose, so that might be
- a good standard to stick with.
-
- CALL GetDisplay (Adapter%, Mono%)
- IF Mono% THEN
- PRINT "Monochrome monitor"
- ELSE
- PRINT "Color monitor"
- END IF
- SELECT CASE Adapter%
- CASE 1: PRINT "MDA"
- CASE 2: PRINT "Hercules"
- CASE 3: PRINT "CGA"
- CASE 4: PRINT "EGA"
- CASE 5: PRINT "MCGA"
- CASE 6: PRINT "VGA"
- END SELECT
-
- Equipment Info page 10
-
-
-
- Aside from some of the oldest semi-clones, it's possible to
- find out what sort of machine you're using by looking at a
- specific data byte. You can access this as follows:
-
- Machine% = PCType%
-
- The result will need decoding. Here are some known values:
-
- 255 PC or XT
- 254 XT
- 253 PCjr
- 252 PC AT
- 251 XT
- 250 PS/2 Model 30
- 249 PC Convertible
- 248 PS/2 Model 70 or 80
- 154 Compaq Portable
- 45 Compaq Portable
-
- Likewise, all but some of the oldest semi-clones maintain a
- BIOS date value which tells you how old the BIOS ROM is. This
- can be retrieved with the following routine:
-
- BIOSdate$ = PCDate$
-
- If your program is running on one of the rare old machines
- which don't maintain a valid BIOS date, this routine will
- return "No Date " instead of an actual date.
-
- As far as a program is concerned, DR DOS is essentially the
- same as MS-DOS. Still, it's always nice to know what sort of
- operating environment you have. You can find out whether your
- program is running under DR DOS with the following function:
-
- IF DRDOS% THEN PRINT "It's DR DOS" ELSE PRINT "MS-DOS"
-
- Extended Math page 11
-
-
-
- The extended math unit provides an expression evaluator and
- extensions to BASIC's math. The math extensions include
- hyperbolic and inverse trig functions, a few handy constants,
- conversions, and more. You can use the new math routines by
- including these lines at the top of your program:
-
- $LINK "extmatha.obj"
- $LINK "extmathb.pbu"
-
- The expression evaluator allows you to find the result of an
- expression contained in a string. Normal algebraic precedence
- is used, e.g. 4+3*5 evaluates to 19. The usual numeric
- operators (*, /, +, -, ^) are supported (multiply, divide, add,
- subtract, and raise to a power). Use of negative numbers is
- just fine, of course. Parentheses for overriding the default
- order of operations are also supported.
-
- You may use either a double asterisk ("**") or a caret ("^")
- symbols to indicate exponentiation.
-
- To evaluate an expression, you pass it to the evaluator as a
- string. You will get back either an error code or a
- single-precision result. Try this example to see how the
- expression evaluator works:
-
- $STACK 4096
- $INCLUDE "pbwiz.inc"
- $LINK "extmath.pbu"
- DO
- INPUT "Expression? "; Expr$
- IF LEN(Expr$) THEN
- CALL Evaluate (Expr$, Result!, ErrCode%)
- IF ErrCode% THEN
- PRINT "Invalid expression. Error = "; ErrCode%
- ELSE
- PRINT "Result: "; Result!
- END IF
- END IF
- LOOP WHILE LEN(Expr$)
- END
-
- An expression evaluator adds convenience to any program that
- needs to accept numbers. Why make someone reach for a
- calculator when number crunching is what a computer does best?
-
- NOTE: The expression evaluator uses recursion and will require
- more than the default amount of stack space. That's why the
- $STACK metacommand is used.
-
- Extended Math page 12
-
-
-
- The new math functions are pretty much self-explanatory, so
- I'll just list them here. A few general notes are given on the
- next page.
-
- Result% = GCDI%(Nr1%, Nr2%) ' greatest common denominator
- Result% = RotateL%(Nr%, Count%) ' rotate left
- Result% = RotateR%(Nr%, Count%) ' rotate right
- Result% = ShiftL%(Nr%, Count%) ' shift left
- Result% = ShiftR%(Nr%, Count%) ' shift right
-
- Result& = GCDL&(Nr1&, Nr2&) ' greatest common denominator
- Result& = RotateLL&(Nr&, Count%) ' rotate left
- Result& = RotateRL&(Nr&, Count%) ' rotate right
- Result& = ShiftLL&(Nr&, Count%) ' shift left
- Result& = ShiftRL&(Nr&, Count%) ' shift right
-
- Result! = ArcCosHS!(Nr!) ' inverse hyperbolic cosine
- Result! = ArcSinHS!(Nr!) ' inverse hyperbolic sine
- Result! = ArcTanHS!(Nr!) ' inverse hyperbolic tangent
- Result! = ArcCosS!(Nr!) ' arc cosine (1 >= Nr >= -1)
- Result! = ArcSinS!(Nr!) ' arc sine (1 >= Nr >= -1)
- Result! = ErfS!(Nr!) ' error function
- Result! = FactS!(Nr%) ' factorial
- Result! = CotS!(Nr!) ' cotangent
- Result! = CscS!(Nr!) ' cosecant
- Result! = SecS!(Nr!) ' secant
- Result! = CosHS!(Nr!) ' hyperbolic cosine
- Result! = SinHS!(Nr!) ' hyperbolic sine
- Result! = TanHS!(Nr!) ' hyperbolic tangent
- Result! = Deg2RadS!(Nr!) ' convert degrees to radians
- Result! = Rad2DegS!(Nr!) ' convert radians to degrees
- Result! = Cent2Fahr!(Nr!) ' centigrade to Fahrenheit
- Result! = Fahr2Cent!(Nr!) ' Fahrenheit to centigrade
- Result! = Kg2Pound!(Nr!) ' convert kilograms to pounds
- Result! = Pound2Kg!(Nr!) ' convert pounds to kilograms
- Pi! = PiS! ' the constant "pi"
- e! = eS! ' the constant "e"
-
- Result# = ArcCosHD#(Nr#) ' inverse hyperbolic cosine
- Result# = ArcSinHD#(Nr#) ' inverse hyperbolic sine
- Result# = ArcTanHD#(Nr#) ' inverse hyperbolic tangent
- Result# = ArcCosD#(Nr#) ' arc cosine (1 >= Nr >= -1)
- Result# = ArcSinD#(Nr#) ' arc sine (1 >= Nr >= -1)
- Result# = ErfD#(Nr#) ' error function
- Result# = FactD#(Nr%) ' factorial
- Result# = CotD#(Nr#) ' cotangent
- Result# = CscD#(Nr#) ' cosecant
- Result# = SecD#(Nr#) ' secant
- Result# = CosHD#(Nr#) ' hyperbolic cosine
- Result# = SinHD#(Nr#) ' hyperbolic sine
- Result# = TanHD#(Nr#) ' hyperbolic tangent
- Result# = Deg2RadD#(Nr#) ' convert degrees to radians
- Result# = Rad2DegD#(Nr#) ' convert radians to degrees
- Pi# = PiD# ' the constant "pi"
- e# = eD# ' the constant "e"
-
- Extended Math page 13
-
-
-
- Like BASIC's trig functions, these trig functions expect the
- angle to be in radians. Conversion functions are provided in
- case you prefer degrees.
-
- Note that there is no ArcTanS! or ArcTanD# function for the
- simple reason that BASIC supplies an ATN function.
-
- Constants are expressed to the maximum precision available.
-
- If you are not familiar with variable postfix symbols, here's a
- brief summary:
-
- Symbol Meaning Range (approximate)
- ------ -------- -------------------------------
- % integer +- 32767
- & long integer +- 2 * 10^9
- ! single precision +- 1 * 10^38
- # double precision +- 1 * 10^308
-
- See PowerBASIC's online help for further details.
-
- Graphics Support page 14
-
-
-
- I was rather surprised to find that PowerBASIC lacks support
- for one of the standard VGA modes-- SCREEN 13, the 320x200
- 256-color mode. I immediately decided to add support for that
- mode: dots, lines, boxes, polygons, and (of course) text.
- While I was at it, I thought I'd add support for a nonstandard
- VGA mode: 360x480 in 256 colors. This mode will work on almost
- any plain VGA system, although it might not work on some older
- not-quite-compatible setups. I'll be adding other modes as I go
- along, including SuperVGA modes. For now, there are only two
- modes:
-
- 13 320x200, 256 colors, 40x25 text, any VGA
- N0 360x480, 256 colors, 45x60 text, almost any VGA
-
- The graphics routines all use the same nomenclature: a G,
- followed by a mode number, followed by the specific name. This
- generic naming convention is used so that this chapter can
- refer to all available modes. For example, if I say "G#Color"
- and you're using mode 13, you'd actually use "G13Color" in your
- program. Ok?
-
- There are two sets of routines for each mode-- the ones written
- in ASM and the ones written in BASIC. The file names for these
- will be suffixed with "A" for ASM and "B" for BASIC. For
- instance, to use the SCREEN 13 routines, you would add the
- following at the top of your program:
-
- $LINK "g13a.obj"
- $LINK "g13b.pbu"
-
- The first thing you will always have to do is to put the screen
- into the proper mode. This is done with the G#Mode routine:
-
- CALL G#Mode (Graphics%)
-
- Use 0 to switch to text mode or any other value to switch to
- graphics mode.
-
- One difference between BASIC and BasWiz is that, instead of
- each "draw" command requiring a color parameter as in BASIC,
- the PBWiz library provides a separate color command:
-
- CALL G#Color (Foreground%, Background%)
-
- The "foreground" color is used by all graphics routines. The
- background color is used by the G#Cls routine. Both foreground
- and background colors are used in the G#Write and G#WriteLn
- routines.
-
- Graphics Support page 15
-
-
-
- Here is a list of the corresponding routines, first BASIC, then
- PBWiz (replace the "#" with the appropriate mode number):
-
- ' get the color of a specified point
- colour% = POINT(x%, y%)
- colour% = G#GetPel%(x%, y%)
-
- ' set the color of a specified point
- PSET (x%, y%), colour%
- CALL G#Color (colour%, backgnd%): CALL G#Plot (x%, y%)
-
- ' draw a line of a specified color
- LINE (x1%, y1%) - (x2%, y2%), colour%
- CALL G#Color (colour%, backgnd%)
- CALL G#Line (x1%, y1%, x2%, y2%)
-
- ' draw a box frame of a specified color
- LINE (x1%, y1%) - (x2%, y2%), colour%, B
- CALL G#Color (colour%, backgnd%)
- CALL G#Box (x1%, y1%, x2%, y2%, 0)
-
- ' draw a box of a specified color and fill it in
- LINE (x1%, y1%) - (x2%, y2%), colour%, BF
- CALL G#Color (colour%, backgnd%)
- CALL G#Box (x1%, y1%, x2%, y2%, 1)
-
- ' clear the screen and home the cursor
- CLS
- CALL G#Cls
-
- ' get the current cursor position
- Row% = CSRLIN: Column% = POS(0)
- CALL G#GetLocate (Row%, Column%)
-
- ' set the current cursor position
- LOCATE Row%, Column%
- CALL G#Locate (Row%, Column%)
-
- ' display a string without a carriage return and linefeed
- PRINT St$;
- CALL G#Write (St$)
-
- ' display a string with a carriage return and linefeed
- PRINT St$
- CALL G#WriteLn (St$)
-
- Note that PBWiz, unlike BASIC, allows both foreground and
- background colors for text in graphics mode.
-
- Graphics Support page 16
-
-
-
- If you need to print a number rather than a string, just use
- the BASIC function STR$ to convert it. If you don't want a
- leading space, use this approach:
-
- St$ = LTRIM$(STR$(Number))
-
- The PBWiz library has other routines which have no BASIC
- equivalent. One allows you to get the current colors:
-
- CALL G#GetColor (Foreground%, Background%)
-
- Circles and ellipses can be drawn with the Ellipse routine.
- This is similar to the BASIC CIRCLE statement. You specify the
- center of the ellipse (X,Y), plus the X and Y radius values:
-
- CALL G#Ellipse (CenterX%, CenterY%, XRadius%, YRadius%)
-
- A circle is an ellipse with a constant radius. So, to draw a
- circle, just set both radius values to the same value.
-
- As well as the usual points, lines, and ellipses, PBWiz also
- allows you to draw regular polygons: triangles, squares,
- pentagons, hexagons, and so on.
-
- CALL G#Polygon (X%, Y%, Radius%, Vertices%, Angle!)
-
- The X% and Y% values represent the coordinates of the center of
- the polygon. The Radius% is the radius of the polygon (as if
- you were fitting it into a circle). Vertices% is the number of
- angles (also the number of sides) for the polygon to have.
- Angle! specifies the rotation of the polygon, and is specified
- in radians.
-
- Keyboard Control page 17
-
-
-
- The keyboard is not a particularly exciting or glamorous
- device. In fact, we tend to forget about it except when it
- gets in the way. Sometimes it's a hardware problem-- squishy
- or clacking keys, or perhaps a commonly-used key placed in an
- out-of-the-way location. Then again, sometimes it's the
- software that's the problem. There are many aspects of
- keyboard control, not all of which are necessarily related to
- input. This unit will let you handle the keyboard in ways you
- may not have realized were possible. Better yet, it can help
- make keyboard control easier than the users of your programs
- dreamed possible. It all starts with the one little line:
-
- $LINK "keyboard.obj"
-
- Let's start out with keyboard output. Yep, not input--
- output. We can stuff up to 15 keys into the keyboard buffer.
- Why would we ever want to do this? Perhaps to allow your
- program to pop-up a TSR automatically, to start another program
- after your program ends, or for creating key macros. You can
- enter extended key codes (such as function keys) by using
- CHR$(0) before the scan code.
-
- CALL TypeIn (St$)
-
- The usual keyboard action is somewhat sluggish. We can make it
- a lot crisper by changing the key repeat rate and the delay
- before repeating begins. This will work on ATs, but not PC/XT
- systems.
-
- CALL SpeedKey (RepDelay%, RepRate%)
-
- The delay may be 0-3 (1 by default):
-
- 0 250 milliseconds
- 1 500 milliseconds
- 2 750 milliseconds
- 3 1 second
-
- The repeat rate may be 0-31 (11 by default). The larger the
- number, the slower the speed-- 0 is around 30 cps, and 31 is
- around 2 cps.
-
- I generally prefer to have the keyboard cranked up to full
- speed, using RepDelay% and RepRate% both set to zero. This may
- be a bit too zippy for some people. Experiment with it to see
- what you like best.
-
- Of course, there may be reasons to make keyboard repeat less
- sensitive instead! That might be a good idea in programs
- written for small children, for example. You can adjust the
- keyboard equally well in either direction.
-
- Keyboard Control page 18
-
-
-
- PowerBASIC allows you to control one of the keys which can
- interrupt your program, namely the Break key. There's another
- dangerous key which PBWiz allows you to control-- the PrtSc
- (PrintScreen) key. PrtSc may not seem like a hazard at first
- glance, but if it's pressed by accident with no printer ready,
- or in a graphics mode which PrtSc doesn't understand how to
- print, the results can be pretty messy. So, we let you turn it
- off or back on:
-
- CALL SetPrtSc (PrtScON%)
-
- Use 0 to turn it off or anything else to turn it back on. If
- you turn off PrtSc, you MUST remember to turn it back on again
- before your program ends! Otherwise, an interrupt vector will
- point into nowhere, causing probable chaos the next time PrtSc
- is pressed.
-
- Regardless of whether you've turned the PrtSc key off, you can
- print the screen yourself just as if PrtSc had been pressed:
-
- CALL PrintScreen
-
- Now here's a strange one for you. When IBM brought out the
- 101-key keyboard, called the "enhanced" keyboard, they did
- something bizarre to the BIOS. They still allowed old keyboard
- calls to work, but they filtered out the new key codes so no
- one would see them. This made sure that no one would be able
- to use the capabilities of the "enhanced" keyboard without
- rewriting their programs. So, the keyboard has been around for
- years, and there are still few programs that even notice when
- you press F11. PowerBASIC v2.1 does not support the enhanced
- keyboard at all. Fortunately, PBWiz -does-. You can find out
- if an enhanced keyboard is installed with the KbdType%
- function, which is in the Equipment unit.
-
- If there is an enhanced keyboard installed, you can activate it
- like so:
-
- CALL SetEnhKbd (Enhanced%)
-
- With enhanced keyboard support activated, all key requests that
- used the old services are translated to the new services. So,
- SetEnhKbd affects INKEY$ and other BASIC functions as well as
- other PBWiz keyboard routines. Note that you MUST deactivate
- enhanced keyboard support before ending your program.
- Otherwise, an interrupt vector will point into nowhere,
- probably causing a crash on the next keypress!
-
- Keyboard Control page 19
-
-
-
- Speaking of INKEY$, I have a neat little function for you. It
- works like INKEY$, but it doesn't remove the key from the
- keyboard buffer:
-
- ky$ = ScanKey$
-
- How is this handy? Well, let's suppose you're writing
- something that will work like the DIR or TYPE commands in DOS.
- It will display what may be a long listing, which you'd like to
- be able to pause with Ctrl-S or cancel with Ctrl-C. Trouble
- is, if you use INKEY$ and the user was using "type ahead" to
- store another command, you've just wiped out his command while
- looking for those control codes. With ScanKey$, you can check
- the key nondestructively.
-
- On the other hand, if you're about to request important input,
- you may not want to chance having it answered from results of
- the keyboard buffer-- could be that the user meant those keys
- for another purpose. In that case, it's a good approach to
- clear out the keyboard buffer just before the input:
-
- CALL ClearKbd
-
- No keyboard unit would be complete without a selection of
- routines to check the shift states and get or set the keyboard
- toggles. Let's start with the toggles, which are so called
- because they get toggled from one state to another:
-
- PRINT "Caps Lock : ";
- IF CapsOn% THEN PRINT "ON" ELSE PRINT "OFF"
- PRINT "Insert : ";
- IF InsertOn% THEN PRINT "ON" ELSE PRINT "OFF"
- PRINT "Num Lock : ";
- IF NumOn% THEN PRINT "ON" ELSE PRINT "OFF"
- PRINT "Scroll Lock: ";
- IF ScrollOn% THEN PRINT "ON" ELSE PRINT "OFF"
-
- You can also turn the toggles off or on. It's courteous to
- restore the original toggle states once you end your program,
- so you might want to save the original values for that
- purpose. Then again, I guess that doesn't apply if your
- program is designed for the specific purpose of setting the
- toggles!
-
- CALL SetCaps (CapsLock%)
- CALL SetInsert (InsertKey%)
- CALL SetNum (NumLock%)
- CALL SetScroll (ScrollLock%)
-
- Does anyone actually use ScrollLock for anything? Just
- wondering...
-
- Keyboard Control page 20
-
-
-
- The shift keys are unique in many respects. They don't return
- codes that can be detected with INKEY$ or stuffed into the
- keyboard buffer; several can be pressed at the same time; and
- they don't repeat. You can detect 'em with PBWiz, at any rate:
-
- IF AltPress% THEN PRINT "An ALT key is pressed."
- IF CtrlPress% THEN PRINT "A CTRL key is pressed."
- IF ShiftPress% THEN PRINT "A SHIFT key is pressed."
-
- IF LAltPress% THEN PRINT "The LEFT ALT key is pressed."
- IF LCtrlPress% THEN PRINT "The LEFT CTRL key is pressed."
- IF LShiftPress% THEN PRINT "The LEFT SHIFT key is pressed."
-
- IF RAltPress% THEN PRINT "The RIGHT ALT key is pressed."
- IF RCtrlPress% THEN PRINT "The RIGHT CTRL key is pressed."
- IF RShiftPress% THEN PRINT "The RIGHT SHIFT key is pressed."
-
- NOTE that LAltPress%, LCtrlPress%, RAltPress%, and RCtrlPress%
- are ONLY available for enhanced keyboards. They will not
- return useful results on older keyboards.
-
- Memory (EMS) page 21
-
-
-
- This unit provides support for expanded memory. It will work
- with older EMS and EEMS drivers as well as the current EMS 4.0
- standard, with the exception of one or two routines (as noted)
- which take advantage of new capabilities.
-
- Expanded memory may be present on any type of computer, from
- 8088 PCs to 80486 ATs. It usually comes as a hardware board
- with a software driver for older machines; on ATs, it may be
- implemented using only a software driver which converts it from
- extended memory. Drivers have also been written which make a
- hard disk function as EMS memory. This broad range of use
- makes EMS support invaluable to programs which need extra
- memory. EMS can theoretically support up to 1 gigabyte of RAM,
- although the documented limit as of v4.0 was only 32 megabytes.
-
- This unit is called EMS. You can access it by including this
- line at the top of your program:
-
- $LINK "ems.obj"
-
- Of course, the first thing you need to know is whether any EMS
- memory actually exists:
-
- IF EMSexists% THEN PRINT "EMS exists"
-
- The EMS version may also be retrieved:
-
- CALL EMSver (MajorV%, MinorV%)
-
- It would be a good idea to check the EMS version if you plan to
- use any features which are only available as of EMS 4.0, such
- as reallocation.
-
- Besides a mere existence and version checks, you will want to
- know how much EMS is available:
-
- PRINT "Total EMS installed: "; EMStotal%
- PRINT "Free EMS memory : "; EMSfree%
-
- If you actually tried the above two lines, you would get a pair
- of values which don't seem to mean much. The trick is to
- multiply them by 16,384 to convert them to bytes. This is
- because EMS memory is always accessed in pages of 16k bytes
- each. Any time you are dealing with a quantity of EMS memory,
- the quantity will be specified as a number of pages.
-
- Memory (EMS) page 22
-
-
-
- Before we get into the mechanics of accessing EMS memory, I'd
- like to bring up an optional routine which can improve access
- speed. It should not be used if your program accesses EMS
- using routines other than the ones included here in PBWiz. If
- you only use these EMS routines, though, you will find that it
- makes some kinds of memory accesses faster. Use 0 for normal
- (slow) mode. Do not use optimization if you are using more
- than one EMS handle!
-
- CALL EMSopt (Fast%)
-
- Ok, let's get down to the nitty gritty. (Where did that
- expression come from, anyway?!) When you allocate EMS memory,
- you specify the number of pages you want, which must be at
- least 1. If the allocation is successful, you are returned a
- "handle" which you can use to access the allocated memory.
- Otherwise, you get back an error code.
-
- CALL EMSopen (Pages%, Handle%, ErrCode%)
-
- There are a limited number of handles available under some EMS
- drivers. The EMS spec, as of v4.0, allowed for a maximum of
- 255 handles, and it's not unusual for a driver to support only
- 20 or so. Bearing in mind that some of these handles may be
- used up by other applications, such as RAMdisks and caches,
- this really doesn't allow much leeway. Try to use as few
- handles as possible! You may well need to store multiple
- values in different areas of the memory allocated for a single
- handle, rather than allocating a new area of memory for each
- value.
-
- Suppose you find you need more memory than you first
- allocated? Or maybe less memory? Well, provided EMS 4.0 or
- later is in use, you can reallocate the block:
-
- CALL EMSresize (Handle%, Pages%, ErrCode%)
-
- There is no way to reallocate memory under older versions of
- EMS. About the best you could do in that case would be to
- allocate a new area of the desired size, copy over the relevant
- data from the old area, and then deallocate the original area.
- Of course, this assumes that there is enough memory available
- to hold both areas, at least temporarily.
-
- When you are finished using EMS, you must be sure to return the
- memory you allocated to the system. It is IMPORTANT to do this
- before ending your program. Otherwise, the memory you
- allocated will be "lost" until the next time you boot the
- computer. Return the memory for each handle as follows:
-
- CALL EMSclose (Handle%)
-
- Memory (EMS) page 23
-
-
-
- Hmmmm... we've covered EMS detection, status info, allocating
- memory, freeing memory, resizing memory... what's missing
- here? Ah! We haven't discussed how to actually access the
- memory!
-
- Accessing EMS memory is quite simple, but it involves a couple
- of steps. EMS is mapped into a 64k block in the low area of
- memory (the area under 1M, which can be directly accessed).
- Since a page is 16k, the EMS block can hold up to four pages at
- a time. To transfer data between normal memory and EMS memory,
- you must map the appropriate page(s) of EMS into the EMS
- block. This is done like so:
-
- CALL EMSmap (Handle%, PPage%, VPage%)
-
- The PPage% is the physical page, that is, the page number
- within the EMS block (0-3). The VPage% is the virtual page,
- which is the number of a page within the EMS memory associated
- with Handle%.
-
- Once you've mapped the desired virtual page into a physical
- page, it can be accessed using standard PowerBASIC memory
- commands, such PEEK$ and POKE$. First, set the segment:
-
- DEF SEG=EMSseg&
-
- The offset within a page may be 0-16,383. To get the
- appropriate offset within the EMS block, you must add the
- offset of the page itself. This may be calculated as follows:
-
- DataOffset& = OffsetWithinPage% + PageNumber% * 16384&
-
- One final note: for best compatibility, it would be good to
- avoid using physical page 3 (the last 16k of the EMS block).
- Some EMS drivers don't handle this page with complete accuracy,
- for technical reasons I'm not going to get into right now.
-
- Memory (XMS) page 24
-
-
-
- This unit provides support for XMS extended memory. It won't
- work with extended memory unless an XMS driver is present.
-
- Extended memory is only present in AT-class computers. It is
- not available on older PCs. An XMS driver must also be used.
- XMS drivers are included with MS-DOS 5.0 and Windows 3.0, among
- other things, so this is not a major limitation. XMS can
- address a maximum of 64 megabytes.
-
- This unit is called XMS. You access it by including this line
- at the top of your program:
-
- $LINK "xms.obj"
-
- The first thing to check is whether any XMS memory exists:
-
- IF XMSexists% THEN PRINT "XMS exists"
-
- The XMS version may also be retrieved:
-
- CALL XMSver (MajorV%, MinorV%)
-
- The amount of XMS memory available may be reported in either of
- two different ways: total amount and largest available block.
-
- PRINT "Total XMS free : "; XMStfree&
- PRINT "Largest free block: "; XMSlfree&
-
- XMS memory is manipulated in terms of 1,024 byte blocks, so the
- amount of free memory is reported in kilobytes. Any time you
- are dealing with a quantity of EMS memory, the quantity will be
- specified as a number of 1K blocks, except as otherwise noted.
-
- Memory (XMS) page 25
-
-
-
- When you allocate XMS memory, you specify the number of
- kilobytes that you want. This may be 0-65535, in theory.
- Dunno, I don't have 64M RAM <grin>. If the allocation is
- successful, you are returned a "handle" which you can use to
- access the allocated memory. Otherwise, you get back an error
- code.
-
- CALL XMSopen (KBytes&, Handle%, ErrCode%)
-
- There are a limited number of handles available, although the
- number can be controlled somewhat by a driver parameter. It's
- probably best to use as few handles as possible, to avoid
- running out. You may well want to store multiple values in
- different areas of the memory allocated for a single handle,
- rather than allocating a new area of memory for each value.
-
- Suppose you find you need more memory than you first
- allocated? Or maybe less memory? Just reallocate the block:
-
- CALL XMSresize (Handle%, KBytes&, ErrCode%)
-
- When you are finished using XMS, you must be sure to return the
- memory you allocated to the system. It is IMPORTANT to do this
- before ending your program. Otherwise, the memory you
- allocated will be "lost" until the next time you boot the
- computer. Return the memory for each handle as follows:
-
- CALL XMSclose (Handle%)
-
- To transfer data between normal memory and XMS memory, you must
- provide the segment and offset of the normal memory area (use
- the PowerBASIC functions VARSEG and VARPTR to find the address
- of a variable). The position within XMS memory is specified as
- a long-integer offset starting at zero.
-
- CALL XMSread (Handle%, Posn&, Bytes&, DSeg%, DOfs%)
-
- CALL XMSwrite (Handle%, Posn&, Bytes&, DSeg%, DOfs%)
-
- Note that the Bytes& to transfer must be an EVEN NUMBER. It is
- not restricted to 64k, however, so you can transfer a great
- deal of data with these routines.
-
- The XMS spec guarantees a "reasonable" number of interrupt
- windows during a transfer; however, it is possible that you
- might experience some communications dropouts if you do large
- transfers during high-speed telecommunications. If this is
- expected to happen, test it carefully.
-
- Mouse Support page 26
-
-
-
- The mouse unit provides full-featured mouse support. You can
- see if a mouse is available and how many buttons it has, get
- the cursor position (either the current position or the
- position at the last press or release of a specified button),
- set the cursor position, change the cursor, set the mouse
- range, get hardware information about the mouse, and so on.
-
- This unit is called MOUSE, so you access it by including the
- following line at the top of your program:
-
- $LINK "mouse.obj"
-
- There are two unusual mouse modes to be aware of. One is text
- mode, which is mapped to a 640x200 virtual display. So, to
- convert the results to text format, you need to divide the
- cursor position by eight and add one. To convert from text
- format, subtract one and multiply by eight.
-
- The second unusual mode is 320x200 CGA mode, which is also
- mapped to 640x200. To convert the coordinates to this mode,
- divide X by two. To convert from this mode, multiply the X
- coordinate by two.
-
- All other modes use the actual display coordinates instead of a
- bizarro virtual screen. Why the peculiar CGA and text modes?
- Well, evidently Microsoft never thought there'd be any video
- adapters besides MDA and CGA, and decided to create a single
- virtual screen size that worked for all modes. Not a bad idea,
- I guess, but rather shortsighted. Oh well.
-
- One other nuisance that you may run into is that the mouse
- cursor can't be directly turned on or off. A "cursor
- visibility" count is maintained-- if the mouse cursor was
- turned on twice, you'll need to turn it off twice before it
- will actually disappear.
-
- Before using the mouse, you must initialize it. The
- initialization routine also checks to make sure that a mouse is
- installed and tells you how many buttons it has. It's best to
- initialize the mouse after setting the screen mode, so the
- mouse driver understands what mode you're using. Not all mouse
- drivers support all screen modes, but you can reasonably expect
- any current mouse driver to support MDA, CGA, EGA, and VGA.
- Hercules graphics mode is rarely supported, as it must be set
- through direct hardware access rather than the standard
- techniques, so the mouse driver has little way of knowing that
- you've changed the mode.
-
- The mouse routines will work equally well with two-button or
- three-button rodents. The middle button functions will return
- 0 with two-button mice.
-
- Mouse Support page 27
-
-
-
- I won't go into great detail on these routines, because they're
- pretty much self-explanatory. The mouse is a fairly easy
- device to deal with.
-
- You can initialize the mouse driver like so:
-
- Buttons% = MouseInit%
-
- This returns the number of mouse buttons available. If there
- is no mouse, zero will be returned. Initialize the mouse after
- setting the screen mode.
-
- You can make the mouse cursor visible or invisible. It will
- function just as well in either state. See the previous page
- for some quirks.
-
- CALL MouseShow ' show the cursor
- CALL MouseHide ' hide the cursor
-
- There are many ways to get the mouse cursor position. You can
- get the current position, the position at which the mouse was
- located when a particular button was pressed, or the position
- when a button was released. If you choose a past position, you
- can also find out how many presses or releases of the button
- have taken place since you last checked.
-
- X% = MouseWhereX% ' current X coordinate
- Y% = MouseWhereY% ' current Y coordinate
-
- CALL MouseLClick (Count%, X%, Y%) ' left presses & posn
- CALL MouseMClick (Count%, X%, Y%) ' middle presses & posn
- CALL MouseRClick (Count%, X%, Y%) ' right presses & posn
-
- CALL MouseLRelease (Count%, X%, Y%) ' left releases & posn
- CALL MouseMRelease (Count%, X%, Y%) ' middle releases & posn
- CALL MouseRRelease (Count%, X%, Y%) ' right releases & posn
-
- If you'd prefer to find out which buttons are currently
- pressed, no problem:
-
- Pressed% = MouseLButton% ' whether left button is pressed
- Pressed% = MouseMButton% ' whether middle button is pressed
- Pressed% = MouseRButton% ' whether right button is pressed
-
- Of course, you can also set the cursor location:
-
- CALL MouseLocate (X%, Y%) ' set the mouse cursor position
-
- The mouse cursor range can be restricted to a given area of the
- screen. This area is expressed by giving the upper left corner
- and lower right corner of the rectangular area to which to
- restrict the cursor.
-
- CALL MouseWindow (X1%, Y1%, X2%, Y2%)
-
- Mouse Support page 28
-
-
-
- There are a variety of cursor shapes available for graphics
- mode:
-
- 0 hourglass ("please wait, program is working" symbol)
- 1 pointing arrow (default)
- 2 pointing hand
- 3 crosshair
- 4 target (box in a box)
- 5 grabbing hand
-
- If you have ideas for more, let me know and I'll see what I can
- do. Cursor shapes are not unduly difficult to define.
-
- The cursor image is set like so:
-
- CALL MouseCursorG (CursorNr%)
-
- Strings page 29
-
-
-
- One of the true strengths of BASIC lies in its powerful string
- handling capability. I'd be remiss if I didn't provide
- extensions which improve it even further. This unit can be
- accessed by including this line at the top of your program:
-
- $LINK "stringa.obj"
- $LINK "stringb.pbu"
-
- The simplest of the PBWiz string routines may seem somewhat
- whimsical, but it has proven useful to me on several occasions
- in the past. It reverses the order of characters in a string.
-
- CALL Reverse (St$)
-
- One of the places this has come in useful is in searching a
- string from the end-- a reverse INSTR routine:
-
- CALL RInstr (MainSt$, SubSt$, Posn%)
-
- Rather than returning the first occurrence of a substring
- within a main string, it returns the last occurrence. Another
- handy string search allows you to search for various types of
- characters, rather than a specific substring:
-
- CALL TInstr (MainSt$, Types%, Posn%)
-
- The type(s) may be specified using any combination of the
- following. Just add them together.
-
- 1 alphabetic
- 2 numeric
- 4 symbolic
- 8 control
- 16 graphics
- 32 space
-
- Since you can search for any specific types, you can also
- readily invert the search to look for any characters that are
- NOT of a given type or types:
-
- Types% = NOT Types%
-
- This gives you complete control. A typical use for TInstr
- might be to clean up user input and make sure that it's valid.
- It's also good for parsing.
-
- Strings page 30
-
-
-
- Another routine that is useful for cleaning up and parsing user
- input is called Crunch. It allows you to eliminate adjacent
- duplicates of a character or list of characters. One use for
- this, for instance, would be to eliminate repeated spaces,
- converting an input string from "*.* *.BAK /B" to a more
- manageable "*.* *.BAK /B".
-
- Result$ = Crunch$(St$, CharList$)
-
- There are a pair of routines that you'll find valuable if you
- need to check the validity of a string. These are designed to
- be compatible with the Xmodem and Ymodem file transfer
- protocols, so you can use them for error checking in
- telecommunications as well.
-
- Chk% = CheckSum% (St$)
-
- CALL CRC16 (St$, HiCRC%, LoCRC%)
-
- Another pair of string routines provide a simple encryption
- and decryption system for text. The method used is not
- particularly secure but are very fast and will be adequate for
- many purposes. As always, it helps to use a long and/or
- complex password.
-
- CALL Cipher (St$, Password$)
- CALL CipherP (St$, Password$)
-
- Both of these routines will encipher text on the first
- run-through and decipher on the second, so you can use the same
- routine either to encrypt or decrypt a message. They are
- different in one respect: the encrypted result of Cipher may
- contain control characters, so it can't be used in a plain
- sequential-access file. The CipherP routine does not allow use
- of extended ASCII characters (CHR$(128) - CHR$(255)), as it
- sets the high bit on each character after encrypting it. This
- causes the results of CipherP to be printable (and useful in
- sequential-access files), although they will look very strange.
-
- The strings are encrypted (or decrypted) in place. This
- provides a certain extra measure of security for encryption--
- the original plaintext strings are not left floating around in
- memory where someone might see them.
-
- One function is as much a file manipulation routine as it is a
- string function. It allows you to compare a file name to a
- file pattern (which may contain wildcards) to see if they
- match. Only bare filespecs are supported-- you may not use
- drive or path specifications in the names.
-
- IF MatchFile% (Pattern$, Filename$) THEN PRINT Filename$
-
- Strings page 31
-
-
-
- The MatchFile function can be used in creating your own
- DOS-style utilities: DIR, COPY, and so forth. Besides the
- usual "accept file if it matches" approach, it can also be used
- to implement the opposite: "exclude file if it matches." This
- gives you more flexibility than DOS itself supplies.
-
- The PowerBASIC compiler provides a very nice function called
- Extract$. This allows you to retrieve a substring running from
- the left side of a main string to a specified character
- delimiter. Not bad, but it might be handy to be able to grab a
- numbered substring from any part of a main string, and to be
- able to use a substring delimiter. For instance, you might
- load a record from a database which contains an address, where
- each line is delimited by a carriage return and linefeed.
- Rather than mucking around with Extract$, which really wasn't
- designed with that sort of thing in mind, you'd do better to
- use the PBWiz function called DelimExtract$:
-
- SubSt$ = DelimExtract$(St$, Delimiter$, Index%)
-
- The index starts at 1 with the first substring. If you choose
- the index of a substring which doesn't actually exist, a null
- string will be returned.
-
- Text-mode Video page 32
-
-
-
- Routines in this unit may be accessed if you include these
- lines at the top of your program:
-
- $LINK "videoa.obj"
- $LINK "videob.pbu"
-
- The graphical interface has become a "sexy" thing to have
- these days, but there are still many good reasons to work in
- text mode. It's relatively fast, it works on all monitors,
- and it's often the most appropriate choice. Graphics is
- overkill for many applications. Besides, you can't redirect
- graphics to a file or to the printer.
-
- Come to think of it, text displayed by the PRINT statement
- can't be redirected either. Fortunately, we can fix that.
- All it takes is sending the output through DOS:
-
- CALL DOSPrint (St$) ' print to the current output device
-
- A nice thing about DOS output is that ANSI display codes will
- work if you have an ANSI driver (such as ANSI.SYS) installed.
- If you're working with existing text, such as captured output
- from a BBS or from an ANSI art program like TheDraw, you can
- just use the DOSPrint routine to handle it. If you're looking
- to do your own ANSI output, though, there's an easier way than
- looking up the individual codes and sending 'em out one at a
- time. The following routines send the appropriate ANSI codes
- to the current DOS output device:
-
- CALL DOSCls ' clear the screen
- CALL DOSColor (Fore%, Back%) ' set the screen colors
- CALL DOSLocate (Row%, Column%) ' set the cursor position
-
- The primary advantage of DOS output is that it can be
- intercepted. It normally goes to the screen, but you can
- redirect it to a file, printer, or comm port, among other
- things. You can also be sure that DOS output will work
- reasonably in a multitasking environment like DESQview or
- Windows, instead of messing up the screen. The disadvantage
- is that DOS output is fairly slow. It's great for command
- line utilities, but not if you plan to do any fancy screen
- work. For that, you probably want direct-access techniques.
-
- The direct screen access provided by PBWiz is rude, crude...
- and faster than a greased euphemism. It can't be redirected,
- doesn't handle control codes, and won't even update the cursor
- position. In return for this lack of amenities, it gives you
- two very valuable things: complete control and raw speed.
-
- Text-mode Video page 33
-
-
-
- The direct-access replacement for PRINT works like so:
-
- CALL XQPrint (St$, Row%, Column%, Attr%)
-
- Now, you might guess that St$ is the text to print, and Row%
- and Column% are where to print it. The Attr% may seem a bit
- more opaque. The Attr% is the color to use-- actually, both
- the foreground and background colors. These are combined into
- a single value because that's the way the display controller
- wants to see it. Remember, the emphasis here is on speed, not
- necessarily convenience! So how do you calculate an attribute
- given the foreground and background colors?
-
- Attr% = CalcAttr% (Fore%, Back%)
-
- An Attr% value is never less than 0 or greater than 255-- it
- will fit into a single byte. That may be useful to know for
- storage purposes. In any event, keep the Attr% in mind,
- because we'll be seeing more of it in the future. By the way,
- you can unpack an attribute into foreground and background
- colors too, if need be:
-
- CALL UnCalcAttr (Attr%, Fore%, Back%)
-
- The direct-access routines allow for one, and only one, option
- which might slow them down. Way back in the dawn of time,
- when IBM brought out the CGA, they knew that software was
- cheap and hardware expensive. Besides, no one would be so
- rash as to bypass the BIOS and DOS routines provided by IBM,
- so who would notice? Well... of course, it didn't work out
- that way. The BIOS and DOS display routines are far too slow
- and cumbersome for many purposes. However, the damage was
- done-- the IBM CGA, and many (though not all) CGAs since then,
- flickers horribly if you access its display memory directly.
- There is a software fix, but it slows the display down
- tremendously. Still, if your program is run on such a CGA,
- you'll want to stop the flickering. This may be done so:
-
- CALL AntiSnow (Slow%) ' any nonzero value to stop flicker
-
- You should provide a command-line switch or configuration
- option to force anti-flicker support. Don't do it by default,
- as the slowdown is very noticeable.
-
- The "menu" approach has become the standard way of allowing a
- user to choose between various program options. There are
- many ways of designing a menu, but they almost always require
- a "highlight" to show the current choice. This highlight is
- generally handled by changing the color of the chosen item:
-
- CALL ReColorArea (TopRow%, LftCol%, BotRow%, RtCol%, Attr%)
-
- Text-mode Video page 34
-
-
-
- Pop-up windows have become ubiquitous. Naturally, PBWiz
- supports them too:
-
- CALL PopWindow (TRow%, LCol%, BRow%, RCol%, Frame%,
- Attr%, Grow%, Shade%, TFore%, Title$) ' use one line!
-
- The first four parameters specify the upper left corner and
- lower right corner of the window. The window frame, if any,
- is created just outside these coordinates. If you choose a
- shadow for a 3D effect, that will extend further outside the
- window. Keep this in mind if you want to save the part of the
- screen under the window... but we'll get to that! Let's see
- what options are available for the frame type:
- 0 no frame
- 1 single lines
- 2 double lines
- 3 single horizontal, double vertical lines
- 4 double horizontal, single vertical lines
- 5 block graphic lines
-
- These are the available shadows:
- -3 transparent shadow on the right
- -2 transparent shadow on the left
- -1 solid black shadow on the left
- 0 no shadow
- 1+ shadow attribute (use CalcAttr) for a colored shadow
-
- Options for growing windows are as follows:
- -1 grow as fast as possible
- 0 pop onto the screen
- 1+ grow with a specified delay in milliseconds
- (15 works well for me)
-
- The TFore% parameter is the foreground color to use for the
- title (Title$), if any (use "" for no title).
-
- It is worth noting that the "milliseconds" value is only
- rather approximate. The delay is based on the video card, and
- is fairly similar on any computer system, but there will be a
- noticeable difference between (say) an XT with a CGA and a 486
- with a VGA. Still, it's a useful delay-- if not really
- precise, it's at least fairly accurate, and it has a fine
- resolution. You can access this delay yourself:
-
- CALL DelayV (MilliSeconds%)
-
- Text-mode Video page 35
-
-
-
- I mentioned screen saves a bit earlier. With PBWiz, you can
- save any part of a screen, and restore it later to the same
- place or an entirely different area. This also offers the
- possibility of creating a screen image, storing it in a file,
- and reading it into your program, among other things. It
- works like this:
-
- Scr$ = ScreenSave$ (TopRow%, LftCol%, BotRow%, RtCol%)
-
- CALL ScreenRestore (Scr$, TopRow%, LftCol%)
-
- It takes about 4K to store a full 80x25 text screen. The
- exact calculation is Bytes = Rows * Columns * 2 + 2, if you
- care to figure it out yourself. You can also take advantage of
- a PBWiz routine to handle it:
-
- Bytes% = CalcSize% (TopRow%, LftCol%, BotRow%, RtCol%) + 2
-
- Finally, we are left with a series of routines which let you
- scroll (or clear) any part of the screen:
-
- CALL ScrollDown (TRow%, LCol%, BRow%, RCol%, Times%, Attr%)
- CALL ScrollLeft (TRow%, LCol%, BRow%, RCol%, Times%, Attr%)
- CALL ScrollRight (TRow%, LCol%, BRow%, RCol%, Times%, Attr%)
- CALL ScrollUp (TRow%, LCol%, BRow%, RCol%, Times%, Attr%)
-
- If you attempt to scroll zero times, or more times than there
- are rows (or columns, depending on which way you scroll), the
- specified area of the screen will be cleared. The Attr% gives
- the color to use on the cleared area of the screen.
-
- Credits page 36
-
-
-
- I'd like to thank Dave Navarro for letting me in on the world
- of PowerBASIC. His assistance has been most valuable to me in
- many respects. Without him, this library would have taken much
- longer to get off the ground or would perhaps not even exist.
-
- I would also like to thank Spectra, publishers of PowerBASIC,
- for sending me the evaluation copy of PowerBASIC which led to
- my decision to write this library.
-
-