home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / basic / baswiz18.zip / BASWIZ.DOC < prev    next >
Text File  |  1992-08-30  |  149KB  |  3,764 lines

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