home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-03-31 | 144.2 KB | 3,251 lines |
- The BASIC Wizard's Library page 1
- =------------------------=
- Version 1.5
-
- BASWIZ Copyright (c) 1990-1991 Thomas G. Hanlin III
-
-
-
- This library is too large for BASIC to cope with as a unit. The Library
- Wizard utility (available separately as LIBWIZxx.ZIP) allows you to create
- custom libraries containing just the routines you need.
-
- This is BASWIZ, a library of assembly language and BASIC routines for use
- with QuickBASIC version 4.5. Support for other recent versions of the BASIC
- compiler is provided with registration. The BASWIZ collection is copyrighted
- and may be distributed only under the following conditions:
-
- 1) No fee of over $10.00 may be charged for distribution. This
- restriction applies only to physical copies and is not meant to
- prevent distribution by telecommunication services.
-
- 2) All BASWIZ files must be distributed together in original, unaltered
- form. See FILES.LST for a list of the BASWIZ files.
-
- 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
- BASWIZ 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 BASWIZ useful, you will register your copy.
- You may not use BASWIZ routines in programs intended for sale unless you have
- registered. Registration entitles you to receive the latest version of
- BASWIZ, complete with full source code in assembly language and BASIC. The
- assembly code is designed for the OPTASM assembler by SLR Systems and will
- require modifications if you wish to use it with MASM or TASM. You will then
- be able to compile the BASIC code with whatever version of the compiler you
- have, allowing you to use BASWIZ with QuickBASIC versions 4.0 - 4.5 and
- BASCOM versions 6.0 - 7.1. Note that Microsoft's "far strings" can't be used
- with BASWIZ at this time, so BASWIZ can't be used with QBX.
-
- Warning: Use of BASWIZ for more than 30 days without registering has been
- determined to cause the author to practice the tuba outside your window!
-
- For an example of how to set up your program to access the BASWIZ library,
- how to LINK the routines, and so forth, take a look at the CREATE.BAT,
- GDEMO.BAS and WDEMO.BAS files. The CREATE.BAT file expects a BASWIZ library
- by the name of BW.LIB. LIBRARY.TXT explains how to use libraries.
-
- So who's the BASIC Wizard? Why, with this library, you will be! Read this
- tome well, for invoking these routines without proper preparation may bring
- unexpected results. Cape and hat (optional) not included. No assembly
- required.
-
- Table of Contents page 2
-
-
-
- Overview and Legal Info ................................................ 1
-
- BCD Math ............................................................... 3
-
- Expression Evaluator ................................................... 6
-
- Extensions to BASIC's math ............................................. 7
-
- Far Strings ............................................................ 9
-
- File Handling ......................................................... 11
-
- Fractions ............................................................. 19
-
- Graphics
- Mode-Specific Routines ............................................. 20
- Printer Routines ................................................... 31
- A Little Geometry .................................................. 32
- Equations, Etc ..................................................... 35
-
- Memory Management and Pointers ........................................ 38
-
- Telecommunications .................................................... 41
-
- Virtual Windowing System .............................................. 47
-
- Other Routines ........................................................ 60
-
- Miscellaneous Notes ................................................... 61
-
- Error Codes ........................................................... 64
-
- Troubleshooting ....................................................... 66
-
- History & Philosophy .................................................. 68
-
- Using BASWIZ with PDQ ................................................. 70
-
- Credits ............................................................... 71
-
- BCD Math page 3
-
-
-
- Some of you may not have heard of BCD math, or at least not have more than a
- passing acquaintance with the subject. BCD (short for Binary-Coded Decimal)
- is a way of encoding numbers. It differs from the normal method of handling
- numbers in several respects. On the down side, BCD math is much slower than
- normal math and the numbers take up more memory. However, the benefits may
- far outweigh these disadvantages, depending on your application: BCD math is
- absolutely precise within your desired specifications, and you can make a BCD
- number as large as you need. If your applications don't require great range
- or precision out of numbers, normal BASIC math is probably the best choice.
- For scientific applications, accounting, engineering and other demanding
- tasks, though, BCD may be just the thing you need.
-
- The BCD math routines provided by BASWIZ allow numbers of up to 255 digits
- long (the sign counts as a digit, but the decimal point doesn't). You may
- set the decimal point to any position you like, as long as there is at least
- one digit position to the left of the decimal.
-
- Since QuickBASIC doesn't support BCD numbers directly, we store the BCD
- numbers in strings. The results are not in text format and won't mean much
- if displayed. A conversion routine allows you to change a BCD number to a
- text string in any of a variety of formats.
-
- Note that the BCD math handler doesn't yet track overflow/underflow error
- conditions. If you anticipate that this may be a problem, it would be a good
- idea to screen your input or to make the BCD range large enough to avoid
- these errors.
-
- Let's start off by examining the routine which allows you to set the BCD
- range:
-
- BCDSetSize LeftDigits%, RightDigits%
-
- The parameters specify the maximum number of digits to the left and to the
- right of the decimal point. There must be at least one digit on the left,
- and the total number of digits must be less than 255. The BCD strings will
- have a length that's one larger than the total number of digits, to account
- for the sign of the number. The decimal point is implicit and doesn't take
- up any extra space.
-
- It is assumed that you will only use one size of BCD number in your program--
- there are no provisions for handling mixed-length BCD numbers. Of course,
- you could manage that yourself with a little extra work, if it seems like a
- useful capability. If you don't use BCDSetSize, the default size of the BCD
- numbers will be 32 (20 to the left, 11 to the right, 1 for the sign).
-
- You can get the current size settings in your program, too:
-
- BCDGetSize LeftDigits%, RightDigits%
-
- BCD Math page 4
-
-
-
- Before doing any BCD calculations, you must have some BCD numbers! The
- BCDSet routine takes a number in text string form and converts it to BCD:
-
- TextSt$ = "1234567890.50"
- Nr$ = BCDSet$(TextSt$)
-
- If your numbers are stored as actual numbers, you can convert them to a text
- string with BASIC's STR$ function, then to BCD. Leading spaces are ignored:
-
- Nr$ = BCDSet$(STR$(AnyNum#))
-
- BCD numbers can also be converted back to text strings, of course. You may
- specify how many digits to the right of the decimal to keep (the number will
- be truncated, not rounded). If the RightDigits% is positive, trailing zeros
- will be kept; if negative, trailing zeros will be removed. There are also
- various formatting options which may be used. Here's how it works:
-
- TextSt$ = BCDFormat$(Nr$, HowToFormat%, RightDigits%)
-
- The HowToFormat% value may be any combination of the following (just add the
- numbers of the desired formats together):
-
- 0 plain number
- 1 use commas to separate thousands, etc
- 2 start number with a dollar sign
- 4 put the sign on the right side instead of the left side
- 8 use a plus sign instead of a space if number is not negative
-
- The BCD math functions are pretty much self-explanatory, so I'll keep the
- descriptions brief. Here are the single-parameter functions:
-
- Result$ = BCDAbs$(Nr$) ' take the absolute value of a number
- Result$ = BCDCos$(Nr$) ' cosine function
- Result$ = BCDCot$(Nr$) ' cotangent function
- Result$ = BCDCsc$(Nr$) ' cosecant function
- Result$ = BCDDeg2Rad$(Nr$) ' convert degrees to radians
- e$ = BCDe$ ' get the value of the constant "e"
- Result$ = BCDFact$(N%) ' calculate the factorial of integer N
- Result$ = BCDFrac$(Nr$) ' return the fractional part of a number
- Result$ = BCDInt$(Nr$) ' return the integer part of a number
- Result$ = BCDNeg$(Nr$) ' negate a number
- pi$ = BCDpi$ ' get the value of the constant "pi"
- Result$ = BCDRad2Deg$(Nr$) ' convert radians to degrees
- Result$ = BCDSec$(Nr$) ' secant function
- Result% = BCDSgn%(Nr$) ' signum function
- Result$ = BCDSin$(Nr$) ' sine function
- Result$ = BCDSqr$(Nr$) ' get the square root of a number
- Result$ = BCDTan$(Nr$) ' tangent function
-
- BCD Math page 5
-
-
-
- Notes on the single-parameter functions:
-
- The signum function returns an integer based on the sign of the BCD number:
- -1 if the BCD number is negative
- 0 if the BCD number is zero
- 1 if the BCD number is positive
-
- BCDpi$ is accurate to the maximum level afforded by the BCD functions.
- BCDe$ is accurate to as many as 115 decimal places. The actual accuracy,
- of course, depends on the size of BCD numbers you've chosen.
-
- The trigonometric functions (cos, sin, tan, sec, csc, cot) expect angles in
- radians. BCDDeg2Rad and BCDRad2Deg will allow you to convert back and
- forth between radians and degrees.
-
-
-
- Here is a list of the two-parameter functions:
-
- Result$ = BCDAdd$(Nr1$, Nr2$) ' add two numbers together
-
- Result$ = BCDSub$(Nr1$, Nr2$) ' subtract the second nr from the first
-
- Result$ = BCDMul$(Nr1$, Nr2$) ' multiply one number by another
-
- Result$ = BCDDiv$(Nr1$, Nr2$) ' divide the first number by the second
-
- Result$ = BCDPower$(Nr$, Power%) ' raise a number to a power
-
- Result% = BCDCompare%(Nr1$, Nr2$) ' compare two numbers
-
- The comparison function returns an integer which reflects how the two numbers
- compare to eachother:
-
- -1 Nr1 < Nr2
- 0 Nr1 = Nr2
- 1 Nr1 > Nr2
-
- Expression Evaluator page 6
-
-
-
- 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 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:
-
- REM $INCLUDE: 'BASWIZ.BI'
- DEFINT A-Z
- DO
- INPUT "Expression? "; Expr$
- IF LEN(Expr$) THEN
- Evaluate Expr$, Result!, ErrCode
- IF ErrCode THEN
- PRINT "Invalid expression. Error code = "; 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?
-
- Extensions to BASIC's math page 7
-
-
-
- For the most part, the math routines in this library is designed to provide
- alternatives to the math routines that are built into BASIC. Still, BASIC's
- own math support is quite adequate for many purposes, so there's no sense in
- ignoring it. Here are some functions which improve on BASIC's math.
-
- 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!) ' convert centigrade to Fahrenheit
- Result! = Fahr2Cent!(Nr!) ' convert 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"
-
- Extensions to BASIC's math page 8
-
-
-
- Result% = GCDI%(Nr1%, Nr2%) ' greatest common denominator
- Result% = Power2I%(Nr%) ' raise 2 to a specified power
-
- Result& = GCDL&(Nr1&, Nr2&) ' greatest common denominator
- Result& = Power2L&(Nr%) ' raise 2 to a specified power
-
-
-
- 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.
-
- The Power2I% and Power2L& functions are vastly quicker than the equivalent
- BASIC formulas. If powers of two are useful to you, try these functions!
-
-
-
- If you are not familiar with variable postfix symbols, here's a brief summary:
-
- Symbol Meaning Range (very approximate)
- ------ -------- ------------------------
- % integer +- 32767
- & long integer +- 2 * 10^9
- ! single precision +- 1 * 10^38 (7-digit precision float. point)
- # double precision +- 1 * 10^308 (15-digit precision float. point)
- $ string [0 to 32767 characters]
-
- See your BASIC manual or QuickBASIC's online help for further details.
-
- Far Strings page 9
-
-
-
- One of the best things about BASIC is its support for variable-length
- strings. Few other languages support such dynamically-allocated strings and
- they're a terrifically efficient way of using memory. At least, they would
- be, except for one minor limitation... in every version of QuickBASIC and
- BASCOM (except for the new, very expensive BASCOM 7.0 "Professional
- Development System"), string space is limited to a mere 50K-60K bytes. As if
- this weren't trouble enough, this space is also shared with a number of other
- things. Running out of string space is a common and painful problem.
-
- Anyway, it used to be. The BASWIZ library comes with an assortment of
- routines and functions which allow you to keep variable-length strings
- outside of BASIC's tiny string area. Currently, you may have up to 65,535
- far strings of up to 255 characters each, subject to available memory.
- Either normal system memory or expanded memory may be used. Extended memory
- can also be used if you have a driver that converts extended memory to
- expanded memory.
-
- Using far strings works almost the same way as using normal strings. Rather
- than referring to a far string with a string variable name, however, you
- refer to it with an integer variable called a "handle". To create a new far
- string, you use a handle of zero. A new handle will be returned to you which
- will identify that string for future reference.
-
- Before you use any far strings, you must initialize the far string handler.
- When you are done using far strings, you must terminate the far string
- handler. Normally, each of these actions will take place only once in your
- program: you initialize at the beginning and terminate at the end.
-
- On the next page is an example program that reads a file into an array of far
- strings, then displays it. I'll leave out such niceties as error trapping to
- keep the example easy to follow.
-
- Far Strings page 10
-
-
-
- REM $INCLUDE: 'BASWIZ.BI'
- DEFINT A-Z
- REDIM Text(1 TO 5000) ' array for far string handles
- FSInit 0 ' initialize far string handler
- TextLines = 0
- OPEN "ANYFILE.TXT" FOR INPUT AS #1
- DO UNTIL EOF(1)
- LINE INPUT#1, TextRow$
- Handle = 0 ' use zero to create new far string
- FSSet Handle, TextRow$ ' set the far string
- TextLines = TextLines + 1
- Text(TextLines) = Handle ' save the far string handle
- LOOP
- CLOSE
- FOR Row = 1 TO TextLines
- PRINT FSGet$(Text(Row)) ' display a far string
- NEXT
- FSDone ' terminate far string handler
- END
-
- If you wanted to change an existing far string, you would specify its
- existing handle for FSSet. The handle of zero is used only to create new far
- strings, rather in the manner of using a new variable for the first time.
-
- Note the zero after the FSInit call. That specifies that main system memory
- is to be used. If you would prefer to use expanded memory, use a one
- instead. If EMS memory is not available, BASWIZ will ignore the one and use
- main memory instead.
-
- File Handling page 11
-
-
-
- The file handling capabilities of BASIC were improved considerably as of
- QuickBASIC 4.0. A binary mode was added and it became possible to use
- structured (TYPE) variables instead of the awkward FIELD-based random access
- handling. Even today, however, BASIC file handling is inefficient for many
- tasks. It requires error trapping to avoid problems like open floppy drive
- doors and cannot transfer information in large quantities at a time.
-
- The BASWIZ routines provide additional flexibility and power. They allow you
- to access files at as low or high a level as you wish. Here are some of the
- features of BASWIZ file handling:
-
- - File sharing is automatically used if the DOS version is high enough,
- providing effortless network compatibility.
- - Critical errors, like other errors, are detected at any point you find
- convenient via a single function call.
- - Optional input buffers speed up reading from files.
- - Up to 32K of data may be read or written at one time.
- - Files can be flushed to disk to avoid loss due to power outages, etc.
-
- Files are not considered to be strongly moded by BASWIZ, although there are a
- few limitations on how you can deal with text files as opposed to other kinds
- of files. Reads and writes normally take place sequentially, like the INPUT
- and OUTPUT modes allowed by BASIC. However, you can also do random access by
- moving the file pointer to anywhere in the file, just as with the RANDOM and
- BINARY modes allowed by BASIC. These routines place no arbitrary limitations
- on the programmer.
-
- As with BASIC, files are referred to by a number after they are opened for
- access. Unlike BASIC, the number is returned to you when the file is
- successfully opened, rather than being specified by you when you open the
- file. This means that you never have to worry about a file number already
- being in use. We'll refer to the file number as a "file handle" from now on.
-
- File Handling page 12
-
-
-
- Before doing anything else, you must initialize the file handling routines.
- This is typically done only once, at the beginning of your program. The
- FInit routine needs to know the number of files you want to deal with. This
- can be up to 15 files, or possibly up to 50 if you are using DOS 3.3 or
- higher. Support for over 15 files has not been tested, since I don't have
- DOS 3.3 or higher, so you use that feature at your own risk! A future
- version of BASWIZ will support over 15 open files for DOS 3.0 and above.
-
- FInit Files, ErrCode
-
- A file is opened for access like so:
-
- FOpen File$, FMode$, BufferLen, Handle, ErrCode
-
- You pass the File$, FMode$, and BufferLen. The Handle and ErrCode are
- returned to you. The "BufferLen" is the length of the buffer desired for
- input. This must be zero if you want to write to the file. The filename is
- passed in File$, naturally enough. There is a choice of various modes for
- FMode$ and these can be combined to some extent:
-
- A Append to file used to add more information to an existing file
- C Create file creates a new file
- R Read access allows reading (input) from a file
- T Text mode file allows text-mode input from a file
- W Write access allows writing (output) to a file
-
- For the most part, the combinations are self-explanatory. For instance, it
- would be reasonable to open a file for read and write, for create and write,
- for append and write, or for read and text. Text files always require a
- buffer. If you request text access without specifying a buffer, a buffer of
- 512 bytes will be provided for you. If you request create access without
- additional parameters, the file will be opened for write by default.
-
- You may not use a buffer if you want to write to a file. This includes text
- files, which always use a buffer, as well as binary files. This is an
- artificial limitation which will change in a future version of BASWIZ. It
- exists now to reduce the internal complexity of the routines which write to
- the file, so that they do not have to account for any buffering as well as
- the current file pointer. However, writing may be done to a text-type file
- if the file was not opened in text mode. We'll see how that works presently.
-
- When you are done using a particular file, you can close it, just as in
- ordinary BASIC:
-
- FClose Handle
-
- Before your program ends, you should terminate the file handler. This will
- close any open files as well as concluding use of the file routines:
-
- FDone
-
- File Handling page 13
-
-
-
- That covers the basic set-up routines: initialize, open, close, and
- terminate. Of more interest are the routines which actually deal with the
- file itself. These provide assorted read/write services, the ability to get
- or set the file read/write pointer, size, time, and date, and the ability to
- get or set the error code for a specific file, among other things. Let's
- take a look at the error handler first.
-
- The FInit and FOpen routines return an error code directly, since you need to
- know immediately if these have failed. The other file routines do not return
- a direct error code, however. In order to discover whether an error has
- occurred, you use the FGetError% function. This will return an error of zero
- if there was no error, or a specific error code (listed at the end of this
- manual) if some problem occurred. The error code will remain the same until
- you reset it using FError. The FError service also allows you to test your
- error handler by forcing specific error codes even when everything is fine.
-
- PRINT "Error code: "; FGetError(Handle)
- FError Handle, 0 ' clear the error code
-
- It is recommended that you check for errors after any file routine is used if
- there is a chance that your program will be executed on a floppy disk. These
- are particularly prone to user errors (like leaving the drive door open) or
- running out of space. If your program will only run on a hard drive, you may
- not need to check as frequently. It's your choice. Note that the error code
- is not cleared automatically-- use FError to reset the error code to zero if
- you determine that it wasn't a "fatal" error.
-
- Down to the nitty-gritty... we've seen how to open and close a file, how to
- check operations for errors, and so forth. So how do we actually manipulate
- the file? There are assorted alternatives, depending on how you want to deal
- with the file: text reads, text writes, byte-oriented reads and writes, and
- block reads and writes, not to mention handling the time, date, size, and
- read/write pointer. We'll start off with the routines which read from a
- file.
-
- If you opened the file for text access, you must want to read the file a line
- at a time. Each line is assumed to be less than 256 characters and delimited
- by a carriage return and linefeed (<CR><LF>, or ^M^J, in normal notation).
- In that case, you should use the FReadLn$ function:
-
- St$ = FReadLn$(Handle)
-
- A simple program to display a text file directly on the screen might look
- something like this in BASIC:
-
- OPEN COMMAND$ FOR INPUT AS #1
- WHILE NOT EOF(1)
- LINE INPUT#1, St$
- PRINT St$
- WEND
- CLOSE #1
-
- File Handling page 14
-
-
-
- The same program using BASWIZ would look something like this:
-
- REM $INCLUDE: 'BASWIZ.BI'
- DEFINT A-Z
- FInit 15, ErrCode
- FOpen COMMAND$, "RT", 0, Handle, ErrCode
- WHILE NOT FEOF(Handle)
- PRINT FReadLn$(Handle)
- WEND
- FDone
-
- In either case, we're accepting a command-line parameter which specifies the
- name of the file. In the BASWIZ example, note the use of the FEOF% function,
- which tells whether we've gone past the end of the file. This works like the
- EOF function in BASIC.
-
- There are two ways of reading from binary files. You can get the results as
- a string of a specified (maximum) length:
-
- St$ = FRead$(Handle, Bytes)
-
- In plain BASIC, the same thing might be expressed this way:
-
- St$ = INPUT$(Bytes, FileNumber)
-
- The other way of reading from a binary file has no equivalent in BASIC. It
- allows you to read in up to 32K bytes at a time, directly into an array or
- TYPEd variable. You can read the information into anything that doesn't
- contain normal strings (the fixed-length string type can be used, though):
-
- Segm = VARSEG(Array(0))
- Offs = VARPTR(Array(0))
- FBlockRead Handle, Segm, Offs, Bytes
-
- That would read the specified number of bytes into Array(), starting at array
- element zero. You can use any data type, whether single variable or array,
- as long as it is not a variable length string. In other words, Vbl$ and
- Vbl$(0) would not work. If you want to use a string with the block read, it
- must be a fixed-length string. For example:
-
- DIM Vbl AS STRING * 1024
- Segm = VARSEG(Vbl)
- Offs = VARPTR(Vbl)
- FBlockRead Handle, Segm, Offs, Bytes
-
- It's a good idea to calculate the Segm and Offs values each time. These tell
- FBlockRead where to store the information it reads. QuickBASIC may move the
- variable around in memory, so VARSEG and VARPTR should be used just before
- FBlockRead, to insure that they return current and correct information.
-
- File Handling page 15
-
-
-
- The file output commands are similar. File output can only be done if there
- is no input buffer. This means that you can't use file output if the file
- was opened in text mode, either, since text mode always requires an input
- buffer. That's a limitation that will be removed in a future version of
- BASWIZ. It is possible to do text output on a file that was opened in binary
- mode, however. The limitation just means that you can't open a file for both
- reading and writing if you use a buffer (or text mode).
-
- To output (write) a string to a file, use this:
-
- FWrite Handle, St$
-
- This is like the plain BASIC statement:
-
- PRINT #FileNumber, St$;
-
- If you would like the string to be terminated by a carriage return and
- linefeed, use this instead:
-
- FWriteLn Handle, St$
-
- This is like the plain BASIC statement:
-
- PRINT #FileNumber, St$
-
- In BASIC, the difference between the two writes is controlled by whether you
- put a semicolon at the end. With BASWIZ, different routines are used
- instead. FWrite is like PRINT with a semicolon and FWriteLn is like PRINT
- without a semicolon.
-
- As well as simple string output, you can also output TYPEd variables and
- even entire arrays. This type of output has no corresponding BASIC
- instruction, although it's somewhat similar to the file PUT statement. Up to
- 32K can be output at a time:
-
- Segm = VARSEG(Array(0))
- Offs = VARPTR(Array(0))
- FBlockWrite Handle, Segm, Offs, Bytes
-
- If you haven't already read the section on FBlockRead, go back a page and
- review it. The same comments apply for FBlockRead: it can handle
- fixed-length strings but not old-style strings, and VARSEG/VARPTR should
- immediately preceed the block I/O, among other things.
-
- File Handling page 16
-
-
-
- Normally, reads and writes take place sequentially. If you want to move to a
- specific spot in the file, though, that's easy. You can do it in text mode
- or binary mode, whether or not you have a buffer, giving you additional
- flexibility over the usual BASIC file handling. Set the location for the
- next read or write like so:
-
- FLocate Handle, Position&
-
- The Position& specified will be where the next read or write takes place. It
- starts at one and (since it's specified as a LONG integer) can go up to
- however many bytes are in the file. If you want a record position rather
- than a byte position, you can do that too. Just convert the record number to
- a byte number, like so:
-
- Position& = (RecordNumber& - 1&) * RecordLength& + 1&
-
- If you do not want to maintain RecordNumber and RecordLength as LONG
- integers, convert them to such by using the CLNG() function on them before
- doing the calculation. Otherwise you may get an overflow error in the
- calculation, since QuickBASIC will assume that the result will be an integer.
-
- You can get the current position of the file read/write pointer too:
-
- Position& = FGetLocate&(Handle)
-
- Let's see... we've examined initialization and termination, opening and
- closing, reading and writing, and manipulating the file read/write pointer.
- What else could there be? Well, how about checking the size of a file and
- getting or setting the file time and date? Why, sure! The "get" routines
- are pretty well self-explanatory:
-
- FileSize& = FGetSize&(Handle)
- FileTime$ = FGetTime$(Handle)
- FileDate$ = FGetDate$(Handle)
-
- Setting the time and date is equally easy. This should be done just before
- you close the file with FClose or FDone. You may use any date and time
- delimiters you choose. If a field is left blank, the appropriate value from
- the current time or date will be used. Years may be specified in four-digit
- or two-digit format. Two-digit years will be assumed to be in the 20th
- century ("90" == "1990"). Careful there! Your program should allow
- four-digit dates to be used or disaster will strike when the year 2000
- rolls around. The 21st century is closer than you think!
-
- FTime Handle, FileTime$
- FDate Handle, FileDate$
-
- File Handling page 17
-
-
-
- There's just one more file routine. It allows you to "flush" a file to disk.
- This insures that the file has been properly updated to the current point, so
- nothing will be lost if there is a power outage or similar problem. If you
- do not use the "flush" routine, data may be lost if the program terminates
- unexpectedly (without going through FClose or FDone). Note that use of
- FFlush requires that a free file handle be available, under most DOS versions.
-
- FFlush Handle
-
- That's it for the BASWIZ file handler. As a quick review, let's run through
- the available routines, then try a couple of example programs. Remember that
- the BASWIZ.REF file contains a brief reference for all of these routines too!
- You might also wish to examine the WDEMO.BAS program, which also makes use of
- the file routines.
-
- FInit initialize the file handler
- FDone terminate the file handler and close any open files
-
- FOpen open a file for access (like OPEN)
- FClose close a file (like CLOSE)
-
- FRead$ read a string from a binary file (like INPUT$)
- FReadLn$ read a string from a text file (like LINE INPUT)
- FBlockRead read an item (TYPE, STRING*##, or array) from a binary file
-
- FWrite write a string to a binary file
- FWriteLn write a string with a <CR><LF> to a binary file
- FBlockWrite write an item (TYPE, STRING*##, or array) to a binary file
-
- FLocate set the read/write pointer to a specified position
- FTime set the time stamp
- FDate set the date stamp
- FError set the error code
-
- FGetLocate& get the read/write pointer
- FGetTime$ get the time stamp
- FGetDate$ get the date stamp
- FGetError get the error code
-
- FFlush flush to disk (makes sure file is updated and current)
- FGetSize& get size
- FEOF determine whether the end of the file has been reached
-
- File Handling page 18
-
-
-
- So much for theory. Let's try something practical. A common problem is
- copying one file to another. We'll limit this to text files, so we can do it
- in both plain BASIC and with BASWIZ. Although BASWIZ can handle any type of
- file readily, BASIC has problems in efficiently handling variable-length
- binary files. So, we'll do this first in BASIC, then BASWIZ, for text files.
-
- In BASIC, a text-file copying program might look like this:
-
- INPUT "File to copy"; FromFile$
- INPUT "Copy file to"; ToFile$
- OPEN FromFile$ FOR INPUT AS #1
- OPEN ToFile$ FOR OUTPUT AS #2
- WHILE NOT EOF(1)
- LINE INPUT#1, St$
- PRINT#2, St$
- WEND
- CLOSE
-
- With BASWIZ, the same program would look more like this:
-
- REM $INCLUDE: 'BASWIZ.BI'
- DEFINT A-Z
- INPUT "File to copy"; FromFile$
- INPUT "Copy file to"; ToFile$
- FInit 15, ErrCode
- FOpen FromFile$, "RT", 1024, FromHandle, ErrCode
- FOpen ToFile$, "CW", 0, ToHandle, ErrCode
- FileTime$ = FGetTime$(FromHandle)
- FileDate$ = FGetDate$(FromHandle)
- WHILE NOT FEOF(FromHandle)
- WriteLn ToHandle, ReadLn$(FromHandle)
- WEND
- FTime ToHandle, FileTime$
- FDate ToHandle, FileDate$
- FDone
-
- You might have noticed that the BASWIZ version of the program is a bit longer
- than the plain BASIC version. It has a number of advantages, however. It's
- faster, produces smaller code under ordinary circumstances, and preserves the
- date and time of the original file in the copied file. Unlike BASIC, the
- BASWIZ routines do not automatically add a ^Z to the end of text files, so
- the BASWIZ example will not alter the original file.
-
- Fractions page 19
-
-
-
- Using BCD allows you to represent numbers with excellent precision, but at a
- fairly large cost in speed. Another way to represent numbers with good
- precision is to use fractions. Fractions can represent numbers far more
- accurately than BCD, but can be handled much more quickly. There are some
- limitations, of course, but by now you've guessed that's always true!
-
- Each fraction is represented by BASWIZ as an 8-byte string. The numerator
- (top part of the fraction) may be anywhere from -999,999,999 to 999,999,999.
- The denominator (the bottom part) may be from 0 to 999,999,999. This allows
- handling a fairly wide range of numbers exactly.
-
- Fractions can be converted to or from numeric text strings in any of three
- formats: real number (e.g., "1.5"), plain fraction (e.g., "3/2"), or whole
- number and fraction (e.g., "1 1/2"). Internally, the numbers are stored as a
- plain fraction, reduced to the smallest fraction possible which means the
- same thing (for instance, "5/10" will be reduced to "1/2").
-
- To convert a numeric text string into a fraction, do this:
-
- Nr$ = FracSet$(NumSt$)
-
- To convert a fraction into a numeric text string, try this:
-
- NumSt$ = FracFormat$(Nr$, HowToFormat%)
-
- The formatting options are:
-
- 0 convert to plain fraction
- 1 convert to whole number and fraction
- 2 convert to decimal number
-
- Here is a list of the other functions available:
-
- Result$ = FracAbs$(Nr$) ' take the absolute value of a fraction
- Result$ = FracAdd$(Nr1$, Nr2$) ' add two fractions
- Result% = FracCompare%(Nr1$, Nr2$) ' compare two fractions
- Result$ = FracDiv$(Nr1$, Nr2$) ' divide the first fraction by the second
- Result$ = FracMul$(Nr1$, Nr2$) ' multiply two fractions
- Result$ = FracNeg$(Nr$) ' negate a fraction
- Result% = FracSgn%(Nr$) ' signum function for a fraction
- Result$ = FracSub$(Nr1$, Nr2$) ' subtract the 2nd fraction from the 1st
-
- Fractions are automatically reduced to allow the greatest possible range.
- Note that little range-checking is done at this point, so you may wish to
- screen any input to keep it reasonable.
-
- Result FracSgn FracCompare
- -1 negative # 1st < 2nd
- 0 # is zero 1st = 2nd
- 1 positive # 1st > 2nd
-
- Graphics: Mode-Specific Routines page 20
-
-
-
- These routines are designed to work with specific graphics modes, so your
- program will only include those routines which apply to the modes you use.
- The following modes are currently supported:
-
- SCREEN Card Graph. Res Colors Text Res. Notes
- ====== ==== ========== ====== ============= =====
- 1 CGA 320 x 200 4 40 x 25
- 2 CGA 640 x 200 2 80 x 25
- 3 HGA 720 x 348 2 90 x 43 *1
- 7 EGA 320 x 200 16 40 x 25
- 8 EGA 640 x 200 16 80 x 25
- 9 EGA 640 x 350 16 80 x 25
- 10 EGA 640 x 350 4 80 x 25 mono
- 11 VGA 640 x 480 2 80 x 30
- 12 VGA 640 x 480 16 80 x 30
- 13 VGA 320 x 200 256 40 x 25
- ----------------------------------------------------------------
- N0 VGA 360 x 480 256 45 x 30 *2
- N1 VGA 320 x 400 256 40 x 25 *2
- N2 <Epson> 480 x 640 2 60 x 80/45/40 *3
- N4 any 80 x 50 2 10 x 6 *4
-
-
- The number of rows of text available depends on the font: 8x8, 8x14, or 8x16.
-
- *1 Note that the BASWIZ Hercules routines, unlike those provided with
- QuickBASIC, do not require the QBHERC TSR to be loaded. They are
- entirely self-contained. However, they may need to be compiled by BC
- instead of QB, which may refuse to deal with the video mode change.
-
- *2 This is a non-standard VGA mode. It should work on many VGAs, however.
-
- *3 This works with an Epson-compatible printer rather than the display. The
- results may be previewed on a VGA, however. See also "Printer Routines".
-
- *4 This actually provides graphics in text mode. It will work on any
- display adapter. 80x25 text remains available through PRINT.
-
- See "Miscellaneous Notes" for additional remarks.
-
- Compatibility notes:
- An EGA can display CGA modes.
- A VGA can display EGA and CGA modes.
- An MCGA can display CGA modes and two VGA modes: SCREEN 11 and SCREEN 13.
-
- Graphics: Mode-Specific Routines page 21
-
-
-
- The routine for a specific mode is indicated by a prefix of "G", followed by
- the mode number, and then the routine name. For example, if you wished to
- plot a point in SCREEN 2 mode, you would use:
-
- G2Plot X%, Y%
-
- Many of these routines correspond with existing BASIC instructions. However,
- they are smaller and usually faster by 22% - 64%. See "Miscellaneous Notes"
- for notes on the differences between BASIC and the BASWIZ routines.
-
- The smaller size may not be noticeable if you use the SCREEN statement, since
- that causes BASIC to link in some of its own graphics routines. If you
- intend to use only BASWIZ routines for graphics, you can avoid that by using
- the G#Mode command instead of SCREEN:
-
- G#Mode Graphics% ' use 0 for SCREEN 0, any other for SCREEN #
-
- One difference between BASIC and BASWIZ is that, instead of each "draw"
- command requiring a color parameter as in BASIC, the BASWIZ library provides
- a separate color command:
-
- 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: Mode-Specific Routines page 22
-
-
-
- Here is a list of the corresponding routines, first BASIC, then BASWIZ
- (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%
- G#Color colour%, backgnd% : G#Plot x%, y%
-
- ' draw a line of a specified color
- LINE (x1%, y1%) - (x2%, y2%), colour%
- G#Color colour%, backgnd% : G#Line x1%, y1%, x2%, y2%
-
- ' draw a box frame of a specified color
- LINE (x1%, y1%) - (x2%, y2%), colour%, B
- G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 0
-
- Graphics: Mode-Specific Routines page 23
-
-
-
- Here are some more BASIC and BASWIZ routines:
-
- ' draw a box of a specified color and fill it in
- LINE (x1%, y1%) - (x2%, y2%), colour%, BF
- G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 1
-
- ' clear the screen and home the cursor
- CLS
- G#Cls
-
- ' get the current cursor position
- Row% = CSRLIN: Column% = POS(0)
- G#GetLocate Row%, Column%
-
- ' set the current cursor position
- LOCATE Row%, Column%
- G#Locate Row%, Column%
-
- ' display a string without a carriage return and linefeed
- PRINT St$;
- G#Write St$
-
- ' display a string with a carriage return and linefeed
- PRINT St$
- G#WriteLn St$
-
- Note that BASWIZ, unlike BASIC, allows both foreground and background colors
- for text in graphics mode. It also displays text substantially faster than
- BASIC. See the "Miscellaneous Notes" section for information on other
- differences in text printing.
-
- 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 (assuming the
- number is not negative), use this formula:
-
- St$ = MID$(STR$(Number), 2)
-
- The BASWIZ library has other routines which have no BASIC equivalent. One
- allows you to get the current colors:
-
- G#GetColor Foreground%, Background%
-
- Graphics: Mode-Specific Routines page 24
-
-
-
- Sometimes the normal text services seem unduly limited. Text is displayed
- only at specific character positions, so it may not align properly with a
- graph, for instance. Text is also of only one specific size. These are
- limitations which make the normal text routines very fast, but for times when
- you need something a little bit more fancy, try:
-
- G#Banner St$, X%, Y%, Xmul%, Ymul%
-
- You may display the string starting at any graphics position. The Xmul% and
- Ymul% values are multipliers, specifying how many times larger than normal
- each character should be. Using Xmul% = 1 and Ymul% = 1 will give you
- normal-sized characters. What "normal" means depends on the font in use.
-
- Since G#Banner "draws" the text onto the screen, it is a bit slower than the
- normal text services. It also uses only the foreground color, so the letters
- go right on top of anything that was previously there. Use G#Box to clear
- the area beforehand if this is a problem for you.
-
- The G#Banner routine supports several fonts. The larger fonts provide a more
- precise character set but leave you with less room on the screen. You may
- choose from these fonts:
-
- Font Number Font Size (width x height)
- 0 8 x 8 --- default
- 1 8 x 14
- 2 8 x 16
-
- Select a font like so:
-
- BFont FontNr%
-
- If you want to find out what the current font is, that's possible too:
-
- FontNr% = GetBFont
-
- Besides looking more elegant, the larger fonts are easier to read. They will
- also suffer less from being increased in size, although some deterioration is
- inevitable when magnifying these kinds of fonts.
-
- The G#Banner routines accept CHR$(0) - CHR$(127). No handling of control
- codes is done. All codes are displayed directly to the screen.
-
- Graphics: Mode-Specific Routines page 25
-
-
-
- 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:
-
- 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 single desired radius.
-
- As well as the usual points, lines, and ellipses, BASWIZ also allows you to
- draw polygons: triangles, squares, pentagons, hexagons, all the way up to
- full circles!
-
- 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. See "A Little Geometry" for more information.
-
- Another routine is designed to manipulate a GET/PUT image. Given an image in
- array Original%() and a blank array of the same dimensions called Flipped%(),
- this routine copies the original image to the new array as a mirror image
- about the horizontal axis. This is the same as the image you'd see if you
- turned your monitor upside-down: the resulting image is upside-down and
- backwards.
-
- G#MirrorH Original%(), Flipped%()
-
- Don't forget to make the Flipped%() array the same DIM size as the original,
- or the picture will overflow into main memory, probably causing disaster!
-
- Note that G#MirrorH will only work properly on images with byte alignment.
- This means that the width of the image must be evenly divisible by four if
- SCREEN 1 is used, or evenly divisible by eight if SCREEN 2 is used. EGA
- modes are not yet supported for this routine.
-
- Graphics: Mode-Specific Routines page 26
-
-
-
- There are more routines that work only with SCREEN 2. One allows you to load
- a MacPaint-type image ("ReadMac" or .MAC files) into an array which can then
- be PUT onto the screen:
-
- G2LoadMAC FileName$, Image%(), StartRow%
-
- Note that a full .MAC picture is 576x720, which won't fit on the screen, so
- the image will be truncated to 576x200. You may specify a starting row
- within the .MAC image, StartRow%, which may be 0-521, allowing the entire
- picture to be loaded in several parts.
-
- The Image%() must be dimensioned with 7202 elements:
-
- DIM Array(1 TO 7202) AS INTEGER
-
- If you don't give an extension in the FileName$, an extension of ".MAC" will
- be used. There is no checking to see if the file actually exists, so you may
- wish to do this beforehand.
-
- There is no way of knowing whether a .MAC picture is supposed to be black on
- white or white on black. If the image doesn't look right when you PUT using
- PSET, you can switch it around by using PUT with PRESET instead.
-
- PC PaintBrush (.PCX) pictures can also be loaded. These images can be of
- various sizes, so you need to dimension a dynamic array for them:
-
- REM $DYNAMIC
- DIM Image(1 TO 2) AS INTEGER
-
- The array will be set to the correct size by the loader. It goes like this:
-
- G2LoadPCX FileName$, Image%(), ErrCode%
-
- If you don't give an extension in the FileName$, an extension of ".PCX" will
- be used. You may wish to check to see if the file exists beforehand.
- Possible errors are as follows:
-
- -1 File is not in PCX format
- 1 Image is too large for desired screen mode
- 2 Image won't work in desired screen mode (too many planes/colors)
-
- Graphics: Mode-Specific Routines page 27
-
-
-
- Two new routines are replacements for the GET and PUT image statements in
- BASIC. They are on the slow side, but if you don't intend to use them for
- animation, they will serve to save some memory:
-
- REM $DYNAMIC
- DIM Image(1 TO 2) AS INTEGER
- G2Get X1%, Y1%, X2%, Y2%, Image()
-
- Note the DIMensioning of a dynamic array. The G2Get routine will set the
- array to the appropriate size to hold the image.
-
- The PUT replacement assumes that you intend to PSET the image. It doesn't
- allow for other display modes yet:
-
- G2Put X%, Y%, Image()
-
- See "Miscellaneous Notes" for more information on using GET/PUT images and
- the directions I'll be taking with them in the future. Note that SCREEN 13
- is also supported, via G13Get and G13Put.
-
- The COLOR statement in SCREEN 1 is anomalous. It doesn't really control
- color at all, which is why QuickBASIC proper doesn't support colored text in
- this (or any graphics) mode. Instead, it is used for controlling the
- background/border color and palette. Since BASWIZ -does- support a true
- G1COLOR routine, there are different routines which allow you to change the
- palette and border colors. To change the background (and border) color, use:
-
- G1Border Colour%
-
- Graphics: Mode-Specific Routines page 28
-
-
-
- There are two palette routines. Why two? Well, QuickBASIC supports two CGA
- palettes. One of the routines works like QuickBASIC and can be used on any
- CGA, EGA or VGA display (as long as it's in CGA mode). The other routine
- gives you a wider choice of palettes, but will only work on true CGAs (and
- some EGA or VGA systems that have been "locked" into CGA mode).
-
- Here's the QuickBASIC-style two-palette routine for any CGA/EGA/VGA:
-
- G1PaletteA PaletteNr%
-
- The PaletteNr% may be as follows:
-
- 0 (bright) Green, Red, Yellow
- 1 Cyan, Violet, White
-
-
- The more flexible six-palette routine (for CGA only) works like this:
-
- G1PaletteB PaletteNr%
-
- Palettes are as follows:
-
- 0 Green, Red, Brown 4 (bright) Green, Red, Yellow
- 1 Cyan, Violet, White 5 (bright) Cyan, Violet, White
- 2 Cyan, Red, White 6 (bright) Cyan, Red, White
-
- Graphics: Mode-Specific Routines page 29
-
-
-
- The EGA has a number of features which work in all its modes, so rather than
- giving them screen mode prefixes, they are simply named with an "E". These
- routines allow you to get or set the palette, get or set the border color,
- and determine whether the higher background colors should be displayed as
- bright colors or as blinking.
-
- To get a palette color value, use:
-
- Colour% = EGetPalette(ColorNumber%)
-
- To set the color value, use:
-
- EPalette ColorNumber%, Colour%
-
- To get the border color:
-
- Colour% = EGetBorder%
-
- You can probably guess how to set the border color:
-
- EBorder Colour%
-
- Finally, the blink vs. intensity. Actually, this is designed for text mode;
- I'm not sure whether it has any function in graphics modes. The text-mode
- default is for blinking to be turned on. With BASIC, you add 16 to the
- foreground color to make it blink. That's a little weird, since the "blink"
- attribute is actually a part of the background color, but that's how BASIC
- views it. You can tell the EGA to turn off blinking, in which case adding 16
- to the foreground color makes the background color intense. This doubles the
- number of available background colors.
-
- EBlink Blink%
-
- Use -1 for blinking (default), or 0 to turn off blinking.
-
- Graphics: Mode-Specific Routines page 30
-
-
-
- Like the EGA, the VGA has a number of features which work in all its modes.
- Again, rather than giving them screen mode prefixes, we simply name them with
- a "V". The current routines allow you to get or set the palette colors.
-
- To get a palette color value, use:
-
- VGetPalette(ColorNumber%, Red%, Green%, Blue%)
-
- To set the color value, use:
-
- VPalette ColorNumber%, Red%, Green%, Blue%
-
- As you've probably noticed, this doesn't work the same way as the QuickBASIC
- PALETTE statement. Rather than using a formula to calculate a single LONG
- color value, like QuickBASIC, the BASWIZ library allows you to specify the
- color in a more meaningful way. The Red%, Green%, and Blue% parameters each
- hold an intensity value (0-63). By mixing these three, you can get an
- immense variety of shades-- over 250,000 combinations in all.
-
- If you need to keep track of the intensities in your program, I'd suggest the
- following TYPE definition:
-
- TYPE VGAcolor
- Red AS INTEGER
- Green AS INTEGER
- Blue AS INTEGER
- END TYPE
-
- If space is more important than speed, you can compress that to half the size
- by using STRING * 1 instead of INTEGER. In that case, you will need to use
- the CHR$ and ASC functions to convert between string and integer values.
-
- Graphics: Printer Routines page 31
-
-
-
- The BASWIZ printer routines allow you to work with a printer using the same
- convenient methods you'd use on a screen. The image is created with the
- usual G# routines (using mode N2), but the results are kept in a buffer in
- memory (about 37K bytes) rather than being displayed directly. The image can
- be previewed on a VGA or printed out at your convenience, to any printer or
- even a file. The results will take up a single printer page, assuming the
- usual 8.5" x 11" paper is used.
-
- Printing a finished page works like this:
-
- GN2Print Device$
-
- The Device$ variable should be set to the name of the device:
-
- LPT1 parallel printer on port 1
- LPT2 parallel printer on port 2
- LPT3 parallel printer on port 3
- COM1 serial printer on port 1
- COM2 serial printer on port 2
-
- Instead of using a device name, you can also use a file name, to store the
- results for later printing. Output is done using BASIC file handling, so it
- would be a good idea to provide an ON ERROR GOTO trap in case of problems.
- The FREEFILE function is used, so you don't have to worry about conflicts
- with any files in use by your program.
-
- Getting a page layout just right can consume a lot of paper. Fortunately,
- there's a "preview" routine that allows you to display the results on a VGA.
- The display will be sideways, allowing the whole page to be seen at once.
- This will exactly match the printed output in N2 mode. Here's how it works:
-
- G11Mode 1 ' set SCREEN 11 (VGA graphics mode, 640x480 x2)
- GN2Display ' display the page
- DO ' wait for a key to be pressed
- LOOP UNTIL LEN(INKEY$) '
- G11Mode 0 ' set SCREEN 0 (text mode)
-
- The GN2Write and GN2WriteLn printer routines are unlike the display versions
- of the same routines in that they don't scroll. These routines only allow
- you to design one page at a time.
-
- Before using GN2Write or GN2WriteLn routines, you must choose a font with
- GN2Font. These are the same fonts as used in G#Banner:
-
- 0 8 x 8 80 text rows
- 1 8 x 14 45 text rows
- 2 8 x 16 40 text rows
-
- The current font can be retrieved with GN2GetFont%. The result will be
- meaningless if the font was never set with GN2Font.
-
- Graphics: A Little Geometry page 32
-
-
-
- The increasing capabilities of computer graphics systems has left many of us
- in the dust. It's great to be able to run dazzling applications or to doodle
- with a "paint" program, but many of us find it difficult to design appealing
- images of our own. Becoming an artist is perhaps a bit more than most of us
- are willing to take on! It is important to remember, however, that computers
- are wonderful number-crunchers. With a little application of plane geometry,
- you can have the computer take on much of the work for you-- and after all,
- isn't that why we have computers in the first place?
-
- A complete review of plane geometry is a bit beyond the scope of this text.
- However, I'm going to run through some of the things I think you'll find most
- useful. I'd also like to suggest that you might dig out your old textbooks
- or rummage through your local used book store. It may have seemed like a dry
- subject at the time, but when you can watch the results growing on your
- computer screen, you will have a much better idea of how geometry can be
- useful to you-- and it can be surprisingly fun, too!
-
- In geometry talk, a "point" doesn't have any actual size. In our case, we
- want to apply geometry to physical reality, namely the computer screen. As
- far as we're concerned, a "point" will be an individual graphics dot, also
- called a "pel" or "pixel" (for "picture element"). We can safely dispense
- with such formalities for our applications, for the most part.
-
- The most important thing about a point is that it has a location! Ok, that
- may not seem staggering, but it happens that there are a number of ways of
- specifying that location. The most common method is called the Cartesian
- coordinate system. It is based on a pair of numbers: X, which represents the
- distance along a horizontal line, and Y, which represents the distance along
- a vertical line. Consider the CGA in SCREEN 2, for instance. It has a
- coordinate system where X can be 0 - 639 and Y can be 0 - 199. The points
- are mapped on kind of an invisible grid.
-
- The Cartesian coordinate system makes it easy to visualize how a given point
- relates to other points on the same plane (or screen). It is particularly
- useful for drawing lines. Horizontal and vertical lines become a cinch: just
- change the X value to draw horizontally, or the Y value to draw vertically.
- Squares and rectangles (or boxes) can be formed by a combination of such
- lines. You can define an area of the screen in terms of an imaginary box
- (as GET and PUT do) with nice, clean boundaries. When we get to diagonal
- lines, it's a bit more of a nuisance, but still easy enough with the proper
- formula. That means we can do triangles too. Curves are worse... when it
- comes to even a simple circle or ellipse, the calculations start to get on
- the messy side. For things like that, though, there is an alternative.
-
- Another way of describing the location of a point is by Polar coordinates.
- In Cartesian coordinates, the location is specified by its horizontal and
- vertical distances from the "origin" or reference point, (0,0). In Polar
- coordinates, the location is specified by its distance and angle from the
- origin. Think of it as following a map: Cartesian coordinates tell you how
- many blocks down and how many blocks over the point is, whereas Polar
- coordinates tell you in which direction the point is and how far away it is
- "as the crow flies".
-
- Graphics: A Little Geometry page 33
-
-
-
- The Polar coordinate system is great for describing many kinds of curves,
- much better than Cartesian. For example, a circle is defined as all of the
- points at a given (fixed) distance from a center point. Polar coordinates
- include both a distance and an angle, and we've already got the distance, so
- all we need to do is plot points at all of the angles on a circle.
- Technically, there is an infinite number of angles, but since our points
- don't follow the mathematical definition (they have a size), we don't have to
- worry about that.
-
- Let me digress for a moment to talk about angles. In BASIC, angles are
- specified in "radians". People more often use "degrees". Fortunately, it
- isn't hard to convert from one to the other. Both may be visualized on a
- circle. In radians, the sum of the angles in a circle is twice pi. In
- degrees, the sum of the angles is 360. That's something like this:
-
-
- 90 deg, 1/2 * pi rad
- /---|---\
- / | \
- / | \
- 180 degrees |___ . ___| 0 deg, 0 rad; or...
- pi radians | | 360 deg, 2 * pi rad
- \ | /
- \ | /
- \---|---/
- 270 deg, 3/2 * pi rad
-
-
- Ok, so that's a grotesquely ugly circle! Hopefully it shows the important
- thing, though. Angles start at zero on the extreme right and get larger as
- they work around counter-clockwise. The places marked on the "circle" are
- places where lines drawn horizontally and vertically through the center
- intersect the outside of the circle. These serve as a useful reference
- point, especially in that they help show how the angles can be construed from
- a Cartesian viewpoint.
-
- So much for angles. I'll go into conversion formulae, the value of pi, and
- other good junk a bit later on. Right now, let's get back to our discussion
- of Polar coordinates.
-
- I've explained how the Polar system makes it easy to draw a circle. Since
- you can vary the range of angles, it's equally simple to draw an arc. If you
- wanted to make a pie chart, you might want to join the ends of the arcs to
- the center of the circle, in which case you'd keep the angle constant (at the
- ends of the arc) and plot by changing the distance from zero to the radius.
- Circles are also handy for drawing equilateral polygons... you know, shapes
- with sides of equal length: triangle, square, pentagon, hexagon, etc. In
- this case, the best features of the Cartesian and Polar systems can be joined
- to accomplish something that would be difficult in either alone.
-
- Graphics: A Little Geometry page 34
-
-
-
- The starting point for these polygons is the circle. Imagine that the
- polygon is inside a circle, with the vertices (pointy ends, that is, wherever
- the sides meet) touching the edge of the circle. These are equilateral
- polygons, so all of the sides and angles are the same size. Each of the
- vertices touches the circle, and each does it at exactly the same distance
- from each other along the arc of the circle. All of this detail isn't
- precisely necessary, but I hope it makes the reasoning a bit more clear!
-
- The circle can be considered as being divided by the polygon into a number of
- arcs that corresponds to the number of vertices (and sides) the polygon has.
- Think of a triangle inside a circle, with the tips all touching the circle.
- If you ignore the area inside the triangle, you will see that the circle is
- divided into three equal arcs. The same property is true of any equilateral
- polygon. As a matter of fact, as the number of vertices goes up, the circle
- is partitioned into more, but smaller, arcs... so that a polygon with a large
- enough number of vertices is effectively a circle itself!
-
- Anyway, the important thing is the equal partitioning. We know how many
- angles, be they degrees or radians, are in a circle. To get the points of a
- polygon, then... well, we already know the "distance" part, that's the same
- as the radius. The angles can be calculated by dividing the angles in the
- whole circle by the number of vertices in the desired polygon. Trying that
- case with the triangle, assuming a radius of 20 (why not), and measuring in
- degrees, that would give us the Polar points (20, 0), (20, 120), (20, 240).
- To make this a triangle, we need to connect the points using lines, which is
- easy in Cartesian coordinates. Since the computer likes Cartesian anyway, we
- just convert the Polar coordinates to Cartesian, draw the lines, and viola!
-
- That's essentially the method used by the G#Polygon routines. It's very
- simple in practice, but I haven't seen it elsewhere... probably because
- people forget about the Polar coordinate system, which is what makes it all
- come together. Polar coordinates also have simple equations for figures that
- look like daisies, hearts, and other unusual things. See "Equations, Etc"
- and ROSES.BAS for more information.
-
- On a side note, the Cartesian system isn't used by all computers, although
- it's the most common. Cartesian coordinates are the standard for what is
- called "raster" displays. The Polar coordinate system is used on "vector"
- displays. One example of a vector display that you may have seen is the old
- Asteroids video arcade game. They tend to be used for drawing monochrome
- "framework" pictures where the image must be very sharp (unlike in raster
- images, the diagonal lines aren't jagged, since there's no raster "grid").
-
- Graphics: Equations, Etc page 35
-
-
-
- In this section, I'm going to list a number of equations and so forth. Some
- of them will be useful to you in experimenting with Polar coordinates. Some
- of them provide formulae for things that are already in BASWIZ, but which you
- might like to understand better. Some of them are just for the heck of it...
- note that not all of this information may be complete enough for you to just
- use without understanding it.
-
- One problem is... if you try to draw a circle, for instance, it will come out
- looking squashed in most SCREEN modes. Remember we said our points, unlike
- mathematical points, have a size? In most graphics modes, the points are
- effectively wider than they are high, so a real circle looks like an ellipse.
-
- Another problem is that these equations are based on an origin of (0,0) which
- is assumed to be at the center of the plane. In our case, (0,0) is at the
- upper right edge, which also makes the Y axis (vertical values) effectively
- upside-down. This isn't necessarily a problem, but sometimes it is! Adding
- appropriate offsets to the plotted X and Y coordinates often fixes it. In
- the case of Y, you may need to subtract the value from the maximum Y value to
- make it appear rightside-up.
-
- The displayed form of these equations may contain "holes", usually again
- because the points have a size, and/or since we try to use integer math to
- speed things up. If the screen had infinite resolution, this would not be a
- problem... meanwhile (!), getting around such problems takes fiddlin'.
-
- There are other problems, mostly due to forcing these simplified-universe
- theoretical equations into practical use. It's a lot easier to shoehorn in
- these simple equations than to use more accurate mathematical descriptions,
- though... a -lot- easier. So a few minor quirks can be ignored!
-
- With those disclaimers, here's the scoop on some handy equations.
-
- Polar coordinates may be expressed as (R, A), where R is radius or
- distance from the origin, and A is the angle.
-
- Cartesian coordinates may be expressed as (X, Y), where X is the distance
- along the horizontal axis and Y is the distance along the vertical axis.
-
- Polar coordinates can be converted to Cartesian coordinates like so:
- X = R * COS(A)
- Y = R * SIN(A)
-
- Angles may be expressed in radians or degrees. BASIC prefers radians.
- Radians are based on PI, with 2 * PI radians in a circle. There are 360
- degrees in a circle. Angles increase counter-clockwise from a 3:00 clock
- position, which is the starting (zero) angle. Angles can wrap around: 720
- degrees is the same as 360 degrees or 0 degrees, just as 3:00 am is at the
- same clock position as 3:00 pm.
-
- Angles may be converted between degrees and radians as follows:
- radians = degrees * PI / 180
- degrees = radians * 180 / PI
-
- Graphics: Equations, Etc page 36
-
-
-
-
- The value PI is approximately 3.14159265358979. For most graphics
- purposes, a simple 3.141593 should do quite nicely. The true value of PI
- is an irrational number (the decimal part repeats forever, as near as
- anyone can tell). It has been calculated out to millions of decimal
- points by people with a scientific bent (and/or nothing better to do)!
-
- Line Drawing:
-
- One of the convenient ways of expressing the formula of a line (Cartesian
- coordinates) is:
- Y = M * X + B
-
- Given the starting and ending points for the line, M (the slope,
- essentially meaning the angle of the line) can be determined by:
- M = (Y2 - Y1) / (X2 - X1)
-
- The B value is called the Y-intercept, and indicates where the line
- intersects with the Y-axis. Given the ingredients above, you can
- calculate that as:
- B = Y1 - M * X1
-
- With this much figured out, you can use the original formula to calculate
- the appropriate Y values, given a FOR X = X1 TO X2 sort of arrangement.
- If the slope is steep, however, this will result in holes in the line. In
- that case, it will be smoother to recalculate the formula in terms of the
- X value and run along FOR Y = Y1 TO Y2... in that case, restate it as:
- X = (Y - B) / M
-
- Keep an eye on conditions where X1 = X2 or Y1 = Y2! In those cases,
- you've got a vertical or horizontal line. Implement those cases by simple
- loops to improve speed and to avoid dividing by zero.
-
-
-
- Circle Drawing:
-
- The Cartesian formula gets messy, especially due to certain aspects of the
- display that are not accounted for (mainly that pixels, unlike theoretical
- points, have a size and shape which is usually rectangular). The Polar
- formula is trivial, though. The radius should be specified to the circle
- routine, along with the center point. Do a FOR ANGLE! = 0 TO 2 * PI! STEP
- 0.5, converting the resulting (Radius, Angle) coordinates to Cartesian,
- then adding the center (X,Y) as an offset to the result. The appropriate
- STEP value for the loop may be determined by trial and error. Smaller
- values make better circles but take more time. Larger values may leave
- "holes" in the circle.
-
- Graphics: Equations, Etc page 37
-
-
-
- Polygon Drawing:
-
- I've already discussed that, so I'll leave it as an exercise... or of
- course you can examine my source code if you register BASWIZ! The polygon
- routines are in BASIC, except for the line-drawing parts.
-
-
-
- Flower Drawing:
-
- This sort of thing would be rather difficult to do using strictly
- Cartesian methods, but with Polar coordinates, no problem. Here we
- calculate the radius based on the angle, using something like:
-
- FOR Angle! = 0 TO PI! * 2 STEP .01
-
- (a low STEP value is a good idea). The radius is calculated like so:
-
- Radius! = TotalRadius! * COS(Petals! * Angle!)
-
- The Petals! value specifies how many petals the flower should have. If it
- is odd, the exact number of petals will be generated; if even, twice that
- number will be generated.
-
- These figures are technically called "roses", although they more resemble
- daisies. Try the ROSES.BAS program to see how they look.
-
-
-
- Other Drawing:
-
- Experiment! There are all sorts of interesting things you can do with the
- Polar coordinate system in particular. Dig up those old Geometry texts or
- see if your Calculus books review it. If you've kept well away from math,
- try your local library or used book store.
-
- Memory Management and Pointers page 38
-
-
-
- On the whole, BASIC is easily a match for any other language, as far as
- general-purpose programming goes. There is one major lack, however-- a set
- of valuable features that is supported by most other languages, but was
- inexplicably left out of BASIC. Perhaps Microsoft felt it was too advanced
- and dangerous for a so-called "beginner's" language. In truth, using
- pointers and memory management takes a little understanding of what you're
- doing-- the compiler can't protect you from all of your mistakes. However,
- they can be extraordinarily useful for many things, so I have added these
- capabilities to BASWIZ.
-
- A "pointer" is essentially just the address of an item. It is useful in two
- respects: it allows you to pass just the pointer, rather than the whole item
- (be it a TYPEd variable, normal variable, entire array, or whatever) to a
- subprogram. This is faster and more memory-efficient than the alternatives.
- Secondly, a pointer combined with memory management allows you to allocate
- and deallocate memory "on the fly", in just the amount you need. You don't
- have to worry about DIMensioning an array too large or too small, or even
- with how large each element of the array should be, for example. You can
- determine that when your program -runs-, rather than at compile time, and set
- up your data structures accordingly. You can also create a large variety of
- data structures, such as trees and linked lists, which would be difficult and
- cumbersome to emulate using BASIC alone.
-
- The BASWIZ memory/pointer routines allow you to allocate and deallocate
- memory; fill, copy or move a block of memory; get or put a single character
- according to a pointer; and convert back and forth between a segment/offset
- address and a pointer.
-
- Pointers are kept in LONG integers, using an absolute memory addressing
- scheme. This means that you can manipulate pointers just like any ordinary
- LONG integer, e.g. to move to the next memory address, just add one. Since
- you can convert from a segment/offset address to a pointer and you can copy
- information from one pointer to another, you can move information back and
- forth between allocated memory and a TYPEd variable, numeric variable, or
- array. You can even do things like set a pointer to screen memory and
- transfer the screen into a variable or vice versa! Or implement your own
- "far string" routines, heirarchical evaluations, or any number of other
- things. Pointers are incredibly powerful!
-
- Note that there are different ways of representing the same segment/offset
- address, but only one absolute pointer representation. If you need to
- compare two addresses, using pointers is terrific. However, it's good to
- keep in mind that an segment/offset address may -appear- to change if you
- convert it to a pointer and then back to a segment/offset address. When you
- convert from a pointer to a segment/offset, the segment will be maximized and
- the offset minimized. So, for example, 0040:001C will turn into 0041:000C.
-
- Although the byte count for these routines is handled through a LONG integer,
- the routines handle a maximum of 65,520 bytes at a time. In other words, a
- pointer can only access a bit less than 64K at a time. If I get enough
- requests to extend this range, I will do so. Meantime, that's the limit!
-
- Memory Management and Pointers page 39
-
-
-
- There are two routines which take care of memory management. These allow you
- to allocate or deallocate memory. Note that if you allocate too much memory,
- QuickBASIC won't have any memory to work with! Use the BASIC function
- "SETMEM" to see how much memory is available before going hog-wild.
-
- You can allocate memory like so:
-
- MAllocate Bytes&, Ptr&, ErrCode%
-
- If there isn't enough memory available, an error code will be returned.
- Otherwise, Ptr& will point to the allocated memory. Memory is allocated in
- chunks of 16 bytes, so there may be some memory wasted if you choose a number
- of bytes that isn't evenly divisible by 16.
-
- When you are finished with that memory, you can free it up by deallocation:
-
- MDeallocate Ptr&, ErrCode%
-
- An error code will be returned if Ptr& doesn't point to previously allocated
- memory.
-
- In the best of all possible worlds, there would be a third routine which
- would allow you to reallocate or resize a block of memory. However, due to
- certain peculiarities of QuickBASIC, I was unable to implement that. You can
- simulate such a thing by allocating a new area of memory of the desired size,
- moving an appropriate amount of information from the old block to the new,
- and finally deallocating the old block.
-
- Once you've allocated memory, you can move any sort of information in or out
- of it except normal strings-- fixed-length strings, TYPEd values, arrays, or
- numeric values. To do that, you use BASIC's VARSEG and VARPTR functions on
- the variable. Convert the resulting segment/offset address to a pointer:
-
- TSeg% = VARSEG(Variable)
- TOfs% = VARPTR(Variable)
- VariablePtr& = MJoinPtr&(TSeg%, TOfs%)
-
- Moving the information from one pointer to another works like so:
-
- MMove FromPtr&, ToPtr&, Bytes&
-
- For STRING or TYPEd values, you can get the number of bytes via the LEN
- function. For numeric values, the following applies:
-
- Type Bytes per value
- ======= ===============
- INTEGER 2
- LONG 4
- SINGLE 4
- DOUBLE 8
-
- Memory Management and Pointers page 40
-
-
-
- The "memory move" (MMove) routine is good for more than just transferring
- information between a variable and allocated memory, of course. Pointers can
- refer to any part of memory. For instance, CGA display memory starts at
- segment &HB800, offset 0, and goes on for 4000 bytes in text mode. That
- gives a pointer of &HB8000. You can transfer from the screen to a variable
- or vice versa. For that matter, you can scroll the screen up, down, left, or
- right by using the appropriate pointers. Add two to the pointer to move it
- to the next character or 160 to move it to the next row. As I said, pointers
- have all kinds of applications! You don't need to worry about overlapping
- memory-- if the two pointers, combined with the bytes to move, overlap at
- some point, why, the MMove routine takes care of that for you. It avoids
- pointer conflicts. MMove is a very efficient memory copying routine.
-
- Suppose you've got a pointer and would like to convert it back to the
- segment/offset address that BASIC understands. That's no problem:
-
- MSplitPtr Ptr&, TSeg%, TOfs%
-
- You might also want to fill an area of memory with a specified byte value,
- perhaps making freshly-allocated memory zeroes, for example:
-
- MFill Ptr&, Value%, Bytes&
-
- Finally, there may be occasions when you might want to transfer a single
- character. Rather than going through putting the character into a STRING*1,
- getting the VARSEG/VARPTR, and using MJoinPtr&, there is a simpler method:
-
- MPutChr Ptr&, Ch$
- Ch$ = MGetChr$(Ptr&)
-
- Hopefully, this will give you some ideas to start with. I'll expand on the
- uses of pointers and give further examples in future versions of BASWIZ.
- There are many, many possible uses for such capabilities. Pointers and
- memory management used to be the only real way in which BASIC could be
- considered inferior to other popular languages-- that is no more!
-
- NOTE:
- QuickBASIC may move its arrays around in memory! Don't expect the address
- of an array to remain constant while your program is running. Be sure to
- get the VARSEG/VARPTR for arrays any time you're not sure they're in the
- same location. Among the things which can cause arrays to move are use of
- DIM, REDIM, or ERASE, and possibly calls to SUBs or FUNCTIONs. I'm not
- sure if anything else may cause the arrays to move, so be cautious!
-
- Telecommunications page 41
-
-
-
- BASIC is unusual among languages in that it comes complete with built-in
- telecommunications support. Unfortunately, that support is somewhat crude.
- Amongst other problems, it turns off the DTR when the program SHELLs or ends,
- making it difficult to write doors for BBSes or good terminal programs. It
- also requires use of the /E switch for error trapping, since it generates
- errors when line noise is encountered, and doesn't provide much control. It
- doesn't even support COM3 and COM4, which have been available for years.
-
- BASWIZ rectifies these troubles. It allows comprehensive control over
- communications, includes COM3 and COM4, and doesn't require error trapping.
- It won't fiddle with the DTR unless you tell it to do so. The one limitation
- is that you may use only a single comm port at a time.
-
- Before you can use communications, you must initialize the communications
- handler. If you didn't have BASWIZ, you would probably use something like:
-
- OPEN "COM1:2400,N,8,1,RS,CS,DS" AS #1
-
- With BASWIZ, you do not have to set the speed, parity, and so forth.
- Communications will proceed with whatever the current settings are, unless
- you choose to specify your own settings. When you initialize the comm
- handler, you specify only the port number (1-4) and the size of the input and
- output buffers (1-32,767 bytes):
-
- TCInit Port, InSize, OutSize, ErrCode
-
- The size you choose for the buffers should be guided by how your program will
- use communications. Generally, a small output buffer of 128 bytes will be
- quite adequate. You may wish to expand it up to 1,500 bytes or so if you
- expect to write file transfer protocols. For the input buffer, you will want
- perhaps 512 bytes for normal use. For file transfer protocols, perhaps 1,500
- bytes would be better. If a high baud rate is used, or for some other reason
- you might not be emptying the buffer frequently, you may wish to expand the
- input buffer size to 4,000 bytes or more.
-
- When you are done with the telecomm routines, you must terminate them. In
- BASIC, this would be done with something like:
-
- CLOSE #1
-
- With the BASWIZ routines, though, you would use this instead:
-
- TCDone
-
- The BASWIZ "TCDone" does not drop the DTR, unlike BASIC's "CLOSE". This
- means that the modem will not automatically be told to hang up. With BASWIZ,
- you have complete control over the DTR with the TCDTR routine. Use a value
- of zero to drop the DTR or nonzero to raise the DTR:
-
- TCDTR DTRstate
-
- Telecommunications page 42
-
-
-
- You may set the speed of the comm port to any baud rate from 1-65,535. If
- you will be dealing with comm programs that were not written using BASWIZ,
- you may wish to restrict that to the more common rates: 300, 1200, 2400,
- 4800, 9600, 19200, 38400, and 57600.
-
- TCSpeed Baud&
-
- The parity, word length, and stop bits can also be specified. You may use
- 1-2 stop bits, 6-8 bit words, and parity settings of None, Even, Odd, Mark,
- or Space. Nearly all BBSes use settings of None, 8 bit words, and 1 stop
- bit, although you will sometimes see Even, 7 bit words, and 1 stop bit. The
- other capabilities are provided for dealing with mainframes and other systems
- which may require unusual communications parameters.
-
- When specifying parity, only the first character in the string is used, and
- uppercase/lowercase distinctions are ignored. Thus, using either "none" or
- "N" would specify that no parity is to be used.
-
- TCParms Parity$, WordLength, StopBits
-
- If your program needs to be aware of when a carrier is present, it can check
- the carrier detect signal from the modem with the TCCarrier function. This
- function returns zero if no carrier is present:
-
- IF TCCarrier THEN
- PRINT "Carrier detected"
- ELSE
- PRINT "No carrier"
- END IF
-
- Suppose, though, that you need to know immediately when someone has dropped
- the carrier? It wouldn't be too convenient to have to spot TCCarrier
- functions all over your program! In that case, try the "ON TIMER" facility
- provided by BASIC for keeping an eye on things. It will enable you to check
- the carrier at specified intervals and act accordingly. Here's a brief
- framework for writing such code:
-
- ON TIMER(30) GOSUB CarrierCheck
- TIMER ON
- ' ...your program goes here...
- CarrierCheck:
- IF TCCarrier THEN ' if the carrier is present...
- RETURN ' ...simply resume where we left off
- ELSE ' otherwise...
- RETURN Restart ' ...return to the "Restart" label
- END IF
-
- Telecommunications page 43
-
-
-
- To get a character from the comm port, use the TCInkey$ function:
-
- ch$ = TCInkey$
-
- To send a string to the comm port, use TCWrite:
-
- TCWrite St$
-
- If you are dealing strictly with text, you may want to have a carriage return
- and a linefeed added to the end of the string. No problem:
-
- TCWriteLn St$
-
- Note that the length of the output buffer affects how the TCWrite and
- TCWriteLn routines work. They don't actually send string directly to the
- comm port. Instead, they put the string into the output buffer, and it gets
- sent to the comm port whenever the comm port is ready. If there is not
- enough room in the output buffer for the whole string, the TCWrite/TCWriteLn
- routines are forced to wait until enough space has been cleared for the
- string. This can delay your program. You can often avoid this delay simply
- by making the output buffer larger.
-
- If you'd like to know how many bytes are waiting in the input buffer or
- output buffer, there are functions which will tell you:
-
- PRINT "Bytes in input buffer:"; TCInStat
- PRINT "Bytes in output buffer:"; TCOutStat
-
- Finally, if you would like to clear the buffers for some reason, you can do
- that too. The following routines clear the buffers, discarding anything
- which was waiting in them:
-
- TCFlushIn
- TCFlushOut
-
- Don't forget to use TCDone to terminate the comm handler before ending your
- program! If you do, the computer will lock up. Worse, it may not lock up
- immediately, so forgetting TCDone can be very unpleasant.
-
- Telecommunications page 44
-
-
-
- Finally, there is a routine which allows you to handle ANSI codes in a
- window. Besides the IBM semi-ANSI display code subset, mock-ANSI music is
- allowed. This routine is designed as a subroutine that you can access via
- GOSUB, since there are a number of variables that the routine needs to
- maintain that would be a nuisance to pass as parameters, and QuickBASIC
- unfortunately can't handle SUBs in $INCLUDE files (so SHARED won't work).
- To use it, either include ANSI.BAS directly in your code, or use:
-
- REM $INCLUDE: 'ANSI.BAS'
-
- Set St$ to the string to process, set Win% to the handle of the window to
- which to display, and set Music% to zero if you don't want sounds or -1 if
- you do want sounds. Then:
-
- GOSUB ANSIprint
-
- Note that the virtual screen tied to the window must be at least an 80 column
- by 25 row screen, since ANSI expects that size. You are also advised to have
- an ON ERROR trap if you use ANSIprint with Music% = -1, just in case a "bad"
- music sequence slips through and makes BASIC unhappy. Check for ERR = 5
- (Illegal Function Call). I'll add a music handler later to avoid this.
-
- To get some idea of how these routines all tie together in practice, see the
- TERM.BAS example program. It provides a simple "dumb terminal" program to
- demonstrate the BASWIZ comm handler. Various command-line switches are
- allowed:
-
- /43 use 43-line mode (EGA and VGA only)
- /COM2 use COM2
- /COM3 use COM3
- /COM4 use COM4
- /300 use 300 baud
- /1200 use 1200 baud
- /QUIET ignore "ANSI" music
-
- By default, the TERM.BAS program will use COM1 at 2400 baud with no parity, 8
- bit words and 1 stop bit. You can exit the program by pressing Alt-X.
-
- Telecommunications page 45
-
-
-
- The Xmodem file transfer protocol is currently supported for sending files
- only. It automatically handles any of the usual variants on the Xmodem
- protocol: 128-byte or 1024-byte blocks, plus checksum or CRC error detection.
- In other words, it is compatible with Xmodem (checksum), Xmodem CRC, and
- Xmodem-1K (single-file Ymodem-like variant).
-
- There are only two routines which must be used to transfer a file. The first
- is called once to initialize the transfer. The second is called repeatedly
- until the transfer is finished or aborted. Complete status information is
- returned by both routines. You can ignore most of this information or
- display it any way you please.
-
- The initialization routine looks like this:
-
- StartXmodemSend Handle, Protocol$, Baud$, MaxRec, Record, EstTime$, ErrCode
-
- Only the first three parameters are passed to the routine. These are the
- Handle of the file that you wish to send (use FOpen to get the handle) and
- the Protocol$ that you wish to use ("Xmodem" or "Xmodem-1K"), and the current
- Baud$. On return, you will get an ErrCode if the other computer did not
- respond, or MaxRec (the number of blocks to be sent), Record (the current
- block number), and EstTime$ (an estimate of the time required to complete the
- transfer. The Protocol$ will have "CHK" or "CRC" added to it to indicate
- whether checksum or CRC error detection is being used, depending on which the
- receiver requested.
-
- The secondary routine looks like this:
-
- XmodemSend Handle, Protocol$, MaxRec, Record, ErrCount, ErrCode
-
- The ErrCode may be zero (no error), greater than zero (error reading file),
- or less than zero (file transfer error, completion or abort). See the
- appendix on Error Codes for specific details. The TERM.BAS example program
- shows how these routines work together in practice.
-
- The file accessed by the Xmodem routine will remain open. Remember to close
- it when the transfer is done (for whatever reason), using the FClose routine.
-
- Telecommunications page 46
-
-
-
- A few notes on the ins and outs of telecommunications...
-
- The DTR signal is frequently used to control the modem. When the DTR is
- "raised" or "high", the modem knows that we're ready to do something. When
- the DTR is "dropped" or "low", the modem knows that we're not going to do
- anything. In most cases, this tells it to hang up or disconnect the phone
- line. Some modems may be set to ignore the DTR, in which case it will not
- disconnect when the DTR is dropped. Usually this can be fixed by changing a
- switch on the modem. On some modems, a short software command may suffice.
-
- The DTR is generally the best way to disconnect. The Hayes "ATH" command is
- supposed to hang up, but it doesn't work very well.
-
- The BASWIZ comm handler makes sure the DTR is raised when TCInit is used. It
- does not automatically drop the DTR when TCDone is used, so you can keep the
- line connected in case another program wants to use it. If this is not
- suitable, just use TCDTR to drop the DTR. Your program must always use
- TCDone before it exits, but it need only drop the DTR if you want it that
- way.
-
- If you want to execute another program via SHELL, it is ok to leave
- communications running as long as control will return to your program when
- the SHELLed program is done. In that case, the input buffer will continue to
- receive characters from the comm port unless the SHELLed program provides
- its own comm support. The output buffer will likewise continue to transmit
- characters unless overruled.
-
- An assortment of file transfer protocols will be provided in future versions
- of BASWIZ. Among the ones supported will be Xmodem, Xmodem-1K, Ymodem
- (batch), and Modem7 (batch). I do not expect to support Kermit or Zmodem,
- since they are unduly complicated. You can handle any file transfer protocol
- you like by SHELLing to an external protocol program, or of course you can
- write your own support code.
-
- The Virtual Windowing System page 47
-
-
-
- The virtual windowing system offers pop-up and collapsing windows, yes... but
- that is just a small fraction of what it provides. When you create a window,
- the part that you see on the screen may be only a view port on a much larger
- window, called a virtual screen. You can make virtual screens of up to 255
- rows long or 255 columns wide. The only limitation is that any single
- virtual screen must take up less than 65,520 bytes. Each virtual screen is
- treated much like the normal screen display, with simple replacements for the
- standard PRINT, LOCATE, and COLOR commands. Many other commands are provided
- for additional flexibility. The window on the virtual screen may be moved,
- resized, or requested to display a different portion of the virtual screen.
- If you like, you may choose to display a frame and/or title around a window.
- When you open a new window, any windows under it are still there and can
- still be updated-- nothing is ever destroyed unless you want it that way!
- With the virtual windowing system, you get a tremendous amount of control for
- a very little bit of work.
-
- The current version of the virtual windowing system only allows text mode
- screens to be used. All standard text modes are supported, however. This
- includes 25x40 CGA screens, the standard 25x80 screen, and longer screens
- such as the 43x80 EGA screen. The virtual windowing system is designed for
- computers that offer hardware-level compatibility with the IBM PC, which
- includes almost all MS-DOS/PC-DOS computers in use today.
-
-
-
- Terminology:
- -----------
-
- DISPLAY
- The actual screen.
-
- SHADOW SCREEN
- This is a screen kept in memory which reflects any changes you make to
- windows. Rather than making changes directly on the actual screen, the
- virtual windowing system works with a "shadow screen" for increased speed
- and flexibility. You specify when to update the display from the shadow
- screen. This makes any changes appear very smoothly.
-
- VIRTUAL SCREEN
- This is a screen kept in memory which can be treated much like the actual
- screen. You may choose to make a virtual screen any reasonable size.
- Every virtual screen will have a corresponding window.
-
- WINDOW
- This is the part of a virtual screen which is actually displayed. You
- might think of a window as a "view port" on a virtual screen. A window
- may be smaller than its virtual screen or the same size. It may have a
- frame or a title and can be moved or resized.
-
- The Virtual Windowing System page 48
-
-
-
- Frankly, the virtual windowing system is one of those things that's more
- difficult to explain than to use. It's very easy to use, as a matter of
- fact, but the basic concepts will need a little explanation. Rather than
- launching into a tedious and long-winded description of the system, I'm
- going to take a more tutorial approach, giving examples and explaining as I
- go along. Take a look at the WDEMO.BAS program for additional insights.
-
- Let's begin with the simplest possible scenario, where only a background
- window is created. This looks just like a normal screen.
-
- REM $INCLUDE: 'BASWIZ.BI'
- DEFINT A-Z
- Rows = 25: Columns = 80 ' define display size
- WInit Rows, Columns, ErrCode ' initialize window system
- IF ErrCode THEN ' stop if we couldn't...
- PRINT "Insufficient memory"
- END
- END IF
- Handle = 0 ' use background handle
- WWriteLn Handle, "This is going to be displayed on the background window."
- WWriteLn Handle, "Right now, that's the full screen."
- WUpdate ' update the display
- WDone ' terminate window system
-
- What we just did was to display two lines on the screen-- nothing at all
- fancy, but it gives you the general idea of how things work. Let's take a
- closer look at what the program does:
-
- - We INCLUDE the BASWIZ.BI definition file to let QuickBASIC know that
- we'll be using the BASWIZ routines.
-
- - We define the size of the display using the integer variables Rows and
- Columns (you can use any variable names you want). If you have an EGA
- display and had previously used WIDTH ,43 to go into 43x80 mode, you'd
- use "Rows = 43" here, for example.
-
- - We initialize the windowing system with WInit, telling it how large the
- display is. It returns an error code if it is unable to initialize.
-
- - We define the Handle of the window that we want to use. The "background
- window" is always available as handle zero, so we choose "Handle = 0".
-
- - We print two strings to the background window with WWriteLn, which is
- like a PRINT without a semicolon on the end (it moves to the next line).
-
- - At this point, only the shadow screen has been updated. We're ready to
- display the information, so we use WUpdate to update the actual screen.
-
- - We're all done with the program, so we finish up with WDone.
-
- The Virtual Windowing System page 49
-
-
-
- See, there's nothing to it! We initialize the screen, print to it or
- whatever else we need to do, tell the windowing system to update the display,
- and when the program is done, we close up shop.
-
- The background screen is always available. It might help to think of it as a
- virtual screen that's the size of the display. The window on this virtual
- screen is exactly the same size, so the entire virtual screen is displayed.
- As with other virtual screens, you can print to it without disturbing
- anything else. That means you can treat the background screen the same way
- regardless of whether it has other windows on top of it-- the other windows
- just "cover" the background information, which will still be there.
-
- This leads us to the topic of creating windows. Both a virtual screen and a
- window are created simultaneously-- remember, a window is just a view port on
- a virtual screen. The window can be the same size as the virtual screen, in
- which case the entire virtual screen is visible (as with the background
- window) or it can be smaller than the virtual screen, in which case just a
- portion of the virtual screen will be visible at any one time.
-
- A window is created like so:
-
- ' This is a partial program and can be inserted in the original example
- ' after the second WWriteLn statement...
- VRows = 43: VColumns = 80 ' define virtual screen size
- WOpen VRows, VColumns, 1, 1, Rows, Columns, Handle, ErrCode ' create window
- IF ErrCode THEN ' error if we couldn't...
- PRINT "Insufficient memory available"
- WDone ' (or use an error handler)
- END
- END IF
-
- What we have done here is to create a virtual screen of 43 rows by 80
- columns. The window will be the size of the display, so if you are in the
- normal 25x80 mode, only the first 25 rows of the virtual screen will be
- visible. If you have an EGA or VGA in 43x80 mode, though, the entire virtual
- screen will be visible! So, this window lets you treat a screen the same way
- regardless of the display size.
-
- The Handle returned is used any time you want to print to this new window or
- otherwise deal with it. If you are using many windows, you might want to
- keep an array of handles, to make it easier to keep track of which is which.
-
- By default, a virtual screen is created with the following attributes:
-
- - The cursor is at (1,1), the upper left corner of the virtual screen.
- - The cursor size is 0 (invisible).
- - The text color is 7,0 (white foreground on a black background).
- - There is no title or frame.
- - The window starts at (1,1) in the virtual screen, which displays the
- area starting at the upper left corner of the virtual screen.
-
- The Virtual Windowing System page 50
-
-
-
- When you create a new window, it becomes the "top" window, and will be
- displayed on top of any other windows that are in the same part of the
- screen. Remember, you can print to a window or otherwise deal with it, even
- if it's only partially visible or entirely covered by other windows.
-
- Don't forget WUpdate! None of your changes are actually displayed until
- WUpdate is used. You can make as many changes as you like before calling
- WUpdate, which will display the results smoothly and at lightning speed.
-
- We've created a window which is exactly the size of the display, but which
- might well be smaller than its virtual screen. Let's assume that the normal
- 25x80 display is being used, in which case our virtual screen (43x80) is
- larger than the window. We can still print to the virtual screen normally,
- but if we print below line 25, the results won't be displayed. What a
- predicament! How do we fix this?
-
- The window is allowed to start at any given location in the virtual screen,
- so if we want to see a different portion of the virtual screen, all we have
- to do is tell the window to start somewhere else. When the window is
- created, it starts at the beginning of the virtual screen, coordinate (1,1).
- The WView routine allows us to change this.
-
- In our example, we're displaying a 43x80 virtual screen in a 25x80 window.
- To begin with, then, rows 1-25 of the virtual screen are visible. To make
- rows 2-26 of the virtual screen visible, we simply do this:
-
- WView Handle, 2, 1
-
- That tells the window to start at row 2, column 1 in the virtual screen.
- Sounds easy enough, doesn't it? Well, if not, don't despair. Play with it
- in the QuickBASIC environment a little until you get the hang of it.
-
- You've noticed that the window doesn't need to be the same size as the
- virtual screen. Suppose we don't want it the same size as the display,
- either... suppose we want it in a nice box, sitting out of the way in a
- corner of the display? Well, we could have created it that way to begin with
- when we used WOpen. Since we've already created it, though, let's take a
- look at the routines to change the size of a window and to move it elsewhere.
- The window can be made as small as 1x1 or as large as its virtual screen, and
- it can be moved anywhere on the display you want it.
-
- Let's make the window a convenient 10 rows by 20 columns:
-
- WSize Handle, 10, 20
-
- And move it into the lower right corner of the display:
-
- WPlace Handle, 12, 55
-
- The Virtual Windowing System page 51
-
-
-
- Don't forget to call WUpdate or the changes won't be visible! Note also that
- we didn't really lose any text. The virtual screen, which holds all the
- text, is still there. We've just changed the size and position of the
- window, which is the part of the virtual screen that we see, so less of the
- text (if there is any!) is visible. If we made the window larger again, the
- text in the window would expand accordingly.
-
- If you were paying close attention, you noticed that we didn't place the
- resized window flush against the corner of the display. We left a little bit
- of room so we can add a frame and a title. Let's proceed to do just that.
-
- Window frames are displayed around the outside of a window and will not be
- displayed unless there is room to do so. We have four different types of
- standard frames available:
-
- 0 (no frame)
- 1 single lines
- 2 double lines
- 3 single horizontal lines, double vertical lines
- 4 single vertical lines, double horizontal lines
-
- We must also choose the colors for the frame. It usually looks best if the
- background color is the same background color as used by the virtual screen.
- Let's go ahead and create a double-line frame in bright white on black:
-
- FType = 2: Fore = 15: Back = 0
- WFrame Handle, FType, Fore, Back
-
- If you'd rather not use the default frame types, there's ample room to get
- creative! Frames 5-9 can be defined any way you please. They are null by
- default. To create a new frame type, you must specify the eight characters
- needed to make the frame: upper left corner, upper middle columns, upper
- right corner, left middle rows, right middle rows, lower left corner, lower
- middle columns, and lower right corner.
-
- +----------------------------------------+
- | Want a plain text frame like this? |
- | Use the definition string "+-+||+-+" |
- +----------------------------------------+
-
- The above window frame would be defined something like this:
-
- Frame = 5
- FrameInfo$ = "+-+||+-+"
- WUserFrame Frame, FrameInfo$
-
- Of course, you can choose any values you like. As always, the names of the
- variables can be anything, as long as you name them consistently within your
- program. You can even use constants if you prefer:
-
- WUserFrame 5, "+-+||+-+"
-
- The Virtual Windowing System page 52
-
-
-
- If you use a frame, you can also have a "shadow", which provides a sort of
- 3-D effect. The shadow can be made up of any character you choose, or it can
- be entirely transparent, in which case anything under the shadow will change
- to the shadow colors. This latter effect can be quite nice. I've found that
- it works best for me when I use a dim foreground color with a black
- background-- a foreground color of 8 produces wonderful effects on machines
- that support it (it's "bright black", or dark gray; some displays will show
- it as entirely black, though, so it may not always work the way you want).
- For a transparent shadow, select CHR$(255) as the shadow character. You can
- turn the shadow off with either a null string or CHR$(0).
-
- Shadow$ = CHR$(255) ' transparent shadow
- Fore = 8: Back = 0 ' dark gray on black
- WShadow Handle, Shadow$, Fore, Back
-
- A shadow will only appear if there is also a frame, and if there is enough
- space for it on the screen. Currently, there is only one type of shadow,
- which appears on the right and bottom sides of the frame. It effectively
- makes the frame wider and longer by one character.
-
- We can have a title regardless of whether a frame is present or not. Like
- the frame, the title is displayed only if there is enough room for it. If
- the window is too small to accommodate the full title, only the part of the
- title that fits will be displayed. The maximum length of a title is 70
- characters. Titles have their own colors.
-
- Title$ = "Wonderful Window!"
- Fore = 0: Back = 7
- WTitle Handle, Title$, Fore, Back
-
- To get rid of a title, just use a null title string (Title$ = "").
-
- It may be convenient to set up a window that isn't always visible-- say, for
- a help window, perhaps. The window could be set up in advance, then shown
- whenever requested using just one statement:
-
- WHide Handle, Hide
-
- You can make a window invisible by using any nonzero value for Hide, or make
- it reappear by setting Hide to zero. As always, the change will only take
- effect after WUpdate is used.
-
- The Virtual Windowing System page 53
-
-
-
- When WWrite or WWriteLn gets to the end of a virtual screen, they normally
- scroll the "screen" up to make room for more text. This is usually what you
- want, of course, but there are occasions when it can be a nuisance. The
- automatic scrolling can be turned off or restored like so:
-
- WScroll Handle, AutoScroll
-
- There are only a few more ways of dealing with windows themselves. After
- that, I'll explain the different things you can do with text in windows and
- how to get information about a specific window or virtual screen.
-
- If you have a lot of windows, one window may be on top of another, obscuring
- part or all of the window(s) below. In order to make sure a window is
- visible, all you need to do is to put it on top, right? Hey, is this easy or
- what?!
-
- WTop Handle
-
- You may also need to "unhide" the window if you used WHide on it previously.
-
- Note that the background window will always be the background window. You
- can't put handle zero, the background window, on top. What? You say you
- need to do that?! Well, that's one of the ways you can use the WCopy
- routine. WCopy copies one virtual screen to another one of the same size:
-
- WCopy FromHandle, ToHandle
-
- You can copy the background window (or any other window) to another window.
- The new window can be put on top, resized, moved, or otherwise spindled and
- mutilated. The WDEMO program uses this trick.
-
- We've been through how to open windows, print to them, resize them and move
- them around, among other things. We've seen how to put a frame and a title
- on a window and pop it onto the display. If you're a fan of flashy displays,
- though, you'd probably like to be able to make a window "explode" onto the
- screen or "collapse" off. It's the little details like that which make a
- program visually exciting and professional-looking. I wouldn't disappoint
- you by leaving something fun like that out!
-
- Since we're using a virtual windowing system rather than just a plain ol'
- ordinary window handler, there's an extra benefit. When a window explodes or
- collapses, it does so complete with its title, frame, shadow, and even its
- text. This adds rather nicely to the effect.
-
- The Virtual Windowing System page 54
-
-
-
- To "explode" a window, we just set up all its parameters the way we normally
- would-- open the window, add a title or frame if we like, print any text that
- we want displayed, and set the screen position. Then we use WExplode to zoom
- the window from a tiny box up to its full size:
-
- WExplode Handle
-
- The "collapse" routine works similarly. It should be used only when you are
- through with a window, because it closes the window when it's done. The
- window is collapsed from its full size down to a tiny box, then eliminated
- entirely:
-
- WCollapse Handle
-
- Note that WExplode and WCollapse automatically use WUpdate to update the
- display. You do not need to use WUpdate yourself and you should make sure
- that the screen is the way you want it displayed before you call either
- routine.
-
- The WCollapse and WExplode routines were written in BASIC, so they'll be easy
- to customize just the way you want them if you register BASWIZ and get the
- source code. They're not particularly difficult routines, however, so you
- might want to design a set of your own similar routines just for the
- exercise. All it takes is moving and resizing the windows.
-
- The great thing about being a programmer is that you can do it your way.
- Hold the pickles, hold the lettuce! Might be fun to add some sound effects
- to those exploding windows, hmmm? I'll do that in a later version, but don't
- feel obliged to wait for me!
-
- That's it for the windows. We've been through all the "tricky stuff". There
- are a number of useful things you can do with a virtual screen, though,
- besides printing to it with WWriteLn. Let's take a look at what we can do.
-
- WWriteLn is fine if you want to use a "PRINT St$" sort of operation. Suppose
- you don't want to move to a new line afterward, though? In BASIC, you'd use
- something like "PRINT St$;" (with a semicolon). With the virtual windowing
- system, you use WWrite, which is called just like WWriteLn:
-
- WWrite Handle, St$
-
- There are also routines that work like CLS, COLOR and LOCATE:
-
- WClear Handle
- WColor Handle, Fore, Back
- WLocate Handle, Row, Column
-
- The WClear routine is not quite like CLS in that it does not affect the
- cursor position. If you want the cursor "homed", use WLocate.
-
- The Virtual Windowing System page 55
-
-
-
- Note that the coordinates for WLocate are based on the virtual screen, not
- the window. If you move the cursor to a location outside the view port
- provided by the window, it will disappear. Speaking of disappearing cursors,
- you might have noticed that our WLocate doesn't mimic LOCATE exactly: it
- doesn't provide for controlling the cursor size. Don't panic! There's
- another routine available for that:
-
- WCursor Handle, CSize
-
- The CSize value may range from zero (in which case the cursor will be
- invisible) to the maximum size allowed by your display adapter. This will
- always be at least eight.
-
- Now, since each virtual screen is treated much like the full display, you may
- be wondering what happens if the cursor is "on" in more than one window.
- Does that mean multiple cursors are displayed? Well, no. That would get a
- little confusing! Only the cursor for the top window is displayed. If you
- put a different window on top, the cursor for that window will be activated
- and the cursor for the old top window will disappear. The virtual windowing
- system remembers the cursor information for each window, but it only actually
- displays the cursor for the window that's on top.
-
- In addition to the usual screen handling, the windowing system provides four
- new capabilities which you may find very handy. These are routines to insert
- and delete both characters and rows. This is done at the current cursor
- position within a selected virtual screen:
-
- WDelChr Handle
- WDelLine Handle
- WInsChr Handle
- WInsLine Handle
-
- These routines can also be used for scrolling. Remember, the display isn't
- updated until you use WUpdate, and then it's updated all at once. You can
- use any of the routines multiple times and the display will still be updated
- perfectly smoothly-- all the real work goes on behind the scenes!
-
- When you are done with a virtual screen and no longer need it, you can
- dispose of it like so:
-
- WClose Handle
-
- All of the information that can be "set" can also be retrieved. That's
- useful in general, of course, but it's also a great feature for writing
- portable subprograms. You can create subprograms that will work with any
- virtual screen, since it can retrieve any information it needs to know about
- the virtual screen or its window. That's power!
-
- The Virtual Windowing System page 56
-
-
-
- Here is a list of the available window data retrieval routines:
-
- WGetColor Handle, Fore, Back
- ' gets the current foreground and background colors
-
- WGetCursor Handle, CSize
- ' gets the cursor size
-
- WGetFrame Handle, Frame, Fore, Back
- ' gets the frame type and frame colors
-
- WGetLocate Handle, Row, Column
- ' gets the cursor position
-
- WGetPlace Handle, Row, Column
- ' gets the starting position of a window on the display
-
- WGetScroll Handle, AutoScroll
- ' gets the status of auto-scroll (scrolling at the end of a virtual screen)
-
- Shadow$ = SPACE$(1)
- WGetShadow Handle, Shadow$, Fore, Back
- ' gets the shadow character (CHR$(0) if there's no shadow) and colors
-
- WGetSize Handle, Rows, Columns
- ' gets the size of a window
-
- Title$ = SPACE$(70)
- WGetTitle Handle, Title$, TLen, Fore, Back
- Title$ = LEFT$(Title$, TLen)
- ' gets the title string (null if there's no title) and title colors
-
- WGetTop Handle
- ' gets the handle of the top window
-
- FrameInfo$ = SPACE$(8)
- WGetUFrame$ Frame, FrameInfo$
- ' gets the specification for a given user-defined frame type
-
- WGetView Handle, Row, Column
- ' gets the starting position of a window within a virtual screen
-
- WGetVSize Handle, Rows, Columns
- ' gets the size of a virtual screen
-
- WHidden Handle, Hidden
- ' tells you whether a window is visible
-
- The Virtual Windowing System page 57
-
-
-
- As well as displaying information in a window, you will frequently want to
- allow for getting input from the user. Of course, INKEY$ will still work
- fine, but that's not an effective way of handling more than single
- characters. The virtual windowing system includes a flexible string input
- routine which is a lot more powerful:
-
- WInput Handle, Valid$, ExitCode$, ExtExitCode$, MaxLength, St$, ExitKey$
-
- The Valid$ variable allows you to specify a list of characters which may be
- entered. If you use a null string (""), any character will be accepted.
-
- ExitCode$ specifies the normal keys that can be used to exit input. You'll
- probably want to use a carriage return, CHR$(13), for this most of the time.
- You can also specify exit on extended key codes like arrow keys and function
- keys via ExtExitCode$.
-
- MaxLength is the maximum length of the string you want. Use zero to get the
- longest possible string. The length may go up to the width of the virtual
- screen, minus one character. The window will be scrolled sideways as needed
- to accommodate the full length of the string.
-
- The St$ variable is used to return the entered string, but you can also use
- it to pass a default string to the routine.
-
- ExitKey$ returns the key that was used to exit input.
-
- A fairly strong set of editing capabilities is available through WInput.
- The editing keys can be overridden by ExitCode$ or ExtExitCode$, but by
- default they include support for both the cursor keypad and WordStar:
-
- Control-S LeftArrow move left once
- Control-D RightArrow move right once
- Control-V Ins switch between insert and overstrike modes
- Control-G Del delete current character
- Control-H Backspace destructive backspace
- Home move to the start of input
- End move to the end of input
-
- The Virtual Windowing System page 58
-
-
-
- Pop-up menus have become very popular in recent years. Fortunately, they are
- a natural application for virtual windows! BASWIZ provides a pop-up menuing
- routine which allows you to have as many as 255 choices-- the window will be
- scrolled automatically to accommodate your "pick list", with a highlight bar
- indicating the current selection.
-
- The pop-up menu routine uses a window which you've already set up, so you can
- use any of the normal window options-- frames, titles, shadows, etc. You
- must provide a virtual screen large enough to hold your entire pick list; the
- window itself can be any size at all.
-
- The pick list is passed to WMenuPopUp through a string array. You can
- dimension this array in any range that suits you. The returned selection
- will be the relative position in the array (1 for the first item, etc); if
- the menu was aborted, 0 will be returned instead.
-
- The current window colors will be used for the "normal" colors. You specify
- the desired highlight colors when calling the pop-up menu routine.
-
- Result = WMenuPopUp(Handle, PickList$(), HiFore, HiBack)
-
- The mouse is not supported, since BASWIZ does not yet have mouse routines.
- However, scrolling can be accomplished with any of the more common methods:
- up and down arrows, WordStar-type Control-E and Control-X, or Lotus-type tab
- and backtab. The ESCape key can be used to abort without choosing an option.
-
- On exit, the menu window will remain in its final position, in case you wish
- to pop up a related window next to it or something similar. Since it's just
- an ordinary window, you can use WClose or WCollapse if you prefer to get rid
- of it.
-
- The WMenuPopUp routine was written in BASIC, so you will find it easy to
- modify to your tastes if you register BASWIZ. It was written with extra
- emphasis on comments and clarity, since I know many people will want to
- customize this routine!
-
- The Virtual Windowing System page 59
-
-
-
- There are two more routines which allow the virtual windowing system to work
- on a wide variety of displays: WFixColor and WSnow.
-
- Chances are, as a software developer you have a color display. However,
- there are many people out there who have monochrome displays, whether due to
- preference, a low budget, or use of notebook-style computers with mono LCD or
- plasma screens. WFixColor allows you to develop your programs in color while
- still supporting monochrome systems. It tells the VWS whether to keep the
- colors as specified or to translate them to their monochrome equivalents:
-
- WFixColor Convert%
-
- Set Convert% to zero if you want true color (default), or to any other value
- if you want the colors to be translated to monochrome. In the latter case,
- the translation will be done based on the relative brightness of the
- foreground and background colors. The result is guaranteed to be readable on
- a monochrome system if it's readable on a color system. You should check the
- results on your system to make sure that such things as highlight bars still
- appear highlighted, however.
-
- In the case of some of the older or less carefully designed CGA cards, the
- high-speed displays of the virtual windowing system can cause the display to
- flicker annoyingly. You can get rid of the flicker at the expense of slowing
- the display:
-
- WSnow Remove%
-
- Set Remove% to zero if there is no problem with "snow" or flickering
- (default), or to any other value if you need "snow removal". Using snow
- removal will slow down the display substantially, which may be a problem if
- you update (WUpdate) it frequently.
-
- Note that you can't detect either of these cases automatically with perfect
- reliability. Not all CGA cards have flicker problems. Monochrome displays
- may be attached to CGA cards and the computer won't know the difference. A
- VGA with a paper-white monitor may well think it has color, and will mostly
- act like it, but some "color" combinations can be very difficult to read.
- While you can self-configure the program to some extent using the GetDisplay
- routine (see Other Routines), you should also provide command-line switches
- so that the user can override your settings. Microsoft generally uses "/B"
- to denote a monochrome ("black and white") display, so you may want to follow
- that as a standard. I would suggest "/F" to turn on CGA flicker suppression.
-
- And that, folks, is all there is to it. See WDEMO.BAS and TERM.BAS for
- working examples. Also see "Telecommunications" for information about a
- routine which handles ANSI display and music codes; it displays to the window
- of your choice.
-
- Other Routines page 60
-
-
-
- There are a number of routines for which I couldn't find a specific category.
-
- To see how much expanded memory is available, use the GetEMS function. It'll
- return zero if there is no expanded memory installed:
-
- PRINT "Kbytes of expanded memory:"; GetEMS
-
- The GetDisplay routine tells what kind of display adapter is active and
- whether it's hooked up to a color monitor. The only time it can't detect the
- monitor type is on CGA setups (it assumes "color"). It's a good idea to
- allow a "/B" switch for your program so the user can specify if a monochrome
- monitor is attached to a CGA.
-
- 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
-
- The ScreenSize routine returns the number of rows and columns on the display
- (text modes only):
-
- ScreenSize Rows%, Columns%
-
- Miscellaneous Notes page 61
-
-
-
- The virtual windowing system allows up to 16 windows to be open at a time,
- including the background window, which is opened automatically. This is
- subject to available memory, of course.
-
- The far string handler allows up to 65,535 strings of up to 255 characters
- each, subject to available memory. When the handler needs additional memory
- for string storage, it allocates more in blocks of 16 Kbytes. If that much
- memory is not available, an "out of memory" error will be generated (BASIC
- error number 7). You can check the size of the available memory pool using
- the SETMEM function provided by QuickBASIC.
-
- The communications handler only allows one comm port to be used at a time.
- This will change in a future version of BASWIZ.
-
- The file handler does not allow you to combine Write mode with Text mode or
- input buffering. This will change in a future version of BASWIZ.
-
- A certain lack of speed is inherent in BCD math, especially if you require
- high precision. The division, root, and trig routines in particular are
- quite slow. I'll attempt to improve this in the future, but the routines are
- already fairly well optimized, so don't expect miracles. Precision costs!
-
- The fraction routines are much faster, but they have a much smaller range.
- I'll have to do some experimenting on that. It may prove practical to use a
- subset of the BCD routines to provide an extended range for fractions without
- an unreasonable loss in speed.
-
- All routines are designed to be as bomb-proof as possible. If you pass an
- invalid value to a routine which does not return an error code, it will
- simply ignore the value.
-
- It's always possible that a problem has escaped notice. If you run into
- something that you believe to be a bug or incompatibility, please tell me
- about it, whether you've registered BASWIZ or not.
-
- Do you like what you see? Tell me what you like, what you don't like, and
- what you'd be interested in seeing in future versions! Chances are good that
- I'll use your suggestions. If you know of a good reference book or text
- file, I'd like to hear about that too! You can reach me through U.S. Mail or
- through several of the international BASIC conferences on BBSes.
-
- Miscellaneous Notes page 62
-
-
-
- The EGA graphics routines are designed for use with EGAs having at least 256K
- RAM on board. They will not operate properly on old 64K EGA systems.
-
- Image loading (.MAC and .PCX) is quite slow. The bulk of the code is in
- BASIC at this point, to make it easier for me to extend the routines to cover
- other graphics modes. They will be translated to assembly later.
-
- The G#Write and G#WriteLn services support three different fonts: 8x8, 8x14,
- and 8x16. The default font is always 8x8, providing the highest possible
- text density. QuickBASIC, on the other hand, allows only one font with a
- text density of as close to 80x25 as possible.
-
- The G#Write and G#WriteLn services interpret ASCII control characters, i.e.
- CHR$(0) - CHR$(31), according to the more standard handling used by DOS
- rather than the esoteric interpretation offered by QuickBASIC. This is not
- exactly a limitation, but it could conceivably cause confusion if your
- program happens to use these characters. The ASCII interpretion works as
- follows:
-
- Code Meaning
- ==== =======
- 7 Bell (sound a beep through the speaker)
- 8 Backspace (destructive: eliminates the previous character)
- 9 Tab (based on 8-character tab fields)
- 10 LineFeed (move down one line, keep current column)
- 12 FormFeed (clear the screen)
- 13 Return (move to the start of the current line)
-
- G#MirrorH will only work properly on images with byte alignment! This means
- that the width of the image must be evenly divisible by four if SCREEN 1 is
- used, or evenly divisible by eight if SCREEN 2 is used.
-
- The graphics routines provide little error checking and will not do clipping
- (which ignores points outside the range of the graphics mode). If you specify
- coordinates which don't exist, the results will be unusual at best. Try to
- keep those values within the proper range!
-
- A very few of the graphics routines are slower than their counterparts in
- QuickBASIC. These are mostly drawing diagonal lines and filling boxes. I
- hope to get these better optimized in a future release. The GET/PUT image
- replacements are quite slow, but that's strictly temporary! I rushed 'em in
- by special request from a registered BASWIZ owner.
-
- Miscellaneous Notes page 63
-
-
-
- If you use PRINT in conjunction with GN4Write or GN4WriteLn, be sure to save
- the cursor position before the PRINT and restore it afterwards. BASIC and
- BASWIZ share the same cursor position, but each interprets it to mean
- something different.
-
- The GN0 (360x480x256) and GN1 (320x400x256) routines use nonstandard VGA
- modes. The GN1 routines should work on just about any VGA, however. The GN0
- routines will work on many VGAs, but are somewhat less likely to work than
- the GN1 routines due to the techniques involved.
-
- The GN0Write, GN0WriteLn, GN1Write and GN1WriteLn routines are somewhat slow
- in general and quite slow when it comes to scrolling the screen. These
- problems are related to peculiarities of these modes that I'm still grappling
- with. They will hopefully be improved in a future release.
-
- The G1Border routine is normally used to select the background (and border)
- color for SCREEN 1 mode. It can also be used in SCREEN 2 mode, where it will
- change the foreground color instead. Note that this may produce peculiar
- results if an EGA or VGA is used and it isn't locked into "CGA" mode, so be
- careful if your program may run on systems with displays other than true CGAs.
-
- GET/PUT images have a lot of possibilities that Microsoft has never touched
- on. I'll be exploring this extensively in future versions. Among other
- things, expect the ability to change the colors, rotate the image, and
- translate the image from one graphics mode format to another. Enlarging and
- shrinking the image will also be a good bet.
-
- Note that you can GET an image in SCREEN 1 and PUT it in SCREEN 2! It'll be
- shaded instead of in colors. This is a side-effect of the CGA display format.
-
- The first two elements of a GET/PUT array (assuming it's an integer array)
- tells you the size of the image. The first element is the width and the
- second is the height, in pixels. Actually, that's not quite true. Divide
- the first element by 2 for the width if the image is for SCREEN 1, or by 8 if
- for SCREEN 13.
-
- Error Codes page 64
-
-
-
- The expression evaluator returns the following error codes:
-
- 0 No error, everything went fine
- 2 A number was expected but not found
- 4 Unbalanced parentheses
- 8 The expression string had a length of zero
- 9 The expression included an attempt to divide by zero
-
-
-
- The far string handler does not return error codes. If an invalid string
- handle is specified for FSSet, it will be ignored; if for FSGet, a null
- string will be returned. If you run out of memory for far strings, an "out
- of memory" error will be generated (BASIC error #7). You can prevent this by
- checking available memory beforehand with the SETMEM function provided by
- QuickBASIC. Far string space is allocated as needed in blocks of just over
- 16 Kbytes, or 16,400 bytes to be exact.
-
-
-
- The telecommunications handler returns the following error codes for TCInit:
-
- 0 No error, everything A-Ok
- 1 The comm handler is already installed (you tried to install it twice)
- 2 Invalid comm port specified
- 3 Not enough memory available for input and output buffers
-
-
-
- The telecommunications handler returns these error codes for Xmodem Send:
-
- -13 FATAL : Abort due to selection of an unsupported transfer protocol
- -12 FATAL : Abort due to excessive errors
- -11 FATAL : Abort (by keyboard <ESC> or receiver CANcel request)
- -5 WARNING : Checksum or CRC error
- -1 WARNING : Time-out error (the receiver didn't respond)
- 0 DONE : No error, transfer completed ok
- >0 ERROR : Problem reading from the file (see file error codes)
-
- Error Codes page 65
-
-
-
- The file services return the following error codes:
- (The asterisk "*" is used to identify so-called "critical errors")
-
- 0 No error
- 1 Invalid function number (usually means "invalid parameter(s)")
- 2 File not found
- 3 Path not found
- 4 Too many open files
- 5 Access denied (probably "write to read-only file")
- 6 Invalid file handle
- 7 Memory control blocks destroyed
- 8 Insufficient memory (usually RAM, sometimes disk)
- 9 Incorrect memory pointer specified
- 15 Invalid drive specified
- * 19 Tried to write on a write-protected disk
- * 21 Drive not ready
- * 23 Disk data error
- * 25 Disk seek error
- * 26 Unknown media type
- * 27 Sector not found
- * 28 Printer out of paper
- * 29 Write fault
- * 30 Read fault
- * 31 General failure
- * 32 Sharing violation
- * 33 Lock violation
- * 34 Invalid disk change
- 36 Sharing buffer overflow
-
-
-
- A "critical error" is one that would normally give you the dreaded prompt:
-
- A>bort, R>etry, I>gnore, F>ail?
-
- Such errors generally require some action on the part of the user. For
- instance, they may need to close a floppy drive door or replace the paper in
- a printer. If a critical error occurs on a hard drive, it may indicate a
- problem in the drive hardware or software setup. In that case, the problem
- may possibly be cleared up by "CHKDSK /F", which should be executed directly
- from the DOS command line (do not execute this by SHELL).
-
- Troubleshooting page 66
-
-
-
- Problem:
- QB says "subprogram not defined".
-
- Solution:
- The definition file was not included. Your program must contain the line
- REM $INCLUDE: 'BASWIZ.BI'
- before any executable code in your program. You should also start
- QuickBASIC with
- QB /L BASWIZ
- so it knows to use the BASWIZ library.
-
-
- Problem:
- LINK says "unresolved external reference".
-
- Solution:
- Did you specify BASWIZ as the library when you used LINK? You should!
- The BASWIZ.LIB file must be in the current directory or along a path
- specified by the LIB environment variable (like PATH, but for LIB files).
-
-
- Problem:
- The virtual windowing system doesn't display anything.
-
- Solution:
- Perhaps you left out the WUpdate routine? If so, the shadow screen is not
- reflected to the actual screen and nothing will appear. The screen also
- needs to be in text mode (either no SCREEN statement or SCREEN 0).
- Finally, only the default "page zero" is supported on color monitors.
-
-
- Problem:
- The virtual windowing system causes the display to flicker on CGAs.
-
- Solution:
- Use the WSnow routine to get rid of it. This will, unfortunately, slow
- the display down severely. You might want to upgrade your display card!
-
-
- Problem:
- QuickBASIC doesn't get along with the Hercules display routines.
-
- Solution:
- Are you using an adapter which includes Hercules mode along with EGA or
- VGA mode? QuickBASIC doesn't like that, since it thinks you'll be using
- EGA or VGA mode. Use the stand-alone compiler (BC.EXE) instead of the
- environment (QB.EXE) and you should be fine. You might also consider
- getting a separate Herc adapter and monochrome monitor. It's possible to
- combine a Hercules monochrome adapter with a CGA, EGA or VGA.
-
- Troubleshooting page 67
-
-
-
- Problem:
- QB says "out of memory" (or "range out of bounds" on a DIM or REDIM).
-
- Solution:
- If you're using the memory management/pointer routines, you've probably
- allocated too much memory! You need to leave some for QuickBASIC. Use
- the SETMEM function provided by BASIC to determine how much memory is
- available before allocating memory. The amount needed by QuickBASIC will
- depend on your program. The primary memory-eaters are arrays and
- recursive subprograms or functions.
-
- Many of the BASWIZ routines need to allocate memory, including the virtual
- window manager, telecommunications handler, and memory management system.
- Besides checking with SETMEM to make sure there's memory to spare, don't
- forget to check the error codes returned by these routines to make sure
- they're working properly!
-
-
- Problem:
- The cursor acts funny (appears when it shouldn't or vice versa).
-
- Solution:
- Try locking your EGA or VGA into a specific video mode using the utility
- provided with your display adapter. Cursor problems are usually related
- either to "auto mode detection" or older EGAs.
-
-
- Problem:
- The BCD trig functions return weird results.
-
- Solution:
- Make sure you've made room in your BCD size definition for some digits to
- the left of the decimal as well as to the right! Calculations with large
- numbers are needed to return trig functions with high accuracy.
-
-
- Problem:
- The G#MirrorH routine is -almost- working right, but the results are
- truncated or wrapped to one side.
-
- Solution:
- Make your GET image a tad wider! The number of pixels wide must be evenly
- divisible by four in SCREEN 1, or by eight in SCREEN 2.
-
- History and Philosophy page 68
-
-
-
- "History," you say. "Philosophy. What the heck does that have to do with a
- BASIC library? Yuck! Go away and leave me alone!"
-
- Ok. This section is not strictly necessary for using BASWIZ. If you're not
- interested, you can certainly avoid reading this without ill effects. "Suit
- yourself," he said with a bow and a flourish.
-
- Still here? Thank you! I'll try to keep it short.
-
- Back in 'bout 1984 or so, I created ADVBAS, one of the very first assembly
- language libraries for BASIC. That was for IBM BASCOM 1.0, well before
- QuickBASIC came out. I created the library for my own use and ended up making
- a moderately successful shareware project out of it.
-
- ADVBAS was designed in bits and pieces that came along whenever I felt like
- adding to the library or needed a new capability. The routines were designed
- at a low level, with most of the actual work needed to accomplish anything
- useful left to BASIC. All this resulted in a decent amount of flexibility
- but also a good deal of chaos as new routines provided capabilities that
- overlapped with old routines. Although I tried to keep the calling sequence
- reasonably standardized, it didn't always work out that way. Then too, the
- library was designed well before the neat capabilities of QuickBASIC 4.0 came
- into being and couldn't take good advantage of them.
-
- Second came ProBas, a commercial version of ADVBAS. ProBas was a vastly more
- powerful superset of the ADVBAS library. Unfortunately, it suffered from the
- same flaws. No old routines could be discarded or even modified if at all
- possible, to provide compatibility from one version to the next. The lack of
- thought inherent in the original design caused a mad proliferation of
- routines, many overlapping, most still low-level and hard to use. At version
- 4.0, there were nearly 600 different routines-- something for everyone, to be
- sure, but tending towards complete pandemonium.
-
- The BASWIZ project is a third-generation library. It is designed to overcome
- the liabilities I've encountered with ADVBAS and every other library I've
- seen for BASIC. Rather than being put together haphazardly, one routine at a
- time, I have designed BASWIZ as a coordinated collection. The virtual
- windowing system is an excellent example of this. Rather than having
- separate print routines, window routines, screen saving routines, virtual
- screen routines and all the rest, it is all combined into one single
- package. The routines are designed at a high level, providing a maximum of
- functionality with a minimum of programming effort. The gritty details are
- kept hidden inside the library where you need never deal with them. Consider
- the apparent simplicity of the far string handler! Many more capabilities
- will be added in future versions, but... very carefully.
-
- History and Philosophy page 69
-
-
-
- This library represents the culmination of many years of experience in the
- fields of BASIC and assembly language programming. I have spared no effort.
- It's the best I can offer and I hope you'll forgive me for taking some pride
- in my work! If you find this library powerful and easy to use, I'll count my
- efforts a great success.
-
- As you might have guessed, I'm not exactly in it "just for the money."
- Nonetheless, money is always nice! If you like BASWIZ, please do register.
- That will enable me to upgrade my equipment and design more advanced BASWIZ
- routines. Currently I have a 386SX with a VGA display. I would like to be
- able to support Super VGA, 9600 bps modems, scanners, sound boards and other
- hardware as well.
-
- Current update: Hammerly Computer Services, which markets ProBas and related
- products, owes me more than a year's worth of royalties, a computer system,
- and sundry other items. They refuse to pay and won't respond to the messages
- I send via U.S. Mail or their BBS. So, I'm releasing a shareware clone of
- the ProBas library in an attempt to get at least some recompense for my
- development efforts. Look for the PBClone library (PBCLONxx.ZIP) on your
- local BBSes. PBCLON can be used in conjunction with BASWIZ for more power!
-
- Using BASWIZ with PDQ page 70
-
-
-
- Most of the BASWIZ routines will work with current versions of PDQ without
- any modification. The major exceptions are the expression evaluator, the BCD
- and fraction math routines, and the polygon-generating graphics routines.
-
- The .EXE files that come with the BASWIZ library are LINKed with PDQ, which
- is why they're so small.
-
- Older versions of Crescent Software's PDQ library do not support the SETMEM
- function, which is required by many BASWIZ routines. If your version of PDQ
- is before v2.10, you must LINK in the SETMEM stub provided with BASWIZ:
-
- LINK program+PDQSTUB/NOD,,NUL,BASWIZ+PDQ;
-
- If you use LINK differently, that's fine. The only thing necessary is to
- make sure "+PDQSTUB" is listed after the name of your program as the first
- LINK argument. Use of /EX and other LINK parameters is no problem. Use of
- other libraries, if any, is also supported. For some reason, PDQ usually
- wants to be the last library listed, by the way.
-
- Crescent thoughtfully provided me with a free copy of PDQ in order that I
- might resolve any incompatibilities between it and BASWIZ. If you are not
- familiar with PDQ, it is a replacement library for BASIC's own runtime
- libraries. While not providing every capability of plain QuickBASIC, it
- allows you to create substantially smaller EXE files for those programs that
- qualify. Support is currently lacking for floating point (single/double
- precision) numbers, music, and graphics, among other things. I understand
- that these features will be available in future revisions. Communications
- support is available as an add-on package. PDQ also adds new capabilities
- which are quite impressive, such as being able to write small TSRs in BASIC.
- Check with Crescent Software for more recent details.
-
- Credits page 71
-
-
-
- For some of the reference works I have used in writing BASWIZ, see the
- BIBLIO.TXT file.
-
- I am also indebted to the following people, among others:
-
- Bill Cliver, president of F & I Controls, which markets software and hardware
- solutions for every aspect of car dealerships. He has provided me with the
- VGA system which has allowed me to support VGA graphics modes in BASWIZ.
-
- Mike Welch, co-sysop of The Shipyard BBS, the best BASIC support BBS that
- I've ever encountered. Among other fine deeds, he is responsible for the
- S&B4EGA and VGABOX demonstration programs which accompany BASWIZ.
-
- The inverse hyperbolic trig functions are based on a set of BASIC routines by
- Kerry Mitchell.
-
- The 360x480 256-color VGA mode was made possible by John Bridges' VGAKIT 3.4
- library for C. Two of the most vital low-level routines are based directly
- on code from VGAKIT. If you use C, check your local BBS for this library.
-
-