ADVBAS.LIB v1.4, 07/29/85 Advanced Function Library for the IBM BASIC Compiler Copyright (C) Thomas Hanlin III, 1985 Requirements: IBM PC or close compatible, with the IBM BASIC Compiler. Some of these routines may be useful for the Microsoft version as well, but they haven't been tested for such use. The IBM BASIC Compiler is a powerful and flexible tool. However, it suffers from a number of serious limitations, as it was designed for MS-DOS v1, and cannot handle version 2+ functions such as subdirectories; it has little direct access to many advanced DOS features such as selective screen scrolling; and is sometimes annoyingly slow, for all its improvement over interpreted BASIC. For these reasons, I have designed a number of machine language routines which perform desirable functions, and put them in a library which the compiler can access. Since I have found these functions to be useful, I thought I'd pass them on to other people. You may use ADVBAS func- tions in any of your programs. If you do so, I would appreciate you sending a contribution (recommended amount $25, which will get you a disk containing the source code to these routines, an explanation of how BASIC tokenizes prog- rams, a crossreference utility, a communications program [Eterm] with source, and lots more). It would also be nice if you acknowledged use of these routines in your program. ADVBAS may be copied and distributed freely as long as this manual is included unchanged. The copyright is to preserve my options, and to protect you from the untoward modifications of others. It is not intended to prevent the free distribution of ADVBAS. Functions provided by ADVBAS: clear to end of screen line; scroll selected portion of screen up or down, or clear it; backspace destructively; return free drive space; get or set default drive; get or set default subdirectory; make or delete a subdirectory; get MS-DOS (PC-DOS) version; translate a string to uppercase or lowercase; remove all occurrences of a given character from a string; wait for one of a list of keys to be pressed, returning the key value; Xmodem/Ymodem checksum and CRC (cyclical redundancy check) calculation; saving and restoring the contents of the screen; translating a character using a string table; passing a string though AND, OR, and XOR functions; printing to the screen with great speed, or using MS-DOS functions which allow ANSI.SYS to function; getting a file's time/date stamp; and more! To use ADVBAS functions, you must copy ADVBAS.LIB to the disk on which you keep your BASIC Compiler library files. When you compile a program which uses an ADVBAS function, you must specify ADVBAS (preceeded by a drive letter if it's on a different disk than the program you're compiling) when LINK asks you which libraries to use. That is, at the LINKer's prompt "Libraries [.LIB]:- " you should say "ADVBAS" (without the quotes!). These functions have not caused me any problems, and seem to be fully debugged; however, I will not be responsible for any damages caused by use, misuse, or inability to use ADVBAS. But I'll try my best to fix any problems you may turn up! Keep in mind that ADVBAS functions will work only with the compiler, not the interpreter, and was tested on IBM BASIC Compiler version 1.00. Aside from their convenience, these functions have some additional value: they allow abilities which are not otherwise available from Compiled BASIC; they are generally faster than the corresponding Compiled BASIC code would be, often greatly so; they usually take up less space in the resulting EXEcutable file; and they often leave you more free programming space. Please mail contributions, suggestions for additional functions, ques- tions, comments, etc. to the following address: Thomas Hanlin III 6812 Sydenstricker Rd Springfield, VA 22152 Function Requirements: Numeric variables used in function calls must be integers. Either declare them using DEFINT, or add a percent sign "%" to the end of the variable name. Strings sometimes must be defined to a certain minimum length, due to limita- tions on what machine language routines are allowed to do to strings. Follow the guidelines for each routine in these respects, or the program will not work as expected! Function Descriptions, the meat of the matter: Name: CLREOL Type: Video Description: Clear from cursor position to end of line. Doesn't move the cursor. No arguments. Example: CALL CLREOL Name: BKSPACE Type: Video Description: Move cursor back one space, destroying the character on the space moved to. Will wrap from one line to the next higher if necessary. If at the top left corner of the screen, no action is performed. Two arguments return the new cursor X,Y coordinates, since machine language programs cannot directly change the BASIC cursor position. Example: CALL BKSPACE(X,Y) : LOCATE Y,X Name: SCROLL Type: Video Description: Scrolls any selected portion of the screen as many times as you like (1-255, or use 0 to clear that part of the screen entirely). Five arguments give coordinates (x1,y1) of the upper left corner of the area to be scrolled, coordinates (x2,y2) of the lower right corner of the area to be scrolled, and the number of times to scroll the area. This routine may be used to create windows. Note that X2 must be at least one greater than X1 (no single-line scrolling, obviously). Parameters are not checked, so be careful not to use illegal screen coordinates. Example: CALL SCROLL(X1,Y1,X2,Y2,LINS) Name: BKSCROLL Type: Video Description: The same as SCROLL (q.v.), but scrolls lines in the opposite direction (Back Scroll). Example: CALL BKSCROLL(X1,Y1,X2,Y2,LINS) Name: QPRINT Type: Video Description: This function bypasses the usual video routines, and prints a string directly on the screen, at a -much- higher speed than the normal PRINT state- ment does. It also contains a built-in LOCATE statement, and doesn't affect the cursor position. The string may be any length. Control characters will show up as graphics characters instead of having their original functions, and the color/attributes used will be the ones already on the screen. This works for 40 or 80 column displays, monochrome or color. Display page zero will be used (if applicable). Note: this function appeared in BYTE magazine in a different form, and has been modified several times since. It is not solely my creation. See the source code for further information. Example: ST$ = "This is a test of fast screen printing" ROW = 10 : COLUMN = 20 CALL QPRINT(ST$,ROW,COLUMN) Name: XQPRINT Type: Video Description: This function is an extended version of QPRINT. It is more flexible, and only a trifle slower. XQPRINT has two advantages over QPRINT: it allows you to choose a color/attribute to use, and lets you choose a display page (color/graphics adapters only!). The attribute ATTR must be set up using a special formula, and the display page is limited to a range of 0-3. This means that in 40-column mode, the display page used will actually be twice the argument you give the function, giving you access to 40-column display pages 0,2,4, and 6. Or so the theory goes. The page argument is ignored for monochrome adapters. Example: ST$ = "This is a test of fast screen printing" ROW = 10 : COLUMN = 20 : PAGE = 0 ATTR = (BACKGROUNDCOLOR AND 7) * 16 + FOREGROUNDCOLOR CALL XQPRINT(ST$,ROW,COLUMN,ATTR,PAGE) Name: MPRINTC Type: Video Description: Using this function, you can at last access device drivers such as ANSI.SYS. This is a video output function which goes through MS-DOS function calls. Advantage: allows use of ANSI.SYS and similar video drivers. Disadvantages: is slower and takes more memory that the usual PRINT statement. Summary: prints a single character out to the display. Example: CH$ = "" : WHILE CH$<>"!" : CH$ = INPUT$(1) : CALL MPRINTC(CH$) : WEND Name: XMPRINT Type: Video Description: This routine combines the XLATE and MPRINTC functions. It takes a char- acter, runs it through a translation table, and prints it to the screen unless the translated value is NUL (ASCII zero). If it's NUL, no printing takes place. MS-DOS calls are used for printing, so ANSI.SYS will work. See the XLATE and MPRINTC routines for further information. Example: CALL XMPRINT(CH$,XLATE$) Name: SCRSAVE Type: Video Description: Stores the current screen display (page 0 only) in an array. Text modes only. Requires an array of 8000 bytes, and an integer which points to the location of the array. The cursor position is not saved. Example: DEFINT A-Z : OPTION BASE 1 : DIM SCR(4000) . . WHER = VARPTR(SCR(1)) : CALL SCRSAVE(WHER) CX = POS(0) : CY = CSRLIN REM Dim of 4000 w/ option base 1 gives us 4000 integers, each of REM which occupy two bytes, giving 8000 bytes of storage space. Name: SCRREST Type: Video Description: Restores the screen display from an image put into an array by SCRSAVE. Same requirements and limitations of SCRSAVE. Example: WHER = VARPTR(SCR(1)) : CALL SCRREST(WHER) : LOCATE CY,CX Name: GETDOSV Type: Miscellaneous Description: Gets MS-DOS version. The major version is returned in the first para- meter, the minor version in the second (e.g., MS-DOS v. 2.11 would return MAJ = 2, MIN = 11). Example: CALL GETDOSV(MAJ,MIN) Name: CHECKSUM Type: Miscellaneous Description: Calculates a checksum for a record of any length. To be used with Xmodem or Ymodem. Example: CALL CHECKSUM(REC$,CHKSM) Name: CRC Type: Miscellaneous Description: Calculates a cyclical redundancy check for a record of any length. To be used with Xmodem/Ymodem CRC. Example: Sending a record: REC$=REC$+STRING$(2,0) : CALL CRC(REC$,HICRC,LOCRC) : MID$(REC$,129,2) = CHR$(HICRC)+CHR$(LOCRC) : send Xmodem record Receiving a record: CALL CRC(REC$,HICRC,LOCRC) : IF HICRC=0 AND LOCRC=0 THEN record is fine, save it ELSE record is bad, request it to be sent again Name: GETKEY Type: Keyboard Description: Waits until one of a list of keys is pressed, and returns it. The key list (any length) should be uppercase, and if the length is null, the first key pressed will be returned. The key returned will be capitalized. The variable to return the key in must be at least one character long. This func- tion is designed for returning one of a menu of choices, for example. Example: GOODKEYS$="KEY LIST" . . KY$="x":CALL GETKEY(GOODKEYS$,KY$) Name: UPCASE Type: String Description: Converts a string to all uppercase. Leaves non-alphabetic characters untouched. String may be any length. Example: MSG$="Four score and seven years ago" . . CALL UPCASE(MSG$) Name: LOCASE Type: String Description: Converts a string to all lowercase. Leaves non-alphabetic characters untouched. String may be any length. Example: MSG$="THis IS a test OF tHe lowercase CONVERTER!" . . CALL LOCASE(MSG$) Name: STRIP Type: String Description: Strips all occurrences of a given target character from a given source string. The source string may be any length; the target string must be at least one character. The new length of the source string will be returned as an integer, since external routines may not change the length of BASIC strings directly. Example: MSG$="12 - 2 = 10" . . CH$=" " : CALL STRIP(MSG$,CH$,LN) : MSG$ = LEFT$(MSG$,LN) Name: XLATE Type: String Description: This function translates a character using a table you supply. The char- acter's ASCII value is used as the index to the table, and the value at that location replaces the character's current value. The character may be one byte in length, in which case it will be translated, or zero bytes, in which case nothing will happen. The translation string must be 256 bytes long (remem- ber, strings may be longer than 255 bytes in Compiled BASIC, so this is ok). Example: XLT$ = "" : FOR X=0 TO 255: XLT$=XLT$+CHR$(X): NEXT MID$(XLT$,1,5) = "ABCDE": CH$ = CHR$(0) CALL XLATE$(CH$,XLT$): PRINT CH$ REM CH$ ends up "A", since the start of the table + zero bytes REM contains "A". We add zero bytes, because CH$ was REM originally equal to CHR$(0). Name: MULTIAND Type: String Description: This is a flexible function with many possible uses. Every character in a given string is ANDed with a value you supply. One thing this could be used for is translating Wordstar files to ASCII files, by using a bit mask (the value that will be ANDed with the character) of &H7F, which strips off the high bit of each character. The string may be any length; the bit mask is an integer, with only the low byte in use (value of 0-255). Example: ST$ = "" : FOR X=65 TO 70: ST$ = CHR$(X)+CHR$(X+128): NEXT : PRINT ST$ BITMASK = &H7F : CALL MULTIAND(ST$,BITMASK) : PRINT ST$ Name: MULTIOR Type: String Description: Does the exact opposite of MULTIAND-- instead of stripping off bits, it turns on bits. This is not quite as useful a function, but is included in case you need it. The parameters are the same as for MULTIAND. Instead of an AND function, this one uses an OR function on each character. Example: ST$ = "ABCDE": PRINT ST$: SETBITS = &H80 CALL MULTIOR(ST$,SETBITS): PRINT ST$ Name: MULTIXOR Type: String Description: An exclusive-or operation for strings. Bits in the string will be set only if they are set in the string byte or mask byte, but not in both of them. See your BASIC manual about functions AND, OR, XOR if you have any questions. Note that this can be used as a "MULTINOT" function by using a mask of &HFF or 255. In this case, all bits are set in the mask, so the result of the XOR will be the same as a NOT operation on the string. Example: CALL MULTIXOR(ST$,MASK) Name: DRVSPACE Type: Disk Description: Returns the amount of free space left on a given disk drive. The drive string may be any legal disk drive, or "@" (AT sign) for the default drive, and must be at least one character long. An illegal drive or other error will cause free space to be returned as a negative value. Example: DRV$="A:" . . CALL DRVSPACE(A$,B,C,D) : FREE = CSNG(B)*CSNG(C)*CSNG(D) : PRINT"Free space on drive ";A$;" is";FREE;"bytes." Name: GETDRV Type: Disk Description: Returns the letter of the default drive. The drive string must be at least one character long. Example: DRV$="x:" : CALL GETDRV(DRV$) Name: SETDRV Type: Disk Description: Sets the default drive. The drive string must be at least one character long, and an uppercase letter representing a disk drive. Example: DRV$="B:" . . CALL SETDRV(DRV$) Name: GETSUB Type: Disk Description: Gets the default subdirectory. The subdirectory string must be 64 charac- ters long, and it is recommended that you set it to ASCII zeroes (the NUL character). The length of the subdirectory string is returned as an integer value. Note that the string will NOT be started by a backslash "\" character-- you should add one if appropriate. Example: SUB$ = STRING$(64,0) : CALL GETSUB(SUB$,LN) : SUB$ = "\" + LEFT$(SUB$,LN) Name: SETSUB Type: Disk Description: Sets the default subdirectory. The subdirectory string must be at least one character in length, since it must be terminated by a NUL character. A negative one will be returned if there was a problem setting to the given subdirectory (either it's not available on the default drive, or a bad name, most likely); else zero will be returned if all went well. Example: TMP$ = SUB$+CHR$(0) : CALL SETSUB(TMP$,ERRCODE) : IF ERRCODE THEN bad subdir ELSE new default subdir selected Name: MAKESUB Type: Disk Description: Makes a subdirectory. Parameters used are the same as in SETSUB. Example: TMP$ = SUB$+CHR$(0) : CALL MAKESUB(TMP$,ERRCODE) : IF ERRCODE THEN couldn't make subdir ELSE subdir created Name: DELSUB Type: Disk Description: Deletes a subdirectory. Parameters used are the same as in SETSUB. Note that you may not delete a subdirectory if it has any files left in it, or if it is the main directory, or if it is the current default subdirectory. Example: TMP$ = SUB$+CHR$(0) : CALL DELSUB(TMP$,ERRCODE) : IF ERRCODE THEN couldn't delete subdir ELSE subdir deleted Name: GETFDATE Type: Disk Description: GETFDATE returns the file creation date, that is, the date you see on a file when you get a DIRectory. The file name must be terminated with an ASCII NUL character. If there is an error, such as there being no such file, the month will be -1. Example: FIL$ = "TESTFILE.TXT" + CHR$(0) CALL GETFDATE(FIL$,MONTH,DAY,YEAR) Name: GETFTIME Type: Disk Description: This function complements GETFDATE, and returns the file creation time. The hour is in 24-hour (military) format, and will be returned as -1 if there is no such file or a bad file name. The seconds are rounded to the next lower even number, due to the DOS storage format. The file name must be terminated with an ASCII zero, or NUL character. Example: FIL$ = "ANYFILE.EXT" + CHR$(0) CALL GETFTIME(FIL$,HOUR,MINUTE,SECOND) Bascom Bugs (info unrelated to ADVBAS!) Following are a few notes on BASIC Compiler bugs that I've run into. These are not caused by the ADVBAS routines, and have no relation to them. I just thought it might be helpful if I mentioned them, since anyone reading this evidently has, or is considering buying, the IBM BASIC Compiler. Illegal file names return a "Bad file number" error, rather than the expected "Bad file name". The control codes to move the cursor left and right work fine, but not the ones to move it up and down, which do nothing. Register BP is not saved by the compiler when it does a CALL. This must be done by the called program, since this register is used by the compiler for vital information. The /E compiler option seems to introduce errors into some programs which crash them by freezing the computer or giving a "String Space Corrupt" error. If this happens, I've found you can fix it by adding the /D option, or using /X instead of /E. The latter method cuts down heavily on available program space, so it may not be as good as the former. Both add a fair bit to the EXE program size. It's a hard life... This problem may also cause programs compiled without the /O option to lock up, which can't be fixed by using /X or /D. Use the /O option if this happens. If you find any other bugs in the BASIC Compiler, or in ADVBAS for that matter, please tell me about it. ADVBAS I can fix, and I can warn people about compiler problems!