home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-11-14 | 42.9 KB | 1,235 lines |
- The Pascal Wizard's Library
- =-------------------------=
- Version 1.3
-
- PasWiz Copyright (c) 1990-1992 Thomas G. Hanlin III
-
-
-
- This is PasWiz, a library of assorted routines for use with
- Turbo Pascal, Quick Pascal, and compatible compilers. Full
- Pascal source code is now included with the shareware version.
- Assembly language sources are provided to registered owners.
- The PasWiz collection is copyrighted, but may be distributed as
- long as the following conditions are met:
-
- All PasWiz files must be distributed together as a unit in
- unmodified form. No files may be left out or added.
-
- You use this library at your own risk. It has been tested by
- me on my own computer, but I will not assume any responsibility
- for any problems which PasWiz may cause you. If you do
- encounter a problem, please let me know about it, and I will do
- my best to verify and repair the error.
-
- It is expected that if you find PasWiz useful, you will
- register your copy. You may not use PasWiz routines in programs
- intended for sale unless you have registered. Registration
- entitles you to receive the latest version of PasWiz, complete
- with full source code. See the file ORDER.FRM for details.
-
- Warning: Use of the PasWiz library for more than 30 days
- without registering has been determined to cause cancer in
- people who eat cigarettes!
-
- So who's the Pascal Wizard? With PasWiz, you are! Read this
- tome well, for invoking these routines without proper
- preparation may bring unexpected results. Cape and hat
- (optional) not included.
-
- Table of Contents page 2
-
-
-
- Overview and Legal Info .................................... 1
-
- BCD Math ................................................... 3
-
- Equipment Info ............................................. 7
-
- Expression Evaluator ...................................... 10
-
- Extensions to Pascal's Math ............................... 11
-
- Keyboard Control .......................................... 13
-
- String Stuff .............................................. 17
-
- Music ..................................................... 21
-
- Mouse ..................................................... 22
-
- BCD Math page 3
-
- Unit: BCD
-
-
-
- Some of you may not have heard of BCD math, or at least not
- have more than a passing acquaintance with the subject. BCD
- (short for Binary-Coded Decimal) is a way of encoding numbers.
- It differs from the normal method of handling numbers in
- several respects. On the down side, BCD math is much slower
- than normal math and the numbers take up more memory. However,
- the benefits may far outweigh these disadvantages, depending on
- your application: BCD math is absolutely precise within your
- desired specifications, and you can make a BCD number as large
- as you need. If your applications don't require great range or
- precision out of numbers, normal Pascal math is probably the
- best choice. For scientific applications, accounting,
- engineering and other demanding tasks, though, BCD may be just
- the thing you need.
-
- The BCD math routines provided by PasWiz allow numbers of up to
- 255 digits long (the sign counts as a digit, but the decimal
- point doesn't). You may set the decimal point to any position
- you like, as long as there is at least one digit position to
- the left of the decimal.
-
- Since Pascal doesn't support BCD numbers directly, we store the
- BCD numbers in strings. The results are not in text format and
- won't mean much if displayed. A conversion routine allows you
- to change a BCD number to a text string in any of a variety of
- formats.
-
- Note that the BCD math handler doesn't yet track
- overflow/underflow error conditions. If you anticipate that
- this may be a problem, it would be a good idea to screen your
- input or to make the BCD range large enough to avoid these
- errors.
-
- Let's start off by considering the BCD range. This is kept in
- two integer variables, LDigits and RDigits, which can be
- accessed by your program. These variables specify the maximum
- number of digits to the left and to the right of the decimal
- point. There must be at least one digit on the left, and the
- total number of digits must be less than 255. The BCD strings
- will have a length that's one larger than the total number of
- digits, to account for the sign of the number. The decimal
- point is implicit and doesn't take up any extra space.
-
- It is assumed that you will only use one size of BCD number in
- your program-- there are no provisions for handling
- mixed-length BCD numbers. Of course, you could manage that
- yourself with a little extra work, if it seems like a useful
- capability. If you don't change LDigits or RDigits, the
- default size of the BCD numbers will be 32 (20 to the left, 11
- to the right, 1 for the sign).
-
- BCD Math page 4
-
- Unit: BCD
-
-
-
- Before doing any BCD calculations, you must have some BCD
- numbers! The BCDSet routine takes a number in text string form
- and converts it to BCD:
-
- TextSt := '1234567890.50';
- Nr := BCDSet(TextSt);
- { FUNCTION BCDSet (TextSt: String): String; }
-
- If your numbers are stored as actual numbers, you can convert
- them to a text string with Pascal's Str procedure, then to BCD:
-
- Str(Number, TextSt);
- Nr := BCDSet(TextSt);
-
- BCD numbers can also be converted back to text strings, of
- course. You may specify how many digits to the right of the
- decimal to keep (the number will be truncated, not rounded).
- If the RightDigits value is positive, trailing zeros will be
- kept; if negative, trailing zeros will be removed. There are
- also various formatting options which may be used. Here's how
- it works:
-
- FUNCTION BCDFormat (Nr: String; HowToFormat,
- RightDigits: Integer): String;
-
- The HowToFormat value may be any combination of the following
- (just add the numbers of the desired formats together):
-
- 0 plain number
- 1 use commas to separate thousands, etc
- 2 start number with a dollar sign
- 4 put the sign on the right instead of the left side
- 8 use plus sign instead of space if nr is not negative
-
- The BCD math functions are pretty much self-explanatory, so
- I'll keep the descriptions brief. The single-parameter
- functions are listed on the next page.
-
- BCD Math page 5
-
- Unit: BCD
-
-
-
- { absolute value }
- FUNCTION BCDAbs (Nr: String): String;
-
- { cosine }
- FUNCTION BCDCos (Nr: String): String;
-
- { cotangent }
- FUNCTION BCDCot (Nr: String): String;
-
- { cosecant }
- FUNCTION BCDCsc (Nr: String): String;
-
- { convert degrees to radians }
- FUNCTION BCDDeg2Rad (Nr: String): String;
-
- { the constant "e" }
- FUNCTION BCDe: String;
-
- { factorial }
- FUNCTION BCDFact (Nr: Integer): String;
-
- { fractional part of number }
- FUNCTION BCDFrac (Nr: String): String;
-
- { integer part of number }
- FUNCTION BCDInt (Nr: String): String;
-
- { negation }
- FUNCTION BCDNeg (Nr: String): String;
-
- { the constant "pi" }
- FUNCTION BCDpi: String;
-
- { convert radians to degrees }
- FUNCTION BCDRad2Deg (Nr: String): String;
-
- { secant }
- FUNCTION BCDSec (Nr: String): String;
-
- { signum }
- FUNCTION BCDSgn (Nr: String): Integer;
-
- { sine }
- FUNCTION BCDSin (Nr: String): String;
-
- { square root }
- FUNCTION BCDSqrt (Nr: String): String;
-
- { tangent }
- FUNCTION BCDTan (Nr: String): String;
-
- BCD Math page 6
-
- Unit: BCD
-
-
-
- Notes on the single-parameter functions:
-
- The signum function returns an integer based on the sign of
- the BCD number:
-
- -1 if the BCD number is negative
- 0 if the BCD number is zero
- 1 if the BCD number is positive
-
- BCDpi is accurate to the maximum level afforded by the BCD
- functions. BCDe is accurate to as many as 115 decimal
- places. The actual accuracy, of course, depends on the size
- of BCD numbers you've chosen.
-
- The trigonometric functions (cos, sin, tan, sec, csc, cot)
- expect angles in radians. BCDDeg2Rad and BCDRad2Deg will
- allow you to convert back and forth between radians and
- degrees.
-
-
-
- Here is a list of the two-parameter functions:
-
-
- { addition }
- FUNCTION BCDAdd (Nr1, Nr2: String): String;
-
- { divide 1st by 2nd }
- FUNCTION BCDDiv (Nr1, Nr2: String): String;
-
- { multiplication }
- FUNCTION BCDMul (Nr1, Nr2: String): String;
-
- { subtract 2nd from 1st }
- FUNCTION BCDSub (Nr1, Nr2: String): String;
-
- { raise to a power }
- FUNCTION BCDPower (Nr: String; Power: Integer): String;
-
- { compare two numbers }
- FUNCTION BCDCompare (Nr1, Nr2: String): Integer;
-
- The comparison function returns an integer which reflects how
- the two numbers compare to each other:
-
- -1 Nr1 < Nr2
- 0 Nr1 = Nr2
- 1 Nr1 > Nr2
-
- Equipment Info page 7
-
- Unit: Equipment
-
-
-
- The equipment unit gives you information about the computing
- environment. This includes both installed software and hardware.
-
- The first function allows you to determine if an "enhanced"
- keyboard (101-key) is installed. It may not be able to figure
- out what the keyboard is on some older not-quite-clone PCs, in
- which case it will take the safe way out and report that there
- is no enhanced keyboard. This function returns -1 if there is
- an enhanced keyboard present, 0 if not.
-
- FUNCTION EnhKbd: Integer;
-
- Want to know the type of processor (CPU) being used? Can do!
-
- FUNCTION Processor: Integer;
-
- The results will be reported as a number which can be decoded
- as follows:
-
- 0 NEC V20
- 1 8088 or 8086
- 2 80186
- 3 80286
- 4 80386
- 5 80486
-
- Maybe you'd like to check for a CD-ROM drive:
-
- FUNCTION CDROM: Integer;
-
- This tells you how many logical drives exist, if there is a
- CD-ROM available. If not, it will return 0. Note that the
- CD-ROM installation check conflicts with the GRAPHICS.COM
- installation check for DOS 4.0, due to some screw-up at IBM or
- Microsoft. I'm not yet sure whether DOS 5.0 is similarly
- afflicted.
-
- The number of floppy drives installed is retrieved with this:
-
- FUNCTION Floppies: Integer;
-
- To get the number of serial (COM) ports and parallel (LPT)
- ports, use the following functions:
-
- FUNCTION CommPorts: Integer;
-
- FUNCTION PrtPorts: Integer;
-
- Equipment Info page 8
-
- Unit: Equipment
-
-
-
- Now, there may be up to four floppy drives in a system;
- however, the AT CMOS data area only directly supports two.
- This makes it easy to find out what kind of drives the first
- two are, but not the second two, if any. Such is life.
-
- PROCEDURE FloppyType (VAR Drive1, Drive2: Integer);
-
- The results from FloppyType are returned as follows:
-
- 0 no drive
- 1 5 1/4" 360K
- 2 5 1/4" 1.2M
- 3 3 1/2" 720K
- 4 3 1/2" 1.44M
-
- Result codes of 5-7 are available, but not yet defined. One
- might guess that the 2.88M drive supported by DOS 5.0 will be
- drive type 5. If anyone knows for sure, speak up!
-
- New memory types sure have burgeoned over the years...
- expanded, extended, and now XMS. There are routines to check
- all of these:
-
- { amount of extended memory installed }
- FUNCTION AllExtMem: LongInt;
-
- { BIOS extended memory available }
- FUNCTION GetExtM: LongInt
-
- { amount of expanded memory (a page is 16 Kbytes) }
- PROCEDURE GetEMSm (VAR TotalPages, FreePages: Integer);
-
- { amount of XMS memory (returned in kilobytes) }
- PROCEDURE GetXMSm (VAR LargestFreeBlock, TotalFree: LongInt);
-
- When you're dealing with extended memory, whether it be
- BIOS-type or using the XMS standard, the results are returned
- in kilobytes. Multiply 'em by 1024 to convert to bytes. When
- you're dealing with expanded memory (EMS), the results are in
- pages of 16,384 bytes.
-
- Equipment Info page 9
-
- Unit: Equipment
-
-
-
- A few more routines to get the versions of the EMS and XMS
- drivers, if any:
-
- PROCEDURE GetEMSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE GetXMSv (VAR MajorV, MinorV: Integer);
-
- These return the major and minor version numbers as two
- separate integers. For example, EMS 4.0 would return major
- version 4, minor version 0.
-
- It's nice to know a little about the operating environment.
- With the below routines, you can find out what the DOS version
- is; what version of 4DOS, if any, is in use; and whether
- Microsoft Windows is running.
-
- PROCEDURE GetDOSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE Get4DOSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE WinCheck (VAR MajorV, MinorV: Integer);
-
- These return results as major and minor version numbers, as
- discussed above. The Get4DOSv and WinCheck routines return
- zeroes if 4DOS and Windows, respectively, are not in use.
-
- There are a couple of curious features of GetDOSv to keep in
- mind. If the version is 10 or higher, you're running under
- OS/2. DOS version 10 is actually OS/2 1.0, version 20 is OS/2
- 2.0, and so on. Secondly, if you're using DOS 5.0, the version
- reported may not be 5.0-- DOS 5.0 can be told to reply with a
- lower version number to allow badly written older software to
- run properly.
-
- One final routine that should be of some value is the one that
- allows you to find out what kind of display is available. It
- tells you the specific adapter and whether the display is color
- or monochrome. There is one case in which it can be confused,
- however-- if the adapter is CGA, the display is assumed to be
- color, since there is no way for the computer to know any
- differently. So, although this routine provides a good idea of
- what is available, it would be a good idea to provide an option
- to tell the program that a monochrome display is attached.
- Microsoft normally uses "/B" for this purpose, so that might be
- a good standard to stick with.
-
- PROCEDURE GetDisplay (VAR Adapter: Integer; VAR Mono: Boolean);
-
- The adapter will be one of the following:
-
- 1 MDA 4 EGA
- 2 Hercules 5 MCGA
- 3 CGA 6 VGA
-
- Expression Evaluator page 10
-
- Unit: ExtMath
-
-
-
- The expression evaluator solves numeric equations. It allows
- you to find the result of an expression contained in a string.
- Normal algebraic precedence is used, e.g. 4+3*5 evaluates to
- 19. The usual numeric operators (*, /, +, -, ^) are supported
- (multiply, divide, add, subtract, and raise to a power).
- Negation is also supported. Parentheses can be used for
- overriding the default order of operations.
-
- You may use either double asterisk ("**") or caret ("^")
- symbols to indicate exponentiation.
-
- The constant PI is recognized, as are the following functions:
- ABS absolute value INT integer
- ACOS inverse cosine LOG natural log
- ASIN inverse sine SIN sine
- ATAN inverse tangent SQRT square root
- COS cosine TAN tangent
- FRAC fraction
-
- Trig functions expect angles in radians.
-
- To evaluate an expression, you pass it to the evaluator as a
- string. You will get back either an error code or a real
- result. See the CALC.PAS program for a working example.
-
- PROCEDURE Evaluate (Expression: String; VAR Result: Real;
- VAR ErrCode: Integer);
-
- An expression evaluator adds convenience to any program that
- needs to accept numbers. Why make someone reach for a
- calculator when number crunching is what a computer does best?
-
- Extensions to Pascal's Math page 11
-
- Unit: ExtMath
-
-
-
- For the most part, the math routines in this library are
- designed to provide alternatives to the math routines that come
- with Pascal. Still, Pascal's own math support is quite
- adequate for many purposes, so there's no sense in ignoring
- it. Here are some functions which improve on Pascal's math.
-
- { inverse cosine }
- FUNCTION ArcCos (Number: Real): Real;
- { 1.0 >= Number >= -1.0 }
-
- { inverse hyperbolic cosine }
- FUNCTION ArcCosH (Number: Real): Real;
-
- { inverse sine }
- FUNCTION ArcSin (Number: Real): Real;
- { 1.0 >= Number >= -1.0 }
-
- { inverse hyperbolic sine }
- FUNCTION ArcSinH (Number: Real): Real;
-
- { inverse hyperbolic tangent }
- FUNCTION ArcTanH (Number: Real): Real;
-
- { ceiling: smallest integer >= specified number }
- FUNCTION Ceil (Number: Real): Real;
-
- { hyperbolic cosine }
- FUNCTION CosH (Number: Real): Real;
-
- { cotangent }
- FUNCTION Cot (Number: Real): Real;
-
- { cosecant }
- FUNCTION Csc (Number: Real): Real;
-
- { convert degrees to radians }
- FUNCTION Deg2Rad (Number: Real): Real;
-
- { the constant "e" }
- FUNCTION e: Real;
-
- { error function }
- FUNCTION Erf (Number: Real): Real;
-
- { factorial }
- FUNCTION Fact (Number: Integer): Real;
-
- { floor: largest integer <= specified number }
- FUNCTION Floor (Number: Real): Real;
-
- Extensions to Pascal's Math page 12
-
- Unit: ExtMath
-
-
-
- { log (base 10) }
- FUNCTION Log (Number: Real): Real;
-
- { convert radians to degrees }
- FUNCTION Rad2Deg (Number: Real): Real;
-
- { raise a number to a power }
- FUNCTION Raise (Number: Real; Power: Integer): Real;
-
- { secant }
- FUNCTION Sec (Number: Real): Real;
-
- { hyperbolic sine }
- FUNCTION SinH (Number: Real): Real;
-
- { tangent }
- FUNCTION Tan (Number: Real): Real;
-
- { hyperbolic tangent }
- FUNCTION TanH (Number: Real): Real;
-
- Keyboard Control page 13
-
- Unit: Keyboard
-
-
-
- The keyboard is not a particularly exciting or glamorous
- device. In fact, we tend to forget about it except when it
- gets in the way. Sometimes it's a hardware problem-- squishy
- or clacking keys, or perhaps a commonly-used key placed in an
- out-of-the-way location. Then again, sometimes it's the
- software that's the problem. There are many aspects of
- keyboard control, not all of which are necessarily related to
- input. This unit will let you handle the keyboard in ways you
- may not have realized were possible. Better yet, it can help
- make keyboard control easier than the users of your programs
- dreamed possible.
-
- Let's start out with keyboard output. Yep, not input--
- output. We can stuff up to 15 keys into the keyboard buffer.
- Why would we ever want to do this? Perhaps to allow your
- program to pop-up a TSR automatically, to start another program
- after your program ends, or for creating key macros. You can
- enter extended key codes (like function keys) by using CHR$(0)
- before the scan code.
-
- PROCEDURE TypeIn (Keys: String);
-
- The usual keyboard action is quite sluggish. We can make it a
- lot crisper by changing the key repeat rate and the delay
- before repeating. This will work on ATs, but not PC/XT systems.
-
- PROCEDURE SpeedKey (RepDelay, RepRate: Integer);
-
- The delay may be 0-3 (1 by default):
-
- 0 250 milliseconds
- 1 500 milliseconds
- 2 750 milliseconds
- 3 1 second
-
- The repeat rate may be 0-31 (11 by default). The larger the
- number, the slower the speed-- 0 is around 30 cps, and 31 is
- around 2 cps.
-
- I generally prefer to have the keyboard cranked up to full
- speed, using RepDelay and RepRate both set to zero. This may
- be a bit too zippy for some people. Experiment with it to see
- what you like best.
-
- Of course, there may be reasons to make keyboard repeat less
- sensitive instead! That might be a good idea in programs
- written for small children, for example. You can adjust the
- keyboard equally well in either direction.
-
- Keyboard Control page 14
-
- Unit: Keyboard
-
-
-
- Pascal allows you to control one of the keys which can
- interrupt your program, namely the Break key. There's another
- dangerous key which PasWiz allows you to control-- the PrtSc
- (PrintScreen) key. PrtSc may not seem like a hazard at first
- glance, but if it's pressed by accident with no printer ready,
- or in a graphics mode which PrtSc doesn't understand how to
- print, the results can be pretty messy. So, we let you turn it
- off or on:
-
- PROCEDURE SetPrtSc (PrtScON: Boolean);
-
- Use FALSE to turn it off or TRUE to turn it back on. If you
- turn off PrtSc, you MUST remember to turn it back on again
- before your program ends! Otherwise, an interrupt vector will
- point into nowhere, causing probable chaos the next time PrtSc
- is pressed.
-
- Regardless of whether you've turned the PrtSc key off, you can
- print the screen yourself just as if PrtSc had been pressed:
-
- PROCEDURE PrintScreen;
-
- Now here's a strange one for you. When IBM brought out the
- 101-key keyboard, called the "enhanced" keyboard, they did
- something bizarre to the BIOS. They still allowed old keyboard
- calls to work, but they filtered out the new key codes so no
- one would see them. This made sure that no one would be able
- to use the capabilities of the "enhanced" keyboard without
- rewriting their programs. So, the keyboard has been around for
- years, and there are still few programs that even notice when
- you press F11. Pascal does not support the enhanced keyboard
- at all. Fortunately, PasWiz -does-. You can find out if an
- enhanced keyboard is installed with the EnhKbd function, which
- is in the Equipment unit.
-
- If there is an enhanced keyboard installed, you can activate it
- with this:
-
- PROCEDURE SetEnhKbd (Enhanced: Boolean);
-
- With enhanced keyboard support activated, all key requests that
- used the old services are translated to the new services. So,
- SetEnhKbd affects the ReadKey (in the CRT unit that comes with
- Pascal) and other Pascal functions as well as other PasWiz
- keyboard routines. Note that you MUST deactivate enhanced
- keyboard support before ending your program. Otherwise, an
- interrupt vector will point into nowhere, probably causing a
- crash on the next keypress!
-
- Keyboard Control page 15
-
- Unit: Keyboard
-
-
-
- If you're about to request important input, you may not want to
- chance having it answered from results of the keyboard buffer--
- could be that the user meant those keys for another purpose.
- In that case, it's a good approach to clear out the keyboard
- buffer just before the input:
-
- PROCEDURE ClearKbd;
-
- No keyboard unit would be complete without a selection of
- routines to check the shift states and get or set the keyboard
- toggles. Let's start with the toggles, which are so called
- because they get toggled from one state to another:
-
- FUNCTION CapsOn: Boolean; { Caps Lock }
-
- FUNCTION InsertOn: Boolean; { Insert }
-
- FUNCTION NumOn: Boolean; { Num Lock }
-
- FUNCTION ScrollOn: Boolean; { Scroll Lock }
-
- You can also turn the toggles off or on. It's courteous to
- restore the original toggle states once you end your program,
- so you might want to save the original values for that
- purpose. Then again, I guess that doesn't apply if your
- program is designed for the specific purpose of setting the
- toggles!
-
- PROCEDURE SetCaps (CapsLock: Boolean); { Caps Lock }
-
- PROCEDURE SetInsert (InsertKey: Boolean); { Insert }
-
- PROCEDURE SetNum (NumLock: Boolean); { Num Lock }
-
- PROCEDURE SetScroll (ScrollLock: Boolean); { Scroll Lock }
-
- Does anyone actually use ScrollLock for anything? Just
- curious...
-
- Keyboard Control page 16
-
- Unit: Keyboard
-
-
-
- The shift keys are unique in many respects. They don't return
- codes that can be detected with ReadKey or stuffed into the
- keyboard buffer; several can be pressed at the same time; and
- they don't repeat. You can detect 'em with PasWiz, at any rate:
-
- FUNCTION AltPress: Boolean; { any ALT }
-
- FUNCTION CtrlPress: Boolean; { any CTRL }
-
- FUNCTION ShiftPress: Boolean; { any SHIFT }
-
- FUNCTION LAltPress: Boolean; { left ALT }
-
- FUNCTION LCtrlPress: Boolean; { left CTRL }
-
- FUNCTION LShiftPress: Boolean; { left SHIFT }
-
- FUNCTION RAltPress: Boolean; { right ALT }
-
- FUNCTION RCtrlPress: Boolean; { right CTRL }
-
- FUNCTION RShiftPress: Boolean; { right SHIFT }
-
- NOTE that LAltPress, LCtrlPress, RAltPress, and RCtrlPress are
- ONLY available for enhanced keyboards. They will not return
- useful results on older keyboards.
-
- String Stuff page 17
-
- Unit: Strings
-
-
-
- Strings have always been something of an afterthought in
- Pascal. This unit brings in the heavy artillery! The PasWiz
- string routines may be divided into the following categories:
- comparison, compression, encryption, extraction, searching, and
- miscellaneous (mostly alteration). Let's take up these
- categories one at a time.
-
- The compression routines are designed to work with ordinary
- text strings. The strings may not contain IBM extended-ASCII
- codes (CHR($80)-CHR($FF)), as these are used in the
- compression. Compression works on spaces, which will give you
- an average of 15% compression on normal text. If you compress
- printable text (i.e., no control codes), you'll get printable
- text in return, which makes these routines handy for use with
- text files. Compression and decompression is done at an
- extreme rate of speed and will not affect the timing of your
- program in any noticeable fashion.
-
- FUNCTION Bsq (St: String): String; { compress a string }
-
- FUNCTION BUsq (St: String): String; { uncompress a string }
-
- Comparing two strings is easy enough in Pascal, but not as
- flexible as might be desired for some applications. You can
- tell if two strings match exactly, but not if they're
- reasonably close matches. PasWiz has two fuzzy comparison
- routines which can help.
-
- The Soundex routine uses a long-established algorithm to
- convert a word into a code which represents the sound of the
- word. It is fast and can work well under properly defined
- circumstances; for instance, it will tell you that "Smith"
- sounds just like "Smythe", but not like "Banks". Between the
- need for speed and the vagaries of the English language,
- however, you may find matches which don't work as well.
- Soundex is certain that "Knight" sounds just like "Smashed",
- for example. So, it may be perfect for something like a phone
- book, but not for a spelling checker!
-
- FUNCTION Soundex (St: String): String;
-
- The Bickel routine, on the other hand, tells you how closely
- two words match. This is a relative measure, not an absolute
- measure, so you'd probably want to search through an entire
- dictionary and just keep the words which matched best. The
- Bickel algorithm is slower than Soundex but is much more
- precise.
-
- FUNCTION Bickel (St1, St2: String): Integer;
-
- String Stuff page 18
-
- Unit: Strings
-
-
-
- There are many cases in which you might want to keep data
- private. The PasWiz encryption routines provide a simple and
- extremely fast method for password-protecting text. The
- encryption technique is trivial and will not withstand any
- concerted attack, but should suffice for casual use. It will
- help if you pick a longish password of unusual characters, for
- example '[^.mE@@&o}' (don't use this example itself, please)!
-
- There are two encryption routines (which also work as
- decryption routines). The first is designed to produce
- printable, if bizarre-looking, results which are suited for use
- with text files. Text to be encrypted by this routine may not
- include IBM extended-ASCII characters (CHR($80) - CHR($FF)),
- since these are used to insure printable text.
-
- FUNCTION CipherP (St, Passwd: String): String;
-
- The other routine will work with any sort of text, but is not
- guaranteed to produce printable results. So, it's not suited
- for use with text files.
-
- FUNCTION Cipher (St, Passwd: String): String;
-
- Of the extraction routines, two are merely convenient
- rephrasings of the Copy function which allow you to grab a
- substring from the left or right side of a string:
-
- FUNCTION Left (St: String; Len: Integer): String;
-
- FUNCTION Right (St: String; Len: Integer): String;
-
- Another extraction routine is more interesting. It allows you
- to extract a substring from a string which contains delimited
- information. For instance, consider the following name and
- address string. It has three fields, each separated by an
- asterisk. We can use Extract to grab any individual field:
-
- St := 'Tom Hanlin*3544 E. Southern Ave. #104*Mesa, AZ 85204';
- FOR PrtAddress := 1 TO 3 DO BEGIN
- AddressLine := Extract(St, '*', PrtAddress);
- WriteLn(AddressLine);
- END;
-
- The extract function is defined as follows:
-
- FUNCTION Extract (St, Delimiter: String;
- Index: Integer): String;
-
- If you try to extract a field which doesn't exist, a null
- string will be returned. Field delimiters may be anything at
- all, by the way-- one possible use for Extract might be to
- block-read a text file, splitting it apart in memory by using
- the carriage return and linefeed as a delimiter.
-
- String Stuff page 19
-
- Unit: Strings
-
-
-
- PasWiz provides an assortment of string search routines. One
- is a simple modification of Pos which allows you to start the
- search at a given place in the string:
-
- FUNCTION Instr (Start: Integer; SubSt, St: String): Integer;
-
- Another works like Pos, but returns the last match rather than
- the first match:
-
- FUNCTION RPos (SubSt, St: String): Integer;
-
- Of course, you don't always want to search for something in
- specific. You might be more interested in finding the first
- character that fits into a given category or categories, like
- perhaps numbers or letters. No problem:
-
- FUNCTION TypePos (ChType: Integer; St: String): Integer;
-
- The ChType value is formed by adding the numbers which
- represent the desired categories. This can also be used to
- search for the first character which is not of a given type,
- since the categories are exclusive:
-
- 1 alphabetic
- 2 numeric
- 4 symbols
- 8 control codes (ASCII 0-31, 127)
- 16 graphics codes (ASCII 128-255)
- 32 space (ASCII 32)
-
- That covers the string routines which can be readily
- categorized. Most of the remaining routines are designed to
- alter a string in one way or another. This includes being able
- to remove selected characters, substrings, types of characters,
- or repeated characters from a string; trimming the left or
- right side of a string of blanks; converting to uppercase,
- lowercase, or using the correct capitalization for a proper
- name; replacing one substring with another; reversing a string;
- and forming a new string by repeating a given substring.
-
- The "case", "trim", and "reverse" functions are pretty much
- self-explanatory:
-
- FUNCTION LowerCase (St: String): String; { lowercase }
-
- FUNCTION NameCase (St: String): String; { name case }
-
- FUNCTION UpperCase (St: String): String; { upper case }
-
- FUNCTION LTrim (St: String): String; { left trim }
-
- FUNCTION RTrim (St: String): String; { right trim }
-
- FUNCTION Reverse (St: String): String; { reverse }
-
- String Stuff page 20
-
- Unit: Strings
-
-
-
- The Crunch function removes adjacent repetitions of a
- substring. This is particularly handy for parsing user input,
- for example-- you can use it to remove repeated spaces between
- options, etc.
-
- FUNCTION Crunch (SubSt, St: String): String;
-
- The Dupe function forms a string by repeating a substring.
- It's handy when you need a string of a given number of spaces,
- zeroes, or nulls. It can also be used for drawing horizontal
- lines and other applications.
-
- FUNCTION Dupe (Count: Integer; SubSt: String): String;
-
- There are many times when it's nice to be able to replace all
- occurrences of one substring with another. PasWiz can do that,
- no problem. You don't have to worry about recursion, either--
- each occurrence is replaced only once, even if the replacement
- substring contains the target substring.
-
- FUNCTION Replace (OldSubSt, NewSubSt, St: String): String;
-
- Of course, you can delete a substring by replacing it with a
- null string. It's faster to use the routine designed for that
- purpose, though:
-
- FUNCTION StripSt (SubSt, St: String): String;
-
- Another routine allows you delete specified characters from a
- string:
-
- FUNCTION StripCh (ChList, St: String): String;
-
- And, last but not least, a routine which deletes specified
- types of characters from a string! This can be very good for
- screening user input.
-
- FUNCTION StripType (ChType: Integer; St: String): String;
-
- The ChType value is formed by adding the numbers which
- represent the desired categories:
-
- 1 alphabetic
- 2 numeric
- 4 symbols
- 8 control codes (ASCII 0-31, 127)
- 16 graphics codes (ASCII 128-255)
- 32 space (ASCII 32)
-
- Music page 21
-
- Unit: Music
-
-
-
- Granted, the PC has never been known for its wonderful sound
- capabilities. Still, it has more potential than you might
- guess, especially given the utterly minimal Sound/Delay/NoSound
- routines that are provided with Pascal. The Music unit makes it
- much easier to use sounds by providing an actual music
- language. The BACHINV and ENTERTNR demo programs demonstrate
- some of the possibilities.
-
- The PasWiz music language is nearly identical to that offered
- by the BASIC PLAY statement. The major difference is that the
- "MB" command (play the music as a background task) is not
- supported. I'll add that later, if I get enough requests.
-
- There are only two music procedures:
-
- PROCEDURE ResetMF;
-
- PROCEDURE PlayMF(Sounds: String);
-
- The ResetMF procedure is used to reset all music parameters to
- the default values. It would typically be used after finishing
- a song to restore the music handler for the next song.
-
- The PlayMF procedure is the one that does the real work.
- Here's a list of the music commands supported:
-
- MB play music as a background task (ignored)
- MF play music as a foreground task (ignored)
- ML legato (8/8 note length)
- MN normal music (7/8 note length)
- MN staccato (6/8 note length)
- Ln Length of notes (n = 1-64; note length = 1/n)
- Nn Note number (n = 0-84; 0 is a rest)
- On Octave (n = 0-6, default 4)
- Pn Pause (n = 1-64; pause length = 1/n)
- Tn Tempo (n = 32-255, default 120; quarter notes/minute)
- < move up an octave (max 6)
- > move down an octave (min 0)
-
- You can also use the actual letters of the notes (C, D, E, F,
- G, A, and B). If you're not particularly musical, these
- correspond to "do, re, mi, fa, so, la, ti" (with the final "do"
- being C again, but an octave higher). To play a scale, you'd
- use 'CDEFGAB>C'. The notes may be followed by dots, by note
- lengths, and by sharp or flat symbols (a '+' or '#' for a
- sharp, a '-' for a flat). For example, 'D-.' is a dotted D
- flat. The dot means that the note will play for half again its
- usual length. Dots can be repeated.
-
- I might note (ahem) that the so-called "ANSI" music offered by
- some BBSes and comm programs is based on this same music
- language. If you're writing telecomm software, this unit makes
- it trivial to add sound.
-
- Mouse page 22
-
- Unit: Mouse
-
-
-
- Considering the ubiquity of the mouse these days, it's a marvel
- to me that none of the popular programming languages provides
- any support for it. Well, BASIC supports it via light pen
- emulation, but that scarcely counts. Anyway, this is a simple
- little unit which provides you direct access to the mouse
- driver. It will work with any Microsoft-compatible mouse
- driver.
-
- A few words are necessary on mouse handling. To begin with,
- the best time to check for a mouse is immediately after you've
- established the desired video mode. The mouse driver
- initializes certain information when you check for it, so it's
- a good idea to check for it only once, at the appropriate time.
-
- The mouse cursor was implemented in a rather bizarre manner.
- If you call ShowCursor, you're guaranteed that the mouse cursor
- will be visible; however, this also increments an internal
- visibility flag. If you call ShowCursor multiple times, you
- will also have to call HideCursor multiple times before the
- dang cursor actually disappears.
-
- The mouse driver was apparently implemented without any thought
- for the future. In text mode, it returns coordinates based on
- CGA hi-res graphics mode-- 640x200 instead of the expected
- 80x25. If you use the mouse driver in text mode, you'll have
- to compensate for this (divide coordinates by 8 to convert to
- text mode, or multiply by 8 to convert to the mouse virtual
- mode). The CGA low-res 320x200 graphics mode is implemented
- likewise. It seems Microsoft thought that 640x200 would be the
- ultimate resolution, so they translated everything to a 640x200
- virtual mode. Arrgh. Fortunately, this does not apply to
- video modes other than text and CGA graphics.
-
- I understand that it's possible to get the mouse working in
- Hercules graphics mode, but I'm not sure what the details are.
- If anyone out there knows, please let me know, and I'll pass it
- along.
-
- Since Microsoft was initially very tight-lipped about the mouse
- functions, older mouse drivers for Microsoft-compatible rodents
- don't necessarily have all the functions available (this
- includes Logitech, amazingly enough). The Microsoft mouse
- driver continues to be updated in a rapid and haphazard manner,
- so keeping up-to-date is no guarantee. However, if you have
- any problems with these routines, you can almost certainly
- clear them up by getting a newer mouse driver. The routines in
- this unit are almost all old, well-established functions.
- "Iffy" ones are marked for your convenience.
-
- Mouse page 23
-
- Unit: Mouse
-
-
-
- The first function to consider simply tells you whether a mouse
- is available, and if so, how many buttons it has. It also
- resets the mouse driver, so it should be used only at the
- beginning of your program (or after changing the video mode).
-
- FUNCTION Init: Integer;
- { returns 0 if no mouse, else # of buttons }
-
- Most often, you'll want to know which mouse button(s) are
- pressed and where the mouse cursor is:
-
- FUNCTION LeftButton: Boolean;
- { TRUE if pressed }
-
- FUNCTION MidButton: Boolean;
- { always FALSE on 2-button rodents }
-
- FUNCTION RightButton: Boolean;
- { TRUE if pressed }
-
- FUNCTION WhereX: Integer;
- { X-coord (see notes on previous page) }
-
- FUNCTION WhereY: Integer;
- { Y-coord (see notes on previous page) }
-
- As well as finding the current mouse information, it's possible
- to find out what the mouse has been doing since you last
- checked. Two sets of routines exist: one to find out how many
- times a button was pressed and where it was at the last press,
- and one to find out how many times a button was released and
- where it was at the last release.
-
- PROCEDURE LeftClick(VAR Count, X, Y: Integer);
-
- PROCEDURE MidClick(VAR Count, X, Y: Integer);
-
- PROCEDURE RightClick(VAR Count, X, Y: Integer);
-
- PROCEDURE LeftRelease(VAR Count, X, Y: Integer);
-
- PROCEDURE MidRelease(VAR Count, X, Y: Integer);
-
- PROCEDURE RightRelease(VAR Count, X, Y: Integer);
-
- Mouse page 24
-
- Unit: Mouse
-
-
-
- There's one more informational routine. It tells you the basic
- mouse software and hardware stats: driver version, connector
- type (serial, bus, etc), and IRQ used. This routine is
- slightly hazardous in that, although Microsoft claims it has
- existed from the first, other manufacturers (including
- Logitech) have taken some time to implement it. In other
- words, it may not return useful information. The routine
- conducts a self-check and will return all zeroes if it suspects
- the information is not good, but even so... proceed with care.
-
- PROCEDURE Info(VAR Version: Real; VAR Connector, IRQ: Byte);
-
- Connector info: 1=bus, 2=serial, 3=InPort, 4=PS/2,
- 5=Hewlett-Packard IRQs: 0=PS/2; 2-5, 7 are actual IRQ numbers.
- It is conceivable that higher IRQ numbers may be supported on
- AT-type machines, though not by Microsoft.
-
- Of course, you can set mouse info as well as retrieving it.
- The following routines are pretty well self-explanatory (don't
- forget the notes about the strange text-mode and CGA coordinate
- handling, and cursor handling):
-
- { hide the mouse cursor }
- PROCEDURE HideCursor;
-
- { (maybe) make the cursor visible }
- PROCEDURE ShowCursor;
-
- { set the cursor position }
- PROCEDURE GotoXY(X, Y: Integer);
-
- { set the cursor range }
- PROCEDURE Window(X1, Y1, X2, Y2: Integer);
-
- There are other possibilities supported by the mouse driver
- that I have not implemented here. They're mostly on the rather
- esoteric side and are not supported by anything except recent
- Microsoft mouse drivers and perhaps some close compatibles,
- such as Logitech.
-
- Among the mouse capabilities I haven't implemented are finding
- out how fast and in what direction the mouse is moving, the
- coordinate size of the screen as far as the mouse is concerned,
- finding out the video modes that the mouse driver understands,
- setting mouse speed and sensitivity parameters, setting up an
- interrupt-driven system for handling mouse events, and a few
- others.
-
- Mouse page 25
-
- Unit: Mouse
-
-
-
- None of these missing capabilities is particularly vital (or
- even useful) for the average mouse application. However, if
- you're interested in any of these capabilities, let me know
- which ones, and I'll be glad to add them to PasWiz.
-
- Note: if you're confused at how I can get away with duplicating
- the names of existing procedures... well, it's easy enough.
- Let's consider WhereX. It means one thing to Pascal's Crt unit
- and another to the PasWiz Mouse unit. Since the Mouse unit
- doesn't use the Crt unit, it has no problem with any
- ambiguity. Existing programs that don't use the Mouse unit
- will likewise have no problems, since they don't know about the
- new routine. Suppose you want to use both the Crt and Mouse
- units together, however? There's the rub!
-
- You can specify a routine from a given unit by including the
- unit name when you use the routine. For instance:
-
- X := Mouse.WhereX; { get the mouse cursor position }
-
- X := Crt.WhereX; { get the normal cursor position }
-
- This allows multiple units to use the same names for things.
- While this may seem like a bit of a pain, since you have to
- specify which you want, it has a major built-in advantage if
- used properly. What's properly? When a routine in one unit
- works just like a routine by the same name in another unit.
- When I call the mouse routine "WhereX", for instance, I've also
- told you what it is for and how to use it. So, the name itself
- contains a lot of useful information on how to use the
- routine! That's what I call a major advantage.
-
-