home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / PROG / BASIC / BASWIZ15.ZIP / BASWIZ.DOC < prev    next >
Encoding:
Text File  |  1991-03-31  |  144.2 KB  |  3,251 lines

  1.                           The BASIC Wizard's Library                    page 1
  2.                           =------------------------=
  3.                                   Version 1.5
  4.  
  5.              BASWIZ  Copyright (c) 1990-1991  Thomas G. Hanlin III
  6.  
  7.  
  8.  
  9. This library is too large for BASIC to cope with as a unit.  The Library
  10. Wizard utility (available separately as LIBWIZxx.ZIP) allows you to create
  11. custom libraries containing just the routines you need.
  12.  
  13. This is BASWIZ, a library of assembly language and BASIC routines for use
  14. with QuickBASIC version 4.5.  Support for other recent versions of the BASIC
  15. compiler is provided with registration.  The BASWIZ collection is copyrighted
  16. and may be distributed only under the following conditions:
  17.  
  18.    1) No fee of over $10.00 may be charged for distribution.  This
  19.       restriction applies only to physical copies and is not meant to
  20.       prevent distribution by telecommunication services.
  21.  
  22.    2) All BASWIZ files must be distributed together in original, unaltered
  23.       form.  See FILES.LST for a list of the BASWIZ files.
  24.  
  25. You use this library at your own risk.  It has been tested by me on my own
  26. computer, but I will not assume any responsibility for any problems which
  27. BASWIZ may cause you.  If you do encounter a problem, please let me know
  28. about it, and I will do my best to verify and repair the error.
  29.  
  30. It is expected that if you find BASWIZ useful, you will register your copy.
  31. You may not use BASWIZ routines in programs intended for sale unless you have
  32. registered.  Registration entitles you to receive the latest version of
  33. BASWIZ, complete with full source code in assembly language and BASIC.  The
  34. assembly code is designed for the OPTASM assembler by SLR Systems and will
  35. require modifications if you wish to use it with MASM or TASM.  You will then
  36. be able to compile the BASIC code with whatever version of the compiler you
  37. have, allowing you to use BASWIZ with QuickBASIC versions 4.0 - 4.5 and
  38. BASCOM versions 6.0 - 7.1.  Note that Microsoft's "far strings" can't be used
  39. with BASWIZ at this time, so BASWIZ can't be used with QBX.
  40.  
  41. Warning: Use of BASWIZ for more than 30 days without registering has been
  42. determined to cause the author to practice the tuba outside your window!
  43.  
  44. For an example of how to set up your program to access the BASWIZ library,
  45. how to LINK the routines, and so forth, take a look at the CREATE.BAT,
  46. GDEMO.BAS and WDEMO.BAS files.  The CREATE.BAT file expects a BASWIZ library
  47. by the name of BW.LIB.  LIBRARY.TXT explains how to use libraries.
  48.  
  49. So who's the BASIC Wizard?  Why, with this library, you will be!  Read this
  50. tome well, for invoking these routines without proper preparation may bring
  51. unexpected results.  Cape and hat (optional) not included.  No assembly
  52. required.
  53.  
  54.                               Table of Contents                         page 2
  55.  
  56.  
  57.  
  58.  Overview and Legal Info ................................................ 1
  59.  
  60.  BCD Math ............................................................... 3
  61.  
  62.  Expression Evaluator ................................................... 6
  63.  
  64.  Extensions to BASIC's math ............................................. 7
  65.  
  66.  Far Strings ............................................................ 9
  67.  
  68.  File Handling ......................................................... 11
  69.  
  70.  Fractions ............................................................. 19
  71.  
  72.  Graphics
  73.     Mode-Specific Routines ............................................. 20
  74.     Printer Routines ................................................... 31
  75.     A Little Geometry .................................................. 32
  76.     Equations, Etc ..................................................... 35
  77.  
  78.  Memory Management and Pointers ........................................ 38
  79.  
  80.  Telecommunications .................................................... 41
  81.  
  82.  Virtual Windowing System .............................................. 47
  83.  
  84.  Other Routines ........................................................ 60
  85.  
  86.  Miscellaneous Notes ................................................... 61
  87.  
  88.  Error Codes ........................................................... 64
  89.  
  90.  Troubleshooting ....................................................... 66
  91.  
  92.  History & Philosophy .................................................. 68
  93.  
  94.  Using BASWIZ with PDQ ................................................. 70
  95.  
  96.  Credits ............................................................... 71
  97.  
  98.                                    BCD Math                             page 3
  99.  
  100.  
  101.  
  102. Some of you may not have heard of BCD math, or at least not have more than a
  103. passing acquaintance with the subject.  BCD (short for Binary-Coded Decimal)
  104. is a way of encoding numbers.  It differs from the normal method of handling
  105. numbers in several respects.  On the down side, BCD math is much slower than
  106. normal math and the numbers take up more memory.  However, the benefits may
  107. far outweigh these disadvantages, depending on your application: BCD math is
  108. absolutely precise within your desired specifications, and you can make a BCD
  109. number as large as you need.  If your applications don't require great range
  110. or precision out of numbers, normal BASIC math is probably the best choice.
  111. For scientific applications, accounting, engineering and other demanding
  112. tasks, though, BCD may be just the thing you need.
  113.  
  114. The BCD math routines provided by BASWIZ allow numbers of up to 255 digits
  115. long (the sign counts as a digit, but the decimal point doesn't).  You may
  116. set the decimal point to any position you like, as long as there is at least
  117. one digit position to the left of the decimal.
  118.  
  119. Since QuickBASIC doesn't support BCD numbers directly, we store the BCD
  120. numbers in strings.  The results are not in text format and won't mean much
  121. if displayed.  A conversion routine allows you to change a BCD number to a
  122. text string in any of a variety of formats.
  123.  
  124. Note that the BCD math handler doesn't yet track overflow/underflow error
  125. conditions.  If you anticipate that this may be a problem, it would be a good
  126. idea to screen your input or to make the BCD range large enough to avoid
  127. these errors.
  128.  
  129. Let's start off by examining the routine which allows you to set the BCD
  130. range:
  131.  
  132.    BCDSetSize LeftDigits%, RightDigits%
  133.  
  134. The parameters specify the maximum number of digits to the left and to the
  135. right of the decimal point.  There must be at least one digit on the left,
  136. and the total number of digits must be less than 255.  The BCD strings will
  137. have a length that's one larger than the total number of digits, to account
  138. for the sign of the number.  The decimal point is implicit and doesn't take
  139. up any extra space.
  140.  
  141. It is assumed that you will only use one size of BCD number in your program--
  142. there are no provisions for handling mixed-length BCD numbers.  Of course,
  143. you could manage that yourself with a little extra work, if it seems like a
  144. useful capability.  If you don't use BCDSetSize, the default size of the BCD
  145. numbers will be 32 (20 to the left, 11 to the right, 1 for the sign).
  146.  
  147. You can get the current size settings in your program, too:
  148.  
  149.    BCDGetSize LeftDigits%, RightDigits%
  150.  
  151.                                    BCD Math                             page 4
  152.  
  153.  
  154.  
  155. Before doing any BCD calculations, you must have some BCD numbers!  The
  156. BCDSet routine takes a number in text string form and converts it to BCD:
  157.  
  158.    TextSt$ = "1234567890.50"
  159.    Nr$ = BCDSet$(TextSt$)
  160.  
  161. If your numbers are stored as actual numbers, you can convert them to a text
  162. string with BASIC's STR$ function, then to BCD.  Leading spaces are ignored:
  163.  
  164.    Nr$ = BCDSet$(STR$(AnyNum#))
  165.  
  166. BCD numbers can also be converted back to text strings, of course.  You may
  167. specify how many digits to the right of the decimal to keep (the number will
  168. be truncated, not rounded).  If the RightDigits% is positive, trailing zeros
  169. will be kept; if negative, trailing zeros will be removed.  There are also
  170. various formatting options which may be used.  Here's how it works:
  171.  
  172.    TextSt$ = BCDFormat$(Nr$, HowToFormat%, RightDigits%)
  173.  
  174. The HowToFormat% value may be any combination of the following (just add the
  175. numbers of the desired formats together):
  176.  
  177.    0   plain number
  178.    1   use commas to separate thousands, etc
  179.    2   start number with a dollar sign
  180.    4   put the sign on the right side instead of the left side
  181.    8   use a plus sign instead of a space if number is not negative
  182.  
  183. The BCD math functions are pretty much self-explanatory, so I'll keep the
  184. descriptions brief.  Here are the single-parameter functions:
  185.  
  186.    Result$ = BCDAbs$(Nr$)              ' take the absolute value of a number
  187.    Result$ = BCDCos$(Nr$)              ' cosine function
  188.    Result$ = BCDCot$(Nr$)              ' cotangent function
  189.    Result$ = BCDCsc$(Nr$)              ' cosecant function
  190.    Result$ = BCDDeg2Rad$(Nr$)          ' convert degrees to radians
  191.    e$ = BCDe$                          ' get the value of the constant "e"
  192.    Result$ = BCDFact$(N%)              ' calculate the factorial of integer N
  193.    Result$ = BCDFrac$(Nr$)             ' return the fractional part of a number
  194.    Result$ = BCDInt$(Nr$)              ' return the integer part of a number
  195.    Result$ = BCDNeg$(Nr$)              ' negate a number
  196.    pi$ = BCDpi$                        ' get the value of the constant "pi"
  197.    Result$ = BCDRad2Deg$(Nr$)          ' convert radians to degrees
  198.    Result$ = BCDSec$(Nr$)              ' secant function
  199.    Result% = BCDSgn%(Nr$)              ' signum function
  200.    Result$ = BCDSin$(Nr$)              ' sine function
  201.    Result$ = BCDSqr$(Nr$)              ' get the square root of a number
  202.    Result$ = BCDTan$(Nr$)              ' tangent function
  203.  
  204.                                    BCD Math                             page 5
  205.  
  206.  
  207.  
  208. Notes on the single-parameter functions:
  209.  
  210.   The signum function returns an integer based on the sign of the BCD number:
  211.      -1   if the BCD number is negative
  212.       0   if the BCD number is zero
  213.       1   if the BCD number is positive
  214.  
  215.   BCDpi$ is accurate to the maximum level afforded by the BCD functions.
  216.   BCDe$ is accurate to as many as 115 decimal places.  The actual accuracy,
  217.   of course, depends on the size of BCD numbers you've chosen.
  218.  
  219.   The trigonometric functions (cos, sin, tan, sec, csc, cot) expect angles in
  220.   radians.  BCDDeg2Rad and BCDRad2Deg will allow you to convert back and
  221.   forth between radians and degrees.
  222.  
  223.  
  224.  
  225. Here is a list of the two-parameter functions:
  226.  
  227.    Result$ = BCDAdd$(Nr1$, Nr2$)      ' add two numbers together
  228.  
  229.    Result$ = BCDSub$(Nr1$, Nr2$)      ' subtract the second nr from the first
  230.  
  231.    Result$ = BCDMul$(Nr1$, Nr2$)      ' multiply one number by another
  232.  
  233.    Result$ = BCDDiv$(Nr1$, Nr2$)      ' divide the first number by the second
  234.  
  235.    Result$ = BCDPower$(Nr$, Power%)   ' raise a number to a power
  236.  
  237.    Result% = BCDCompare%(Nr1$, Nr2$)  ' compare two numbers
  238.  
  239. The comparison function returns an integer which reflects how the two numbers
  240. compare to eachother:
  241.  
  242.    -1   Nr1 < Nr2
  243.     0   Nr1 = Nr2
  244.     1   Nr1 > Nr2
  245.  
  246.                              Expression Evaluator                       page 6
  247.  
  248.  
  249.  
  250. The expression evaluator allows you to find the result of an expression
  251. contained in a string.  Normal algebraic precedence is used, e.g. 4+3*5
  252. evaluates to 19.  The usual numeric operators (*, /, +, -, ^) are supported
  253. (multiply, divide, add, subtract, and raise to a power).  Use of negative
  254. numbers is just fine, of course.  Parentheses for overriding the default
  255. order of operations are also supported.
  256.  
  257. You may use either double asterisk ("**") or a caret ("^") symbols to
  258. indicate exponentiation.
  259.  
  260. To evaluate an expression, you pass it to the evaluator as a string.  You
  261. will get back either an error code or a single-precision result.  Try this
  262. example to see how the expression evaluator works:
  263.  
  264.    REM $INCLUDE: 'BASWIZ.BI'
  265.    DEFINT A-Z
  266.    DO
  267.       INPUT "Expression? "; Expr$
  268.       IF LEN(Expr$) THEN
  269.          Evaluate Expr$, Result!, ErrCode
  270.          IF ErrCode THEN
  271.             PRINT "Invalid expression.  Error code = "; ErrCode
  272.          ELSE
  273.             PRINT "Result: "; Result!
  274.          END IF
  275.       END IF
  276.    LOOP WHILE LEN(Expr$)
  277.    END
  278.  
  279. An expression evaluator adds convenience to any program that needs to accept
  280. numbers.  Why make someone reach for a calculator when number crunching is
  281. what a computer does best?
  282.  
  283.                           Extensions to BASIC's math                    page 7
  284.  
  285.  
  286.  
  287. For the most part, the math routines in this library is designed to provide
  288. alternatives to the math routines that are built into BASIC.  Still, BASIC's
  289. own math support is quite adequate for many purposes, so there's no sense in
  290. ignoring it.  Here are some functions which improve on BASIC's math.
  291.  
  292.    Result! = ArcCosHS!(Nr!)    ' inverse hyperbolic cosine
  293.    Result! = ArcSinHS!(Nr!)    ' inverse hyperbolic sine
  294.    Result! = ArcTanHS!(Nr!)    ' inverse hyperbolic tangent
  295.    Result! = ArcCosS!(Nr!)     ' arc cosine     (1 >= Nr >= -1)
  296.    Result! = ArcSinS!(Nr!)     ' arc sine       (1 >= Nr >= -1)
  297.    Result! = ErfS!(Nr!)        ' error function
  298.    Result! = FactS!(Nr%)       ' factorial
  299.    Result! = CotS!(Nr!)        ' cotangent
  300.    Result! = CscS!(Nr!)        ' cosecant
  301.    Result! = SecS!(Nr!)        ' secant
  302.    Result! = CosHS!(Nr!)       ' hyperbolic cosine
  303.    Result! = SinHS!(Nr!)       ' hyperbolic sine
  304.    Result! = TanHS!(Nr!)       ' hyperbolic tangent
  305.    Result! = Deg2RadS!(Nr!)    ' convert degrees to radians
  306.    Result! = Rad2DegS!(Nr!)    ' convert radians to degrees
  307.    Result! = Cent2Fahr!(Nr!)   ' convert centigrade to Fahrenheit
  308.    Result! = Fahr2Cent!(Nr!)   ' convert Fahrenheit to centigrade
  309.    Result! = Kg2Pound!(Nr!)    ' convert kilograms to pounds
  310.    Result! = Pound2Kg!(Nr!)    ' convert pounds to kilograms
  311.    Pi! = PiS!                  ' the constant "pi"
  312.    e! = eS!                    ' the constant "e"
  313.  
  314.    Result# = ArcCosHD#(Nr#)    ' inverse hyperbolic cosine
  315.    Result# = ArcSinHD#(Nr#)    ' inverse hyperbolic sine
  316.    Result# = ArcTanHD#(Nr#)    ' inverse hyperbolic tangent
  317.    Result# = ArcCosD#(Nr#)     ' arc cosine     (1 >= Nr >= -1)
  318.    Result# = ArcSinD#(Nr#)     ' arc sine       (1 >= Nr >= -1)
  319.    Result# = ErfD#(Nr#)        ' error function
  320.    Result# = FactD#(Nr%)       ' factorial
  321.    Result# = CotD#(Nr#)        ' cotangent
  322.    Result# = CscD#(Nr#)        ' cosecant
  323.    Result# = SecD#(Nr#)        ' secant
  324.    Result# = CosHD#(Nr#)       ' hyperbolic cosine
  325.    Result# = SinHD#(Nr#)       ' hyperbolic sine
  326.    Result# = TanHD#(Nr#)       ' hyperbolic tangent
  327.    Result# = Deg2RadD#(Nr#)    ' convert degrees to radians
  328.    Result# = Rad2DegD#(Nr#)    ' convert radians to degrees
  329.    Pi# = PiD#                  ' the constant "pi"
  330.    e# = eD#                    ' the constant "e"
  331.  
  332.                           Extensions to BASIC's math                    page 8
  333.  
  334.  
  335.  
  336.    Result% = GCDI%(Nr1%, Nr2%) ' greatest common denominator
  337.    Result% = Power2I%(Nr%)     ' raise 2 to a specified power
  338.  
  339.    Result& = GCDL&(Nr1&, Nr2&) ' greatest common denominator
  340.    Result& = Power2L&(Nr%)     ' raise 2 to a specified power
  341.  
  342.  
  343.  
  344. Like BASIC's trig functions, these trig functions expect the angle to be in
  345. radians.  Conversion functions are provided in case you prefer degrees.
  346.  
  347. Note that there is no ArcTanS! or ArcTanD! function for the simple reason
  348. that BASIC supplies an ATN function.
  349.  
  350. Constants are expressed to the maximum precision available.
  351.  
  352. The Power2I% and Power2L& functions are vastly quicker than the equivalent
  353. BASIC formulas.  If powers of two are useful to you, try these functions!
  354.  
  355.  
  356.  
  357. If you are not familiar with variable postfix symbols, here's a brief summary:
  358.  
  359.   Symbol   Meaning             Range (very approximate)
  360.   ------   --------            ------------------------
  361.     %      integer             +- 32767
  362.     &      long integer        +- 2 * 10^9
  363.     !      single precision    +- 1 * 10^38   (7-digit precision float. point)
  364.     #      double precision    +- 1 * 10^308  (15-digit precision float. point)
  365.     $      string              [0 to 32767 characters]
  366.  
  367. See your BASIC manual or QuickBASIC's online help for further details.
  368.  
  369.                                  Far Strings                            page 9
  370.  
  371.  
  372.  
  373. One of the best things about BASIC is its support for variable-length
  374. strings.  Few other languages support such dynamically-allocated strings and
  375. they're a terrifically efficient way of using memory.  At least, they would
  376. be, except for one minor limitation... in every version of QuickBASIC and
  377. BASCOM (except for the new, very expensive BASCOM 7.0 "Professional
  378. Development System"), string space is limited to a mere 50K-60K bytes.  As if
  379. this weren't trouble enough, this space is also shared with a number of other
  380. things.  Running out of string space is a common and painful problem.
  381.  
  382. Anyway, it used to be.  The BASWIZ library comes with an assortment of
  383. routines and functions which allow you to keep variable-length strings
  384. outside of BASIC's tiny string area.  Currently, you may have up to 65,535
  385. far strings of up to 255 characters each, subject to available memory.
  386. Either normal system memory or expanded memory may be used.  Extended memory
  387. can also be used if you have a driver that converts extended memory to
  388. expanded memory.
  389.  
  390. Using far strings works almost the same way as using normal strings.  Rather
  391. than referring to a far string with a string variable name, however, you
  392. refer to it with an integer variable called a "handle".  To create a new far
  393. string, you use a handle of zero.  A new handle will be returned to you which
  394. will identify that string for future reference.
  395.  
  396. Before you use any far strings, you must initialize the far string handler.
  397. When you are done using far strings, you must terminate the far string
  398. handler.  Normally, each of these actions will take place only once in your
  399. program: you initialize at the beginning and terminate at the end.
  400.  
  401. On the next page is an example program that reads a file into an array of far
  402. strings, then displays it.  I'll leave out such niceties as error trapping to
  403. keep the example easy to follow.
  404.  
  405.                                  Far Strings                           page 10
  406.  
  407.  
  408.  
  409.    REM $INCLUDE: 'BASWIZ.BI'
  410.    DEFINT A-Z
  411.    REDIM Text(1 TO 5000)                   ' array for far string handles
  412.    FSInit 0                                ' initialize far string handler
  413.    TextLines = 0
  414.    OPEN "ANYFILE.TXT" FOR INPUT AS #1
  415.    DO UNTIL EOF(1)
  416.       LINE INPUT#1, TextRow$
  417.       Handle = 0                           ' use zero to create new far string
  418.       FSSet Handle, TextRow$               ' set the far string
  419.       TextLines = TextLines + 1
  420.       Text(TextLines) = Handle             ' save the far string handle
  421.    LOOP
  422.    CLOSE
  423.    FOR Row = 1 TO TextLines
  424.       PRINT FSGet$(Text(Row))              ' display a far string
  425.    NEXT
  426.    FSDone                                  ' terminate far string handler
  427.    END
  428.  
  429. If you wanted to change an existing far string, you would specify its
  430. existing handle for FSSet.  The handle of zero is used only to create new far
  431. strings, rather in the manner of using a new variable for the first time.
  432.  
  433. Note the zero after the FSInit call.  That specifies that main system memory
  434. is to be used.  If you would prefer to use expanded memory, use a one
  435. instead.  If EMS memory is not available, BASWIZ will ignore the one and use
  436. main memory instead.
  437.  
  438.                                 File Handling                          page 11
  439.  
  440.  
  441.  
  442. The file handling capabilities of BASIC were improved considerably as of
  443. QuickBASIC 4.0.  A binary mode was added and it became possible to use
  444. structured (TYPE) variables instead of the awkward FIELD-based random access
  445. handling.  Even today, however, BASIC file handling is inefficient for many
  446. tasks.  It requires error trapping to avoid problems like open floppy drive
  447. doors and cannot transfer information in large quantities at a time.
  448.  
  449. The BASWIZ routines provide additional flexibility and power.  They allow you
  450. to access files at as low or high a level as you wish.  Here are some of the
  451. features of BASWIZ file handling:
  452.  
  453.   - File sharing is automatically used if the DOS version is high enough,
  454.     providing effortless network compatibility.
  455.   - Critical errors, like other errors, are detected at any point you find
  456.     convenient via a single function call.
  457.   - Optional input buffers speed up reading from files.
  458.   - Up to 32K of data may be read or written at one time.
  459.   - Files can be flushed to disk to avoid loss due to power outages, etc.
  460.  
  461. Files are not considered to be strongly moded by BASWIZ, although there are a
  462. few limitations on how you can deal with text files as opposed to other kinds
  463. of files.  Reads and writes normally take place sequentially, like the INPUT
  464. and OUTPUT modes allowed by BASIC.  However, you can also do random access by
  465. moving the file pointer to anywhere in the file, just as with the RANDOM and
  466. BINARY modes allowed by BASIC.  These routines place no arbitrary limitations
  467. on the programmer.
  468.  
  469. As with BASIC, files are referred to by a number after they are opened for
  470. access.  Unlike BASIC, the number is returned to you when the file is
  471. successfully opened, rather than being specified by you when you open the
  472. file.  This means that you never have to worry about a file number already
  473. being in use.  We'll refer to the file number as a "file handle" from now on.
  474.  
  475.                                 File Handling                          page 12
  476.  
  477.  
  478.  
  479. Before doing anything else, you must initialize the file handling routines.
  480. This is typically done only once, at the beginning of your program.  The
  481. FInit routine needs to know the number of files you want to deal with.  This
  482. can be up to 15 files, or possibly up to 50 if you are using DOS 3.3 or
  483. higher.  Support for over 15 files has not been tested, since I don't have
  484. DOS 3.3 or higher, so you use that feature at your own risk!  A future
  485. version of BASWIZ will support over 15 open files for DOS 3.0 and above.
  486.  
  487.    FInit Files, ErrCode
  488.  
  489. A file is opened for access like so:
  490.  
  491.    FOpen File$, FMode$, BufferLen, Handle, ErrCode
  492.  
  493. You pass the File$, FMode$, and BufferLen.  The Handle and ErrCode are
  494. returned to you.  The "BufferLen" is the length of the buffer desired for
  495. input.  This must be zero if you want to write to the file.  The filename is
  496. passed in File$, naturally enough.  There is a choice of various modes for
  497. FMode$ and these can be combined to some extent:
  498.  
  499.    A   Append to file      used to add more information to an existing file
  500.    C   Create file         creates a new file
  501.    R   Read access         allows reading (input) from a file
  502.    T   Text mode file      allows text-mode input from a file
  503.    W   Write access        allows writing (output) to a file
  504.  
  505. For the most part, the combinations are self-explanatory.  For instance, it
  506. would be reasonable to open a file for read and write, for create and write,
  507. for append and write, or for read and text.  Text files always require a
  508. buffer.  If you request text access without specifying a buffer, a buffer of
  509. 512 bytes will be provided for you.  If you request create access without
  510. additional parameters, the file will be opened for write by default.
  511.  
  512. You may not use a buffer if you want to write to a file.  This includes text
  513. files, which always use a buffer, as well as binary files.  This is an
  514. artificial limitation which will change in a future version of BASWIZ.  It
  515. exists now to reduce the internal complexity of the routines which write to
  516. the file, so that they do not have to account for any buffering as well as
  517. the current file pointer.  However, writing may be done to a text-type file
  518. if the file was not opened in text mode.  We'll see how that works presently.
  519.  
  520. When you are done using a particular file, you can close it, just as in
  521. ordinary BASIC:
  522.  
  523.    FClose Handle
  524.  
  525. Before your program ends, you should terminate the file handler.  This will
  526. close any open files as well as concluding use of the file routines:
  527.  
  528.    FDone
  529.  
  530.                                 File Handling                          page 13
  531.  
  532.  
  533.  
  534. That covers the basic set-up routines: initialize, open, close, and
  535. terminate.  Of more interest are the routines which actually deal with the
  536. file itself.  These provide assorted read/write services, the ability to get
  537. or set the file read/write pointer, size, time, and date, and the ability to
  538. get or set the error code for a specific file, among other things.  Let's
  539. take a look at the error handler first.
  540.  
  541. The FInit and FOpen routines return an error code directly, since you need to
  542. know immediately if these have failed.  The other file routines do not return
  543. a direct error code, however.  In order to discover whether an error has
  544. occurred, you use the FGetError% function.  This will return an error of zero
  545. if there was no error, or a specific error code (listed at the end of this
  546. manual) if some problem occurred.  The error code will remain the same until
  547. you reset it using FError.  The FError service also allows you to test your
  548. error handler by forcing specific error codes even when everything is fine.
  549.  
  550.    PRINT "Error code: "; FGetError(Handle)
  551.    FError Handle, 0                          ' clear the error code
  552.  
  553. It is recommended that you check for errors after any file routine is used if
  554. there is a chance that your program will be executed on a floppy disk.  These
  555. are particularly prone to user errors (like leaving the drive door open) or
  556. running out of space.  If your program will only run on a hard drive, you may
  557. not need to check as frequently.  It's your choice.  Note that the error code
  558. is not cleared automatically-- use FError to reset the error code to zero if
  559. you determine that it wasn't a "fatal" error.
  560.  
  561. Down to the nitty-gritty... we've seen how to open and close a file, how to
  562. check operations for errors, and so forth.  So how do we actually manipulate
  563. the file?  There are assorted alternatives, depending on how you want to deal
  564. with the file: text reads, text writes, byte-oriented reads and writes, and
  565. block reads and writes, not to mention handling the time, date, size, and
  566. read/write pointer.  We'll start off with the routines which read from a
  567. file.
  568.  
  569. If you opened the file for text access, you must want to read the file a line
  570. at a time.  Each line is assumed to be less than 256 characters and delimited
  571. by a carriage return and linefeed (<CR><LF>, or ^M^J, in normal notation).
  572. In that case, you should use the FReadLn$ function:
  573.  
  574.    St$ = FReadLn$(Handle)
  575.  
  576. A simple program to display a text file directly on the screen might look
  577. something like this in BASIC:
  578.  
  579.    OPEN COMMAND$ FOR INPUT AS #1
  580.    WHILE NOT EOF(1)
  581.       LINE INPUT#1, St$
  582.       PRINT St$
  583.    WEND
  584.    CLOSE #1
  585.  
  586.                                 File Handling                          page 14
  587.  
  588.  
  589.  
  590. The same program using BASWIZ would look something like this:
  591.  
  592.    REM $INCLUDE: 'BASWIZ.BI'
  593.    DEFINT A-Z
  594.    FInit 15, ErrCode
  595.    FOpen COMMAND$, "RT", 0, Handle, ErrCode
  596.    WHILE NOT FEOF(Handle)
  597.       PRINT FReadLn$(Handle)
  598.    WEND
  599.    FDone
  600.  
  601. In either case, we're accepting a command-line parameter which specifies the
  602. name of the file.  In the BASWIZ example, note the use of the FEOF% function,
  603. which tells whether we've gone past the end of the file.  This works like the
  604. EOF function in BASIC.
  605.  
  606. There are two ways of reading from binary files.  You can get the results as
  607. a string of a specified (maximum) length:
  608.  
  609.    St$ = FRead$(Handle, Bytes)
  610.  
  611. In plain BASIC, the same thing might be expressed this way:
  612.  
  613.    St$ = INPUT$(Bytes, FileNumber)
  614.  
  615. The other way of reading from a binary file has no equivalent in BASIC.  It
  616. allows you to read in up to 32K bytes at a time, directly into an array or
  617. TYPEd variable.  You can read the information into anything that doesn't
  618. contain normal strings (the fixed-length string type can be used, though):
  619.  
  620.    Segm = VARSEG(Array(0))
  621.    Offs = VARPTR(Array(0))
  622.    FBlockRead Handle, Segm, Offs, Bytes
  623.  
  624. That would read the specified number of bytes into Array(), starting at array
  625. element zero.  You can use any data type, whether single variable or array,
  626. as long as it is not a variable length string.  In other words, Vbl$ and
  627. Vbl$(0) would not work.  If you want to use a string with the block read, it
  628. must be a fixed-length string.  For example:
  629.  
  630.    DIM Vbl AS STRING * 1024
  631.    Segm = VARSEG(Vbl)
  632.    Offs = VARPTR(Vbl)
  633.    FBlockRead Handle, Segm, Offs, Bytes
  634.  
  635. It's a good idea to calculate the Segm and Offs values each time.  These tell
  636. FBlockRead where to store the information it reads.  QuickBASIC may move the
  637. variable around in memory, so VARSEG and VARPTR should be used just before
  638. FBlockRead, to insure that they return current and correct information.
  639.  
  640.                                 File Handling                          page 15
  641.  
  642.  
  643.  
  644. The file output commands are similar.  File output can only be done if there
  645. is no input buffer.  This means that you can't use file output if the file
  646. was opened in text mode, either, since text mode always requires an input
  647. buffer.  That's a limitation that will be removed in a future version of
  648. BASWIZ.  It is possible to do text output on a file that was opened in binary
  649. mode, however.  The limitation just means that you can't open a file for both
  650. reading and writing if you use a buffer (or text mode).
  651.  
  652. To output (write) a string to a file, use this:
  653.  
  654.    FWrite Handle, St$
  655.  
  656. This is like the plain BASIC statement:
  657.  
  658.    PRINT #FileNumber, St$;
  659.  
  660. If you would like the string to be terminated by a carriage return and
  661. linefeed, use this instead:
  662.  
  663.    FWriteLn Handle, St$
  664.  
  665. This is like the plain BASIC statement:
  666.  
  667.    PRINT #FileNumber, St$
  668.  
  669. In BASIC, the difference between the two writes is controlled by whether you
  670. put a semicolon at the end.  With BASWIZ, different routines are used
  671. instead.  FWrite is like PRINT with a semicolon and FWriteLn is like PRINT
  672. without a semicolon.
  673.  
  674. As well as simple string output, you can also output TYPEd variables and
  675. even entire arrays.  This type of output has no corresponding BASIC
  676. instruction, although it's somewhat similar to the file PUT statement.  Up to
  677. 32K can be output at a time:
  678.  
  679.    Segm = VARSEG(Array(0))
  680.    Offs = VARPTR(Array(0))
  681.    FBlockWrite Handle, Segm, Offs, Bytes
  682.  
  683. If you haven't already read the section on FBlockRead, go back a page and
  684. review it.  The same comments apply for FBlockRead: it can handle
  685. fixed-length strings but not old-style strings, and VARSEG/VARPTR should
  686. immediately preceed the block I/O, among other things.
  687.  
  688.                                 File Handling                          page 16
  689.  
  690.  
  691.  
  692. Normally, reads and writes take place sequentially.  If you want to move to a
  693. specific spot in the file, though, that's easy.  You can do it in text mode
  694. or binary mode, whether or not you have a buffer, giving you additional
  695. flexibility over the usual BASIC file handling.  Set the location for the
  696. next read or write like so:
  697.  
  698.    FLocate Handle, Position&
  699.  
  700. The Position& specified will be where the next read or write takes place.  It
  701. starts at one and (since it's specified as a LONG integer) can go up to
  702. however many bytes are in the file.  If you want a record position rather
  703. than a byte position, you can do that too.  Just convert the record number to
  704. a byte number, like so:
  705.  
  706.    Position& = (RecordNumber& - 1&) * RecordLength& + 1&
  707.  
  708. If you do not want to maintain RecordNumber and RecordLength as LONG
  709. integers, convert them to such by using the CLNG() function on them before
  710. doing the calculation.  Otherwise you may get an overflow error in the
  711. calculation, since QuickBASIC will assume that the result will be an integer.
  712.  
  713. You can get the current position of the file read/write pointer too:
  714.  
  715.    Position& = FGetLocate&(Handle)
  716.  
  717. Let's see... we've examined initialization and termination, opening and
  718. closing, reading and writing, and manipulating the file read/write pointer.
  719. What else could there be?  Well, how about checking the size of a file and
  720. getting or setting the file time and date?  Why, sure!  The "get" routines
  721. are pretty well self-explanatory:
  722.  
  723.    FileSize& = FGetSize&(Handle)
  724.    FileTime$ = FGetTime$(Handle)
  725.    FileDate$ = FGetDate$(Handle)
  726.  
  727. Setting the time and date is equally easy.  This should be done just before
  728. you close the file with FClose or FDone.  You may use any date and time
  729. delimiters you choose.  If a field is left blank, the appropriate value from
  730. the current time or date will be used.  Years may be specified in four-digit
  731. or two-digit format.  Two-digit years will be assumed to be in the 20th
  732. century ("90" == "1990").  Careful there!  Your program should allow
  733. four-digit dates to be used or disaster will strike when the year 2000
  734. rolls around.  The 21st century is closer than you think!
  735.  
  736.    FTime Handle, FileTime$
  737.    FDate Handle, FileDate$
  738.  
  739.                                 File Handling                          page 17
  740.  
  741.  
  742.  
  743. There's just one more file routine.  It allows you to "flush" a file to disk.
  744. This insures that the file has been properly updated to the current point, so
  745. nothing will be lost if there is a power outage or similar problem.  If you
  746. do not use the "flush" routine, data may be lost if the program terminates
  747. unexpectedly (without going through FClose or FDone).  Note that use of
  748. FFlush requires that a free file handle be available, under most DOS versions.
  749.  
  750.    FFlush Handle
  751.  
  752. That's it for the BASWIZ file handler.  As a quick review, let's run through
  753. the available routines, then try a couple of example programs.  Remember that
  754. the BASWIZ.REF file contains a brief reference for all of these routines too!
  755. You might also wish to examine the WDEMO.BAS program, which also makes use of
  756. the file routines.
  757.  
  758. FInit         initialize the file handler
  759. FDone         terminate the file handler and close any open files
  760.  
  761. FOpen         open a file for access (like OPEN)
  762. FClose        close a file (like CLOSE)
  763.  
  764. FRead$        read a string from a binary file (like INPUT$)
  765. FReadLn$      read a string from a text file (like LINE INPUT)
  766. FBlockRead    read an item (TYPE, STRING*##, or array) from a binary file
  767.  
  768. FWrite        write a string to a binary file
  769. FWriteLn      write a string with a <CR><LF> to a binary file
  770. FBlockWrite   write an item (TYPE, STRING*##, or array) to a binary file
  771.  
  772. FLocate       set the read/write pointer to a specified position
  773. FTime         set the time stamp
  774. FDate         set the date stamp
  775. FError        set the error code
  776.  
  777. FGetLocate&   get the read/write pointer
  778. FGetTime$     get the time stamp
  779. FGetDate$     get the date stamp
  780. FGetError     get the error code
  781.  
  782. FFlush        flush to disk (makes sure file is updated and current)
  783. FGetSize&     get size
  784. FEOF          determine whether the end of the file has been reached
  785.  
  786.                                 File Handling                          page 18
  787.  
  788.  
  789.  
  790. So much for theory.  Let's try something practical.  A common problem is
  791. copying one file to another.  We'll limit this to text files, so we can do it
  792. in both plain BASIC and with BASWIZ.  Although BASWIZ can handle any type of
  793. file readily, BASIC has problems in efficiently handling variable-length
  794. binary files.  So, we'll do this first in BASIC, then BASWIZ, for text files.
  795.  
  796. In BASIC, a text-file copying program might look like this:
  797.  
  798.    INPUT "File to copy"; FromFile$
  799.    INPUT "Copy file to"; ToFile$
  800.    OPEN FromFile$ FOR INPUT AS #1
  801.    OPEN ToFile$ FOR OUTPUT AS #2
  802.    WHILE NOT EOF(1)
  803.       LINE INPUT#1, St$
  804.       PRINT#2, St$
  805.    WEND
  806.    CLOSE
  807.  
  808. With BASWIZ, the same program would look more like this:
  809.  
  810.    REM $INCLUDE: 'BASWIZ.BI'
  811.    DEFINT A-Z
  812.    INPUT "File to copy"; FromFile$
  813.    INPUT "Copy file to"; ToFile$
  814.    FInit 15, ErrCode
  815.    FOpen FromFile$, "RT", 1024, FromHandle, ErrCode
  816.    FOpen ToFile$, "CW", 0, ToHandle, ErrCode
  817.    FileTime$ = FGetTime$(FromHandle)
  818.    FileDate$ = FGetDate$(FromHandle)
  819.    WHILE NOT FEOF(FromHandle)
  820.       WriteLn ToHandle, ReadLn$(FromHandle)
  821.    WEND
  822.    FTime ToHandle, FileTime$
  823.    FDate ToHandle, FileDate$
  824.    FDone
  825.  
  826. You might have noticed that the BASWIZ version of the program is a bit longer
  827. than the plain BASIC version.  It has a number of advantages, however.  It's
  828. faster, produces smaller code under ordinary circumstances, and preserves the
  829. date and time of the original file in the copied file.  Unlike BASIC, the
  830. BASWIZ routines do not automatically add a ^Z to the end of text files, so
  831. the BASWIZ example will not alter the original file.
  832.  
  833.                                   Fractions                            page 19
  834.  
  835.  
  836.  
  837. Using BCD allows you to represent numbers with excellent precision, but at a
  838. fairly large cost in speed.  Another way to represent numbers with good
  839. precision is to use fractions.  Fractions can represent numbers far more
  840. accurately than BCD, but can be handled much more quickly.  There are some
  841. limitations, of course, but by now you've guessed that's always true!
  842.  
  843. Each fraction is represented by BASWIZ as an 8-byte string.  The numerator
  844. (top part of the fraction) may be anywhere from -999,999,999 to 999,999,999.
  845. The denominator (the bottom part) may be from 0 to 999,999,999.  This allows
  846. handling a fairly wide range of numbers exactly.
  847.  
  848. Fractions can be converted to or from numeric text strings in any of three
  849. formats: real number (e.g., "1.5"), plain fraction (e.g., "3/2"), or whole
  850. number and fraction (e.g., "1 1/2").  Internally, the numbers are stored as a
  851. plain fraction, reduced to the smallest fraction possible which means the
  852. same thing (for instance, "5/10" will be reduced to "1/2").
  853.  
  854. To convert a numeric text string into a fraction, do this:
  855.  
  856.    Nr$ = FracSet$(NumSt$)
  857.  
  858. To convert a fraction into a numeric text string, try this:
  859.  
  860.    NumSt$ = FracFormat$(Nr$, HowToFormat%)
  861.  
  862. The formatting options are:
  863.  
  864.    0   convert to plain fraction
  865.    1   convert to whole number and fraction
  866.    2   convert to decimal number
  867.  
  868. Here is a list of the other functions available:
  869.  
  870.    Result$ = FracAbs$(Nr$)            ' take the absolute value of a fraction
  871.    Result$ = FracAdd$(Nr1$, Nr2$)     ' add two fractions
  872.    Result% = FracCompare%(Nr1$, Nr2$) ' compare two fractions
  873.    Result$ = FracDiv$(Nr1$, Nr2$)     ' divide the first fraction by the second
  874.    Result$ = FracMul$(Nr1$, Nr2$)     ' multiply two fractions
  875.    Result$ = FracNeg$(Nr$)            ' negate a fraction
  876.    Result% = FracSgn%(Nr$)            ' signum function for a fraction
  877.    Result$ = FracSub$(Nr1$, Nr2$)     ' subtract the 2nd fraction from the 1st
  878.  
  879. Fractions are automatically reduced to allow the greatest possible range.
  880. Note that little range-checking is done at this point, so you may wish to
  881. screen any input to keep it reasonable.
  882.  
  883.    Result     FracSgn      FracCompare
  884.      -1       negative #    1st < 2nd
  885.       0       # is zero     1st = 2nd
  886.       1       positive #    1st > 2nd
  887.  
  888.                       Graphics: Mode-Specific Routines                 page 20
  889.  
  890.  
  891.  
  892. These routines are designed to work with specific graphics modes, so your
  893. program will only include those routines which apply to the modes you use.
  894. The following modes are currently supported:
  895.  
  896.  SCREEN   Card     Graph. Res   Colors   Text Res.         Notes
  897.  ======   ====     ==========   ======   =============     =====
  898.     1      CGA     320 x 200       4     40 x 25
  899.     2      CGA     640 x 200       2     80 x 25
  900.     3      HGA     720 x 348       2     90 x 43             *1
  901.     7      EGA     320 x 200      16     40 x 25
  902.     8      EGA     640 x 200      16     80 x 25
  903.     9      EGA     640 x 350      16     80 x 25
  904.    10      EGA     640 x 350       4     80 x 25            mono
  905.    11      VGA     640 x 480       2     80 x 30
  906.    12      VGA     640 x 480      16     80 x 30
  907.    13      VGA     320 x 200     256     40 x 25
  908.  ----------------------------------------------------------------
  909.    N0      VGA     360 x 480     256     45 x 30             *2
  910.    N1      VGA     320 x 400     256     40 x 25             *2
  911.    N2    <Epson>   480 x 640       2     60 x 80/45/40       *3
  912.    N4      any      80 x  50       2     10 x 6              *4
  913.  
  914.  
  915. The number of rows of text available depends on the font: 8x8, 8x14, or 8x16.
  916.  
  917. *1  Note that the BASWIZ Hercules routines, unlike those provided with
  918.     QuickBASIC, do not require the QBHERC TSR to be loaded.  They are
  919.     entirely self-contained.  However, they may need to be compiled by BC
  920.     instead of QB, which may refuse to deal with the video mode change.
  921.  
  922. *2  This is a non-standard VGA mode.  It should work on many VGAs, however.
  923.  
  924. *3  This works with an Epson-compatible printer rather than the display.  The
  925.     results may be previewed on a VGA, however.  See also "Printer Routines".
  926.  
  927. *4  This actually provides graphics in text mode.  It will work on any
  928.     display adapter.  80x25 text remains available through PRINT.
  929.  
  930. See "Miscellaneous Notes" for additional remarks.
  931.  
  932. Compatibility notes:
  933.    An EGA can display CGA modes.
  934.    A VGA can display EGA and CGA modes.
  935.    An MCGA can display CGA modes and two VGA modes: SCREEN 11 and SCREEN 13.
  936.  
  937.                       Graphics: Mode-Specific Routines                 page 21
  938.  
  939.  
  940.  
  941. The routine for a specific mode is indicated by a prefix of "G", followed by
  942. the mode number, and then the routine name.  For example, if you wished to
  943. plot a point in SCREEN 2 mode, you would use:
  944.  
  945.    G2Plot X%, Y%
  946.  
  947. Many of these routines correspond with existing BASIC instructions.  However,
  948. they are smaller and usually faster by 22% - 64%.  See "Miscellaneous Notes"
  949. for notes on the differences between BASIC and the BASWIZ routines.
  950.  
  951. The smaller size may not be noticeable if you use the SCREEN statement, since
  952. that causes BASIC to link in some of its own graphics routines.  If you
  953. intend to use only BASWIZ routines for graphics, you can avoid that by using
  954. the G#Mode command instead of SCREEN:
  955.  
  956.    G#Mode Graphics%         ' use 0 for SCREEN 0, any other for SCREEN #
  957.  
  958. One difference between BASIC and BASWIZ is that, instead of each "draw"
  959. command requiring a color parameter as in BASIC, the BASWIZ library provides
  960. a separate color command:
  961.  
  962.    G#Color Foreground%, Background%
  963.  
  964. The "foreground" color is used by all graphics routines.  The background
  965. color is used by the G#Cls routine.  Both foreground and background colors
  966. are used in the G#Write and G#WriteLn routines.
  967.  
  968.                       Graphics: Mode-Specific Routines                 page 22
  969.  
  970.  
  971.  
  972. Here is a list of the corresponding routines, first BASIC, then BASWIZ
  973. (replace the "#" with the appropriate mode number):
  974.  
  975.    ' get the color of a specified point
  976.    colour% = POINT(x%, y%)
  977.    colour% = G#GetPel(x%, y%)
  978.  
  979.    ' set the color of a specified point
  980.    PSET (x%, y%), colour%
  981.    G#Color colour%, backgnd% : G#Plot x%, y%
  982.  
  983.    ' draw a line of a specified color
  984.    LINE (x1%, y1%) - (x2%, y2%), colour%
  985.    G#Color colour%, backgnd% : G#Line x1%, y1%, x2%, y2%
  986.  
  987.    ' draw a box frame of a specified color
  988.    LINE (x1%, y1%) - (x2%, y2%), colour%, B
  989.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 0
  990.  
  991.                       Graphics: Mode-Specific Routines                 page 23
  992.  
  993.  
  994.  
  995. Here are some more BASIC and BASWIZ routines:
  996.  
  997.    ' draw a box of a specified color and fill it in
  998.    LINE (x1%, y1%) - (x2%, y2%), colour%, BF
  999.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 1
  1000.  
  1001.    ' clear the screen and home the cursor
  1002.    CLS
  1003.    G#Cls
  1004.  
  1005.    ' get the current cursor position
  1006.    Row% = CSRLIN: Column% = POS(0)
  1007.    G#GetLocate Row%, Column%
  1008.  
  1009.    ' set the current cursor position
  1010.    LOCATE Row%, Column%
  1011.    G#Locate Row%, Column%
  1012.  
  1013.    ' display a string without a carriage return and linefeed
  1014.    PRINT St$;
  1015.    G#Write St$
  1016.  
  1017.    ' display a string with a carriage return and linefeed
  1018.    PRINT St$
  1019.    G#WriteLn St$
  1020.  
  1021. Note that BASWIZ, unlike BASIC, allows both foreground and background colors
  1022. for text in graphics mode.  It also displays text substantially faster than
  1023. BASIC.  See the "Miscellaneous Notes" section for information on other
  1024. differences in text printing.
  1025.  
  1026. If you need to print a number rather than a string, just use the BASIC
  1027. function STR$ to convert it.  If you don't want a leading space (assuming the
  1028. number is not negative), use this formula:
  1029.  
  1030.    St$ = MID$(STR$(Number), 2)
  1031.  
  1032. The BASWIZ library has other routines which have no BASIC equivalent.  One
  1033. allows you to get the current colors:
  1034.  
  1035.    G#GetColor Foreground%, Background%
  1036.  
  1037.                       Graphics: Mode-Specific Routines                 page 24
  1038.  
  1039.  
  1040.  
  1041. Sometimes the normal text services seem unduly limited.  Text is displayed
  1042. only at specific character positions, so it may not align properly with a
  1043. graph, for instance.  Text is also of only one specific size.  These are
  1044. limitations which make the normal text routines very fast, but for times when
  1045. you need something a little bit more fancy, try:
  1046.  
  1047.    G#Banner St$, X%, Y%, Xmul%, Ymul%
  1048.  
  1049. You may display the string starting at any graphics position.  The Xmul% and
  1050. Ymul% values are multipliers, specifying how many times larger than normal
  1051. each character should be.  Using Xmul% = 1 and Ymul% = 1 will give you
  1052. normal-sized characters.  What "normal" means depends on the font in use.
  1053.  
  1054. Since G#Banner "draws" the text onto the screen, it is a bit slower than the
  1055. normal text services.  It also uses only the foreground color, so the letters
  1056. go right on top of anything that was previously there.  Use G#Box to clear
  1057. the area beforehand if this is a problem for you.
  1058.  
  1059. The G#Banner routine supports several fonts.  The larger fonts provide a more
  1060. precise character set but leave you with less room on the screen.  You may
  1061. choose from these fonts:
  1062.  
  1063.    Font Number     Font Size (width x height)
  1064.         0            8 x 8    --- default
  1065.         1            8 x 14
  1066.         2            8 x 16
  1067.  
  1068. Select a font like so:
  1069.  
  1070.    BFont FontNr%
  1071.  
  1072. If you want to find out what the current font is, that's possible too:
  1073.  
  1074.    FontNr% = GetBFont
  1075.  
  1076. Besides looking more elegant, the larger fonts are easier to read.  They will
  1077. also suffer less from being increased in size, although some deterioration is
  1078. inevitable when magnifying these kinds of fonts.
  1079.  
  1080. The G#Banner routines accept CHR$(0) - CHR$(127).  No handling of control
  1081. codes is done.  All codes are displayed directly to the screen.
  1082.  
  1083.                       Graphics: Mode-Specific Routines                 page 25
  1084.  
  1085.  
  1086.  
  1087. Circles and ellipses can be drawn with the Ellipse routine.  This is similar
  1088. to the BASIC CIRCLE statement.  You specify the center of the ellipse (X,Y),
  1089. plus the X and Y radius values:
  1090.  
  1091.    G#Ellipse CenterX%, CenterY%, XRadius%, YRadius%
  1092.  
  1093. A circle is an ellipse with a constant radius.  So, to draw a circle, just
  1094. set both radius values to the single desired radius.
  1095.  
  1096. As well as the usual points, lines, and ellipses, BASWIZ also allows you to
  1097. draw polygons: triangles, squares, pentagons, hexagons, all the way up to
  1098. full circles!
  1099.  
  1100.    G#Polygon X%, Y%, Radius%, Vertices%, Angle!
  1101.  
  1102. The X% and Y% values represent the coordinates of the center of the polygon.
  1103. The Radius% is the radius of the polygon (as if you were fitting it into a
  1104. circle).  Vertices% is the number of angles (also the number of sides) for
  1105. the polygon to have.  Angle! specifies the rotation of the polygon, and is
  1106. specified in radians.  See "A Little Geometry" for more information.
  1107.  
  1108. Another routine is designed to manipulate a GET/PUT image.  Given an image in
  1109. array Original%() and a blank array of the same dimensions called Flipped%(),
  1110. this routine copies the original image to the new array as a mirror image
  1111. about the horizontal axis.  This is the same as the image you'd see if you
  1112. turned your monitor upside-down: the resulting image is upside-down and
  1113. backwards.
  1114.  
  1115.    G#MirrorH Original%(), Flipped%()
  1116.  
  1117. Don't forget to make the Flipped%() array the same DIM size as the original,
  1118. or the picture will overflow into main memory, probably causing disaster!
  1119.  
  1120. Note that G#MirrorH will only work properly on images with byte alignment.
  1121. This means that the width of the image must be evenly divisible by four if
  1122. SCREEN 1 is used, or evenly divisible by eight if SCREEN 2 is used.  EGA
  1123. modes are not yet supported for this routine.
  1124.  
  1125.                       Graphics: Mode-Specific Routines                 page 26
  1126.  
  1127.  
  1128.  
  1129. There are more routines that work only with SCREEN 2.  One allows you to load
  1130. a MacPaint-type image ("ReadMac" or .MAC files) into an array which can then
  1131. be PUT onto the screen:
  1132.  
  1133.    G2LoadMAC FileName$, Image%(), StartRow%
  1134.  
  1135. Note that a full .MAC picture is 576x720, which won't fit on the screen, so
  1136. the image will be truncated to 576x200.  You may specify a starting row
  1137. within the .MAC image, StartRow%, which may be 0-521, allowing the entire
  1138. picture to be loaded in several parts.
  1139.  
  1140. The Image%() must be dimensioned with 7202 elements:
  1141.  
  1142.    DIM Array(1 TO 7202) AS INTEGER
  1143.  
  1144. If you don't give an extension in the FileName$, an extension of ".MAC" will
  1145. be used.  There is no checking to see if the file actually exists, so you may
  1146. wish to do this beforehand.
  1147.  
  1148. There is no way of knowing whether a .MAC picture is supposed to be black on
  1149. white or white on black.  If the image doesn't look right when you PUT using
  1150. PSET, you can switch it around by using PUT with PRESET instead.
  1151.  
  1152. PC PaintBrush (.PCX) pictures can also be loaded.  These images can be of
  1153. various sizes, so you need to dimension a dynamic array for them:
  1154.  
  1155.    REM $DYNAMIC
  1156.    DIM Image(1 TO 2) AS INTEGER
  1157.  
  1158. The array will be set to the correct size by the loader.  It goes like this:
  1159.  
  1160.    G2LoadPCX FileName$, Image%(), ErrCode%
  1161.  
  1162. If you don't give an extension in the FileName$, an extension of ".PCX" will
  1163. be used.  You may wish to check to see if the file exists beforehand.
  1164. Possible errors are as follows:
  1165.  
  1166.    -1   File is not in PCX format
  1167.     1   Image is too large for desired screen mode
  1168.     2   Image won't work in desired screen mode (too many planes/colors)
  1169.  
  1170.                       Graphics: Mode-Specific Routines                 page 27
  1171.  
  1172.  
  1173.  
  1174. Two new routines are replacements for the GET and PUT image statements in
  1175. BASIC.  They are on the slow side, but if you don't intend to use them for
  1176. animation, they will serve to save some memory:
  1177.  
  1178.    REM $DYNAMIC
  1179.    DIM Image(1 TO 2) AS INTEGER
  1180.    G2Get X1%, Y1%, X2%, Y2%, Image()
  1181.  
  1182. Note the DIMensioning of a dynamic array.  The G2Get routine will set the
  1183. array to the appropriate size to hold the image.
  1184.  
  1185. The PUT replacement assumes that you intend to PSET the image.  It doesn't
  1186. allow for other display modes yet:
  1187.  
  1188.    G2Put X%, Y%, Image()
  1189.  
  1190. See "Miscellaneous Notes" for more information on using GET/PUT images and
  1191. the directions I'll be taking with them in the future.  Note that SCREEN 13
  1192. is also supported, via G13Get and G13Put.
  1193.  
  1194. The COLOR statement in SCREEN 1 is anomalous.  It doesn't really control
  1195. color at all, which is why QuickBASIC proper doesn't support colored text in
  1196. this (or any graphics) mode.  Instead, it is used for controlling the
  1197. background/border color and palette.  Since BASWIZ -does- support a true
  1198. G1COLOR routine, there are different routines which allow you to change the
  1199. palette and border colors. To change the background (and border) color, use:
  1200.  
  1201.    G1Border Colour%
  1202.  
  1203.                       Graphics: Mode-Specific Routines                 page 28
  1204.  
  1205.  
  1206.  
  1207. There are two palette routines.  Why two?  Well, QuickBASIC supports two CGA
  1208. palettes.  One of the routines works like QuickBASIC and can be used on any
  1209. CGA, EGA or VGA display (as long as it's in CGA mode).  The other routine
  1210. gives you a wider choice of palettes, but will only work on true CGAs (and
  1211. some EGA or VGA systems that have been "locked" into CGA mode).
  1212.  
  1213. Here's the QuickBASIC-style two-palette routine for any CGA/EGA/VGA:
  1214.  
  1215.    G1PaletteA PaletteNr%
  1216.  
  1217. The PaletteNr% may be as follows:
  1218.  
  1219.    0     (bright) Green, Red, Yellow
  1220.    1     Cyan, Violet, White
  1221.  
  1222.  
  1223. The more flexible six-palette routine (for CGA only) works like this:
  1224.  
  1225.    G1PaletteB PaletteNr%
  1226.  
  1227. Palettes are as follows:
  1228.  
  1229.    0     Green, Red, Brown            4     (bright) Green, Red, Yellow
  1230.    1     Cyan, Violet, White          5     (bright) Cyan, Violet, White
  1231.    2     Cyan, Red, White             6     (bright) Cyan, Red, White
  1232.  
  1233.                       Graphics: Mode-Specific Routines                 page 29
  1234.  
  1235.  
  1236.  
  1237. The EGA has a number of features which work in all its modes, so rather than
  1238. giving them screen mode prefixes, they are simply named with an "E".  These
  1239. routines allow you to get or set the palette, get or set the border color,
  1240. and determine whether the higher background colors should be displayed as
  1241. bright colors or as blinking.
  1242.  
  1243. To get a palette color value, use:
  1244.  
  1245.    Colour% = EGetPalette(ColorNumber%)
  1246.  
  1247. To set the color value, use:
  1248.  
  1249.    EPalette ColorNumber%, Colour%
  1250.  
  1251. To get the border color:
  1252.  
  1253.    Colour% = EGetBorder%
  1254.  
  1255. You can probably guess how to set the border color:
  1256.  
  1257.    EBorder Colour%
  1258.  
  1259. Finally, the blink vs. intensity.  Actually, this is designed for text mode;
  1260. I'm not sure whether it has any function in graphics modes.  The text-mode
  1261. default is for blinking to be turned on.  With BASIC, you add 16 to the
  1262. foreground color to make it blink.  That's a little weird, since the "blink"
  1263. attribute is actually a part of the background color, but that's how BASIC
  1264. views it.  You can tell the EGA to turn off blinking, in which case adding 16
  1265. to the foreground color makes the background color intense.  This doubles the
  1266. number of available background colors.
  1267.  
  1268.    EBlink Blink%
  1269.  
  1270. Use -1 for blinking (default), or 0 to turn off blinking.
  1271.  
  1272.                       Graphics: Mode-Specific Routines                 page 30
  1273.  
  1274.  
  1275.  
  1276. Like the EGA, the VGA has a number of features which work in all its modes.
  1277. Again, rather than giving them screen mode prefixes, we simply name them with
  1278. a "V".  The current routines allow you to get or set the palette colors.
  1279.  
  1280. To get a palette color value, use:
  1281.  
  1282.    VGetPalette(ColorNumber%, Red%, Green%, Blue%)
  1283.  
  1284. To set the color value, use:
  1285.  
  1286.    VPalette ColorNumber%, Red%, Green%, Blue%
  1287.  
  1288. As you've probably noticed, this doesn't work the same way as the QuickBASIC
  1289. PALETTE statement.  Rather than using a formula to calculate a single LONG
  1290. color value, like QuickBASIC, the BASWIZ library allows you to specify the
  1291. color in a more meaningful way.  The Red%, Green%, and Blue% parameters each
  1292. hold an intensity value (0-63).  By mixing these three, you can get an
  1293. immense variety of shades-- over 250,000 combinations in all.
  1294.  
  1295. If you need to keep track of the intensities in your program, I'd suggest the
  1296. following TYPE definition:
  1297.  
  1298.    TYPE VGAcolor
  1299.       Red AS INTEGER
  1300.       Green AS INTEGER
  1301.       Blue AS INTEGER
  1302.    END TYPE
  1303.  
  1304. If space is more important than speed, you can compress that to half the size
  1305. by using STRING * 1 instead of INTEGER.  In that case, you will need to use
  1306. the CHR$ and ASC functions to convert between string and integer values.
  1307.  
  1308.                          Graphics: Printer Routines                    page 31
  1309.  
  1310.  
  1311.  
  1312. The BASWIZ printer routines allow you to work with a printer using the same
  1313. convenient methods you'd use on a screen.  The image is created with the
  1314. usual G# routines (using mode N2), but the results are kept in a buffer in
  1315. memory (about 37K bytes) rather than being displayed directly.  The image can
  1316. be previewed on a VGA or printed out at your convenience, to any printer or
  1317. even a file.  The results will take up a single printer page, assuming the
  1318. usual 8.5" x 11" paper is used.
  1319.  
  1320. Printing a finished page works like this:
  1321.  
  1322.    GN2Print Device$
  1323.  
  1324. The Device$ variable should be set to the name of the device:
  1325.  
  1326.    LPT1    parallel printer on port 1
  1327.    LPT2    parallel printer on port 2
  1328.    LPT3    parallel printer on port 3
  1329.    COM1    serial printer on port 1
  1330.    COM2    serial printer on port 2
  1331.  
  1332. Instead of using a device name, you can also use a file name, to store the
  1333. results for later printing.  Output is done using BASIC file handling, so it
  1334. would be a good idea to provide an ON ERROR GOTO trap in case of problems.
  1335. The FREEFILE function is used, so you don't have to worry about conflicts
  1336. with any files in use by your program.
  1337.  
  1338. Getting a page layout just right can consume a lot of paper.  Fortunately,
  1339. there's a "preview" routine that allows you to display the results on a VGA.
  1340. The display will be sideways, allowing the whole page to be seen at once.
  1341. This will exactly match the printed output in N2 mode.  Here's how it works:
  1342.  
  1343.    G11Mode 1               ' set SCREEN 11 (VGA graphics mode, 640x480 x2)
  1344.    GN2Display              ' display the page
  1345.    DO                      ' wait for a key to be pressed
  1346.    LOOP UNTIL LEN(INKEY$)  '
  1347.    G11Mode 0               ' set SCREEN 0 (text mode)
  1348.  
  1349. The GN2Write and GN2WriteLn printer routines are unlike the display versions
  1350. of the same routines in that they don't scroll.  These routines only allow
  1351. you to design one page at a time.
  1352.  
  1353. Before using GN2Write or GN2WriteLn routines, you must choose a font with
  1354. GN2Font.  These are the same fonts as used in G#Banner:
  1355.  
  1356.     0     8 x 8        80 text rows
  1357.     1     8 x 14       45 text rows
  1358.     2     8 x 16       40 text rows
  1359.  
  1360. The current font can be retrieved with GN2GetFont%.  The result will be
  1361. meaningless if the font was never set with GN2Font.
  1362.  
  1363.                          Graphics: A Little Geometry                   page 32
  1364.  
  1365.  
  1366.  
  1367. The increasing capabilities of computer graphics systems has left many of us
  1368. in the dust.  It's great to be able to run dazzling applications or to doodle
  1369. with a "paint" program, but many of us find it difficult to design appealing
  1370. images of our own.  Becoming an artist is perhaps a bit more than most of us
  1371. are willing to take on!  It is important to remember, however, that computers
  1372. are wonderful number-crunchers.  With a little application of plane geometry,
  1373. you can have the computer take on much of the work for you-- and after all,
  1374. isn't that why we have computers in the first place?
  1375.  
  1376. A complete review of plane geometry is a bit beyond the scope of this text.
  1377. However, I'm going to run through some of the things I think you'll find most
  1378. useful.  I'd also like to suggest that you might dig out your old textbooks
  1379. or rummage through your local used book store.  It may have seemed like a dry
  1380. subject at the time, but when you can watch the results growing on your
  1381. computer screen, you will have a much better idea of how geometry can be
  1382. useful to you-- and it can be surprisingly fun, too!
  1383.  
  1384. In geometry talk, a "point" doesn't have any actual size.  In our case, we
  1385. want to apply geometry to physical reality, namely the computer screen.  As
  1386. far as we're concerned, a "point" will be an individual graphics dot, also
  1387. called a "pel" or "pixel" (for "picture element").  We can safely dispense
  1388. with such formalities for our applications, for the most part.
  1389.  
  1390. The most important thing about a point is that it has a location!  Ok, that
  1391. may not seem staggering, but it happens that there are a number of ways of
  1392. specifying that location.  The most common method is called the Cartesian
  1393. coordinate system.  It is based on a pair of numbers: X, which represents the
  1394. distance along a horizontal line, and Y, which represents the distance along
  1395. a vertical line.  Consider the CGA in SCREEN 2, for instance.  It has a
  1396. coordinate system where X can be 0 - 639 and Y can be 0 - 199.  The points
  1397. are mapped on kind of an invisible grid.
  1398.  
  1399. The Cartesian coordinate system makes it easy to visualize how a given point
  1400. relates to other points on the same plane (or screen).  It is particularly
  1401. useful for drawing lines.  Horizontal and vertical lines become a cinch: just
  1402. change the X value to draw horizontally, or the Y value to draw vertically.
  1403. Squares and rectangles (or boxes) can be formed by a combination of such
  1404. lines.  You can define an area of the screen in terms of an imaginary box
  1405. (as GET and PUT do) with nice, clean boundaries.  When we get to diagonal
  1406. lines, it's a bit more of a nuisance, but still easy enough with the proper
  1407. formula.  That means we can do triangles too.  Curves are worse... when it
  1408. comes to even a simple circle or ellipse, the calculations start to get on
  1409. the messy side.  For things like that, though, there is an alternative.
  1410.  
  1411. Another way of describing the location of a point is by Polar coordinates.
  1412. In Cartesian coordinates, the location is specified by its horizontal and
  1413. vertical distances from the "origin" or reference point, (0,0).  In Polar
  1414. coordinates, the location is specified by its distance and angle from the
  1415. origin.  Think of it as following a map: Cartesian coordinates tell you how
  1416. many blocks down and how many blocks over the point is, whereas Polar
  1417. coordinates tell you in which direction the point is and how far away it is
  1418. "as the crow flies".
  1419.  
  1420.                          Graphics: A Little Geometry                   page 33
  1421.  
  1422.  
  1423.  
  1424. The Polar coordinate system is great for describing many kinds of curves,
  1425. much better than Cartesian.  For example, a circle is defined as all of the
  1426. points at a given (fixed) distance from a center point.  Polar coordinates
  1427. include both a distance and an angle, and we've already got the distance, so
  1428. all we need to do is plot points at all of the angles on a circle.
  1429. Technically, there is an infinite number of angles, but since our points
  1430. don't follow the mathematical definition (they have a size), we don't have to
  1431. worry about that.
  1432.  
  1433. Let me digress for a moment to talk about angles.  In BASIC, angles are
  1434. specified in "radians".  People more often use "degrees".  Fortunately, it
  1435. isn't hard to convert from one to the other.  Both may be visualized on a
  1436. circle.  In radians, the sum of the angles in a circle is twice pi.  In
  1437. degrees, the sum of the angles is 360.  That's something like this:
  1438.  
  1439.  
  1440.                           90 deg, 1/2 * pi rad
  1441.                                 /---|---\
  1442.                                /    |    \
  1443.                               /     |     \
  1444.                 180 degrees   |___  .  ___|    0 deg, 0 rad; or...
  1445.                 pi radians    |           |  360 deg, 2 * pi rad
  1446.                               \     |     /
  1447.                                \    |    /
  1448.                                 \---|---/
  1449.                           270 deg, 3/2 * pi rad
  1450.  
  1451.  
  1452. Ok, so that's a grotesquely ugly circle!  Hopefully it shows the important
  1453. thing, though.  Angles start at zero on the extreme right and get larger as
  1454. they work around counter-clockwise.  The places marked on the "circle" are
  1455. places where lines drawn horizontally and vertically through the center
  1456. intersect the outside of the circle.  These serve as a useful reference
  1457. point, especially in that they help show how the angles can be construed from
  1458. a Cartesian viewpoint.
  1459.  
  1460. So much for angles.  I'll go into conversion formulae, the value of pi, and
  1461. other good junk a bit later on.  Right now, let's get back to our discussion
  1462. of Polar coordinates.
  1463.  
  1464. I've explained how the Polar system makes it easy to draw a circle.  Since
  1465. you can vary the range of angles, it's equally simple to draw an arc.  If you
  1466. wanted to make a pie chart, you might want to join the ends of the arcs to
  1467. the center of the circle, in which case you'd keep the angle constant (at the
  1468. ends of the arc) and plot by changing the distance from zero to the radius.
  1469. Circles are also handy for drawing equilateral polygons... you know, shapes
  1470. with sides of equal length: triangle, square, pentagon, hexagon, etc.  In
  1471. this case, the best features of the Cartesian and Polar systems can be joined
  1472. to accomplish something that would be difficult in either alone.
  1473.  
  1474.                          Graphics: A Little Geometry                   page 34
  1475.  
  1476.  
  1477.  
  1478. The starting point for these polygons is the circle.  Imagine that the
  1479. polygon is inside a circle, with the vertices (pointy ends, that is, wherever
  1480. the sides meet) touching the edge of the circle.  These are equilateral
  1481. polygons, so all of the sides and angles are the same size.  Each of the
  1482. vertices touches the circle, and each does it at exactly the same distance
  1483. from each other along the arc of the circle.  All of this detail isn't
  1484. precisely necessary, but I hope it makes the reasoning a bit more clear!
  1485.  
  1486. The circle can be considered as being divided by the polygon into a number of
  1487. arcs that corresponds to the number of vertices (and sides) the polygon has.
  1488. Think of a triangle inside a circle, with the tips all touching the circle.
  1489. If you ignore the area inside the triangle, you will see that the circle is
  1490. divided into three equal arcs.  The same property is true of any equilateral
  1491. polygon.  As a matter of fact, as the number of vertices goes up, the circle
  1492. is partitioned into more, but smaller, arcs... so that a polygon with a large
  1493. enough number of vertices is effectively a circle itself!
  1494.  
  1495. Anyway, the important thing is the equal partitioning.  We know how many
  1496. angles, be they degrees or radians, are in a circle.  To get the points of a
  1497. polygon, then... well, we already know the "distance" part, that's the same
  1498. as the radius.  The angles can be calculated by dividing the angles in the
  1499. whole circle by the number of vertices in the desired polygon.  Trying that
  1500. case with the triangle, assuming a radius of 20 (why not), and measuring in
  1501. degrees, that would give us the Polar points (20, 0), (20, 120), (20, 240).
  1502. To make this a triangle, we need to connect the points using lines, which is
  1503. easy in Cartesian coordinates.  Since the computer likes Cartesian anyway, we
  1504. just convert the Polar coordinates to Cartesian, draw the lines, and viola!
  1505.  
  1506. That's essentially the method used by the G#Polygon routines.  It's very
  1507. simple in practice, but I haven't seen it elsewhere... probably because
  1508. people forget about the Polar coordinate system, which is what makes it all
  1509. come together.  Polar coordinates also have simple equations for figures that
  1510. look like daisies, hearts, and other unusual things.  See "Equations, Etc"
  1511. and ROSES.BAS for more information.
  1512.  
  1513. On a side note, the Cartesian system isn't used by all computers, although
  1514. it's the most common.  Cartesian coordinates are the standard for what is
  1515. called "raster" displays.  The Polar coordinate system is used on "vector"
  1516. displays.  One example of a vector display that you may have seen is the old
  1517. Asteroids video arcade game.  They tend to be used for drawing monochrome
  1518. "framework" pictures where the image must be very sharp (unlike in raster
  1519. images, the diagonal lines aren't jagged, since there's no raster "grid").
  1520.  
  1521.                           Graphics: Equations, Etc                     page 35
  1522.  
  1523.  
  1524.  
  1525. In this section, I'm going to list a number of equations and so forth.  Some
  1526. of them will be useful to you in experimenting with Polar coordinates.  Some
  1527. of them provide formulae for things that are already in BASWIZ, but which you
  1528. might like to understand better.  Some of them are just for the heck of it...
  1529. note that not all of this information may be complete enough for you to just
  1530. use without understanding it.
  1531.  
  1532. One problem is... if you try to draw a circle, for instance, it will come out
  1533. looking squashed in most SCREEN modes.  Remember we said our points, unlike
  1534. mathematical points, have a size?  In most graphics modes, the points are
  1535. effectively wider than they are high, so a real circle looks like an ellipse.
  1536.  
  1537. Another problem is that these equations are based on an origin of (0,0) which
  1538. is assumed to be at the center of the plane.  In our case, (0,0) is at the
  1539. upper right edge, which also makes the Y axis (vertical values) effectively
  1540. upside-down.  This isn't necessarily a problem, but sometimes it is!  Adding
  1541. appropriate offsets to the plotted X and Y coordinates often fixes it.  In
  1542. the case of Y, you may need to subtract the value from the maximum Y value to
  1543. make it appear rightside-up.
  1544.  
  1545. The displayed form of these equations may contain "holes", usually again
  1546. because the points have a size, and/or since we try to use integer math to
  1547. speed things up.  If the screen had infinite resolution, this would not be a
  1548. problem... meanwhile (!), getting around such problems takes fiddlin'.
  1549.  
  1550. There are other problems, mostly due to forcing these simplified-universe
  1551. theoretical equations into practical use.  It's a lot easier to shoehorn in
  1552. these simple equations than to use more accurate mathematical descriptions,
  1553. though... a -lot- easier.  So a few minor quirks can be ignored!
  1554.  
  1555. With those disclaimers, here's the scoop on some handy equations.
  1556.  
  1557.    Polar coordinates may be expressed as (R, A), where R is radius or
  1558.    distance from the origin, and A is the angle.
  1559.  
  1560.    Cartesian coordinates may be expressed as (X, Y), where X is the distance
  1561.    along the horizontal axis and Y is the distance along the vertical axis.
  1562.  
  1563.    Polar coordinates can be converted to Cartesian coordinates like so:
  1564.       X = R * COS(A)
  1565.       Y = R * SIN(A)
  1566.  
  1567.    Angles may be expressed in radians or degrees.  BASIC prefers radians.
  1568.    Radians are based on PI, with 2 * PI radians in a circle.  There are 360
  1569.    degrees in a circle.  Angles increase counter-clockwise from a 3:00 clock
  1570.    position, which is the starting (zero) angle.  Angles can wrap around: 720
  1571.    degrees is the same as 360 degrees or 0 degrees, just as 3:00 am is at the
  1572.    same clock position as 3:00 pm.
  1573.  
  1574.    Angles may be converted between degrees and radians as follows:
  1575.       radians = degrees * PI / 180
  1576.       degrees = radians * 180 / PI
  1577.  
  1578.                           Graphics: Equations, Etc                     page 36
  1579.  
  1580.  
  1581.  
  1582.  
  1583.    The value PI is approximately 3.14159265358979.  For most graphics
  1584.    purposes, a simple 3.141593 should do quite nicely.  The true value of PI
  1585.    is an irrational number (the decimal part repeats forever, as near as
  1586.    anyone can tell).  It has been calculated out to millions of decimal
  1587.    points by people with a scientific bent (and/or nothing better to do)!
  1588.  
  1589. Line Drawing:
  1590.  
  1591.    One of the convenient ways of expressing the formula of a line (Cartesian
  1592.    coordinates) is:
  1593.       Y = M * X + B
  1594.  
  1595.    Given the starting and ending points for the line, M (the slope,
  1596.    essentially meaning the angle of the line) can be determined by:
  1597.       M = (Y2 - Y1) / (X2 - X1)
  1598.  
  1599.    The B value is called the Y-intercept, and indicates where the line
  1600.    intersects with the Y-axis.  Given the ingredients above, you can
  1601.    calculate that as:
  1602.       B = Y1 - M * X1
  1603.  
  1604.    With this much figured out, you can use the original formula to calculate
  1605.    the appropriate Y values, given a FOR X = X1 TO X2 sort of arrangement.
  1606.    If the slope is steep, however, this will result in holes in the line.  In
  1607.    that case, it will be smoother to recalculate the formula in terms of the
  1608.    X value and run along FOR Y = Y1 TO Y2... in that case, restate it as:
  1609.       X = (Y - B) / M
  1610.  
  1611.    Keep an eye on conditions where X1 = X2 or Y1 = Y2!  In those cases,
  1612.    you've got a vertical or horizontal line.  Implement those cases by simple
  1613.    loops to improve speed and to avoid dividing by zero.
  1614.  
  1615.  
  1616.  
  1617. Circle Drawing:
  1618.  
  1619.    The Cartesian formula gets messy, especially due to certain aspects of the
  1620.    display that are not accounted for (mainly that pixels, unlike theoretical
  1621.    points, have a size and shape which is usually rectangular).  The Polar
  1622.    formula is trivial, though.  The radius should be specified to the circle
  1623.    routine, along with the center point.  Do a FOR ANGLE! = 0 TO 2 * PI! STEP
  1624.    0.5, converting the resulting (Radius, Angle) coordinates to Cartesian,
  1625.    then adding the center (X,Y) as an offset to the result.  The appropriate
  1626.    STEP value for the loop may be determined by trial and error.  Smaller
  1627.    values make better circles but take more time.  Larger values may leave
  1628.    "holes" in the circle.
  1629.  
  1630.                           Graphics: Equations, Etc                     page 37
  1631.  
  1632.  
  1633.  
  1634. Polygon Drawing:
  1635.  
  1636.    I've already discussed that, so I'll leave it as an exercise... or of
  1637.    course you can examine my source code if you register BASWIZ!  The polygon
  1638.    routines are in BASIC, except for the line-drawing parts.
  1639.  
  1640.  
  1641.  
  1642. Flower Drawing:
  1643.  
  1644.    This sort of thing would be rather difficult to do using strictly
  1645.    Cartesian methods, but with Polar coordinates, no problem.  Here we
  1646.    calculate the radius based on the angle, using something like:
  1647.  
  1648.       FOR Angle! = 0 TO PI! * 2 STEP .01
  1649.  
  1650.    (a low STEP value is a good idea).  The radius is calculated like so:
  1651.  
  1652.       Radius! = TotalRadius! * COS(Petals! * Angle!)
  1653.  
  1654.    The Petals! value specifies how many petals the flower should have.  If it
  1655.    is odd, the exact number of petals will be generated; if even, twice that
  1656.    number will be generated.
  1657.  
  1658.    These figures are technically called "roses", although they more resemble
  1659.    daisies.  Try the ROSES.BAS program to see how they look.
  1660.  
  1661.  
  1662.  
  1663. Other Drawing:
  1664.  
  1665.    Experiment!  There are all sorts of interesting things you can do with the
  1666.    Polar coordinate system in particular.  Dig up those old Geometry texts or
  1667.    see if your Calculus books review it.  If you've kept well away from math,
  1668.    try your local library or used book store.
  1669.  
  1670.                         Memory Management and Pointers                 page 38
  1671.  
  1672.  
  1673.  
  1674. On the whole, BASIC is easily a match for any other language, as far as
  1675. general-purpose programming goes.  There is one major lack, however-- a set
  1676. of valuable features that is supported by most other languages, but was
  1677. inexplicably left out of BASIC.  Perhaps Microsoft felt it was too advanced
  1678. and dangerous for a so-called "beginner's" language.  In truth, using
  1679. pointers and memory management takes a little understanding of what you're
  1680. doing-- the compiler can't protect you from all of your mistakes.  However,
  1681. they can be extraordinarily useful for many things, so I have added these
  1682. capabilities to BASWIZ.
  1683.  
  1684. A "pointer" is essentially just the address of an item.  It is useful in two
  1685. respects: it allows you to pass just the pointer, rather than the whole item
  1686. (be it a TYPEd variable, normal variable, entire array, or whatever) to a
  1687. subprogram.  This is faster and more memory-efficient than the alternatives.
  1688. Secondly, a pointer combined with memory management allows you to allocate
  1689. and deallocate memory "on the fly", in just the amount you need.  You don't
  1690. have to worry about DIMensioning an array too large or too small, or even
  1691. with how large each element of the array should be, for example.  You can
  1692. determine that when your program -runs-, rather than at compile time, and set
  1693. up your data structures accordingly.  You can also create a large variety of
  1694. data structures, such as trees and linked lists, which would be difficult and
  1695. cumbersome to emulate using BASIC alone.
  1696.  
  1697. The BASWIZ memory/pointer routines allow you to allocate and deallocate
  1698. memory; fill, copy or move a block of memory; get or put a single character
  1699. according to a pointer; and convert back and forth between a segment/offset
  1700. address and a pointer.
  1701.  
  1702. Pointers are kept in LONG integers, using an absolute memory addressing
  1703. scheme.  This means that you can manipulate pointers just like any ordinary
  1704. LONG integer, e.g. to move to the next memory address, just add one.  Since
  1705. you can convert from a segment/offset address to a pointer and you can copy
  1706. information from one pointer to another, you can move information back and
  1707. forth between allocated memory and a TYPEd variable, numeric variable, or
  1708. array.  You can even do things like set a pointer to screen memory and
  1709. transfer the screen into a variable or vice versa!  Or implement your own
  1710. "far string" routines, heirarchical evaluations, or any number of other
  1711. things.  Pointers are incredibly powerful!
  1712.  
  1713. Note that there are different ways of representing the same segment/offset
  1714. address, but only one absolute pointer representation.  If you need to
  1715. compare two addresses, using pointers is terrific.  However, it's good to
  1716. keep in mind that an segment/offset address may -appear- to change if you
  1717. convert it to a pointer and then back to a segment/offset address.  When you
  1718. convert from a pointer to a segment/offset, the segment will be maximized and
  1719. the offset minimized.  So, for example, 0040:001C will turn into 0041:000C.
  1720.  
  1721. Although the byte count for these routines is handled through a LONG integer,
  1722. the routines handle a maximum of 65,520 bytes at a time.  In other words, a
  1723. pointer can only access a bit less than 64K at a time.  If I get enough
  1724. requests to extend this range, I will do so.  Meantime, that's the limit!
  1725.  
  1726.                         Memory Management and Pointers                 page 39
  1727.  
  1728.  
  1729.  
  1730. There are two routines which take care of memory management.  These allow you
  1731. to allocate or deallocate memory.  Note that if you allocate too much memory,
  1732. QuickBASIC won't have any memory to work with!  Use the BASIC function
  1733. "SETMEM" to see how much memory is available before going hog-wild.
  1734.  
  1735. You can allocate memory like so:
  1736.  
  1737.    MAllocate Bytes&, Ptr&, ErrCode%
  1738.  
  1739. If there isn't enough memory available, an error code will be returned.
  1740. Otherwise, Ptr& will point to the allocated memory.  Memory is allocated in
  1741. chunks of 16 bytes, so there may be some memory wasted if you choose a number
  1742. of bytes that isn't evenly divisible by 16.
  1743.  
  1744. When you are finished with that memory, you can free it up by deallocation:
  1745.  
  1746.    MDeallocate Ptr&, ErrCode%
  1747.  
  1748. An error code will be returned if Ptr& doesn't point to previously allocated
  1749. memory.
  1750.  
  1751. In the best of all possible worlds, there would be a third routine which
  1752. would allow you to reallocate or resize a block of memory.  However, due to
  1753. certain peculiarities of QuickBASIC, I was unable to implement that.  You can
  1754. simulate such a thing by allocating a new area of memory of the desired size,
  1755. moving an appropriate amount of information from the old block to the new,
  1756. and finally deallocating the old block.
  1757.  
  1758. Once you've allocated memory, you can move any sort of information in or out
  1759. of it except normal strings-- fixed-length strings, TYPEd values, arrays, or
  1760. numeric values.  To do that, you use BASIC's VARSEG and VARPTR functions on
  1761. the variable.  Convert the resulting segment/offset address to a pointer:
  1762.  
  1763.    TSeg% = VARSEG(Variable)
  1764.    TOfs% = VARPTR(Variable)
  1765.    VariablePtr& = MJoinPtr&(TSeg%, TOfs%)
  1766.  
  1767. Moving the information from one pointer to another works like so:
  1768.  
  1769.    MMove FromPtr&, ToPtr&, Bytes&
  1770.  
  1771. For STRING or TYPEd values, you can get the number of bytes via the LEN
  1772. function.  For numeric values, the following applies:
  1773.  
  1774.    Type       Bytes per value
  1775.    =======    ===============
  1776.    INTEGER           2
  1777.    LONG              4
  1778.    SINGLE            4
  1779.    DOUBLE            8
  1780.  
  1781.                         Memory Management and Pointers                 page 40
  1782.  
  1783.  
  1784.  
  1785. The "memory move" (MMove) routine is good for more than just transferring
  1786. information between a variable and allocated memory, of course.  Pointers can
  1787. refer to any part of memory.  For instance, CGA display memory starts at
  1788. segment &HB800, offset 0, and goes on for 4000 bytes in text mode.  That
  1789. gives a pointer of &HB8000.  You can transfer from the screen to a variable
  1790. or vice versa.  For that matter, you can scroll the screen up, down, left, or
  1791. right by using the appropriate pointers.  Add two to the pointer to move it
  1792. to the next character or 160 to move it to the next row.  As I said, pointers
  1793. have all kinds of applications!  You don't need to worry about overlapping
  1794. memory-- if the two pointers, combined with the bytes to move, overlap at
  1795. some point, why, the MMove routine takes care of that for you.  It avoids
  1796. pointer conflicts.  MMove is a very efficient memory copying routine.
  1797.  
  1798. Suppose you've got a pointer and would like to convert it back to the
  1799. segment/offset address that BASIC understands.  That's no problem:
  1800.  
  1801.    MSplitPtr Ptr&, TSeg%, TOfs%
  1802.  
  1803. You might also want to fill an area of memory with a specified byte value,
  1804. perhaps making freshly-allocated memory zeroes, for example:
  1805.  
  1806.    MFill Ptr&, Value%, Bytes&
  1807.  
  1808. Finally, there may be occasions when you might want to transfer a single
  1809. character.  Rather than going through putting the character into a STRING*1,
  1810. getting the VARSEG/VARPTR, and using MJoinPtr&, there is a simpler method:
  1811.  
  1812.    MPutChr Ptr&, Ch$
  1813.    Ch$ = MGetChr$(Ptr&)
  1814.  
  1815. Hopefully, this will give you some ideas to start with.  I'll expand on the
  1816. uses of pointers and give further examples in future versions of BASWIZ.
  1817. There are many, many possible uses for such capabilities.  Pointers and
  1818. memory management used to be the only real way in which BASIC could be
  1819. considered inferior to other popular languages-- that is no more!
  1820.  
  1821. NOTE:
  1822.    QuickBASIC may move its arrays around in memory!  Don't expect the address
  1823.    of an array to remain constant while your program is running.  Be sure to
  1824.    get the VARSEG/VARPTR for arrays any time you're not sure they're in the
  1825.    same location.  Among the things which can cause arrays to move are use of
  1826.    DIM, REDIM, or ERASE, and possibly calls to SUBs or FUNCTIONs.  I'm not
  1827.    sure if anything else may cause the arrays to move, so be cautious!
  1828.  
  1829.                               Telecommunications                       page 41
  1830.  
  1831.  
  1832.  
  1833. BASIC is unusual among languages in that it comes complete with built-in
  1834. telecommunications support.  Unfortunately, that support is somewhat crude.
  1835. Amongst other problems, it turns off the DTR when the program SHELLs or ends,
  1836. making it difficult to write doors for BBSes or good terminal programs.  It
  1837. also requires use of the /E switch for error trapping, since it generates
  1838. errors when line noise is encountered, and doesn't provide much control.  It
  1839. doesn't even support COM3 and COM4, which have been available for years.
  1840.  
  1841. BASWIZ rectifies these troubles.  It allows comprehensive control over
  1842. communications, includes COM3 and COM4, and doesn't require error trapping.
  1843. It won't fiddle with the DTR unless you tell it to do so.  The one limitation
  1844. is that you may use only a single comm port at a time.
  1845.  
  1846. Before you can use communications, you must initialize the communications
  1847. handler.  If you didn't have BASWIZ, you would probably use something like:
  1848.  
  1849.    OPEN "COM1:2400,N,8,1,RS,CS,DS" AS #1
  1850.  
  1851. With BASWIZ, you do not have to set the speed, parity, and so forth.
  1852. Communications will proceed with whatever the current settings are, unless
  1853. you choose to specify your own settings.  When you initialize the comm
  1854. handler, you specify only the port number (1-4) and the size of the input and
  1855. output buffers (1-32,767 bytes):
  1856.  
  1857.    TCInit Port, InSize, OutSize, ErrCode
  1858.  
  1859. The size you choose for the buffers should be guided by how your program will
  1860. use communications.  Generally, a small output buffer of 128 bytes will be
  1861. quite adequate.  You may wish to expand it up to 1,500 bytes or so if you
  1862. expect to write file transfer protocols.  For the input buffer, you will want
  1863. perhaps 512 bytes for normal use.  For file transfer protocols, perhaps 1,500
  1864. bytes would be better.  If a high baud rate is used, or for some other reason
  1865. you might not be emptying the buffer frequently, you may wish to expand the
  1866. input buffer size to 4,000 bytes or more.
  1867.  
  1868. When you are done with the telecomm routines, you must terminate them.  In
  1869. BASIC, this would be done with something like:
  1870.  
  1871.    CLOSE #1
  1872.  
  1873. With the BASWIZ routines, though, you would use this instead:
  1874.  
  1875.    TCDone
  1876.  
  1877. The BASWIZ "TCDone" does not drop the DTR, unlike BASIC's "CLOSE".  This
  1878. means that the modem will not automatically be told to hang up.  With BASWIZ,
  1879. you have complete control over the DTR with the TCDTR routine.  Use a value
  1880. of zero to drop the DTR or nonzero to raise the DTR:
  1881.  
  1882.    TCDTR DTRstate
  1883.  
  1884.                               Telecommunications                       page 42
  1885.  
  1886.  
  1887.  
  1888. You may set the speed of the comm port to any baud rate from 1-65,535.  If
  1889. you will be dealing with comm programs that were not written using BASWIZ,
  1890. you may wish to restrict that to the more common rates: 300, 1200, 2400,
  1891. 4800, 9600, 19200, 38400, and 57600.
  1892.  
  1893.    TCSpeed Baud&
  1894.  
  1895. The parity, word length, and stop bits can also be specified.  You may use
  1896. 1-2 stop bits, 6-8 bit words, and parity settings of None, Even, Odd, Mark,
  1897. or Space.  Nearly all BBSes use settings of None, 8 bit words, and 1 stop
  1898. bit, although you will sometimes see Even, 7 bit words, and 1 stop bit.  The
  1899. other capabilities are provided for dealing with mainframes and other systems
  1900. which may require unusual communications parameters.
  1901.  
  1902. When specifying parity, only the first character in the string is used, and
  1903. uppercase/lowercase distinctions are ignored.  Thus, using either "none" or
  1904. "N" would specify that no parity is to be used.
  1905.  
  1906.    TCParms Parity$, WordLength, StopBits
  1907.  
  1908. If your program needs to be aware of when a carrier is present, it can check
  1909. the carrier detect signal from the modem with the TCCarrier function.  This
  1910. function returns zero if no carrier is present:
  1911.  
  1912.    IF TCCarrier THEN
  1913.       PRINT "Carrier detected"
  1914.    ELSE
  1915.       PRINT "No carrier"
  1916.    END IF
  1917.  
  1918. Suppose, though, that you need to know immediately when someone has dropped
  1919. the carrier?  It wouldn't be too convenient to have to spot TCCarrier
  1920. functions all over your program!  In that case, try the "ON TIMER" facility
  1921. provided by BASIC for keeping an eye on things.  It will enable you to check
  1922. the carrier at specified intervals and act accordingly.  Here's a brief
  1923. framework for writing such code:
  1924.  
  1925.    ON TIMER(30) GOSUB CarrierCheck
  1926.    TIMER ON
  1927.    ' ...your program goes here...
  1928. CarrierCheck:
  1929.    IF TCCarrier THEN              ' if the carrier is present...
  1930.       RETURN                      ' ...simply resume where we left off
  1931.    ELSE                           ' otherwise...
  1932.       RETURN Restart              ' ...return to the "Restart" label
  1933.    END IF
  1934.  
  1935.                               Telecommunications                       page 43
  1936.  
  1937.  
  1938.  
  1939. To get a character from the comm port, use the TCInkey$ function:
  1940.  
  1941.    ch$ = TCInkey$
  1942.  
  1943. To send a string to the comm port, use TCWrite:
  1944.  
  1945.    TCWrite St$
  1946.  
  1947. If you are dealing strictly with text, you may want to have a carriage return
  1948. and a linefeed added to the end of the string.  No problem:
  1949.  
  1950.    TCWriteLn St$
  1951.  
  1952. Note that the length of the output buffer affects how the TCWrite and
  1953. TCWriteLn routines work.  They don't actually send string directly to the
  1954. comm port.  Instead, they put the string into the output buffer, and it gets
  1955. sent to the comm port whenever the comm port is ready.  If there is not
  1956. enough room in the output buffer for the whole string, the TCWrite/TCWriteLn
  1957. routines are forced to wait until enough space has been cleared for the
  1958. string.  This can delay your program.  You can often avoid this delay simply
  1959. by making the output buffer larger.
  1960.  
  1961. If you'd like to know how many bytes are waiting in the input buffer or
  1962. output buffer, there are functions which will tell you:
  1963.  
  1964.    PRINT "Bytes in input buffer:"; TCInStat
  1965.    PRINT "Bytes in output buffer:"; TCOutStat
  1966.  
  1967. Finally, if you would like to clear the buffers for some reason, you can do
  1968. that too.  The following routines clear the buffers, discarding anything
  1969. which was waiting in them:
  1970.  
  1971.    TCFlushIn
  1972.    TCFlushOut
  1973.  
  1974. Don't forget to use TCDone to terminate the comm handler before ending your
  1975. program!  If you do, the computer will lock up.  Worse, it may not lock up
  1976. immediately, so forgetting TCDone can be very unpleasant.
  1977.  
  1978.                               Telecommunications                       page 44
  1979.  
  1980.  
  1981.  
  1982. Finally, there is a routine which allows you to handle ANSI codes in a
  1983. window.  Besides the IBM semi-ANSI display code subset, mock-ANSI music is
  1984. allowed.  This routine is designed as a subroutine that you can access via
  1985. GOSUB, since there are a number of variables that the routine needs to
  1986. maintain that would be a nuisance to pass as parameters, and QuickBASIC
  1987. unfortunately can't handle SUBs in $INCLUDE files (so SHARED won't work).
  1988. To use it, either include ANSI.BAS directly in your code, or use:
  1989.  
  1990.    REM $INCLUDE: 'ANSI.BAS'
  1991.  
  1992. Set St$ to the string to process, set Win% to the handle of the window to
  1993. which to display, and set Music% to zero if you don't want sounds or -1 if
  1994. you do want sounds.  Then:
  1995.  
  1996.    GOSUB ANSIprint
  1997.  
  1998. Note that the virtual screen tied to the window must be at least an 80 column
  1999. by 25 row screen, since ANSI expects that size.  You are also advised to have
  2000. an ON ERROR trap if you use ANSIprint with Music% = -1, just in case a "bad"
  2001. music sequence slips through and makes BASIC unhappy.  Check for ERR = 5
  2002. (Illegal Function Call).  I'll add a music handler later to avoid this.
  2003.  
  2004. To get some idea of how these routines all tie together in practice, see the
  2005. TERM.BAS example program.  It provides a simple "dumb terminal" program to
  2006. demonstrate the BASWIZ comm handler.  Various command-line switches are
  2007. allowed:
  2008.  
  2009.    /43     use 43-line mode (EGA and VGA only)
  2010.    /COM2   use COM2
  2011.    /COM3   use COM3
  2012.    /COM4   use COM4
  2013.    /300    use 300 baud
  2014.    /1200   use 1200 baud
  2015.    /QUIET  ignore "ANSI" music
  2016.  
  2017. By default, the TERM.BAS program will use COM1 at 2400 baud with no parity, 8
  2018. bit words and 1 stop bit.  You can exit the program by pressing Alt-X.
  2019.  
  2020.                               Telecommunications                       page 45
  2021.  
  2022.  
  2023.  
  2024. The Xmodem file transfer protocol is currently supported for sending files
  2025. only.  It automatically handles any of the usual variants on the Xmodem
  2026. protocol: 128-byte or 1024-byte blocks, plus checksum or CRC error detection.
  2027. In other words, it is compatible with Xmodem (checksum), Xmodem CRC, and
  2028. Xmodem-1K (single-file Ymodem-like variant).
  2029.  
  2030. There are only two routines which must be used to transfer a file.  The first
  2031. is called once to initialize the transfer.  The second is called repeatedly
  2032. until the transfer is finished or aborted.  Complete status information is
  2033. returned by both routines.  You can ignore most of this information or
  2034. display it any way you please.
  2035.  
  2036. The initialization routine looks like this:
  2037.  
  2038.    StartXmodemSend Handle, Protocol$, Baud$, MaxRec, Record, EstTime$, ErrCode
  2039.  
  2040. Only the first three parameters are passed to the routine.  These are the
  2041. Handle of the file that you wish to send (use FOpen to get the handle) and
  2042. the Protocol$ that you wish to use ("Xmodem" or "Xmodem-1K"), and the current
  2043. Baud$.  On return, you will get an ErrCode if the other computer did not
  2044. respond, or MaxRec (the number of blocks to be sent), Record (the current
  2045. block number), and EstTime$ (an estimate of the time required to complete the
  2046. transfer.  The Protocol$ will have "CHK" or "CRC" added to it to indicate
  2047. whether checksum or CRC error detection is being used, depending on which the
  2048. receiver requested.
  2049.  
  2050. The secondary routine looks like this:
  2051.  
  2052.    XmodemSend Handle, Protocol$, MaxRec, Record, ErrCount, ErrCode
  2053.  
  2054. The ErrCode may be zero (no error), greater than zero (error reading file),
  2055. or less than zero (file transfer error, completion or abort).  See the
  2056. appendix on Error Codes for specific details.  The TERM.BAS example program
  2057. shows how these routines work together in practice.
  2058.  
  2059. The file accessed by the Xmodem routine will remain open.  Remember to close
  2060. it when the transfer is done (for whatever reason), using the FClose routine.
  2061.  
  2062.                               Telecommunications                       page 46
  2063.  
  2064.  
  2065.  
  2066. A few notes on the ins and outs of telecommunications...
  2067.  
  2068. The DTR signal is frequently used to control the modem.  When the DTR is
  2069. "raised" or "high", the modem knows that we're ready to do something.  When
  2070. the DTR is "dropped" or "low", the modem knows that we're not going to do
  2071. anything.  In most cases, this tells it to hang up or disconnect the phone
  2072. line.  Some modems may be set to ignore the DTR, in which case it will not
  2073. disconnect when the DTR is dropped.  Usually this can be fixed by changing a
  2074. switch on the modem.  On some modems, a short software command may suffice.
  2075.  
  2076. The DTR is generally the best way to disconnect.  The Hayes "ATH" command is
  2077. supposed to hang up, but it doesn't work very well.
  2078.  
  2079. The BASWIZ comm handler makes sure the DTR is raised when TCInit is used.  It
  2080. does not automatically drop the DTR when TCDone is used, so you can keep the
  2081. line connected in case another program wants to use it.  If this is not
  2082. suitable, just use TCDTR to drop the DTR.  Your program must always use
  2083. TCDone before it exits, but it need only drop the DTR if you want it that
  2084. way.
  2085.  
  2086. If you want to execute another program via SHELL, it is ok to leave
  2087. communications running as long as control will return to your program when
  2088. the SHELLed program is done.  In that case, the input buffer will continue to
  2089. receive characters from the comm port unless the SHELLed program provides
  2090. its own comm support.  The output buffer will likewise continue to transmit
  2091. characters unless overruled.
  2092.  
  2093. An assortment of file transfer protocols will be provided in future versions
  2094. of BASWIZ.  Among the ones supported will be Xmodem, Xmodem-1K, Ymodem
  2095. (batch), and Modem7 (batch).  I do not expect to support Kermit or Zmodem,
  2096. since they are unduly complicated.  You can handle any file transfer protocol
  2097. you like by SHELLing to an external protocol program, or of course you can
  2098. write your own support code.
  2099.  
  2100.                          The Virtual Windowing System                  page 47
  2101.  
  2102.  
  2103.  
  2104. The virtual windowing system offers pop-up and collapsing windows, yes... but
  2105. that is just a small fraction of what it provides.  When you create a window,
  2106. the part that you see on the screen may be only a view port on a much larger
  2107. window, called a virtual screen.  You can make virtual screens of up to 255
  2108. rows long or 255 columns wide.  The only limitation is that any single
  2109. virtual screen must take up less than 65,520 bytes.  Each virtual screen is
  2110. treated much like the normal screen display, with simple replacements for the
  2111. standard PRINT, LOCATE, and COLOR commands.  Many other commands are provided
  2112. for additional flexibility.  The window on the virtual screen may be moved,
  2113. resized, or requested to display a different portion of the virtual screen.
  2114. If you like, you may choose to display a frame and/or title around a window.
  2115. When you open a new window, any windows under it are still there and can
  2116. still be updated-- nothing is ever destroyed unless you want it that way!
  2117. With the virtual windowing system, you get a tremendous amount of control for
  2118. a very little bit of work.
  2119.  
  2120. The current version of the virtual windowing system only allows text mode
  2121. screens to be used.  All standard text modes are supported, however.  This
  2122. includes 25x40 CGA screens, the standard 25x80 screen, and longer screens
  2123. such as the 43x80 EGA screen.  The virtual windowing system is designed for
  2124. computers that offer hardware-level compatibility with the IBM PC, which
  2125. includes almost all MS-DOS/PC-DOS computers in use today.
  2126.  
  2127.  
  2128.  
  2129. Terminology:
  2130. -----------
  2131.  
  2132. DISPLAY
  2133.    The actual screen.
  2134.  
  2135. SHADOW SCREEN
  2136.    This is a screen kept in memory which reflects any changes you make to
  2137.    windows.  Rather than making changes directly on the actual screen, the
  2138.    virtual windowing system works with a "shadow screen" for increased speed
  2139.    and flexibility.  You specify when to update the display from the shadow
  2140.    screen.  This makes any changes appear very smoothly.
  2141.  
  2142. VIRTUAL SCREEN
  2143.    This is a screen kept in memory which can be treated much like the actual
  2144.    screen.  You may choose to make a virtual screen any reasonable size.
  2145.    Every virtual screen will have a corresponding window.
  2146.  
  2147. WINDOW
  2148.    This is the part of a virtual screen which is actually displayed.  You
  2149.    might think of a window as a "view port" on a virtual screen.  A window
  2150.    may be smaller than its virtual screen or the same size.  It may have a
  2151.    frame or a title and can be moved or resized.
  2152.  
  2153.                          The Virtual Windowing System                  page 48
  2154.  
  2155.  
  2156.  
  2157. Frankly, the virtual windowing system is one of those things that's more
  2158. difficult to explain than to use.  It's very easy to use, as a matter of
  2159. fact, but the basic concepts will need a little explanation.  Rather than
  2160. launching into a tedious and long-winded description of the system, I'm
  2161. going to take a more tutorial approach, giving examples and explaining as I
  2162. go along.  Take a look at the WDEMO.BAS program for additional insights.
  2163.  
  2164. Let's begin with the simplest possible scenario, where only a background
  2165. window is created.  This looks just like a normal screen.
  2166.  
  2167.    REM $INCLUDE: 'BASWIZ.BI'
  2168.    DEFINT A-Z
  2169.    Rows = 25: Columns = 80                         ' define display size
  2170.    WInit Rows, Columns, ErrCode                    ' initialize window system
  2171.    IF ErrCode THEN                                 ' stop if we couldn't...
  2172.       PRINT "Insufficient memory"
  2173.       END
  2174.    END IF
  2175.    Handle = 0                                      ' use background handle
  2176.    WWriteLn Handle, "This is going to be displayed on the background window."
  2177.    WWriteLn Handle, "Right now, that's the full screen."
  2178.    WUpdate                                         ' update the display
  2179.    WDone                                           ' terminate window system
  2180.  
  2181. What we just did was to display two lines on the screen-- nothing at all
  2182. fancy, but it gives you the general idea of how things work.  Let's take a
  2183. closer look at what the program does:
  2184.  
  2185.   - We INCLUDE the BASWIZ.BI definition file to let QuickBASIC know that
  2186.     we'll be using the BASWIZ routines.
  2187.  
  2188.   - We define the size of the display using the integer variables Rows and
  2189.     Columns (you can use any variable names you want).  If you have an EGA
  2190.     display and had previously used WIDTH ,43 to go into 43x80 mode, you'd
  2191.     use "Rows = 43" here, for example.
  2192.  
  2193.   - We initialize the windowing system with WInit, telling it how large the
  2194.     display is.  It returns an error code if it is unable to initialize.
  2195.  
  2196.   - We define the Handle of the window that we want to use.  The "background
  2197.     window" is always available as handle zero, so we choose "Handle = 0".
  2198.  
  2199.   - We print two strings to the background window with WWriteLn, which is
  2200.     like a PRINT without a semicolon on the end (it moves to the next line).
  2201.  
  2202.   - At this point, only the shadow screen has been updated.  We're ready to
  2203.     display the information, so we use WUpdate to update the actual screen.
  2204.  
  2205.   - We're all done with the program, so we finish up with WDone.
  2206.  
  2207.                          The Virtual Windowing System                  page 49
  2208.  
  2209.  
  2210.  
  2211. See, there's nothing to it!  We initialize the screen, print to it or
  2212. whatever else we need to do, tell the windowing system to update the display,
  2213. and when the program is done, we close up shop.
  2214.  
  2215. The background screen is always available.  It might help to think of it as a
  2216. virtual screen that's the size of the display.  The window on this virtual
  2217. screen is exactly the same size, so the entire virtual screen is displayed.
  2218. As with other virtual screens, you can print to it without disturbing
  2219. anything else.  That means you can treat the background screen the same way
  2220. regardless of whether it has other windows on top of it-- the other windows
  2221. just "cover" the background information, which will still be there.
  2222.  
  2223. This leads us to the topic of creating windows.  Both a virtual screen and a
  2224. window are created simultaneously-- remember, a window is just a view port on
  2225. a virtual screen.  The window can be the same size as the virtual screen, in
  2226. which case the entire virtual screen is visible (as with the background
  2227. window) or it can be smaller than the virtual screen, in which case just a
  2228. portion of the virtual screen will be visible at any one time.
  2229.  
  2230. A window is created like so:
  2231.  
  2232.    ' This is a partial program and can be inserted in the original example
  2233.    ' after the second WWriteLn statement...
  2234.    VRows = 43: VColumns = 80                       ' define virtual screen size
  2235.    WOpen VRows, VColumns, 1, 1, Rows, Columns, Handle, ErrCode ' create window
  2236.    IF ErrCode THEN                                 ' error if we couldn't...
  2237.       PRINT "Insufficient memory available"
  2238.       WDone                                        ' (or use an error handler)
  2239.       END
  2240.    END IF
  2241.  
  2242. What we have done here is to create a virtual screen of 43 rows by 80
  2243. columns.  The window will be the size of the display, so if you are in the
  2244. normal 25x80 mode, only the first 25 rows of the virtual screen will be
  2245. visible.  If you have an EGA or VGA in 43x80 mode, though, the entire virtual
  2246. screen will be visible!  So, this window lets you treat a screen the same way
  2247. regardless of the display size.
  2248.  
  2249. The Handle returned is used any time you want to print to this new window or
  2250. otherwise deal with it.  If you are using many windows, you might want to
  2251. keep an array of handles, to make it easier to keep track of which is which.
  2252.  
  2253. By default, a virtual screen is created with the following attributes:
  2254.  
  2255.   - The cursor is at (1,1), the upper left corner of the virtual screen.
  2256.   - The cursor size is 0 (invisible).
  2257.   - The text color is 7,0 (white foreground on a black background).
  2258.   - There is no title or frame.
  2259.   - The window starts at (1,1) in the virtual screen, which displays the
  2260.     area starting at the upper left corner of the virtual screen.
  2261.  
  2262.                          The Virtual Windowing System                  page 50
  2263.  
  2264.  
  2265.  
  2266. When you create a new window, it becomes the "top" window, and will be
  2267. displayed on top of any other windows that are in the same part of the
  2268. screen.  Remember, you can print to a window or otherwise deal with it, even
  2269. if it's only partially visible or entirely covered by other windows.
  2270.  
  2271. Don't forget WUpdate!  None of your changes are actually displayed until
  2272. WUpdate is used.  You can make as many changes as you like before calling
  2273. WUpdate, which will display the results smoothly and at lightning speed.
  2274.  
  2275. We've created a window which is exactly the size of the display, but which
  2276. might well be smaller than its virtual screen.  Let's assume that the normal
  2277. 25x80 display is being used, in which case our virtual screen (43x80) is
  2278. larger than the window.  We can still print to the virtual screen normally,
  2279. but if we print below line 25, the results won't be displayed.  What a
  2280. predicament!  How do we fix this?
  2281.  
  2282. The window is allowed to start at any given location in the virtual screen,
  2283. so if we want to see a different portion of the virtual screen, all we have
  2284. to do is tell the window to start somewhere else.  When the window is
  2285. created, it starts at the beginning of the virtual screen, coordinate (1,1).
  2286. The WView routine allows us to change this.
  2287.  
  2288. In our example, we're displaying a 43x80 virtual screen in a 25x80 window.
  2289. To begin with, then, rows 1-25 of the virtual screen are visible.  To make
  2290. rows 2-26 of the virtual screen visible, we simply do this:
  2291.  
  2292.    WView Handle, 2, 1
  2293.  
  2294. That tells the window to start at row 2, column 1 in the virtual screen.
  2295. Sounds easy enough, doesn't it?  Well, if not, don't despair.  Play with it
  2296. in the QuickBASIC environment a little until you get the hang of it.
  2297.  
  2298. You've noticed that the window doesn't need to be the same size as the
  2299. virtual screen.  Suppose we don't want it the same size as the display,
  2300. either... suppose we want it in a nice box, sitting out of the way in a
  2301. corner of the display?  Well, we could have created it that way to begin with
  2302. when we used WOpen.  Since we've already created it, though, let's take a
  2303. look at the routines to change the size of a window and to move it elsewhere.
  2304. The window can be made as small as 1x1 or as large as its virtual screen, and
  2305. it can be moved anywhere on the display you want it.
  2306.  
  2307. Let's make the window a convenient 10 rows by 20 columns:
  2308.  
  2309.    WSize Handle, 10, 20
  2310.  
  2311. And move it into the lower right corner of the display:
  2312.  
  2313.    WPlace Handle, 12, 55
  2314.  
  2315.                          The Virtual Windowing System                  page 51
  2316.  
  2317.  
  2318.  
  2319. Don't forget to call WUpdate or the changes won't be visible!  Note also that
  2320. we didn't really lose any text.  The virtual screen, which holds all the
  2321. text, is still there.  We've just changed the size and position of the
  2322. window, which is the part of the virtual screen that we see, so less of the
  2323. text (if there is any!) is visible.  If we made the window larger again, the
  2324. text in the window would expand accordingly.
  2325.  
  2326. If you were paying close attention, you noticed that we didn't place the
  2327. resized window flush against the corner of the display.  We left a little bit
  2328. of room so we can add a frame and a title.  Let's proceed to do just that.
  2329.  
  2330. Window frames are displayed around the outside of a window and will not be
  2331. displayed unless there is room to do so.  We have four different types of
  2332. standard frames available:
  2333.  
  2334.    0   (no frame)
  2335.    1   single lines
  2336.    2   double lines
  2337.    3   single horizontal lines, double vertical lines
  2338.    4   single vertical lines, double horizontal lines
  2339.  
  2340. We must also choose the colors for the frame.  It usually looks best if the
  2341. background color is the same background color as used by the virtual screen.
  2342. Let's go ahead and create a double-line frame in bright white on black:
  2343.  
  2344.    FType = 2: Fore = 15: Back = 0
  2345.    WFrame Handle, FType, Fore, Back
  2346.  
  2347. If you'd rather not use the default frame types, there's ample room to get
  2348. creative!  Frames 5-9 can be defined any way you please.  They are null by
  2349. default.  To create a new frame type, you must specify the eight characters
  2350. needed to make the frame: upper left corner, upper middle columns, upper
  2351. right corner, left middle rows, right middle rows, lower left corner, lower
  2352. middle columns, and lower right corner.
  2353.  
  2354.    +----------------------------------------+
  2355.    |  Want a plain text frame like this?    |
  2356.    |  Use the definition string "+-+||+-+"  |
  2357.    +----------------------------------------+
  2358.  
  2359. The above window frame would be defined something like this:
  2360.  
  2361.    Frame = 5
  2362.    FrameInfo$ = "+-+||+-+"
  2363.    WUserFrame Frame, FrameInfo$
  2364.  
  2365. Of course, you can choose any values you like.  As always, the names of the
  2366. variables can be anything, as long as you name them consistently within your
  2367. program.  You can even use constants if you prefer:
  2368.  
  2369.    WUserFrame 5, "+-+||+-+"
  2370.  
  2371.                          The Virtual Windowing System                  page 52
  2372.  
  2373.  
  2374.  
  2375. If you use a frame, you can also have a "shadow", which provides a sort of
  2376. 3-D effect.  The shadow can be made up of any character you choose, or it can
  2377. be entirely transparent, in which case anything under the shadow will change
  2378. to the shadow colors.  This latter effect can be quite nice.  I've found that
  2379. it works best for me when I use a dim foreground color with a black
  2380. background-- a foreground color of 8 produces wonderful effects on machines
  2381. that support it (it's "bright black", or dark gray; some displays will show
  2382. it as entirely black, though, so it may not always work the way you want).
  2383. For a transparent shadow, select CHR$(255) as the shadow character.  You can
  2384. turn the shadow off with either a null string or CHR$(0).
  2385.  
  2386.    Shadow$ = CHR$(255)                     ' transparent shadow
  2387.    Fore = 8: Back = 0                      ' dark gray on black
  2388.    WShadow Handle, Shadow$, Fore, Back
  2389.  
  2390. A shadow will only appear if there is also a frame, and if there is enough
  2391. space for it on the screen.  Currently, there is only one type of shadow,
  2392. which appears on the right and bottom sides of the frame.  It effectively
  2393. makes the frame wider and longer by one character.
  2394.  
  2395. We can have a title regardless of whether a frame is present or not.  Like
  2396. the frame, the title is displayed only if there is enough room for it.  If
  2397. the window is too small to accommodate the full title, only the part of the
  2398. title that fits will be displayed.  The maximum length of a title is 70
  2399. characters.  Titles have their own colors.
  2400.  
  2401.    Title$ = "Wonderful Window!"
  2402.    Fore = 0: Back = 7
  2403.    WTitle Handle, Title$, Fore, Back
  2404.  
  2405. To get rid of a title, just use a null title string (Title$ = "").
  2406.  
  2407. It may be convenient to set up a window that isn't always visible-- say, for
  2408. a help window, perhaps.  The window could be set up in advance, then shown
  2409. whenever requested using just one statement:
  2410.  
  2411.    WHide Handle, Hide
  2412.  
  2413. You can make a window invisible by using any nonzero value for Hide, or make
  2414. it reappear by setting Hide to zero.  As always, the change will only take
  2415. effect after WUpdate is used.
  2416.  
  2417.                          The Virtual Windowing System                  page 53
  2418.  
  2419.  
  2420.  
  2421. When WWrite or WWriteLn gets to the end of a virtual screen, they normally
  2422. scroll the "screen" up to make room for more text.  This is usually what you
  2423. want, of course, but there are occasions when it can be a nuisance.  The
  2424. automatic scrolling can be turned off or restored like so:
  2425.  
  2426.    WScroll Handle, AutoScroll
  2427.  
  2428. There are only a few more ways of dealing with windows themselves.  After
  2429. that, I'll explain the different things you can do with text in windows and
  2430. how to get information about a specific window or virtual screen.
  2431.  
  2432. If you have a lot of windows, one window may be on top of another, obscuring
  2433. part or all of the window(s) below.  In order to make sure a window is
  2434. visible, all you need to do is to put it on top, right?  Hey, is this easy or
  2435. what?!
  2436.  
  2437.    WTop Handle
  2438.  
  2439. You may also need to "unhide" the window if you used WHide on it previously.
  2440.  
  2441. Note that the background window will always be the background window.  You
  2442. can't put handle zero, the background window, on top.  What?  You say you
  2443. need to do that?!  Well, that's one of the ways you can use the WCopy
  2444. routine.  WCopy copies one virtual screen to another one of the same size:
  2445.  
  2446.    WCopy FromHandle, ToHandle
  2447.  
  2448. You can copy the background window (or any other window) to another window.
  2449. The new window can be put on top, resized, moved, or otherwise spindled and
  2450. mutilated.  The WDEMO program uses this trick.
  2451.  
  2452. We've been through how to open windows, print to them, resize them and move
  2453. them around, among other things.  We've seen how to put a frame and a title
  2454. on a window and pop it onto the display.  If you're a fan of flashy displays,
  2455. though, you'd probably like to be able to make a window "explode" onto the
  2456. screen or "collapse" off.  It's the little details like that which make a
  2457. program visually exciting and professional-looking.  I wouldn't disappoint
  2458. you by leaving something fun like that out!
  2459.  
  2460. Since we're using a virtual windowing system rather than just a plain ol'
  2461. ordinary window handler, there's an extra benefit.  When a window explodes or
  2462. collapses, it does so complete with its title, frame, shadow, and even its
  2463. text.  This adds rather nicely to the effect.
  2464.  
  2465.                          The Virtual Windowing System                  page 54
  2466.  
  2467.  
  2468.  
  2469. To "explode" a window, we just set up all its parameters the way we normally
  2470. would-- open the window, add a title or frame if we like, print any text that
  2471. we want displayed, and set the screen position.  Then we use WExplode to zoom
  2472. the window from a tiny box up to its full size:
  2473.  
  2474.    WExplode Handle
  2475.  
  2476. The "collapse" routine works similarly.  It should be used only when you are
  2477. through with a window, because it closes the window when it's done.  The
  2478. window is collapsed from its full size down to a tiny box, then eliminated
  2479. entirely:
  2480.  
  2481.    WCollapse Handle
  2482.  
  2483. Note that WExplode and WCollapse automatically use WUpdate to update the
  2484. display.  You do not need to use WUpdate yourself and you should make sure
  2485. that the screen is the way you want it displayed before you call either
  2486. routine.
  2487.  
  2488. The WCollapse and WExplode routines were written in BASIC, so they'll be easy
  2489. to customize just the way you want them if you register BASWIZ and get the
  2490. source code.  They're not particularly difficult routines, however, so you
  2491. might want to design a set of your own similar routines just for the
  2492. exercise.  All it takes is moving and resizing the windows.
  2493.  
  2494. The great thing about being a programmer is that you can do it your way.
  2495. Hold the pickles, hold the lettuce!  Might be fun to add some sound effects
  2496. to those exploding windows, hmmm?  I'll do that in a later version, but don't
  2497. feel obliged to wait for me!
  2498.  
  2499. That's it for the windows.  We've been through all the "tricky stuff".  There
  2500. are a number of useful things you can do with a virtual screen, though,
  2501. besides printing to it with WWriteLn.  Let's take a look at what we can do.
  2502.  
  2503. WWriteLn is fine if you want to use a "PRINT St$" sort of operation.  Suppose
  2504. you don't want to move to a new line afterward, though?  In BASIC, you'd use
  2505. something like "PRINT St$;" (with a semicolon).  With the virtual windowing
  2506. system, you use WWrite, which is called just like WWriteLn:
  2507.  
  2508.    WWrite Handle, St$
  2509.  
  2510. There are also routines that work like CLS, COLOR and LOCATE:
  2511.  
  2512.    WClear Handle
  2513.    WColor Handle, Fore, Back
  2514.    WLocate Handle, Row, Column
  2515.  
  2516. The WClear routine is not quite like CLS in that it does not affect the
  2517. cursor position.  If you want the cursor "homed", use WLocate.
  2518.  
  2519.                          The Virtual Windowing System                  page 55
  2520.  
  2521.  
  2522.  
  2523. Note that the coordinates for WLocate are based on the virtual screen, not
  2524. the window.  If you move the cursor to a location outside the view port
  2525. provided by the window, it will disappear.  Speaking of disappearing cursors,
  2526. you might have noticed that our WLocate doesn't mimic LOCATE exactly: it
  2527. doesn't provide for controlling the cursor size.  Don't panic!  There's
  2528. another routine available for that:
  2529.  
  2530.    WCursor Handle, CSize
  2531.  
  2532. The CSize value may range from zero (in which case the cursor will be
  2533. invisible) to the maximum size allowed by your display adapter.  This will
  2534. always be at least eight.
  2535.  
  2536. Now, since each virtual screen is treated much like the full display, you may
  2537. be wondering what happens if the cursor is "on" in more than one window.
  2538. Does that mean multiple cursors are displayed?  Well, no.  That would get a
  2539. little confusing!  Only the cursor for the top window is displayed.  If you
  2540. put a different window on top, the cursor for that window will be activated
  2541. and the cursor for the old top window will disappear.  The virtual windowing
  2542. system remembers the cursor information for each window, but it only actually
  2543. displays the cursor for the window that's on top.
  2544.  
  2545. In addition to the usual screen handling, the windowing system provides four
  2546. new capabilities which you may find very handy.  These are routines to insert
  2547. and delete both characters and rows.  This is done at the current cursor
  2548. position within a selected virtual screen:
  2549.  
  2550.    WDelChr Handle
  2551.    WDelLine Handle
  2552.    WInsChr Handle
  2553.    WInsLine Handle
  2554.  
  2555. These routines can also be used for scrolling.  Remember, the display isn't
  2556. updated until you use WUpdate, and then it's updated all at once.  You can
  2557. use any of the routines multiple times and the display will still be updated
  2558. perfectly smoothly-- all the real work goes on behind the scenes!
  2559.  
  2560. When you are done with a virtual screen and no longer need it, you can
  2561. dispose of it like so:
  2562.  
  2563.    WClose Handle
  2564.  
  2565. All of the information that can be "set" can also be retrieved.  That's
  2566. useful in general, of course, but it's also a great feature for writing
  2567. portable subprograms.  You can create subprograms that will work with any
  2568. virtual screen, since it can retrieve any information it needs to know about
  2569. the virtual screen or its window.  That's power!
  2570.  
  2571.                          The Virtual Windowing System                  page 56
  2572.  
  2573.  
  2574.  
  2575. Here is a list of the available window data retrieval routines:
  2576.  
  2577.    WGetColor Handle, Fore, Back
  2578.    ' gets the current foreground and background colors
  2579.  
  2580.    WGetCursor Handle, CSize
  2581.    ' gets the cursor size
  2582.  
  2583.    WGetFrame Handle, Frame, Fore, Back
  2584.    ' gets the frame type and frame colors
  2585.  
  2586.    WGetLocate Handle, Row, Column
  2587.    ' gets the cursor position
  2588.  
  2589.    WGetPlace Handle, Row, Column
  2590.    ' gets the starting position of a window on the display
  2591.  
  2592.    WGetScroll Handle, AutoScroll
  2593.    ' gets the status of auto-scroll (scrolling at the end of a virtual screen)
  2594.  
  2595.    Shadow$ = SPACE$(1)
  2596.    WGetShadow Handle, Shadow$, Fore, Back
  2597.    ' gets the shadow character (CHR$(0) if there's no shadow) and colors
  2598.  
  2599.    WGetSize Handle, Rows, Columns
  2600.    ' gets the size of a window
  2601.  
  2602.    Title$ = SPACE$(70)
  2603.    WGetTitle Handle, Title$, TLen, Fore, Back
  2604.    Title$ = LEFT$(Title$, TLen)
  2605.    ' gets the title string (null if there's no title) and title colors
  2606.  
  2607.    WGetTop Handle
  2608.    ' gets the handle of the top window
  2609.  
  2610.    FrameInfo$ = SPACE$(8)
  2611.    WGetUFrame$ Frame, FrameInfo$
  2612.    ' gets the specification for a given user-defined frame type
  2613.  
  2614.    WGetView Handle, Row, Column
  2615.    ' gets the starting position of a window within a virtual screen
  2616.  
  2617.    WGetVSize Handle, Rows, Columns
  2618.    ' gets the size of a virtual screen
  2619.  
  2620.    WHidden Handle, Hidden
  2621.    ' tells you whether a window is visible
  2622.  
  2623.                          The Virtual Windowing System                  page 57
  2624.  
  2625.  
  2626.  
  2627. As well as displaying information in a window, you will frequently want to
  2628. allow for getting input from the user.  Of course, INKEY$ will still work
  2629. fine, but that's not an effective way of handling more than single
  2630. characters.  The virtual windowing system includes a flexible string input
  2631. routine which is a lot more powerful:
  2632.  
  2633.    WInput Handle, Valid$, ExitCode$, ExtExitCode$, MaxLength, St$, ExitKey$
  2634.  
  2635. The Valid$ variable allows you to specify a list of characters which may be
  2636. entered.  If you use a null string (""), any character will be accepted.
  2637.  
  2638. ExitCode$ specifies the normal keys that can be used to exit input.  You'll
  2639. probably want to use a carriage return, CHR$(13), for this most of the time.
  2640. You can also specify exit on extended key codes like arrow keys and function
  2641. keys via ExtExitCode$.
  2642.  
  2643. MaxLength is the maximum length of the string you want.  Use zero to get the
  2644. longest possible string.  The length may go up to the width of the virtual
  2645. screen, minus one character.  The window will be scrolled sideways as needed
  2646. to accommodate the full length of the string.
  2647.  
  2648. The St$ variable is used to return the entered string, but you can also use
  2649. it to pass a default string to the routine.
  2650.  
  2651. ExitKey$ returns the key that was used to exit input.
  2652.  
  2653. A fairly strong set of editing capabilities is available through WInput.
  2654. The editing keys can be overridden by ExitCode$ or ExtExitCode$, but by
  2655. default they include support for both the cursor keypad and WordStar:
  2656.  
  2657.    Control-S   LeftArrow    move left once
  2658.    Control-D   RightArrow   move right once
  2659.    Control-V   Ins          switch between insert and overstrike modes
  2660.    Control-G   Del          delete current character
  2661.    Control-H   Backspace    destructive backspace
  2662.                Home         move to the start of input
  2663.                End          move to the end of input
  2664.  
  2665.                          The Virtual Windowing System                  page 58
  2666.  
  2667.  
  2668.  
  2669. Pop-up menus have become very popular in recent years.  Fortunately, they are
  2670. a natural application for virtual windows!  BASWIZ provides a pop-up menuing
  2671. routine which allows you to have as many as 255 choices-- the window will be
  2672. scrolled automatically to accommodate your "pick list", with a highlight bar
  2673. indicating the current selection.
  2674.  
  2675. The pop-up menu routine uses a window which you've already set up, so you can
  2676. use any of the normal window options-- frames, titles, shadows, etc.  You
  2677. must provide a virtual screen large enough to hold your entire pick list; the
  2678. window itself can be any size at all.
  2679.  
  2680. The pick list is passed to WMenuPopUp through a string array.  You can
  2681. dimension this array in any range that suits you.  The returned selection
  2682. will be the relative position in the array (1 for the first item, etc); if
  2683. the menu was aborted, 0 will be returned instead.
  2684.  
  2685. The current window colors will be used for the "normal" colors.  You specify
  2686. the desired highlight colors when calling the pop-up menu routine.
  2687.  
  2688.    Result = WMenuPopUp(Handle, PickList$(), HiFore, HiBack)
  2689.  
  2690. The mouse is not supported, since BASWIZ does not yet have mouse routines.
  2691. However, scrolling can be accomplished with any of the more common methods:
  2692. up and down arrows, WordStar-type Control-E and Control-X, or Lotus-type tab
  2693. and backtab.  The ESCape key can be used to abort without choosing an option.
  2694.  
  2695. On exit, the menu window will remain in its final position, in case you wish
  2696. to pop up a related window next to it or something similar.  Since it's just
  2697. an ordinary window, you can use WClose or WCollapse if you prefer to get rid
  2698. of it.
  2699.  
  2700. The WMenuPopUp routine was written in BASIC, so you will find it easy to
  2701. modify to your tastes if you register BASWIZ.  It was written with extra
  2702. emphasis on comments and clarity, since I know many people will want to
  2703. customize this routine!
  2704.  
  2705.                          The Virtual Windowing System                  page 59
  2706.  
  2707.  
  2708.  
  2709. There are two more routines which allow the virtual windowing system to work
  2710. on a wide variety of displays: WFixColor and WSnow.
  2711.  
  2712. Chances are, as a software developer you have a color display.  However,
  2713. there are many people out there who have monochrome displays, whether due to
  2714. preference, a low budget, or use of notebook-style computers with mono LCD or
  2715. plasma screens.  WFixColor allows you to develop your programs in color while
  2716. still supporting monochrome systems.  It tells the VWS whether to keep the
  2717. colors as specified or to translate them to their monochrome equivalents:
  2718.  
  2719.    WFixColor Convert%
  2720.  
  2721. Set Convert% to zero if you want true color (default), or to any other value
  2722. if you want the colors to be translated to monochrome.  In the latter case,
  2723. the translation will be done based on the relative brightness of the
  2724. foreground and background colors.  The result is guaranteed to be readable on
  2725. a monochrome system if it's readable on a color system.  You should check the
  2726. results on your system to make sure that such things as highlight bars still
  2727. appear highlighted, however.
  2728.  
  2729. In the case of some of the older or less carefully designed CGA cards, the
  2730. high-speed displays of the virtual windowing system can cause the display to
  2731. flicker annoyingly.  You can get rid of the flicker at the expense of slowing
  2732. the display:
  2733.  
  2734.    WSnow Remove%
  2735.  
  2736. Set Remove% to zero if there is no problem with "snow" or flickering
  2737. (default), or to any other value if you need "snow removal".  Using snow
  2738. removal will slow down the display substantially, which may be a problem if
  2739. you update (WUpdate) it frequently.
  2740.  
  2741. Note that you can't detect either of these cases automatically with perfect
  2742. reliability.  Not all CGA cards have flicker problems.  Monochrome displays
  2743. may be attached to CGA cards and the computer won't know the difference.  A
  2744. VGA with a paper-white monitor may well think it has color, and will mostly
  2745. act like it, but some "color" combinations can be very difficult to read.
  2746. While you can self-configure the program to some extent using the GetDisplay
  2747. routine (see Other Routines), you should also provide command-line switches
  2748. so that the user can override your settings.  Microsoft generally uses "/B"
  2749. to denote a monochrome ("black and white") display, so you may want to follow
  2750. that as a standard.  I would suggest "/F" to turn on CGA flicker suppression.
  2751.  
  2752. And that, folks, is all there is to it.  See WDEMO.BAS and TERM.BAS for
  2753. working examples.  Also see "Telecommunications" for information about a
  2754. routine which handles ANSI display and music codes; it displays to the window
  2755. of your choice.
  2756.  
  2757.                                 Other Routines                         page 60
  2758.  
  2759.  
  2760.  
  2761. There are a number of routines for which I couldn't find a specific category.
  2762.  
  2763. To see how much expanded memory is available, use the GetEMS function.  It'll
  2764. return zero if there is no expanded memory installed:
  2765.  
  2766.    PRINT "Kbytes of expanded memory:"; GetEMS
  2767.  
  2768. The GetDisplay routine tells what kind of display adapter is active and
  2769. whether it's hooked up to a color monitor.  The only time it can't detect the
  2770. monitor type is on CGA setups (it assumes "color").  It's a good idea to
  2771. allow a "/B" switch for your program so the user can specify if a monochrome
  2772. monitor is attached to a CGA.
  2773.  
  2774.    GetDisplay Adapter, Mono
  2775.    IF Mono THEN
  2776.       PRINT "Monochrome monitor"
  2777.    ELSE
  2778.       PRINT "Color monitor"
  2779.    END IF
  2780.    SELECT CASE Adapter
  2781.       CASE 1: PRINT "MDA"
  2782.       CASE 2: PRINT "Hercules"
  2783.       CASE 3: PRINT "CGA"
  2784.       CASE 4: PRINT "EGA"
  2785.       CASE 5: PRINT "MCGA"
  2786.       CASE 6: PRINT "VGA"
  2787.    END SELECT
  2788.  
  2789. The ScreenSize routine returns the number of rows and columns on the display
  2790. (text modes only):
  2791.  
  2792.    ScreenSize Rows%, Columns%
  2793.  
  2794.                              Miscellaneous Notes                       page 61
  2795.  
  2796.  
  2797.  
  2798. The virtual windowing system allows up to 16 windows to be open at a time,
  2799. including the background window, which is opened automatically.  This is
  2800. subject to available memory, of course.
  2801.  
  2802. The far string handler allows up to 65,535 strings of up to 255 characters
  2803. each, subject to available memory.  When the handler needs additional memory
  2804. for string storage, it allocates more in blocks of 16 Kbytes.  If that much
  2805. memory is not available, an "out of memory" error will be generated (BASIC
  2806. error number 7).  You can check the size of the available memory pool using
  2807. the SETMEM function provided by QuickBASIC.
  2808.  
  2809. The communications handler only allows one comm port to be used at a time.
  2810. This will change in a future version of BASWIZ.
  2811.  
  2812. The file handler does not allow you to combine Write mode with Text mode or
  2813. input buffering.  This will change in a future version of BASWIZ.
  2814.  
  2815. A certain lack of speed is inherent in BCD math, especially if you require
  2816. high precision.  The division, root, and trig routines in particular are
  2817. quite slow.  I'll attempt to improve this in the future, but the routines are
  2818. already fairly well optimized, so don't expect miracles.  Precision costs!
  2819.  
  2820. The fraction routines are much faster, but they have a much smaller range.
  2821. I'll have to do some experimenting on that.  It may prove practical to use a
  2822. subset of the BCD routines to provide an extended range for fractions without
  2823. an unreasonable loss in speed.
  2824.  
  2825. All routines are designed to be as bomb-proof as possible.  If you pass an
  2826. invalid value to a routine which does not return an error code, it will
  2827. simply ignore the value.
  2828.  
  2829. It's always possible that a problem has escaped notice.  If you run into
  2830. something that you believe to be a bug or incompatibility, please tell me
  2831. about it, whether you've registered BASWIZ or not.
  2832.  
  2833. Do you like what you see?  Tell me what you like, what you don't like, and
  2834. what you'd be interested in seeing in future versions!  Chances are good that
  2835. I'll use your suggestions.  If you know of a good reference book or text
  2836. file, I'd like to hear about that too!  You can reach me through U.S. Mail or
  2837. through several of the international BASIC conferences on BBSes.
  2838.  
  2839.                              Miscellaneous Notes                       page 62
  2840.  
  2841.  
  2842.  
  2843. The EGA graphics routines are designed for use with EGAs having at least 256K
  2844. RAM on board.  They will not operate properly on old 64K EGA systems.
  2845.  
  2846. Image loading (.MAC and .PCX) is quite slow.  The bulk of the code is in
  2847. BASIC at this point, to make it easier for me to extend the routines to cover
  2848. other graphics modes.  They will be translated to assembly later.
  2849.  
  2850. The G#Write and G#WriteLn services support three different fonts: 8x8, 8x14,
  2851. and 8x16.  The default font is always 8x8, providing the highest possible
  2852. text density.  QuickBASIC, on the other hand, allows only one font with a
  2853. text density of as close to 80x25 as possible.
  2854.  
  2855. The G#Write and G#WriteLn services interpret ASCII control characters, i.e.
  2856. CHR$(0) - CHR$(31), according to the more standard handling used by DOS
  2857. rather than the esoteric interpretation offered by QuickBASIC.  This is not
  2858. exactly a limitation, but it could conceivably cause confusion if your
  2859. program happens to use these characters.  The ASCII interpretion works as
  2860. follows:
  2861.  
  2862.     Code       Meaning
  2863.     ====       =======
  2864.       7        Bell      (sound a beep through the speaker)
  2865.       8        Backspace (destructive: eliminates the previous character)
  2866.       9        Tab       (based on 8-character tab fields)
  2867.      10        LineFeed  (move down one line, keep current column)
  2868.      12        FormFeed  (clear the screen)
  2869.      13        Return    (move to the start of the current line)
  2870.  
  2871. G#MirrorH will only work properly on images with byte alignment!  This means
  2872. that the width of the image must be evenly divisible by four if SCREEN 1 is
  2873. used, or evenly divisible by eight if SCREEN 2 is used.
  2874.  
  2875. The graphics routines provide little error checking and will not do clipping
  2876. (which ignores points outside the range of the graphics mode). If you specify
  2877. coordinates which don't exist, the results will be unusual at best.  Try to
  2878. keep those values within the proper range!
  2879.  
  2880. A very few of the graphics routines are slower than their counterparts in
  2881. QuickBASIC.  These are mostly drawing diagonal lines and filling boxes.  I
  2882. hope to get these better optimized in a future release.  The GET/PUT image
  2883. replacements are quite slow, but that's strictly temporary!  I rushed 'em in
  2884. by special request from a registered BASWIZ owner.
  2885.  
  2886.                              Miscellaneous Notes                       page 63
  2887.  
  2888.  
  2889.  
  2890. If you use PRINT in conjunction with GN4Write or GN4WriteLn, be sure to save
  2891. the cursor position before the PRINT and restore it afterwards.  BASIC and
  2892. BASWIZ share the same cursor position, but each interprets it to mean
  2893. something different.
  2894.  
  2895. The GN0 (360x480x256) and GN1 (320x400x256) routines use nonstandard VGA
  2896. modes.  The GN1 routines should work on just about any VGA, however.  The GN0
  2897. routines will work on many VGAs, but are somewhat less likely to work than
  2898. the GN1 routines due to the techniques involved.
  2899.  
  2900. The GN0Write, GN0WriteLn, GN1Write and GN1WriteLn routines are somewhat slow
  2901. in general and quite slow when it comes to scrolling the screen. These
  2902. problems are related to peculiarities of these modes that I'm still grappling
  2903. with.  They will hopefully be improved in a future release.
  2904.  
  2905. The G1Border routine is normally used to select the background (and border)
  2906. color for SCREEN 1 mode.  It can also be used in SCREEN 2 mode, where it will
  2907. change the foreground color instead.  Note that this may produce peculiar
  2908. results if an EGA or VGA is used and it isn't locked into "CGA" mode, so be
  2909. careful if your program may run on systems with displays other than true CGAs.
  2910.  
  2911. GET/PUT images have a lot of possibilities that Microsoft has never touched
  2912. on.  I'll be exploring this extensively in future versions.  Among other
  2913. things, expect the ability to change the colors, rotate the image, and
  2914. translate the image from one graphics mode format to another.  Enlarging and
  2915. shrinking the image will also be a good bet.
  2916.  
  2917. Note that you can GET an image in SCREEN 1 and PUT it in SCREEN 2!  It'll be
  2918. shaded instead of in colors.  This is a side-effect of the CGA display format.
  2919.  
  2920. The first two elements of a GET/PUT array (assuming it's an integer array)
  2921. tells you the size of the image.  The first element is the width and the
  2922. second is the height, in pixels.  Actually, that's not quite true.  Divide
  2923. the first element by 2 for the width if the image is for SCREEN 1, or by 8 if
  2924. for SCREEN 13.
  2925.  
  2926.                                   Error Codes                           page 64
  2927.  
  2928.  
  2929.  
  2930. The expression evaluator returns the following error codes:
  2931.  
  2932.    0    No error, everything went fine
  2933.    2    A number was expected but not found
  2934.    4    Unbalanced parentheses
  2935.    8    The expression string had a length of zero
  2936.    9    The expression included an attempt to divide by zero
  2937.  
  2938.  
  2939.  
  2940. The far string handler does not return error codes.  If an invalid string
  2941. handle is specified for FSSet, it will be ignored; if for FSGet, a null
  2942. string will be returned.  If you run out of memory for far strings, an "out
  2943. of memory" error will be generated (BASIC error #7).  You can prevent this by
  2944. checking available memory beforehand with the SETMEM function provided by
  2945. QuickBASIC.  Far string space is allocated as needed in blocks of just over
  2946. 16 Kbytes, or 16,400 bytes to be exact.
  2947.  
  2948.  
  2949.  
  2950. The telecommunications handler returns the following error codes for TCInit:
  2951.  
  2952.    0    No error, everything A-Ok
  2953.    1    The comm handler is already installed (you tried to install it twice)
  2954.    2    Invalid comm port specified
  2955.    3    Not enough memory available for input and output buffers
  2956.  
  2957.  
  2958.  
  2959. The telecommunications handler returns these error codes for Xmodem Send:
  2960.  
  2961.  -13    FATAL   : Abort due to selection of an unsupported transfer protocol
  2962.  -12    FATAL   : Abort due to excessive errors
  2963.  -11    FATAL   : Abort (by keyboard <ESC> or receiver CANcel request)
  2964.   -5    WARNING : Checksum or CRC error
  2965.   -1    WARNING : Time-out error (the receiver didn't respond)
  2966.    0    DONE    : No error, transfer completed ok
  2967.   >0    ERROR   : Problem reading from the file (see file error codes)
  2968.  
  2969.                                  Error Codes                           page 65
  2970.  
  2971.  
  2972.  
  2973. The file services return the following error codes:
  2974. (The asterisk "*" is used to identify so-called "critical errors")
  2975.  
  2976.    0    No error
  2977.    1    Invalid function number (usually means "invalid parameter(s)")
  2978.    2    File not found
  2979.    3    Path not found
  2980.    4    Too many open files
  2981.    5    Access denied (probably "write to read-only file")
  2982.    6    Invalid file handle
  2983.    7    Memory control blocks destroyed
  2984.    8    Insufficient memory (usually RAM, sometimes disk)
  2985.    9    Incorrect memory pointer specified
  2986.   15    Invalid drive specified
  2987. * 19    Tried to write on a write-protected disk
  2988. * 21    Drive not ready
  2989. * 23    Disk data error
  2990. * 25    Disk seek error
  2991. * 26    Unknown media type
  2992. * 27    Sector not found
  2993. * 28    Printer out of paper
  2994. * 29    Write fault
  2995. * 30    Read fault
  2996. * 31    General failure
  2997. * 32    Sharing violation
  2998. * 33    Lock violation
  2999. * 34    Invalid disk change
  3000.   36    Sharing buffer overflow
  3001.  
  3002.  
  3003.  
  3004. A "critical error" is one that would normally give you the dreaded prompt:
  3005.  
  3006.    A>bort, R>etry, I>gnore, F>ail?
  3007.  
  3008. Such errors generally require some action on the part of the user.  For
  3009. instance, they may need to close a floppy drive door or replace the paper in
  3010. a printer.  If a critical error occurs on a hard drive, it may indicate a
  3011. problem in the drive hardware or software setup.  In that case, the problem
  3012. may possibly be cleared up by "CHKDSK /F", which should be executed directly
  3013. from the DOS command line (do not execute this by SHELL).
  3014.  
  3015.                                Troubleshooting                         page 66
  3016.  
  3017.  
  3018.  
  3019. Problem:
  3020.    QB says "subprogram not defined".
  3021.  
  3022. Solution:
  3023.    The definition file was not included.  Your program must contain the line
  3024.       REM $INCLUDE: 'BASWIZ.BI'
  3025.    before any executable code in your program.  You should also start
  3026.    QuickBASIC with
  3027.       QB /L BASWIZ
  3028.    so it knows to use the BASWIZ library.
  3029.  
  3030.  
  3031. Problem:
  3032.    LINK says "unresolved external reference".
  3033.  
  3034. Solution:
  3035.    Did you specify BASWIZ as the library when you used LINK?  You should!
  3036.    The BASWIZ.LIB file must be in the current directory or along a path
  3037.    specified by the LIB environment variable (like PATH, but for LIB files).
  3038.  
  3039.  
  3040. Problem:
  3041.    The virtual windowing system doesn't display anything.
  3042.  
  3043. Solution:
  3044.    Perhaps you left out the WUpdate routine?  If so, the shadow screen is not
  3045.    reflected to the actual screen and nothing will appear.  The screen also
  3046.    needs to be in text mode (either no SCREEN statement or SCREEN 0).
  3047.    Finally, only the default "page zero" is supported on color monitors.
  3048.  
  3049.  
  3050. Problem:
  3051.    The virtual windowing system causes the display to flicker on CGAs.
  3052.  
  3053. Solution:
  3054.    Use the WSnow routine to get rid of it.  This will, unfortunately, slow
  3055.    the display down severely.  You might want to upgrade your display card!
  3056.  
  3057.  
  3058. Problem:
  3059.    QuickBASIC doesn't get along with the Hercules display routines.
  3060.  
  3061. Solution:
  3062.    Are you using an adapter which includes Hercules mode along with EGA or
  3063.    VGA mode?  QuickBASIC doesn't like that, since it thinks you'll be using
  3064.    EGA or VGA mode.  Use the stand-alone compiler (BC.EXE) instead of the
  3065.    environment (QB.EXE) and you should be fine.  You might also consider
  3066.    getting a separate Herc adapter and monochrome monitor.  It's possible to
  3067.    combine a Hercules monochrome adapter with a CGA, EGA or VGA.
  3068.  
  3069.                                Troubleshooting                         page 67
  3070.  
  3071.  
  3072.  
  3073. Problem:
  3074.    QB says "out of memory" (or "range out of bounds" on a DIM or REDIM).
  3075.  
  3076. Solution:
  3077.    If you're using the memory management/pointer routines, you've probably
  3078.    allocated too much memory!  You need to leave some for QuickBASIC.  Use
  3079.    the SETMEM function provided by BASIC to determine how much memory is
  3080.    available before allocating memory.  The amount needed by QuickBASIC will
  3081.    depend on your program.  The primary memory-eaters are arrays and
  3082.    recursive subprograms or functions.
  3083.  
  3084.    Many of the BASWIZ routines need to allocate memory, including the virtual
  3085.    window manager, telecommunications handler, and memory management system.
  3086.    Besides checking with SETMEM to make sure there's memory to spare, don't
  3087.    forget to check the error codes returned by these routines to make sure
  3088.    they're working properly!
  3089.  
  3090.  
  3091. Problem:
  3092.    The cursor acts funny (appears when it shouldn't or vice versa).
  3093.  
  3094. Solution:
  3095.    Try locking your EGA or VGA into a specific video mode using the utility
  3096.    provided with your display adapter.  Cursor problems are usually related
  3097.    either to "auto mode detection" or older EGAs.
  3098.  
  3099.  
  3100. Problem:
  3101.    The BCD trig functions return weird results.
  3102.  
  3103. Solution:
  3104.    Make sure you've made room in your BCD size definition for some digits to
  3105.    the left of the decimal as well as to the right!  Calculations with large
  3106.    numbers are needed to return trig functions with high accuracy.
  3107.  
  3108.  
  3109. Problem:
  3110.    The G#MirrorH routine is -almost- working right, but the results are
  3111.    truncated or wrapped to one side.
  3112.  
  3113. Solution:
  3114.    Make your GET image a tad wider!  The number of pixels wide must be evenly
  3115.    divisible by four in SCREEN 1, or by eight in SCREEN 2.
  3116.  
  3117.                             History and Philosophy                     page 68
  3118.  
  3119.  
  3120.  
  3121. "History," you say.  "Philosophy.  What the heck does that have to do with a
  3122. BASIC library?  Yuck!  Go away and leave me alone!"
  3123.  
  3124. Ok.  This section is not strictly necessary for using BASWIZ.  If you're not
  3125. interested, you can certainly avoid reading this without ill effects.  "Suit
  3126. yourself," he said with a bow and a flourish.
  3127.  
  3128. Still here?  Thank you!  I'll try to keep it short.
  3129.  
  3130. Back in 'bout 1984 or so, I created ADVBAS, one of the very first assembly
  3131. language libraries for BASIC.  That was for IBM BASCOM 1.0, well before
  3132. QuickBASIC came out. I created the library for my own use and ended up making
  3133. a moderately successful shareware project out of it.
  3134.  
  3135. ADVBAS was designed in bits and pieces that came along whenever I felt like
  3136. adding to the library or needed a new capability.  The routines were designed
  3137. at a low level, with most of the actual work needed to accomplish anything
  3138. useful left to BASIC.  All this resulted in a decent amount of flexibility
  3139. but also a good deal of chaos as new routines provided capabilities that
  3140. overlapped with old routines.  Although I tried to keep the calling sequence
  3141. reasonably standardized, it didn't always work out that way.  Then too, the
  3142. library was designed well before the neat capabilities of QuickBASIC 4.0 came
  3143. into being and couldn't take good advantage of them.
  3144.  
  3145. Second came ProBas, a commercial version of ADVBAS.  ProBas was a vastly more
  3146. powerful superset of the ADVBAS library.  Unfortunately, it suffered from the
  3147. same flaws.  No old routines could be discarded or even modified if at all
  3148. possible, to provide compatibility from one version to the next.  The lack of
  3149. thought inherent in the original design caused a mad proliferation of
  3150. routines, many overlapping, most still low-level and hard to use.  At version
  3151. 4.0, there were nearly 600 different routines-- something for everyone, to be
  3152. sure, but tending towards complete pandemonium.
  3153.  
  3154. The BASWIZ project is a third-generation library.  It is designed to overcome
  3155. the liabilities I've encountered with ADVBAS and every other library I've
  3156. seen for BASIC.  Rather than being put together haphazardly, one routine at a
  3157. time, I have designed BASWIZ as a coordinated collection.  The virtual
  3158. windowing system is an excellent example of this.  Rather than having
  3159. separate print routines, window routines, screen saving routines, virtual
  3160. screen routines and all the rest, it is all combined into one single
  3161. package.  The routines are designed at a high level, providing a maximum of
  3162. functionality with a minimum of programming effort.  The gritty details are
  3163. kept hidden inside the library where you need never deal with them.  Consider
  3164. the apparent simplicity of the far string handler!  Many more capabilities
  3165. will be added in future versions, but... very carefully.
  3166.  
  3167.                             History and Philosophy                     page 69
  3168.  
  3169.  
  3170.  
  3171. This library represents the culmination of many years of experience in the
  3172. fields of BASIC and assembly language programming.  I have spared no effort.
  3173. It's the best I can offer and I hope you'll forgive me for taking some pride
  3174. in my work!  If you find this library powerful and easy to use, I'll count my
  3175. efforts a great success.
  3176.  
  3177. As you might have guessed, I'm not exactly in it "just for the money."
  3178. Nonetheless, money is always nice!  If you like BASWIZ, please do register.
  3179. That will enable me to upgrade my equipment and design more advanced BASWIZ
  3180. routines.  Currently I have a 386SX with a VGA display.  I would like to be
  3181. able to support Super VGA, 9600 bps modems, scanners, sound boards and other
  3182. hardware as well.
  3183.  
  3184. Current update: Hammerly Computer Services, which markets ProBas and related
  3185. products, owes me more than a year's worth of royalties, a computer system,
  3186. and sundry other items.  They refuse to pay and won't respond to the messages
  3187. I send via U.S. Mail or their BBS.  So, I'm releasing a shareware clone of
  3188. the ProBas library in an attempt to get at least some recompense for my
  3189. development efforts.  Look for the PBClone library (PBCLONxx.ZIP) on your
  3190. local BBSes.  PBCLON can be used in conjunction with BASWIZ for more power!
  3191.  
  3192.                             Using BASWIZ with PDQ                      page 70
  3193.  
  3194.  
  3195.  
  3196. Most of the BASWIZ routines will work with current versions of PDQ without
  3197. any modification.  The major exceptions are the expression evaluator, the BCD
  3198. and fraction math routines, and the polygon-generating graphics routines.
  3199.  
  3200. The .EXE files that come with the BASWIZ library are LINKed with PDQ, which
  3201. is why they're so small.
  3202.  
  3203. Older versions of Crescent Software's PDQ library do not support the SETMEM
  3204. function, which is required by many BASWIZ routines.  If your version of PDQ
  3205. is before v2.10, you must LINK in the SETMEM stub provided with BASWIZ:
  3206.  
  3207.    LINK program+PDQSTUB/NOD,,NUL,BASWIZ+PDQ;
  3208.  
  3209. If you use LINK differently, that's fine.  The only thing necessary is to
  3210. make sure "+PDQSTUB" is listed after the name of your program as the first
  3211. LINK argument.  Use of /EX and other LINK parameters is no problem.  Use of
  3212. other libraries, if any, is also supported.  For some reason, PDQ usually
  3213. wants to be the last library listed, by the way.
  3214.  
  3215. Crescent thoughtfully provided me with a free copy of PDQ in order that I
  3216. might resolve any incompatibilities between it and BASWIZ.  If you are not
  3217. familiar with PDQ, it is a replacement library for BASIC's own runtime
  3218. libraries.  While not providing every capability of plain QuickBASIC, it
  3219. allows you to create substantially smaller EXE files for those programs that
  3220. qualify.  Support is currently lacking for floating point (single/double
  3221. precision) numbers, music, and graphics, among other things.  I understand
  3222. that these features will be available in future revisions.  Communications
  3223. support is available as an add-on package.    PDQ also adds new capabilities
  3224. which are quite impressive, such as being able to write small TSRs in BASIC.
  3225. Check with Crescent Software for more recent details.
  3226.  
  3227.                                   Credits                              page 71
  3228.  
  3229.  
  3230.  
  3231. For some of the reference works I have used in writing BASWIZ, see the
  3232. BIBLIO.TXT file.
  3233.  
  3234. I am also indebted to the following people, among others:
  3235.  
  3236. Bill Cliver, president of F & I Controls, which markets software and hardware
  3237. solutions for every aspect of car dealerships.  He has provided me with the
  3238. VGA system which has allowed me to support VGA graphics modes in BASWIZ.
  3239.  
  3240. Mike Welch, co-sysop of The Shipyard BBS, the best BASIC support BBS that
  3241. I've ever encountered.  Among other fine deeds, he is responsible for the
  3242. S&B4EGA and VGABOX demonstration programs which accompany BASWIZ.
  3243.  
  3244. The inverse hyperbolic trig functions are based on a set of BASIC routines by
  3245. Kerry Mitchell.
  3246.  
  3247. The 360x480 256-color VGA mode was made possible by John Bridges' VGAKIT 3.4
  3248. library for C.  Two of the most vital low-level routines are based directly
  3249. on code from VGAKIT.  If you use C, check your local BBS for this library.
  3250.  
  3251.