T U R B O W H E E L S version 1.00 Copyright 1984 by Neil J. Rubenking This disk contains quite a few procedures and functions that make TURBO Pascal easier to use. Why re-invent the wheel when you can get TURBO WHEELS? I am releasing it for distribution in the User Group/Bulletin Board network subject to the following stipulations: 1) Anyone may get a copy of these files for examina- tion, either through their local Users Group or Bulletin Board, or by sending me a blank, DOUBLE-sided diskette and a prepaid, self-addressed diskette mailer. Regardless of how the disk is obtained, anyone who actually finds the contents USEFUL should send me $10, so I can continue writing and releasing software in this User-Supported fashion. Send $10 to: Neil J. Rubenking 300 Page St. San Francisco, CA 94102 2) I retain all rights to the SOURCE code. Recipients of the procedures may freely $INCLUDE them in compiled programs, but may not release the SOURCE. 3) Clubs may freely copy and distribute the disk for a nominal fee, not to exceed $8. With the legalities aside, I hope you find these procedures useful in your programs. Each has at least one "driver" program, to illustrate its actual use. If you are new to the concept of $INCLUDEing pre-written code in your TURBO Pascal programs, study the drivers. There are also several minor applications/utilities constructed using 8 or 10 of the handy procedures. A listing and description of the procedures follows. A keen observer might correctly deduce the following from the type of files I have put on this disk. 1) I don't have a Color/Graphics display 2) I don't do much in math and scientific programming 3) I do write programs that involve creating and manipu- lating disk files. 4) I do like my programs to look and sound good. You may have noticed other disks of TURBO files on the market. One that I have found useful is just called "Procedures and Functions for TURBO Pascal", from: The Success Press P.O. Box 2795 Des Plaines, IL Send Bill Todd $20 to receive these procedures. A list of them is on this disk as "SUCCESS.DOC". TURBO WHEELS page 2 *** SETTING UP THE DISK *** Format a blank diskette with the /S option, to make it a "bootable" DOS disk. Copy COMMAND.COM onto it, too. Copy all the files from this diskette onto the new diskette, and finally copy the files TURBO.COM and TURBO.MSG from the TURBO Pascal disk. Now your TURBO is a more powerful development tool -- it has WHEELS! development tool -- it has WHEELS! *** FILES ON THIS DISK *** The file "README.###" is a list of all the files, with a one-line description of each for quick reference. The files for INCLUsion in your programs have the extension .LIB or .TYP. Almost every .LIB file has a short program to illustrate its action (often called a "driver"). The drivers have the same name as their .LIB file, but the extension is .PAS. There are several utility application programs that use 8 or 10 .LIB files, and a few data files (extension .DAT). Now on to the descriptions of the individual files. *** TYPE DECLARATION FILES *** Most of the files on this disk use variables of type REGPACK (for REGister PACK) or FILENAME_TYPE. The description at the top of the INCLUDE file will indicate if these or any other files need to also be present. The reason to NOT write these type declarations directly into the files that require them is that TURBO objects to multiple descriptions of the same TYPE. FILENAME.TYP contains the definition of "filename_type" as a string of up to 64 characters. REGPACK.TYP describes the type of variable required as input by TURBO's procedures INTR and MSDOS. You do not need to understand these to use them! (But if you DO, you can do a lot!) SCREENS.TYP is the declaration of variable type SCREEN, which is exactly the same "shape" as the (text) video display memory. Using variables of this TYPE, you can easily do direct screen manipulation. ERRMESSG.LIB is another file that is required by quite a few others. It contains the function MESSAGE which receives as input a one-byte error code (output of a DOS function) and returns the "translation" of that code, as specified in the DOS 2.0 manual. TURBO WHEELS page 3 *** DOS 2.0 FILE HANDLING *** TURBO's file handling procedures do NOT work with subdirec- tories, as you may have found out. The following procedures are implementations of the DOS 2.0 procedures--all the ordinary ones and some new ones, too. EXTENDIO.DAT is an exact description of the parameters passed to and from these new IO functions. Until you are used to using them, you may want to actually insert this document into your source for reference (or refer to it using SIDEKICK!). EXTENDIO.LIB, for EXTENDed Input/Output contains 2.0 versions of Reset, Rewrite, Close, Read, Write, Seek, and Erase. Each new procedure has the same name as the one it replaces, preceded by an X (Xreset, Xclose, etc.). Any time you use these Extended IO procedures, you will also have to $INCLUDE the TYPE files REGPACK.TYP and FILENAME.TYP, and the file ERRMESSG.LIB--all of these procedures return a one-byte error code if anything goes wrong, and ERRMESSG.LIB lets you interpret the error by saying "writeLn(message(error))". In the DOS 2.0 mode, instead of a File Variable (a variable of TYPE "file of something") you will use an INTEGER File Handle. XReset and XRewrite receive a full- path filename (up to 64 characters) and return the file handle, which you will use for all further references to the file. XClose receives just the file handle (any open file has a handle), and XErase receives just the path/filename. Since DOS 2.0 files are effectively just files of bytes, the XRead and XWrite operations work rather diffe- rently from their forebears. You pass the File Handle, the variable to/from which data is to be read/written, and the SIZE of that variable (easily obtained with TURBO's SizeOf function). If the variable is a 1K array, then 1K will be read into it (or written from it). The Size-passing is necessary. Without it, you would have to write a new XRead and XWrite for each type of variable! XSeek is a bit complicated. You pass the File Handle (as usual), the Size of the records in your file, and the point from which you want to start your XSeek (Beginning, End, or Current position), and you get back the new current position. Even if you don't want the new current position (e.g., you just wanted to set the file pointer back to the beginning, or all the way to the end for APPEND), you still have to provide a dummy variable for it. For very detailed descriptions of the parameters to pass to and from these EXTENDed Input Output operations, see EXTENDIO.DAT. MOVEFILE.LIB might well be called "XRename", because it does serve to rename files on any path. However, the Renaming extends to the full path--you can MOVE a file to a different subdirectory simply by changing its path. You pass the old path and the new path, and receive the usual one-byte error code if anything goes wrong. TURBO WHEELS page 4 GETFILE.LIB contains two procedures, Find_First and Find_Next. Find_First serves to find the first occurrence of a file matching the template you supply (using the standard DOS wildcard characters, ? for any character and * for anything at all, AND using full-path filenames). You also specify the File Attribute--you can GET files that are Read-Only, Hidden, System, Volume label, or Directory. Find_First sets the DTA (Disk Transfer Area) to a buffer supplied by you and either puts information about the file in the buffer, or returns an error code. Once you have Found the First occurrence, you repeat Find_Next until you don't find any more. ALLFILES.LIB is a very handy procedure to include in any program that makes use of other files (e.g., a word processor, picture editor, music maker, &c.). You pass the top left and bottom right coordinates of an available screen area, and a template for the files you want, and ALLFILES takes over. It opens and frames a window at the coordinates and displays all matching files. The user positions a pointer at the required file and presses to select it. If there are more files than will fit in the window, the user has the choice of selecting a visible file or going on to another window full. Once a file is selected, ALLFILES erases its window and returns the filename. Note that your program will not have to test for existence of the file before trying to open it--you KNOW it exists. For an extremely classy use of ALLFILES, you may want to use the technique described in SCREENS.LIB to save whatever is on the screen before calling ALLFILES and pop it right back when ALLFILES is done. MKRMDIR.LIB brings the DOS MKDIR and RMDIR (MaKe DIRectory and DIRectory) into TURBO. If you want to do it, you can. FILEATTR.LIB lets you change the File Attribute byte (Read-Only, Hidden, System, Archive) of a file on any path. GTSETDIR.LIB lets you GET or SET the current subDIRectory. It may well be used in conjunction with GETSTDD below. *** DOS 1 OR 2 FILE HANDLING *** GETSETDD.LIB uses DOS function calls to GET or SET the Default Drive. EXISTFIL.LIB checks for the existence of a file. You pass it the "old-fashioned" filename (no subdirectory!) and it returns true or false. (The EXTENDed I/O operations do not directly crash your program if the file requested does not exist, so they don't need a corresponding 2.0 function.) *** DISK READ/WRITE PROCEDURES *** DISKTYP.LIB checks the type of disk (single/double sided, 8/9 sectors per track). You pass the drive letter, and it returns the number of K of disk space (an integer, 160, 180, 320, or 360), 0 if an invalid drive was specified, or 1 for a non-standard format. TURBO WHEELS page 5 GETSECTR.LIB conducts I/O between a specific sector on the disk and a buffer variable declared by you. You specify [R]ead or [W]rite and the side, sector, and track, and the buffer variable is either read from or written to the disk. As usual, a one-byte error code is returned. On the advice of the DOS Manual, GetSector makes three tries at reading the sector before it gives up and returns an error code. The buffer variable must be 512 bytes, but you can choose to arrange these bytes in convenient ways. For example, in the application LABEL.PAS, the buffer is an array[1..16] of type directory_entry, and reading a direc- tory sector gives you instant access to its 16 entries. NOTE that, unlike most of the procedures on this disk, GETSECTR does not have a driver with the same name. The sample programs that use GETSECTR are LABEL and DISKMOD. LABEL.PAS uses DISKTYP.LIB, GETSECTR.LIB, and several other files to read and write the volume label. It first seeks an existing label in the directory (NOTE: the volume label is just a special kind of directory entry.) If found, you may change it. If not found, the first directory slot that is either never-used or erased is converted to a label of your choice. The current date and time are properly included with your volume label, but the bit-manipulation that does that is horrifying! DISKMOD.PAS is a working Disk Sector Viewing and Modifying program, based on DISKMODF.BAS by John VanderGrift. You select a sector and get it displayed both in (filtered) ASCII and hex. You can modify the displayed sector by simply typing in new values, but you must specifically ask to record the modifications. Pressing PgDn and PgUp move to the next or previous sectors--the procedures "increment" and "decrement" embody the DOS sector numbering scheme. *** VIDEO DISPLAY PROCEDURES *** CURSOR.LIB contains the procedure Cursor_Control. You set the top and bottom "scan lines" for the cursor. You'll want to $INCLUDE the file MONITOR.LIB and ask to CheckColor before you change the cursor around, because the Monochrome cursor has 14 scan lines (numbered 0 at the top to 13 at the bottom) while the Color cursor is only 7 high (0 to 6). The normal cursor is 12,13 in Mono and 6,7 in color. In Monochrome, you can get a two-part cursor by setting the top line below the bottom. NOTE that you can "kill" the cursor by setting the top line to 48, bottom to 0. MONITOR.LIB sets the values of the variables COLOR (boolean) and ScreenSeg (integer) for use by other procedures. Besides $INCLUDEing it, you must invoke CheckColor at the beginning of your program. TURBO WHEELS page 6 SCREEN.LIB contains procedures to read and write the character and screen attribute (i.e., COLOR) at any location on the screen IN TEXT MODE. The driver, SCREEN.PAS, is a little video game showing how handy these procedures can be. POPSCREN.LIB is a slightly frivolous use of the SCREEN data type, declared in SCREENS.TYP. Several SCREEN variables are created and rapidly switched to the display. A pop-up menu example is included. POPSCREN.DAT is a screen file used by POPSCREN.LIB GRFXTABL.LIB defines a table of ROMEntries "on top" of the ROM graphics table, giving us (read-only) access to the dot patterns used to create the monochrome characters. TITLES.LIB contains the procedure MakeTitle. Given a title up to ten characters and a starting row, it makes a big title on the screen by using the character patterns from GRFXTABL. WINDOWS.LIB offers another approach to using windows. The variable type "corners" is declared to be an array[1..4] of byte. Windows that your program will use are set at the beginning of the program by declaring CONSTants of type "corners". The procedures DoWindow and DoFrame operate on input of type "corners". If, later in the development of your program, you want to move the windows around, you just change the CONSTant declaration at the top. *** kEYBOARD PROCEDURES *** GETKEYS.LIB is one of my favorites. The line "GetKeys(C,D)" causes your program to wait for a keystroke and, if it is an "ordinary" keystroke, returns the character in C and chr(0) in D. If, however, it was a "special" keystroke (arrow key, function key), it returns chr(27) in C and a code character in D. The file KEYCHART.DAT tabulates these special codes. KEYBOARD.LIB is another approach to trapping keystrokes. It uses the keyboard BIOS interrupt $16 to get the scan code and ASCII code of any key pressed. The file SCANCODE.DAT is a chart of keyboard codes, along with a table of "extended" scan codes. FANCYKEY.LIB goes KEYBOARD one better. It returns a phrase describing the key pressed, such as "Alt-A", "Shift-F1", "Back Tab", etc. TURBO WHEELS page 7 NEWINT9.LIB is an ambitious procedure. The keyboard's output is generally handled by Interrupt $9, which is called BY THE KEYBOARD whenever a key is struck. This interrupt checks for shift states, filters out key release codes, and produces the "typematic" effect, whereby a key held down repeats. Certain applications might be better off WITHOUT the typematic and WITH access to the key release codes -- my own PIANO MAN program comes to mind. I required a note to sound ONCE when a key was pressed and stop when that key was released. Games might requires this feature. If you do use it, your program should: 1) invoke procedure SetUpInt, which creates the new interrupt. 2) invoke NewInt, which saves the normal interrupt vector and replaces it with directions to the new one. 3) MOST IMPORTANT, before the program ends, invoke OldInt to restore the normal interrupt. If you don't do this, or if your program crashes before it can do it, you cannot communicate through your keyboard, and you have to turn the PC off and on again. Used with care, NEWINT9 can satisfy a real need. *** GRAPHICS *** (Let me note that I myself do not have a Color/Graphics adapter, so I haven't had much opportunity to write for one. However, the mighty BORLAND has a Graphics tool set for their usual price of $50.) CIRCLE.LIB draws a circle on your screen. You specify six parameters: H, K and R are the X and Y coordinates of the circle's center and its radius. "Res" is the resolution -- the number of dots used to draw the circle is proportional to Res, as is the time required to draw it. "Aspect" is a real value that describes the circle's "roundness" -- adjust to a perfect circle, or change it to get an ellipse. Finally, "color" can be 1, 2, or 3 if you are in the Graphics mode that supports four colors. (See the descrip- tion of graphics modes in the TURBO 2.0 manual). RECTANGL.LIB naturally draws a rectangle on the screen. You tell it the X and Y coordinates of the upper left and lower right corners, the color (1, 2, or 3 if appropriate), and 1 for a filled rectangle, 0 for hollow. TURBO WHEELS page 8 *** MISCELLANEOUS ROUTINES *** EQUIPMNT.LIB uses Interrupt $11 to check the equipment attached to your PC. It reports on number of printers, RS232 ports, game ports, and diskette drives, the initial video mode, or the amount of RAM on the motherboard. GETINTGR.LIB is intended to save you the embarrassment of having your program crash because someone made an invalid entry for an integer. At the same time, it makes sure that the entry is within a ranges you specify. Non-numeric keystrokes are ignored, BackSpace works, and the function does not give up until a valid integer is entered. GETFREE.LIB is another face-saver. It gets the amount of free space on the current disk. That way, your programs can check for space and give alternatives if there's not enough, rather than ignominiously crashing. HEXFUNCT.LIB contains the procedure HEX which receives an integer and returns a 5-character hex string (e.g., $BF00). The hex string always refers to a positive number -- TURBO's integer variable type uses its highest bit to indicate sign, thus restricting the integer range to -32,768 to +32,767. Hex equivalents are calculated by considering negative integers as offsets down from $10000 (decimal 65,536). Thus, HEX(-1) = $FFFF. (NOTE: the TURBO manual says that the integer range is as stated above, but in my experience, it is not possible to enter -32,768. ) KAVAIL.LIB returns the number of KiloBytes of memory available. It takes into account the MemAvail function's quirk of reporting amounts greater than 32,767 as negative numbers. NOSOUND.PAS does nothing but shut off the sound, if one of your programs crashes with sound on. When you need it, you NEED it! PARAMETR.LIB contains the function GetParameter, which returns a string of up to 80 characters consisting of whatever was entered on the command line after the name of the program. This O N L Y works in COMPILED programs. QUEUE.LIB is a generic Queue data structure. One of Pascal's great advantages over BASIC is its implementation of Pointer^ variables and dynamic lists. By keeping your data in a linked list instead of an array, you can dedicate only as much memory as you need, up to all the memory the system has. If you test for memory available with KAVAIL before you add each item to the list, you can safely expand to the maximum memory of different systems without crashing for lack of memory. TURBO WHEELS page 9 REBOOT.LIB does just what it says. The "warm" reboot produced by Interrupt $19 does NOT clear the RAM, so, for example, SIDEKICK will stay resident. The programs LESSRAM and NUMDISKS use REBOOT to cause the PC to act as if its internal DIP switches had been reset to indicate a different number of disk drives or different amount of RAM. One note of caution -- There seems to be some interference in this reboot process from certain device drivers in the CONFIG.SYS file. The symptom is that the driver (e.g., your hard disk driver, or a RAMdisk) installs itself and then the A: drive spins . . . and spins . . . and that's it. To avoid this problem, you could always rename CONFIG.SYS to something else temporarily. IF you can figure out why this happens and how to get around it, PLEASE let me know! LESSRAM.COM is handy if you always write your programs on your souped-up 640K SuperPC and want to test whether it will actually run on a lesser machine with, say 96K. You COULD open the box and change the switches, but it's a lot easier just to go back to DOS and type LESSRAM 96. NUMDISKS's raison d'etre is the current confusion of method among RAMdisks. Some require that the internal switches be set to the total number of physical drives and RAMdisks, while others insist that the switches show physical drives only. If you need to switch around, you can enter NUMDISKS . If you put NUMDISKS in a batch file, be sure to add an "n" (or "N") to the number so the program won't pause for a keypress before rebooting. SAFEWRIT.LIB is one way to get around the fact that you cannot WRITE certain characters to the screen -- they get inter- preted as Control Characters and warp your display. Procedure SafeWrite catches these characters and replaces them with a related character in Low Video. Note that another approach would be to use the procedures in SCREEN.LIB to send characters directly to the screen memory. Using this latter method, you can put ANY character on the screen.