*************************************************************************** *************************************************************************** The UCR Standard Library for Assembly Language Programmers, Written By Randall Hyde and others, is sssssss ss ss ss sssssss sssssss ss ss ss ssss ss ss ss ss ss ss ss ss ss ss ss sssssss sssssssss ssssssss sssssss sssss ssssssss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss sssssss ss ss ss ss ss ss sssssss ww ww ww sssssss sssssss ww ww wwww ss ss ss ww ww ww ww ww ss ss ss ww wwww ww wwwwwwww sssssss sssss ww ww ww ww ww ww ss ss ss wwww wwww ww ww ss ss ss ww ww ww ww ss ss sssssss We do not want any registration fees for this software. Now for the catch... It is more blessed to give than to receive. If this software saves you time and effort and you enjoy using it, our lives will be enriched knowing that others have appreciated our work. We would like to share this wonderful feeling with you. If you like this software and use it, we would like you to contribute at least one routine to the library. Perhaps you think this library has some neat-o routines in it. Imagine how nice it would become if everyone used their imagination to contribute something useful to it. We hereby release this software to the public domain. You can use it in any way you see fit. However, we would appreciate it if you share this software with others as much as it has been shared it with you. That is not to suggest that you give away software you have written with this package (We're not quite as crazy as Richard Stallman, bless his heart), but if someone else would like a copy of this library, please help them out. Naturally, we would be tickeled pink to receive credit in software that uses these routines (which is the honorable thing to do) but we understand the way many corporations operate and won't be terribly put off if you use it without giving due credit. Enjoy! If you have comments, bug reports, new code to contribute, etc., you can reach us through: rhyde (On BIX). rhyde@ucrmath.ucr.edu (On Internet). or Randall Hyde Dept of Computer Science 122 University Office Bldg University of California Riverside, Ca. 92521 COMMENTS ABOUT THE CODE: ************************ Please don't expect super optimal code here. Most of it is fairly mediocre (from a size/speed point of view). Hopefully, you'll agree, it's the idea that counts. If you do not like something I have done, you have got the sources -- have at it. (Of course, it would be appreciated if you would send any modifications to one of the E-MAIL addresses above.) ************************************ NOTE ************************************ Please understand the purpose of this code! This library is here to make assembly language programming easy. The nature of this library encourages people to write code in a fashion similar to that employed when they write programs in a high level language like C. While this familiar style of programming does make the task easier, it is not the most appropriate approach to use when flat-out performance is what you're seeking. "C code written with MOV instructions" is never as fast as pure assembly language code employing the proper programming paradigm. Why mention this? Well, some readers may have heard about assembly language's legendary performance and they're expecting to achieve that using this library. While programs written with this library may very well run faster than a comparable program written in a HLL, you will not get fantastic performance improvement until you stop thinking in HLLs and starting "thinking" in assembly. The purpose of this library is to help you *avoid* thinking in assembly language. There- fore, this code will not help you achieve those fantastic performance levels you've been hearing about; indeed, this library may stand in the way of that goal. It's not that these routines are terribly slow, mind you. They just encourage an inappropriate programming style if speed is what you're after. On the other hand, since only 10-20% of the code of any given program represents the time critical stuff (an argument long employed by HLL supporters), there is nothing wrong with judicious use of this code within a program that has to be fast. As usual, if performance is your primary goal, you must study the problem and the program you generate very carefully to isolate the time critical portions. If you are interested in high- performance programming at the "micro-algorithm" level, you should take a look at Michael Abrash's text "Zen of Assembly." This excellent book will explain many ways to improve the performance of your code at the sub-algorithm level (where assembly language really shines). COMMENTS ABOUT THIS DOCUMENTATION: ********************************** You will have to forgive us for the inconsistent style appearing throughout this document. Keep in mind that this document has been prepared by many different people. Keeping the styles consistent is a time consuming and difficult task. Whenever a routine's description claims that the flags are not affected, you should not interpret this to mean that the routine preserves the flags. Most routines do *not* preserve any of the flags. Such a statement simply means that the routine does not *explicitly* return a value in one (or more) of the flag bits. Note that proper credit has been given to the author of each of the various routines appearing in this library *except* for those written by Randall Hyde. All routines without an author by-line were probably written by Randall Hyde (unless we screwed up somewhere and forgot to put a name in the documentation). Most of these routines were tested and documented by various students in Randy Hyde's CS 13 (assembly language) and CS 191X / CS 185 courses (Commercial Software Development). There are too many names to mention here, but these students definitely deserve the credit for locating numerous bugs in the code, providing many suggestions, and doing other work. ============================================================================= Version History: Version 0.0- Initial release as "Randy Hyde's Standard Library for 80x86 Assembly Language programmers" Version 1.0- Initial release as "UCR Standard Library..." CS 191X students did some testing and documentation in this release. Version 2.0- More testing on several routines. Added floating point library and several other routines. Version 2.1- Fixed *MAJOR* bugs in floating point package. Added 11-1-91 several new routines. Included new "TEST" files with the library. Also included SHELL.ASM file inadvertently left out of Version 2.0. Version 2.2- Made some minor modifications to puth, putl, ltoa, and htoa 11-14-91 as per suggestions made by David Holm and Terje Maithesen Version 2.3- Made a small but *major* modification to the stdlib.a and 11-22-91 stdlib.a6 files to force library calls into the STDGRP group. Otherwise the linker substitued bad segment addresses for the far calls to the library routines. A real problem when accessing variables in StdData. Version 2.4- Yet more changes to fix the stupid MASM group/segment:offset 12-7-91 bug. Made various changes to the STDLIB.A file. Also fixed a problem in the FP routines- forgot to declare sl_sefpa public. Finally, created batch file to automatically unpack everything from DOS (assuming presence of PKUNZIP somewhere in the current path). Version 2.5- Some new macros (DOS, ExitPgm), fixed a problem with the 12-25-91 PUTI routine, added some SmartArray items. Also added the GetEnv routine. ============================================================================== ROUTINES WE WOULD LIKE TO HAVE: ******************************* If you're interested in adding some routines to this package, GREAT! Here are some suggestions. 1) Routines which manipulate directories (read/write/etc.) 2) A regular expression interpreter. 3) Length-prefixed strings package. 4) A graphics package. 5) An object-oriented programming class library. 6) Just about anything else appearing in a HLL "standard" library. If you've got any ideas, we would love to discuss them with you. The best way to reach us is through the E-MAIL addresses above. MISSING ROUTINES TO BE SUPPLIED IN THE FUTURE: ********************************************** Character strings: trim- Removes trailing blanks from a string. blkdel- Removes leading blanks from a string. translit- Transliterates characters in a string based on a translation table. Pattern matching and character sets: span- Skips through a sequence of characters in a string which belong to a character set. break- Skips through a sequence of characters in a string which do not belong to a character set. any- Skips over a character if it is a member of a set. notany- Skips over a character in a string if it is not a member of a set. skip- Skips "n" characters in the string. tab- Matches up to the nth character in a string. rtab- Matches up to the nth character from the end of a string. pos- Matches if we are currently at the nth position in a string. rpos- Matches if we are at the nth position from the end of the string. mark- Marks a position in a string during pattern matching grab- Copies everything from the last mark and creates a new string on the stack from this substring. match- Initialize pattern matching system. alternate- Try an alternative if the current pattern does not match. arb- Skip over an arbitrary number of characters in a match. replace- Replace a substring from the last mark to the current position with some other string. fail- Force a match failure. succeed- Force a match success. Memory Manager Package Memavail- Largest block of free memory available on the heap. Memfree- Total amount of free space on the heap. BlockSize- Returns the size of the memory block which es:di points at. Process Manager Package CoCall- Call a coroutine. CoInit- Initialize a coroutine. CoRet- Quit a coroutine. HOW TO USE THE STANDARD LIBRARY: ******************************** When you are ready to begin programming with the library, you should copy the shell.asm file, provided in the package, to another file in which you will be working, i.e. myprog.asm. The shell.asm file sets up the machine (segments, etc.) as the UCR Standard Library expects them. Results are undefined for other setups. Therefore, I strongly suggest, that when you begin using these routines, you follow the shell.asm format. Later, when you are familiar with the software, you may wish to create your own shell.asm file, but it is wise to initially use the one provided. The shell.asm file has comments which tell you where to place your code, variables, etc. There is an include file, stdlib.a (stdlib.a6 for MASM 6.0 users), which you should include in every assembly you perform which calls the stdlib routines. SHELL.ASM already includes this file. *YOU MUST PLACE THE INCLUDE STATEMENT OUTSIDE OF ANY SEGMENTS IN YOUR PROGRAM*. Preferably as the first line of your program (just like SHELL.ASM). If you place this include directive inside a segment, certain assemblers/linkers (especially MASM) will not properly assemble and link your programs. They will assemble and link without error, but the resulting program will not execute correctly. The STDLIB.A file contains macros you can use to call each of the routines in the standard library. For example, to call PRINTF you would use the statement printf db "format string",0 db other,vars rather than "calling" printf. Printf is actually a macro, you cannot call it directly (all of the standard library routines have names like "sl_printf" and the macro issues a call to the appropriate routine). These macros have two main purposes-- first, the differentiate calls to the standard library routines (i.e., no "call" instruction is the difference); and second, they contain some extra code to perform "smart linking" with MASM 5.1 & earlier, TASM, and OPTASM. MASM 6.0 supports a new directive, extrndef, which eliminates the need for this extra code, but the extra code works nonetheless. There is a special include file, STDLIB.A6, for MASM 6.0 users which is smaller and, therefore, speeds up assemblies and consumes less memory during assembly. All of the standard library routines, and most of their local data values, are in a segment named "stdlib". You should not create such a segment unless you plan on adding new routines to the standard library. HOW THE STANDARD LIBRARY IS ORGANIZED: ************************************** In the next several pages are the documentation spec sheets for each of the standard library routines. The routines are listed by category. The listing of the categories and their order in the documentation is below. Standard Input Routines Standard Output Routines Conversion Routines Utility Routines String Handling Routines Memory Management Routines Character Set Routines Floating Point Routines File I/O Miscellaneous Routines SmartArray Package In addition, at the beginning of each of the category is a brief discussion of the purpose of its routines. Standard Input Routines: Character Input Routines ------------------------ The character input routines take input from either a standard device (keyboard, etc.) or a standard library. After the character input routines receive the characters they either place the characters on the stack and/or return. The character input routines work similar to the "C" character input routines. Routine: Getc -------------- Category: Character Input Routine Registers on Entry: None Registers on Return: AL- Character from input device. AH- 0 if eof, 1 if not eof. Flags Affected: Carry- 0 if no error, 1 if error. If error occurs, AX contains DOS error code. Example of Usage: getc mov KbdChar, al putc Description: This routine reads a character from the standard input device. This call is synchronous, that is, it does not return until a character is available. The Default input device is DOS standard input. Getc returns two types of values: extended ASCII (codes 1-255) and IBM keyboard scan codes. If Getc returns a non-zero value, you may interpret this value as an ASCII character. If Getc returns zero, you must call Getc again to get the actual keypress. The second call returns an IBM PC keyboard scan code. Since the user may redirect input from the DOS command line, there is the possibility of encountering end-of-file (eof) when calling getc. Getc uses the AH register to return eof status. AH contains the number of characters actually read from the standard input device. If it returns one, then you've got a valid character. If it returns zero, you've reached end of file. Note that pressing control-z forces an end of file condition when reading data from the keyboard. This routine returns the carry flag clear if the operation was successful. It returns the carry flag set if some sort of error occurred while reading the character. Note that eof is not an error condition. Upon reaching the end of file, Getc returns with the carry flag clear. If getc is seen from a file the control-z is not seen as an end-of-file marker, but just read in as a character of the file. Control-c if read from a keyboard device aborts the program. However if when reading something other than a keyboard (files, serial ports), control-c from the input source returns control-c. However when pressing control-break the program will abort regardless of the input source. Regarding CR/LF, if the input is from a device, (eg. keyboard serial port) getc returns whatever that device driver returns, (generally CR without a LF). However if the input is from a file, getc stripes a single LF if it immediately follows the CR. When using getc files operate in "cooked" mode. While devices operate in "pseudo-cooked" mode, which means no buffering, no CR -> CR/LF, but it handles control-c, and control-z. See the sources for more information about GETC's internal operation. Include: stdlib.a Routine: GetcStdIn -------------------- Category: Character Input Routine Register on entry: None. Register on return: AL- Character from input device. Flags affected: AH- 0 if eof, 1 if not eof. Carry- 0 if no error, 1 if error (AX contains DOS error code if error occurs). Example of Usage: GetcStdIn mov InputChr, al putc Description: This routine reads a character from the DOS standard input device. This call is synchronous, that is, it does not return until a character is available. See the description of Getc above for more details. The difference between Getc and GetcStdIn is that your program can redirect Getc using other calls in this library. GetcStdIn calls DOS directly without going through this redirection mechanism. Include: stdlib.a Routine: GetcBIOS ------------------- Category: Character Input Routine Register on entry: None Register on return: AL- Character from the keyboard. Flags affected: AH- 1 (always). Carry- 0 (always). Example of Usage: GetcBIOS mov CharRead, al putc Description: This routine reads a character from the keyboard. This call is synchronous, that is it does not return until a character is available. Note that there is no special character processing. This code does *not* check for EOF, control-C, or anything else like that. Include: stdlib.a Routine: SetInAdrs ------------------- Category: Character Input Routine Registers on Entry: ES:DI - address of new input routine Registers on return: None Flags affected: Examples of Usage: mov es, seg NewInputRoutine mov di, offset NewInputRoutine SetInAdrs les di, RoutinePtr SetInAdrs Description: This routine redirects the stdlib standard input so that it calls the routine who's address you pass in es:di. The routine (whose address appears in es:di) should be a "getc" routine which reads a character from somewhere and returns that character in AL. It should also return EOF status in the AH register and error status in the carry flag (see the description of GETC for more details). Include: stdlib.a Routine: GetInAdrs -------------------- Category: Character Input Routine Register on entry: None Register on return: ES:DI - address of current input routine (called by Getc). Flags affected: None Example of Usage: GetInAdrs mov word ptr SaveInAdrs, di mov word ptr SaveInAdrs+2, es Description: You can use this function to get the address of the current input routine, perhaps so you can save it or see if it is currently pointing at some particular piece of code. If you want to temporarily redirect the input and then restore the original input or outline, consider using PushInAdrs/PopInAdrs described later. Include: stdlib.a Routine: PushInAdrs --------------------- Category: Character Input Routine Register on entry: ES:DI - Address of new input routine. Register on return: Carry=0 if operation successful. Carry=1 if there were already 16 items on the stack. Example of Usage: mov es, seg NewInputRoutine mov di, offset NewInputRoutine PushInAdrs . . . les di, RoutinePtr PushInAdrs Description: This routine "pushes" the current input address onto an internal stack and then copies the value in es:di into the current input routine pointer. The PushInAdrs and PopInAdrs routines let you easily save and redirect the standard output and then restore the original output routine address later on. If you attempt to push more than 16 items on the stack, PushInAdrs will ignore your request and return with the carry flag set. If PushInAdrs is successful, it will return with the carry flag clear. Include: stdlib.a Routine: PopInAdrs -------------------- Category: Character Input Routine Register on entry: None Register on return: ES:DI - Points at the previous stdout routine before the pop. Example of Usage: mov es, seg NewInRoutine mov di, offset NewInputRoutine PushInAdrs . . . PopInAdrs Description: PopInAdrs undoes the effects of PushInAdrs. It pops an item off the internal stack and stores it into the input routine pointer. The previous value in the output pointer is returned in es:di. Include: stdlib.a Routine: Gets, Getsm --------------------- Category: Character Input Routine Register on entry: ES:DI- Pointer to input buffer (gets only). Register on return: ES:DI - address of input of text. carry- 0 if no error, 1 if error. If error, AX contains: 0- End of file encountered in middle of string. 1- Memory allocation error (getsm only). Other- DOS error code. Flags affected: None Example of usage: getsm ;Read a string from the ;keyboard puts ;Print it putcr ;Print a new line free ;Deallocate storage for ;string. mov di, seg buffer mov es, di lea di, buffer gets puts putcr Description: Reads a line of text from the stdlib standard input device. You must pass a pointer to the recipient buffer in es:di to the GETS routine. GETSM automatically allocates storage for the string on the heap (up to 256 bytes) and returns a pointer to this block in es:di. Gets(m) returns all characters typed by the user except for the carriage return (ENTER) key code. These routines return a zero-terminated string (with es:di pointing at the string). Exactly how Gets(m) treats the incoming data depends upon the source device, however, you can usually count on Gets(m) properly handling backspace (erases previous character), escape (erase entire line), and ENTER (accept current line). Other keys may affect Gets(m) as well. For example, Gets(m), by default, calls Getc which, in turn, usually calls DOS' standard input routine. If you type control-C or break while read from DOS' standard input it may abort the program. If an error occurs during input (e.g., EOF encountered in the middle of a line) Gets(m) returns the error code in AX. If no error occurs, Gets(m) preserves AX. Include: stdlib.a Routine: Scanf --------------- Category: Character Input Routine Register on entry: None Register on return: None Flags affected: None Example of usage: scanf db "%i %h %^s",0 dd i, x, sptr Description: * Formatted input from stdlib standard input. * Similar to C's scanf routine. * Converts ASCII to integer, unsigned, character, string, hex, and long values of the above. Scanf provides formatted input in a fashion analogous to printf's output facilities. Actually, it turns out that scanf is considerably less useful than printf because it doesn't provide reasonable error checking facilities (neither does C's version of this routine). But for quick and dirty programs whose input can be controlled in a rigid fashion (or if you're willing to live by "garbage in, garbage out") scanf provides a convenient way to get input from the user. Like printf, the scanf routine expects you to follow the call with a format string and then a list of (far pointer) memory addresses. The items in the scanf format string take the following form: %^f, where f represents d, i, x, h, u, c, x, ld, li, lx, or lu. Like printf, the "^" symbol tells scanf that the address following the format string is the address of a (far) pointer to the data rather than the address of the data location itself. By default, scanf automatically skips any leading whitespace before attempting to read a numeric value. You can instruct scanf to skip other characters by placing that character in the format string. For example, the following call instructs scanf to read three integers separated by commas (and/or whitespace): scanf db "%i,%i,%i",0 dd i1,i2,i3 Whenever scanf encounters a non-blank character in the format string, it will skip that character (including multiple occurrences of that character) if it appears next in the input stream. Scanf always calls gets to read a new line of text from stdlib's standard input. If scanf exhausts the format list, it ignores any remaining characters on the line. If scanf exhausts the input line before processing all of the format items, it leaves the remaining variables unchanged. Scanf always deallocates the storage allocated by gets. Include: stdlib.a Character Output Routines ------------------------- The stdlib character output routines allow you to print to the standard output device. Although the processing of non-ASCII characters is undefined, most output devices handle these characters properly. In particular, they can handle return, line feed, back space, and tab. Most of the output routines in the standard library output data through the Putc routine. They generally use the AX register upon entry and print the character(s) to the standard output device by calling DOS by default. The output is redirectable to the user-written routine. However, the PutcBIOS routine prints doesn't use DOS. Instead it uses BIOS routines to print the character in AL using the INT command for teletype-like output. The print routines are similar to those in C, however, they differ in their implementation. The print routine returns to the address immediately following the terminating byte, therefore, it is important to remember to terminate your string with zero or you will print an unexpected sequence of characters. Routine: Putc -------------- Category: Character Output Routine Registers on Entry: AL- character to output Registers on Return: None Flags affected: None Example of Usage: mov al, 'C' putc ;Prints "C" to std output. Description: Putc is the primitive character output routine. Most other output routines in the standard library output data through this procedure. It prints the ASCII character in AL register. The processing of control codes is undefined although most output routines this routine links to should be able to handle return, line feed, back space, and tab. By default, this routine calls DOS to print the character to the standard output device. The output is redirectable to to user-written routine. Include: stdlib.a Routine: PutCR --------------- Category: Character Output Routine Register on entry: None Register on return: None Flags affected: None Example of Usage: PutCR Description: Using PutCR is an easy way of printing a newline to the stdlib standard output. It prints a newline (carriage return/line feed) to the current standard output device. Include: stdlib.a Routine: PutcStdOut ------------------- Category: Character Output Routine Registers on Entry: AL- character to output Registers on Return: None Flags Affected: None Example of Usage: mov AL, 'C' PutcStdOut ; Writes "C" to standard output Description: PutcStdOut calls DOS to print the character in AL to the standard output device. Although processing of non-ASCII characters and control characters is undefined, most output devices handle these characters properly. In particular, most output devices properly handle return, line feed, back space, and tab. The output is redirectable via DOS I/O redirection. Include: stdlib.a Routine: PutcBIOS ----------------- Category: Character Output Routine Registers on Entry: AL- character to print Registers on Return: None Flags Affected: None Example of Usage: mov AL, "C" PutcBIOS Description: PutcBIOS prints the character in AL using the BIOS routines, using INT 10H/AH=14 for teletype-like output. Output through this routine cannot be redirected; such output is always sent to the video display on the PC (unless, of course, someone has patched INT 10h). Handles return, line feed, back space, and tab. Prints other control characters using the IBM Character set. Include: stdlib.a Routine: GetOutAdrs ------------------- Category: Character Output Routine Registers on Entry: None Registers on Return: ES:DI- address of current output routine (called by Putc) Flags Affected: None Example of Usage: GetOutAdrs mov word ptr SaveOutAdrs, DI mov word ptr SaveOutAdrs+2, ES Description: GetOutAdrs gets the address of the current output routine, perhaps so you can save it or see if it is currently pointing at some particular piece of code. If you want to temporarily redirect the output and then restore the original output routine, consider using PushOutAdrs/PopOutAdrs described later. Include: stdlib.a Routine: SetOutAdrs -------------------- Category: Character Output Routine Registers on Entry: ES:DI - address of new output routine Registers on return: None Flags affected: None Example of Usage: mov es, seg NewOutputRoutine mov di, offset NewOutputRoutine SetOutAdrs les di, RoutinePtr SetOutAdrs Description: This routine redirects the stdlib standard output so that it calls the routine who's address you pass in es:di. This routine expects the character to be in AL and must preserve all registers. It handles the printable ASCII characters and the four control characters return, line feed, back space, and tab. (The routine may be modified in the case that you wish to handle these codes in a different fashion.) Include: stdlib.a Routine: PushOutAdrs --------------------- Category: Character Output Routine Registers on Entry: ES:DI- Address of new output routine Registers on Return: None Flags Affected: Carry = 0 if operation is successful Carry = 1 if there were already 16 items on the stack Example of Usage: mov ES, seg NewOutputRoutine mov DI, offset NewOutputRoutine PushOutAdrs . . . les DI, RoutinePtr PushOutAdrs Description: This routine "pushes" the current output address onto an internal stack and then uses the value in es:di as the current output routine address. The PushOutAdrs and PopOutAdrs routines let you easily save and redirect the standard output and then restore the original output routine address later on. If you attempt to push more than 16 items on the stack, PushOutAdrs will ignore your request and return with the carry flag set. If PushOutAdrs is successful, it will return with the carry flag clear. Include: stdlib.a Routine: PopOutAdrs -------------------- Category: Character Output Routine Registers on Entry: None Registers on Return: ES:DI- Points at the previous stdout routine before the pop Flags Affected: None Example of Usage: mov ES, seg NewOutputRoutine mov DI, offset NewOutputRoutine PushOutAdrs . . . PopOutAdrs Description: PopOutAdrs undoes the effects of PushOutAdrs. It pops an item off the internal stack and stores it into the output routine pointer. The previous value in the output pointer is returned in es:di. Defaults to PutcStdOut if you attempt to pop too many items off the stack. Include: stdlib.a Routine: Puts -------------- Category: Character Output Routine Register on entry: ES:DI register - contains the address of the string Register on return: None Flags affected: None Example of Usage: les di, StrToPrt puts putcr Description: Puts prints a zero-terminated string whose address appears in es:di. Each character appearing in the string is printed verbatim. There are no special escape characters. Unlike the "C" routine by the same name, puts does not print a newline after printing the string. Use putcr if you want to print the newline after printing a string with puts. Include: stdlib.a Routine: Puth -------------- Category: Character Output Routine Register on entry: AL Register on return: AL Flags affected: None Example of Usage: mov al, 1fh puth Description: The Puth routine Prints the value in the AL register as two hexadecimal digits. If the value in AL is between 0 and 0Fh, puth will print a leading zero. This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: Putw -------------- Category: Character Output Routine Registers on Entry: AX- Value to print Registers on Return: None Flags Affected: None Example of Usage: mov AX, 0f1fh putw Description: The Putw routine prints the value in the AX register as four hexadecimal digits (including leading zeros if necessary). This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: Puti -------------- Category: Character Output Routine Registers on Entry: AX- Value to print Registers on Return: None Flags Affected: None Example of Usage: mov AX, -1234 puti Description: Puti prints the value in the AX register as a decimal integer. This routine uses the exact number of screen positions required to print the number (including a position for the minus sign, if the number is negative). This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: Putu -------------- Category: Character Output Routine Register on entry: AX- Unsigned value to print. Register on return: None Flags affected: None Example of Usage: mov ax, 1234 putu Description: Putu prints the value in the AX register as an unsigned integer. This routine uses the exact number of screen positions required to print the number. This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: Putl -------------- Category: Character Output Routine Register on entry: DX:AX- Value to print Register on return: None Flags affected: None Example of Usage: mov dx, 0ffffh mov ax, -1234 putl Description: Putl prints the value in the DX:AX registers as an integer. This routine uses the exact number of screen positions required to print the number (including a position for the minus sign, if the number is negative). This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: Putul --------------- Category: Character Output Routine Register on entry: DX:AX register Register on return: None Flags affected: None Example of Usage: mov dx, 12h mov ax, 1234 putul Description: Putul prints the value in the DX:AX registers as an unsigned integer. This routine uses the exact number of screen positions required to print the number. This routine calls the stdlib standard output routine (putc) to print all characters. Include: stdlib.a Routine: PutISize ------------------ Category: Character Output Routine Registers on Entry: AX - Integer value to print CX - Minimum number of print positions to use Registers on return: None Flags affected: Example of Usage: mov cx, 5 mov ax, I PutISize . . . mov cx, 12 mov ax, J PutISize Description: PutISize prints the signed integer value in AX to the stdlib standard output device using a minimum of n print positions. CX contains n, the minimum field width for the output value. The number (including any necessary minus sign) is printed right justified in the output field. If the number in AX requires more print positions than specified by CX, PutISize uses however many print positions are necessary to actually print the number. If you specify zero in CX, PutISize uses the minimum number of print positions required. Of course, PutI will also use the minimum number of print positions without disturbing the value in the CX register. Note that, under no circumstances, will the number in AX ever require more than 6 print positions (-32,767 requires the most print positions). Include: stdlib.a Routine: PutUSize ------------------ Category: Character Output Routine Registers on entry: AX- Value to print CX- Minimum field width Registers on return: None Flags affected: None Example of usage: mov cx, 8 mov ax, U PutUSize Description: PutUSize prints the value in AX as an unsigned decimal integer. The minimum field width specified by the value in CX. Like PutISize above except this one prints unsigned values. Note that the maximum number of print positions required by any number (e.g., 65,535) is five. Include: stdlib.a Routine: PutLSize ------------------ Category: Character Output Routine Register on entry: DX:AX-32 bit value to print CX- Minimum field width Register on return: None Flags affected: None Example of Usage: mov cx, 16 mov dx, word ptr L+2 mov ax, word ptr L PutLSize Description: PutLSize is similar to PutISize, except this prints the long integer value in DX:AX. Note that there may be as many as 11 print positions (e.g., -1,000,000,000). Include: stdlib.a Routine: PutULSize ------------------- Category: Character Output Routine Register on entry: AX : DX and CX Register on return: None Flags affected: None Example of usage: mov cx, 8 mov dx, word ptr UL+2 mov ax, word ptr UL PutULSize Description: Prints the value in DX:AX as a long unsigned decimal integer. Prints the number in a minimum field width specified by the value in CX. Just like PutLSize above except this one prints unsigned numbers rather than signed long integers. The largest field width for such a value is 10 print positions. Include: stdlib.a Routine: Print ---------------- Category: Character Output Routine Register on entry: CS:RET - Return address points at the string to print. Register on return: None Flags affected: None Examples of Usage: print db "Print this string to the display device" db 13,10 db "This appears on a new line" db 13,10 db 0 Description: Print lets you print string literals in a convenient fashion. The string to print immediately follows the call to the print routine. The string must contain a zero terminating byte and may not contain any intervening zero bytes. Since the print routine returns to the address immediately following the zero terminating byte, forgetting this byte or attempting to print a zero byte in the middle of a literal string will cause print to return to an unexpected instruction. This usually hangs up the machine. Be very careful when using this routine! Include: stdlib.a Routine: Printf ---------------------- Category: Character Output Routine Register on entry: CS:RET - Return address points at the format string Register on return: None Flags affected: None Example of Usage: printf db "Indirect access to i: %^d",13,10,0 dd IPtr; printf db "A string allocated on the heap: %-\.32^s" db 13,10,0 dd SPtr Descriptions: Printf, like its "C" namesake, provides formatted output capabilities for the stdlib package. A typical call to printf always takes the following form: printf db "format string",0 dd operand1, operand2, ..., operandn The format string is comparable to the one provided in the "C" programming language. For most characters, printf simply prints the characters in the format string up to the terminating zero byte. The two exceptions are characters prefixed by a backslash ("\") and characters prefixed by a percent sign ("%"). Like C's printf, stdlib's printf uses the backslash as an escape character and the percent sign as a lead-in to a format string. Printf uses the escape character ("\") to print special characters in a fashion similar to, but not identical to C's printf. Stdlib's printf routine supports the following special characters: * r Print a carriage return (but no line feed) * n Print a new line character (carriage return/line feed). * b Print a backspace character. * t Print a tab character. * l Print a line feed character (but no carriage return). * f Print a form feed character. * \ Print the backslash character. * % Print the percent sign character. * 0xhh Print ASCII code hh, represented by two hex digits. C users should note a couple of differences between stdlib's escape sequences and C's. First, use "\%" to print a percent sign within a format string, not "%%". C doesn't allow the use of "\%" because the C compiler processes "\%" at compile time (leaving a single "%" in the object code) whereas printf processes the format string at run-time. It would see a single "%" and treat it as a format lead-in character. Stdlib's printf, on the other hand, processes both the "\" and "%" and run-time, therefore it can distinguish "\%". Strings of the form "\0xhh" must contain exactly two hex digits. The current printf routine isn't robust enough to handle sequences of the form "\0xh" which contain only a single hex digit. Keep this in mind if you find printf chopping off characters after you print a value. There is absolutely no reason to use any escape character sequences except "\0x00". Printf grabs all characters following the call to printf up to the terminating zero byte (which is why you'd need to use "\0x00" if you want to print the null character, printf will not print such values). Stdlib's printf routine doesn't care how those characters got there. In particular, you are not limited to using a single string after the printf call. The following is perfectly legal: printf db "This is a string",13,10 db "This is on a new line",13,10 db "Print a backspace at the end of this line:" db 8,13,10,0 Your code will run a tiny amount faster if you avoid the use of the escape character sequences. More importantly, the escape character sequences take at least two bytes. You can encode most of them as a single byte by simply embedding the ASCII code for that byte directly into the code stream. Don't forget, you cannot embed a zero byte into the code stream. A zero byte terminates the format string. Instead, use the "\0x00" escape sequence. Format sequences always between with "%". For each format sequence you must provide a far pointer to the associated data immediately following the format string, e.g., printf db "%i %i",0 dd i,j Format sequences take the general form "%s\cn^f" where: * "%" is always the "%" character. Use "\%" if you actually want to print a percent sign. * s is either nothing or a minus sign ("-"). * "\c" is also optional, it may or may not appear in the format item. "c" represents any printable character. * "n" represents a string of 1 or more decimal digits. * "^" is just the caret (up-arrow) character. * "f" represents one of the format characters: i, d, x, h, u, c, s, ld, li, lx, or lu. The "s", "\c", "n", and "^" items are optional, the "%" and "f" items must be present. Furthermore, the order of these items in the format item is very important. The "\c" entry, for example, cannot precede the "s" entry. Likewise, the "^" character, if present, must follow everything except the "f" character(s). The format characters i, d, x, h, u, c, s, ld, li, lx, and lu control the output format for the data. The i and d format characters perform identical functions, they tell printf to print the following value as a 16-bit signed decimal integer. The x and h format characters instruct printf to print the specified value as a 16-bit or 8-bit hexadecimal value (respectively). If you specify u, printf prints the value as a 16-bit unsigned decimal integer. Using c tells printf to print the value as a single character. S tells printf that you're supplying the address of a zero-terminated character string, printf prints that string. The ld, li, lx, and lu entries are long (32-bit) versions of d/i, x, and u. The corresponding address points at a 32-bit value which printf will format and print to the standard output. The following example demonstrates these format items: printf db "I= %i, U= %u, HexC= %h, HexI= %x, C= %c, " db "S= %s",13,10 db "L= %ld",13,10,0 dd i,u,c,i,c,s,l The number of far addresses (specified by operands to the "dd" pseudo-opcode) must match the number of "%" format items in the format string. Printf counts the number of "%" format items in the format string and skips over this many far addresses following the format string. If the number of items do not match, the return address for printf will be incorrect and the program will probably hang or otherwise malfunction. Likewise (as for the print routine), the format string must end with a zero byte. The addresses of the items following the format string must point directly at the memory locations where the specified data lies. When used in the format above, printf always prints the values using the minimum number of print positions for each operand. If you want to specify a minimum field width, you can do so using the "n" format option. A format item of the format "%10d" prints a decimal integer using at least ten print positions. Likewise, "%16s" prints a string using at least 16 print positions. If the value to print requires more than the specified number of print positions, printf will use however many are necessary. If the value to print requires fewer, printf will always print the specified number, padding the value with blanks. Printf will print the value right justified in the print field (regardless of the data's type). If you want to print the value left justified in the output file, use the "-" format character as a prefix to the field width, e.g., printf db "%-17s",0 dd string In this example, printf prints the string using a 17 character long field with the string left justified in the output field. By default, printf blank fills the output field if the value to print requires fewer print positions than specified by the format item. The "\c" format item allows you to change the padding character. For example, to print a value, right justified, using "*" as the padding character you would use the format item "%\*10d". To print it left justified you would use the format item "%-\*10d". Note that the "-" must precede the "\*". This is a limitation of the current version of the software. The operands must appear in this order. Normally, the address(es) following the printf format string must be far pointers to the actual data to print. On occasion, especially when allocating storage on the heap (using malloc), you may not know (at assembly time) the address of the object you want to print. You may have only a pointer to the data you want to print. The "^" format option tells printf that the far pointer following the format string is the address of a pointer to the data rather than the address of the data itself. This option lets you access the data indirectly. Note: unlike C, stdlib's printf routine does not support floating point output. Putting floating point into printf would increase the size of this routine a tremendous amount. Since most people don't need the floating point output facilities, it doesn't appear here. Check out PRINTFF. Include: stdlib.a Routine: PRINTFF ----------------- Category: Character Output Routine Registers on Entry: CS:RET- Points at format string and other parameters. Registers on Return: If your program prints floating point values, this routine modifies the floating point accumulator and floating point operand "pseudo-registers" in the floating point package. Flags Affected: None Examples of Usage: printff db "I = %d, R = %7.2f F = 12.5e G = 9.2gf\n",0 dd i, r, f, g Description: This code works just like printf except it also allows the output of floating point values. The output formats are the following: Single Precision: mm.nnF- Prints a field width of mm chars with nn digits appearing after the decimal point. nnE- Prints a floating point value using scientific notation in a field width of nn chars. Double Precision: mm.nnGF- As above, for double precision values. nnGE- As above, for double precision values. Extended Precision- mm.nnLF- As above, for extended precision values. nnLE- As above, for extended precision values. Since PRINTFF supports everything PRINTF does, you should not use both routines in the same program (just use PRINTF). The PRINTF & PRINTFF macros check for this and will print a warning message if you've included both routines. Using both will not cause your program to fail, but it will make your program unnecessarily larger. You should not use PRINTFF unless you really need to print floating point values. When you use PRINTFF, it forces the linker to load in the entire floating point package, making your program considerably larger. Include: stdlib.a Conversion Routines ------------------- The stdlib conversion routines follow a uniform format of storing the data to be converted and returned. Most routines accept input and return data of either an ASCII string of characters, stored in the ES:DI register, or integers, stored in the DX:AX register. If a value is just a 16 or 8-bit value then it will be stored in AX or AL. Since there is a possibility of an error in the input values to be converted, such as it does not contain a proper value to convert, we use the carry flag to show error status. If the error flag is set then an error has occured and things are okay if the carry flag is clear. Routine: ATOL (2) ------------------ Category: Conversion Routine Registers on Entry: ES:DI- Points at string to convert Registers on Return: DX:AX- Long integer converted from string ES:DI- Points at first non-digit (ATOL2 only) Flags Affected: Carry flag- Error status Examples of Usage: gets ;Get a string from user ATOL ;Convert to a value in DX:AX Description: ATOL converts the string of digits that ES:DI points at to a long (signed) integer value and returns this value in DX:AX. Note that the routine stops on the first non-digit. If the string does not begin with a digit, this routine returns zero. The only exception to the "string of digits" only rule is that the number can have a preceding minus sign to denote a negative number. Note that this routine does not allow leading spaces. ATOL2 works in a similar fashion except it doesn't preserve the DI register. That is, ATOL2 leaves DI pointing at the first character beyond the string of digits. ATOL/ATOL2 both return the carry flag clear if it translated the string of digits without error. It returns the carry flag set if overflow occurred. Include: stdlib.a Routine: AtoUL (2) ------------------- Category: Conversion Routine Register on entry: ES:DI- address of the string to be converted Register on return: DX:AX- 32-bit unsigned integer ES:DI- Points at first character beyond digits (ATOUL2 only) Flags affected: Carry flag- Set if error, clear if okay. Examples of Usage: les InputString AtoUL Description: AtoUL converts the string pointed by ES:DI to a 32-bit unsigned integer. It places the 32-bit unsigned integer into the memory address pointed by DX:AX. If there is an error in conversion, the carry flag will set to one. If there is not an error, the carry flag will be set to zero. ATOUL2 does not preserve DI. It returns with DI pointing at the first non-digit character in the string. Include: stdlib.a Routine: ATOU (2) -------------------- Category: Conversion Routine Register on entry: ES:DI points at string to convert Register on return: AX- unsigned 16-bit integer ES:DI- points at first non-digit (ATOU2 only) Flags affected: carry flag - error status Example of Usage: Description: ATOU converts an ASCII string of digits, pointed to by ES:DI, to unsigned integer format. It places the unsigned 16-bit integer, converted from the string, into the AX register. ATOI works the same, except it handle unsigned 16-bit integers in the range 0..65535. ATOU2 leaves DI pointing at the first non-digit in the string. Include: stdlib.a Routine: ATOH (2) ----------------- Category: Conversion Routine Registers on Entry: ES:DI- Points to string to convert Registers on Return: AX- Unsigned 16-bit integer converted from hex string DI (ATOH2)- First character beyond string of hex digits Flags Affected: Carry = Error status Example of Usage: les DI, Str2Convrt atoh ;Convert to value in AX. putw ;Print word in AX. Description: ATOH converts a string of hexadecimal digits, pointed to by ES:DI, into unsigned 16-bit numeric form. It returns the value in the AX register. If there is an error in conversion, the carry flag will set to one. If there is not an error, the carry flag will be clear. ATOH2 works the same except it leaves DI pointing at the first character beyond the string of hex digits. Include: stdlib.a Routine: ATOLH (2) ------------------ Category: Conversion Routine Registers on Entry: ES:DI- Points to string to convert Registers on Return: DX:AX- Unsigned 32-bit integer converted from hex string DI (ATOLH2)- First character beyond string of hex digits Flags Affected: Carry = Error status Example of Usage: les DI, Str2Convrt atolh ;Convert to value in DX:AX Description: ATOLH converts a string of hexadecimal digits, pointed to by ES:DI, into unsigned 32-bit numeric form. It returns the value in the DX:AX register. If there is an error in conversion, the carry flag will set to one. If there is not an error, the carry flag will be clear. ATOLH2 works the same except it leaves the DI register pointing at the first non-hex digit. Include: stdlib.a Routine: ATOI (2) ------------------- Category: Conversion Routine Register on entry: ES:DI- Points at string to convert. Register on return: AX- Integer converted from string. DI (ATOI2)- First character beyond string of digits. Flags affected: Error status Examples of Usage: les DI, Str2Convrt atoi ;Convert to value in AX Description: Works just like ATOL except it translates the string to a signed 16-bit integer rather than a 32-bit long integer. Include: stdlib.a Routine ITOA (2,M) ------------------ Category: Conversion Routine Registers on Entry: AX- Signed 16-bit value to convert to a string ES:DI- Pointer to buffer to hold result (ITOA/ITOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (ITOA/ITOAM only). ES:DI- Pointer to zero-terminating byte of converted string (ITOA2 only). Flags Affected: Carry flag is set on memory allocation error (ITOAM only) Examples of Usage: mov ax, -1234 ITOAM ;Convert to string. puts ;Print it. free ;Deallocate string. mov di, seg buffer mov es, di lea di, buffer mov ax, -1234 ITOA ;Leaves string in BUFFER. mov di, seg buffer mov es, di lea di, buffer mov ax, -1234 ITOA2 ;Leaves string in BUFFER and ;ES:DI pointing at end of string. Description: These routines convert an integer value to a string of characters which represent that integer. AX contains the signed integer you wish to convert. ITOAM automatically allocates storage on the heap for the resulting string, you do not have to pre-allocate this storage. ITOAM returns a pointer to the (zero-terminated) string in the ES:DI registers. It ignores the values in ES:DI on input. ITOA requires that the caller allocate the storage for the string (maximum you will need is seven bytes) and pass a pointer to this buffer in ES:DI. ITOA returns with ES:DI pointing at the beginning of the converted string. ITOA2 also requires that you pass in the address of a buffer in the ES:DI register pair. However, it returns with ES:DI pointing at the zero-terminating byte of the string. This lets you easily build up longer strings via multiple calls to routines like ITOA2. Include: stdlib.a Routine: UTOA (2,M) --------------------- Category: Conversion Routine Registers on entry: AX - unsigned 16-bit integer to convert to a string ES:DI- Pointer to buffer to hold result (UTOA/UTOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (UTOA/UTOAM only). ES:DI- Pointer to zero-terminating byte of converted string (UTOA2 only). Flags affected: Carry set denotes malloc error (UTOAM only) Example of Usage: mov ax, 65000 utoa puts free mov di, seg buffer mov es, di lea di, buffer mov ax, -1234 ITOA ;Leaves string in BUFFER. mov di, seg buffer mov es, di lea di, buffer mov ax, -1234 ITOA2 ;Leaves string in BUFFER and ;ES:DI pointing at end of string. Description: UTOAx converts a 16-bit unsigned integer value in AX to a string of characters which represents that value. UTOA, UTOA2, and UTOAM behave in a manner analogous to ITOAx. See the description of those routines for more details. Include: stdlib.a Routine: HTOA (2,M) --------------------- Category: Conversion Routine Registers on entry: AL - 8-bit integer to convert to a string ES:DI- Pointer to buffer to hold result (HTOA/HTOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (HTOA/HTOAM only). ES:DI- Pointer to zero-terminating byte of converted string (HTOA2 only). Flags affected: Carry set denotes memory allocation error (HTOAM only) Description: The HTOAx routines convert an 8-bit value in AL to the two- character hexadecimal representation of that byte. Other that that, they behave just like ITOAx/UTOAx. Note that the resulting buffer must have at least three bytes for HTOA/HTOA2. Include: stdlib.a Routine: WTOA (2,M) -------------------- Category: Conversion Routine Registers on Entry: AX- 16-bit value to convert to a string ES:DI- Pointer to buffer to hold result (WTOA/WTOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (WTOA/WTOAM only). ES:DI- Pointer to zero-terminating byte of converted string (WTOA2 only). Flags Affected: Carry set denotes memory allocation error (WTOAM only) Example of Usage: Like WTOA above Description: WTOAx converts the 16-bit value in AX to a string of four hexadecimal digits. It behaves exactly like HTOAx except it outputs four characters (and requires a five byte buffer). Include: stdlib.a Routine: LTOA (2,M) -------------------- Category: Conversion Routine Registers on entry: DX:AX (contains a signed 32 bit integer) ES:DI- Pointer to buffer to hold result (LTOA/LTOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (LTOA/LTOAM only). ES:DI- Pointer to zero-terminating byte of converted string (LTOA2 only). Flags affected: Carry set if memory allocation error (LTOAM only) Example of Usage: mov di, seg buffer ;Get address of storage mov es, di ; buffer. lea di, buffer mov ax, word ptr value mov dx, word ptr value+2 ltoa Description: LtoA converts the 32-bit signed integer in DX:AX to a string of characters. LTOA stores the string at the address specified in ES:DI (there must be at least twelve bytes available at this address) and returns with ES:DI pointing at this buffer. LTOA2 works the same way, except it returns with ES:DI pointing at the zero terminating byte. LTOAM allocates storage for the string on the heap and returns a pointer to the string in ES:DI. Include: stdlib.a Routine: ULTOA (2,M) --------------------- Category: Conversion Routine Registers on Entry: DX:AX- Unsigned 32-bit value to convert to a string ES:DI- Pointer to buffer to hold result (LTOA/LTOA2 only). Registers on Return: ES:DI- Pointer to string containing converted characters (LTOA/LTOAM only). ES:DI- Pointer to zero-terminating byte of converted string (LTOA2 only). Flags Affected: Carry is set if malloc error (ULTOAM only) Example of Usage: Like LTOA Description: Like LTOA except this routine handles unsigned integer values. Include: stdlib.a Routine: SPrintf (2,M) ----------------------- Category: Conversion Routine In-Memory Formatting Routine Registers on entry: CS:RET - Pointer to format string and operands of the sprintf routine ES:DI- Address of buffer to hold output string (sprintf/sprintf2 only) Register on return: ES:DI register - pointer to a string containing output data (sprintf/sprintfm only). Pointer to zero-terminating byte at the end of the converted string (sprintf2 only). Flags affected: Carry is set if memory allocation error (sprintfm only). Example of Usage: sprintfm db "I=%i, U=%u, S=%s",13,10,0 db i,u,s puts free Description: SPrintf is an in-memory formatting routine. It is similar to C's sprintf routine. The programmer selects the maximum length of the output string. SPrintf works in a manner quite similar to printf, except sprintf writes its output to a string variable rather than to the stdlib standard output. SPrintfm, by default, allocates 2048 characters for the string and then deallocates any unnecessary storage. An external variable, sp_MaxBuf, holds the number of bytes to allocate upon entry into sprintfm. If you wish to allocate more or less than 2048 bytes when calling sprintf, simply change the value of this public variable (type is word). Sprintfm calls malloc to allocate the storage dynamically. You should call free to return this buffer to the heap when you are through with it. Sprintf and Sprintf2 expect you to pass the address of a buffer to them. You are responsible for supplying a sufficiently sized buffer to hold the result. Include: stdlib.a Routine: SScanf ---------------- Category: Conversion Routine Formatted In-Memory Conversion Routine Registers on Entry: ES:DI - points at string containing values to convert Registers on return: None Flags affected: None Example of Usage: ; this code reads the values for i, j, and s from the characters ; starting at memory location Buffer. les di, Buffer SScanf db "%i %i %s",0 dd i, j, s Description: SScanf provides formatted input in a fashion analogous to scanf. The difference is that scanf reads in a line of text from the stdlib standard input whereas you pass the address of a sequence of characters to SScanf in es:di. Include: stdlib.a Routine: ToLower ----------------- Category: Conversion Routine Register on entry: AL- Character to (possibly) convert to lower case. Register on return: AL- Converted character. Flags affected: None Example of usage: mov al, char ToLower Description: ToLower checks the character in the AL register, if it is upper case it converts it to lower case. If it is anything else, ToLower leaves the value in AL unchanged. For high performance this routine is implemented as a macro rather than as a procedure call. This routine is so short you would spend more time actually calling the routine than executing the code inside. However, the code is definitely longer than a (far) procedure call, so if space is critical and you're invoking this code several times, you may want to convert it to a procedure call to save a little space. Include: stdlib.a Routine: ToUpper ------------------ Category: Conversion Routine Registers on Entry: AL- Character to (possibly) convert to upper case Registers on Return: AL- Converted character Flags Affected: None Example of Usage: mov al, char ToUpper Description: ToUpper checks the character in the AL register, if it is lower case it converts it to upper case. If it is anything else, ToUpper leaves the value in AL unchanged. For high performance this routine is implemented as a macro rather than as a procedure call (see ToLower, above). Include: stdlib.a Utility Routines ---------------- The following routines are all Utility Routines. The first routines listed below compute the number of print positions required by a 16-bit and 32-bit signed and unsigned integer value. UlSize is like the LSize except it treats the value in DX:AX as an unsigned long integer. The next set of routines in this section check the character in the AL register to see whether it is a hexidecimal digit, if it alphabetic, if it is a lower case alphabetic, if it is a upper case alphabetic, and if it is numeric. Then there are some miscellaneous routines (macros) which process command line parameters, invoke DOS and exit the program. Routine: ISize --------------- Category: Utility Routine Register on entry: AX- 16-bit value to compute the output size for. Register on return: AX- Number of print positions required by this number (including the minus sign, if necessary). Flags affected: None Example of usage: mov ax, I ISize puti ;Prints positions ;req'd by I. Description: This routine computes the number of print positions required by a 16-bit signed integer value. ISize computes the minimum number of character positions it takes to print the signed decimal value in the AX register. If the number is negative, it will include space for the minus sign in the count. Include: stdlib.a Routine: USize --------------- Category: Utility Routine Register on entry: AX- 16 bit value to compute the output size for Register on return: AX- number of print positions required by this number (including the minus sign, if necessary) Flags affected: None Example of usage: mov ax, I USize puti ;prints position ;required by I Description: This routine computes the number of print positions required by a 16-bit signed integer value. It also computes the number of print positions required by a 16-bit unsigned value. USize computes the minimum number of character positions it will take to print an unsigned decimal value in the AX register. If the number is negative, it will include space for the minus sign in the count. Include: stdlib.a Routine: LSize --------------- Category: Utility Routine Register on entry: DX:AX - 32-bit value to compute the output size for. Register on return: AX - Number of print positions required by this number (including the minus sign, if necessary). Flags affected: None Example of Usage: mov ax, word ptr L mov dx, word ptr L+2 LSize puti ;Prints positions ;req'd by L. Description: This routine computes the number of print positions required by a 32-bit signed integer value. LSize computes the minimum number of character positions it will take to print the signed decimal value in the DX:AX registers. If the number is negative, it will include space for the minus sign in the count. Include: stdlib.a Routine: ULSize ---------------- Category: Utility Routine Registers on Entry: DX:AX - 32-bit value to compute the output size for. Registers on return: AX - number of print positions required by this number Flags affected: None Example of Usage: mov ax, word ptr L mov dx, word ptr L+2 ULSize puti ; Prints positions req'd by L Description: ULSize computes the minimum number of character positions it will take to print an unsigned decimal value in the DX:AX registers. Include: stdlib.a Routine: IsAlNum ----------------- Category: Utility routine Register on entry: AL - character to check. Register on return: None Flags affected: Zero flag - set if character is alphanumeric, clear if not. Example of usage : mov al, char IsAlNum je IsAlNumChar Description : This routine checks the character in the AL register to see if it is in the range A-Z, a-z, or 0-9. Upon return, you can use the JE instruction to check to see if the character was in this range (or, conversely, you can use JNE to see if it is not in range). Include: stdlib.a Routine: IsXDigit ------------------ Category: Utility Routine Register on Entry: AL- character to check Registers on Return: None Flags Affected: Zero flag- Set if character is a hex digit, clear if not Example of Usage: mov al, char IsXDigit je IsXDigitChar Description: This routine checks the character in the AL register to see if it is in the range A-F, a-f, or 0-9. Upon return, you can use the JE instruction to check to see if the character was in this range (or, conversely, you can use jne to see if it is not in the range). Include: stdlib.a Routine: IsDigit ------------------ Category: Utility Routine Register on entry: AL- Character to check Register on return: None Flags affected: Zero flag- set if character is numeric, clear if not. Example of Usage: mov al, char IsDigit je IsDecChar Description: This routine checks the character in the AL register to see if it is in the range 0-9. Upon return, you can use the JE instruction to check to see if the character was in the range (or, conversely, you can use JNE to see if it is not in the range). Include: stdlib.a Routine: IsAlpha ------------------ Category: Utility Routine Register on entry: AL- Character to check Register on return: None Flags affected: Zero flag- set if character is alphabetic, clear if not. Example of Usage: mov al, char IsAlpha je IsAlChar Description: This routine checks the character in the AL register to see if it is in the range A-Z or a-z. Upon return, you can use the JE instruction to check to see if the character was in the range (or, conversely, you can use JNE to see if it is not in the range). Include: stdlib.a Routine: IsLower ---------------- Category: Utility Routine Registers on Entry: AL- character to test Registers on Return: None Flags Affected: Zero = 1 if character is a lower case alphabetic character Zero = 0 if character is not a lower case alphabetic character Example of Usage: mov AL, char ; put char in AL IsLower ; is char lower a-z? je IsLowerChar ; if yes, jump to IsLowerChar Description: This routine checks the character in the AL register to see if it is in the range a-z. Upon return, you can use the JE instruction to check and see if the character was in this range (or you can use JNE to check and see if the character was not in this range). This procedure is implemented as a macro for high performance. Include: stdlib.a Routine: IsUpper ----------------- Category: Utility Routine Registers on Entry: AL- character to check Registers on Return: None Flags Affected: Zero flag - set if character is uppercase alpha, clear if not. Example of Usage: mov al, char IsUpper je IsUpperChar Description: This routine checks the character in the AL register to see if it is in the ranger A-Z. Upon return, you can use the JE instruction to check to see if it not in the range). It uses macro implementation for high performance. Include: stdlib.a Routine: Argc -------------- Category: Utility Routine Registers on Entry: None Registers on Return: CX- Number of command line parameters Flags Affected: None Example of Usage: print db "There were ",0 argc mov ax, cx puti print db " command line parameters here",cr,lf,0 Description: This routine returns the number of command line para- meters on the DOS command line. Note that strings enclosed in quotation marks or apostrophes are counted as a single command line parameter. Include: stdlib.a Routine: Argv -------------- Category: Utility Routine Registers on Entry: AX- Which parameter to grab (1..n). PSP- Global variable containing the DOS program segment prefix value. Registers on Return: ES:DI- Pointer to string on heap containing the specified parameter (empty string if the parameter does not exist). Flags Affected: carry- Set if malloc error. Example of Usage: mov ax, 2 argv print db "The second command line parameter is ",0 puts free Description: This routine returns a string containing the specified command line argument. You must pass the position number of the argument in AX; this routine returns the specified string on the heap with ES:DI pointing at the string. Note that the command line parameters are numbered starting from one. If you specify an out of range value, this routine returns a pointer to a zero byte (the empty string). Include: stdlib.a Routine: GetEnv ---------------- Category: Utility Routine Registers on Entry: ES:DI- Points at a string containing the name of the environment variable you want to find. PSP- Global variable containing the DOS program segment prefix value. Registers on Return: ES:DI- Pointer to string in the environment space containing the characters immediately after the name of the environment variable in the environment string space. Flags Affected: carry- Set if malloc error. Example of Usage: les di, EnvVarStrPtr getenv print db "The value of the environment variable is ",0 puts free Description: This routine returns a pointer to the first characters following an environment variable in the program's environment variable space. It points at the very first character following the name, so it typically points at an equal sign (e.g., the PATH environment variable is typically of the form "PATH=xxxxxxxx" and the "=" is the first char past the name). If this routine does not find the specified environment variable, it returns a pointer to a single zero byte. Since the pointer is in the environment space, you should not store anything at this address. Instead, first copy the string with STRDUP if you need to modify it. Include: stdlib.a Routine: DOS ------------- Category: Utility Routine Registers on Entry: AH- DOS opcode Registers on Return: Depends on particular DOS call Flags Affected: Depends on DOS call. Example of Usage: mov ah, 9 DOS . . . DOS 7 Description: This macro invokes DOS via the INT 21h interrupt. If there is no parameter to the macro, it simply issues the INT 21h instruction. If a parameter is present, it emits "mov ah, operand" followed by the INT 21h instruction. Include: stdlib.a Routine: ExitPgm ----------------- Category: Utility Routine Registers on Entry: None Registers on Return: Doesn't return Flags Affected: N/A Example of Usage: ExitPgm Description: This macro exits the program and returns to DOS. Include: stdlib.a String Handling Routines ------------------------ Manipulating text is a major part of many computer applications. Typically, strings are inputed and interpreted. This interpretation may involve some chores such as extracting certain part of the text, copying it, or comparing with other strings. The string manipulation routines in C provides various functions. Therefore, the stdlib has some C-like string handling functions (e.g. strcpy, strcmp). In C a string is an array of characters; similarly, the string are terminated by a "0" as a null character. In general, the input strings of these routines are pointed by ES:DI. In some routines, the carry flag will be set to indicate an error. The following string routines take as many as four different forms: strxxx, strxxxl, strxxxm, and strxxxlm. These routines differ in how they store the destination string into memory and where they obtain their source strings. Routines of the form strxxx generally expect a single source string address in ES:DI or a source and destination string in ES:DI & DX:SI. If these routines produce a string, they generally store the result into the buffer pointed at by ES:DI upon entry. They return with ES:DI pointing at the first character of the destination string. Routines of the form strxxxl have a "literal source string". A literal source string follows the call to the routine in the code stream. E.g., strcatl db "Add this string to ES:DI",0 Routines of the form strxxxm automatically allocate storage for a source string on the heap and return a pointer to this string in ES:DI. Routines of the form strxxxlm have a literal source string in the code stream and allocate storage for the destination string on the heap. Routine: Strcpy (l) -------------------- Category: String Handling Routine Registers on Entry: ES:DI - pointer to source string (Strcpy only) CS:RET - pointer to source string (Strcpy1 only) DX:SI - pointer to destination string Registers on return: ES:DI - points at the destination string Flags affected: None Example of Usage: mov dx, seg Dest mov si, offset Dest mov di, seg Source mov es, di mov si, offset Source Strcpy mov dx, seg Dest mov si, offset Dest Strcpyl db "String to copy",0 Description: Strcpy is used to copy a zero-terminated string from one location to another. ES:DI points at the source string, DX:SI points at the destination address. Strcpy copies all bytes, up to and including the zero byte, from the source address to the destination address. The target buffer must be large enough to hold the string. Strcpy performs no error checking on the size of the destination buffer. Strcpyl copies the zero-terminated string immediately following the call instruction to the destination address specified by DX:SI. Again, this routine expects you to ensure that the taraget buffer is large enough to hold the result. Note: There are no "Strcpym" or "Strcpylm" routines. The reason is simple: "StrDup" and "StrDupl" provide these functions using names which are familiar to MSC and Borland C users. Include: stdlib.a Routine: StrDup (l) -------------------- Category: String Handling Routine Register on entry: ES:dI - pointer to source string (StrDup only). CS:RET - Pointer to source string (StrDupl only). Register on return: ES:DI - Points at the destination string allocated on heap. Carry=0 if operation successful. Carry=0 if insufficient memory for new string. Flags affected: Carry flag Example of usage: StrDupl db "String for StrDupl",0 jc MallocError mov word ptr Dest1, di mov word ptr Dest1+2, es ;create another ;copy of this ;string. Note ;that es:di points ;at Dest1 upon ;entry to StrDup, ;but it points at ;the new string on ;exit StrDup jc MallocError mov word ptr Dest2, di mov word ptr Dest2+2, es Description: StrDup and StrDupl duplicate strings. You pass them a pointer to the string (in es:di for strdup, via the return address for strdupl) and they allocate sufficient storage on the heap for a copy of this string. Then these two routines copy their source strings to the newly allocated storage and return a pointer to the new string in ES:DI. Include: stdlib.a Routine: Strlen ---------------- Category: String Handling Routine Registers on entry: ES:DI - pointer to source string. Register on return: CX - length of specified string. Flags Affected: None Examples of Usage: les di, String strlen mov sl, cx printf db "Length of '%s' is %d\n",0 dd String, sl Description: Strlen computes the length of the string whose address appears in ES:DI. It returns the number of characters up to, but not including, the zero terminating byte. Include: stdlib.a Routine: Strcat (m,l,ml) ------------------------- Category: String Handling Routine Registers on Entry: ES:DI- Pointer to first string DX:SI- Pointer to second string (Strcat and Strcatm only) Registers on Return: ES:DI- Pointer to new string (Strcatm and Strcatml only) Flags Affected: Carry = 0 if no error Carry = 1 if insufficient memory (Strcatm and Strcatml only) Example of Usage: les DI, String1 mov DX, seg String2 lea SI, String2 Strcat ; String1 <- String1 + String2 les DI, String1 Strcatl ; String1 <- String1 + db "Appended String",0 ; "Appended String",0 les DI, String1 mov DX, seg String2 lea SI, String2 Strcatm ; NewString <- String1 + String2 puts free les DI, String1 Strcatml ; NewString <- String1 + db "Appended String",0 ; "Appended String",0 puts free Description: These routines concatenate two strings together. They differ mainly in the location of their source and destination operands. Strcat concatenates the string pointed at by DX:SI to the end of the string pointed at by ES:DI in memory. Both strings must be zero-terminated. The buffer pointed at by ES:DI must be large enough to hold the resulting string. Strcat does NOT perform bounds checking on the data. ( continued on next page ) Routine: Strcat (m,l,ml) ( continued ) ----------------------------------------- Strcatm computes the length of the two strings pointed at by ES:DI and DX:SI and attempts to allocate this much storage on the heap. If it is not successful, Strcatm returns with the Carry flag set, otherwise it copies the string pointed at by ES:DI to the heap, concatenates the string DX:SI points at to the end of this string on the heap, and returns with the Carry flag clear and ES:DI pointing at the new (concatenated) string on the heap. Strcatl and Strcatml work just like Strcat and Strcatm except you supply the second string as a literal constant immediately AFTER the call rather than pointing DX:SI at it (see examples above). Include: stdlib.a Routine: Strchr ---------------- Category: String Handling Routine Register on entry: ES:DI- Pointer to string. AL- Character to search for. Register on return: CX- Position (starting at zero) where Strchr found the character. Flags affected: Carry=0 if Strchr found the character. Carry=1 if the character was not present in the string. Example of usage: les di, String mov al, Char2Find Strchr jc NotPresent mov CharPosn, cx Description: Strchr locates the first occurrence of a character within a string. It searches through the zero-terminated string pointed at by es:di for the character passed in AL. If it locates the character, it returns the position of that character to the CX register. The first character in the string corresponds to the location zero. If the character is not in the string, Strchr returns the carry flag set. CX's value is undefined in that case. If Strchr locates the character in the string, it returns with the carry clear. Include: stdlib.a Routine: Strstr (l) -------------------- Category: String Handling Routine Register on entry: ES:DI - Pointer to string. DX:SI - Pointer to substring(strstr). CS:RET - Pointer to substring (strstrl). Register on return: CX - Position (starting at zero) where Strstr/Strstrl found the character. Carry=0 if Strstr/ Strstrl found the character. Carry=1 if the character was not present in the string. Flags affected: Carry flag Example of usage : les di, MainString lea si, Substring mov dx, seg Substring Strstr jc NoMatch mov i, cx printf db "Found the substring '%s' at location %i\n",0 dd Substring, i Description: Strstr searches for the position of a substring within another string. ES:DI points at the string to search through, DX:SI points at the substring. Strstr returns the index into ES:DI's string where DX:SI's string is found. If the string is found, Strstr returns with the carry flag clear and CX contains the (zero based) index into the string. If Strstr cannot locate the substring within the string ES:DI points at, it returns the carry flag set. Strstrl works just like Strstr except it excepts the substring to search for immediately after the call instruction (rather than passing this address in DX:SI). Include: stdlib.a Routine: Strcmp (l) -------------------- Category: String Handling Routine Registers on entry: ES:DI contains the address of the first string DX:SI contains the address of the second string (strcmp) CS:RET (contains the address of the substring (strcmpl) Register on return: CX (contains the position where the two strings differ) Flags affected: Carry flag and zero flag (string1 > string2 if C + Z = 0) (string1 < string2 if C = 1) Example of Usage: les di, String1 mov dx, seg String2 lea si, String2 strcmp ja OverThere les di, String1 strcmpl db "Hello",0 jbe elsewhere Description: Strcmp compares the first strings pointed by ES:DI with the second string pointed by DX:SI. The carry and zero flag will contain the corresponding result. So unsigned branch instructions such as JA or JB is recommended. If string1 equals string2, strcmp will return with CX containing the offset of the zero byte in the two strings. Strcmpl compares the first string pointed by ES:DI with the substring pointed by CS:RET. The carry and zero flag will contain the corresponding result. So unsigned branch instructions such as JA or JB are recommended. If string1 equals to the substring, strcmp will return with CX containing the offset of the zero byte in the two strings. Include: stdlib.a Routine: Strupr (m) -------------------- Category: String Handling Routine Conversion Routine Register on entry: ES:DI (contains the pointer to input string) Register on return: ES:DI (contains the pointer to input string with characters converted to upper case) Note: struprm allocates storage for a new string on the heap and returns the pointer to this routine in ES:DI. Flags affected: Carry = 1 if memory allocation error (Struprm only). Example of Usage: les di, lwrstr1 strupr puts mov di, seg StrWLwr mov es, di lea di, StrWLwr struprm puts free Description: Strupr converts the input string pointed by ES:DI to upper case. It will actually modify the string you pass to it. Struprm first makes a copy of the string on the heap and then converts the characters in this new string to upper case. It returns a pointer to the new string in ES:DI. Include: stdlib.a Routine: Strlwr (m) -------------------- Category: String Handling Routine Conversion Routine Register on entry: ES:DI (contains the pointer to input string) Register on return: ES:DI (contains the pointer to input string with characters converted to lower case). Flags affected: Carry = 1 if memory allocation error (strlwrm only) Example of Usage: les di, uprstr1 strlwr puts mov di, seg StrWLwr mov es, di lea di, StrWLwr strlwrm puts free Description: Strlwr converts the input string pointed by ES:DI to lower case. It will actually modify the string you pass to it. Strlwrm first copies the characters onto the heap and then returns a pointer to this string after converting all the alphabetic characters to lower case. Include: stdlib.a Routine: Strset (m) -------------------- Category: String Handling Routine Register on entry: ES:DI contains the pointer to input string (StrSet only) AL contains the character to copy CX contains number of characters to allocate for the string (Strsetm only) Register on return: ES:DI pointer to newly allocated string (Strsetm only) Flags affected: Carry set if memory allocation error (Strsetm only) Example of Usage: les di, string1 mov al, " " ;Blank fill string. Strset mov cx, 32 mov al, "*" ;Create a new string w/32 Strsetm ; asterisks. puts free Description: Strset overwrites the data on input string pointed by ES:DI with the character on AL. Strsetm creates a new string on the heap with the number of characters specified in CX. All characters in the string are initialized with the value in AL. Include: stdlib.a Routine: Strspan (l) --------------------- Category: String Handling Routine Registers on Entry: ES:DI - Pointer to string to scan DX:SI - Pointer to character set (Strspan only) CS:RET- Pointer to character set (Strspanl only) Registers on Return: CX- First position in scanned string which does not contain one of the characters in the character set Flags Affected: None Example of Usage: les DI, String mov DX, seg CharSet lea SI, CharSet Strspan ; find first position in String with a mov i, CX ; char not in CharSet printf db "The first char which is not in CharSet " db "occurs at position %d in String.\n",0 dd i les DI, String Strspanl ; find first position in String which db "aeiou",0 ; is not a vowel mov j, CX printf db "The first char which is not a vowel " db "occurs at position %d in String.\n",0 dd j Description: Strspan(l) scans a string, counting the number of characters which are present in a second string (which represents a character set). ES:DI points at a zero-terminated string of characters to scan. DX:SI (strspan) or CS:RET (strspanl) points at another zero- terminated string containing the set of characters to compare against. The position of the first character in the string pointed to by ES:DI which is NOT in the character set is returned. If all the characters in the string are in the character set, the position of the zero-terminating byte will be returned. Although strspan and (especially) strspanl are very compact and convenient to use, they are not particularly efficient. The character set routines provide a much faster alternative at the expense of a little more space. Include: stdlib.a Routine: Strcspan, Strcspanl ----------------------------- Category: String Handling Routine Registers on Entry: ES:DI - Pointer to string to scan DX:SI - Pointer to character set (Strcspan only) CS:RET- Pointer to character set (Strcspanl only) Registers on Return: CX- First position in scanned string which contains one of the characters in the character set Flags Affected: None Example of Usage: les DI, String mov DX, seg CharSet lea SI, CharSet Strcspan ; find first position in String with a mov i, CX ; char in CharSet printf db "The first char which is in CharSet " db "occurs at position %d in String.\n",0 dd i les DI, String Strcspanl ; find first position in String which db "aeiou",0 ; is a vowel. mov j, CX printf db "The first char which is a vowel occurs " db "at position %d in String.\n",0 dd j Description: Strcspan(l) scans a string, counting the number of characters which are NOT present in a second string (which represents a character set). ES:DI points at a zero-terminated string of characters to scan. DX:SI (strcspan) or CS:RET (strcspanl) points at another zero-terminated string containing the set of characters to compare against. The position of the first character in the string pointed to by ES:DI which is in the character set is returned. If all the characters in the string are not in the character set, the position of the zero-terminating byte will be returned. Although strcspan and strcspanl are very compact and convenient to use, they are not particularly efficient. The character set routines provide a much faster alternative at the expense of a little more space. Include: stdlib.a Routine: StrIns (m,l,ml) ------------------------- Category: String Handling Routine Registers on Entry: ES:DI - Pointer to destination string (to insert into) DX:SI - Pointer to string to insert (StrIns and StrInsm only) CX - Insertion point in destination string Registers on Return: ES:DI - Pointer to new string (StrInsm and StrInsml only) Flags Affected: Carry = 0 if no error Carry = 1 if insufficient memory (StrInsm and StrInsml only) Example of Usage: les DI, DestStr mov DX, word ptr SrcStr+2 mov SI, word ptr SrcStr mov CX, 5 StrIns ; Insert SrcStr before the 6th char of DestStr les DI, DestStr mov CX, 2 StrInsl ; Insert "Hello" before the 3rd char of DestStr db "Hello",0 les DI, DestStr mov DX, word ptr SrcStr+2 mov SI, word ptr SrcStr mov CX, 11 StrInsm ; Create a new string by inserting SrcStr ; before the 12th char of DestStr puts putcr free Description: These routines insert one string into another string. ES:DI points at the string into which you want to insert another. CX contains the position (or index) where you want the string inserted. This index is zero-based, so if CX contains zero, the source string will be inserted before the first character in the destination string. If CX contains a value larger than the size of the destination string, the source string will be appended to the destination string. StrIns inserts the string pointed at by DX:SI into the string pointed at by ES:DI at position CX. The buffer pointed at by ES:DI must be large enough to hold the resulting string. StrIns does NOT perform bounds checking on the data. ( continued on next page ) Routine: StrIns (m,l,ml) ( continued ) ----------------------------------------- StrInsm does not modify the source or destination strings, but instead attempts to allocate a new buffer on the heap to hold the resulting string. If it is not successful, StrInsm returns with the Carry flag set, otherwise the resulting string is created and its address is returned in the ES:DI registers. StrInsl and StrInsml work just like StrIns and StrInsm except you supply the second string as a literal constant immediately AFTER the call rather than pointing DX:SI at it (see examples above). Routine: StrDel, StrDelm ------------------------- Category: String Handling Routine Registers on Entry: ES:DI - pointer to string CX - deletion point in string AX - number of characters to delete Registers on return: ES:DI - pointer to new string (StrDelm only) Flags affected: Carry = 1 if memory allocation error, 0 if okay (StrDelm only). Example of Usage: les di, Str2Del mov cx, 3 ; Delete starting at 4th char mov ax, 5 ; Delete five characters StrDel ; Delete in place les di, Str2Del2 mov cx, 5 mov ax, 12 StrDelm puts free Description: StrDel deletes characters from a string. It works by computing the beginning and end of the deletion point. Then it copies all the characters from the end of the deletion point to the end of the string (including the zero byte) to the beginning of the deletion point. This covers up (thereby effectively deleting) the undesired characters in the string. Here are two degenerate cases to worry about -- 1) when you specify a deletion point which is beyond the end of the string; and 2) when the deletion point is within the string but the length of the deletion takes you beyond the end of the string. In the first case StrDel simply ignores the deletion request. It does not modify the original string. In the second case, StrDel simply deletes everything from the deletion point to the end of the string. StrDelm works just like StrDel except it does not delete the characters in place. Instead, it creates a new string on the heap consisting of the characters up to the deletion point and those following the characters to delete. It returns a pointer to the new string on the heap in ES:DI, assuming that it properly allocated the storage on the heap. Include: stdlib.a Routine: StrRev, StrRevm ------------------------- Author: Michael Blaszczak (.B ekiM) Category: String Handling Routine Registers on Entry: ES:DI - pointer to string Registers on return: ES:DI - pointer to new string (StrRevm only). Flags affected: Carry = 1 if memory allocation error, 0 if okay (StrRevm only). Example of Usage: Description: StrRev reverses the characters in a string. StrRev reverses, in place, the characters in the string that ES:SI points at. StrRevm creates a new string on the heap (which contains the characters in the string ES:DI points at, only reversed) and returns a pointer to the new string in ES:DI. If StrRevm cannot allocate sufficient memory for the string, it returns with the carry flag set. Include: stdlib.a Routine: ToHex --------------- Category: String Handling Routine/ Conversion Routine Registers on Entry: ES:DI - pointer to byte array BX- memory base address for bytes CX- number of entries in byte array Registers on return: ES:DI - pointer to Intel Hex format string. Flags affected: Carry = 1 if memory allocation error, 0 if okay Example of Usage: mov bx, 100h ;Put data at address 100h in hex file. mov cx, 10h ;Total of 16 bytes in this array. les di, Buffer ;Pointer to data bytes ToHex ;Convert to Intel HEX string format. puts ;Print it. Description: ToHex converts a stream of binary values to Intel Hex format. Intel HEX format is a common ASCII data interchange format for binary data. It takes the following form: : BB HHLL RR DDDD...DDDD SS (Note:spaces were added for clarity, they are not actually present in the hex string) BB is a pair of hex digits which represent the number of data bytes (The DD entries) and is the value passed in CX. HHLL is the hexadecimal load address for these data bytes (passed in BX). RR is the record type. ToHex always produces data records with the RR field containing "00". If you need to output other field types (usually just an end record) you must create that string yourself. ToHex will not do it. DD...DD is the actual data in hex form. This is the number of bytes specified in the BB field. SS is the two's complement of the checksum (which is the sum of the binary values of the BB, HH, LL, RR, and all DD fields). This routine allocates storage for the string on the heap and returns a pointer to that string in ES:DI. Include: stdlib.a Memory Management Routines -------------------------- The stdlib memory management routines let you dynamically allocate storage on the heap. These routines are somewhat similar to those provided by the "C" programming language. However, these routines do not perform garbage collection, as this would introduce too many restrictions and have a very adverse effect on speed. The following paragraph gives a description of how the memory management routines work. These routines may be updated in future revisions, however, so you should never make assumptions about the structure of the memory management record (described below) or else your code may not work on the next revision. The allocation/deallocation routines should be fairly fast. Malloc and free use a modified first/next fit algorithm which lets the system quickly find a memory block of the desired size without undue fragmentation problems (average case). The memory manager data structure has an overhead of eight bytes (meaning each malloc operation requires at least eight more bytes than you ask for) and a granularity of 16 bytes. The overhead (eight bytes) per allocated block may seem rather high, but that is part of the price to pay for faster malloc and free routines. All pointers are far pointers and each new item is allocated on a paragraph boundary. The current memory manager routines always allocate (n+8) bytes, rounding up to the next multiple of 16 if the result is not evenly divisible by sixteen. The first eight bytes of the structure are used by the memory management routines, the remaining bytes are available for use by the caller (malloc, et. al., return a pointer to the first byte beyond the memory management overhead structure). Routine: MemInit ----------------- Category: Memory Management Routine Registers on Entry: DX - number of paragraphs to reserve Globals Affected: zzzzzzseg - segment name of the last segment in your program PSP - public word variable which holds the PSP value for your program Registers on return: CX - number of paragraphs actually reserved by MemInit Flags affected: Carry = 0 if no error. Carry = 1 if error; AX contains DOS error code. Example of Usage: ; Don't forget to set up PSP ; and zzzzzzseg before calling ; MemInit mov dx, dx ; Allocate all available RAM MemInit jc MemoryError ; CX contains the number of ; paragraphs actually ; allocated Description: This routine initializes the memory manager system. You must call it before using any routines which call any of the memory manager procedures (since a good number of the stdlib routines call the memory manager, you should get in the habit of always calling this routine.) The system will "die a horrible death" if you call a memory manager routine (like malloc) without first calling MemInit. This routine expects you to define (and set up) two global names: zzzzzzseg and PSP. "zzzzzzseg" is a dummy segment which must be the name of the very last segment defined in your program. MemInit uses the name of this segment to determine the address of the last byte in your program. If you do not declare this segment last, the memory manager will overwrite anything which follows zzzzzzseg. The "shell.asm" file provides you with a template for your programs which properly defines this segment. PSP should be a word variable which contains the program segment prefix value for your program. MS-DOS passes the PSP value to your program in the DS and ES registers. You should save this value in the PSP variable. Don't forget to make PSP a public symbol in your main program's source file. The "shell.asm" file demonstrates how to properly set up this value. The DX register contnains the number of 16-byte paragraphs you want to reserve for the heap. If DX contains zero, MemInit will allocate all of the available memory to the heap. If your program is going to allow the user to run a copy of the command interpreter, or if your program is going to EXEC some other program, you should not allocate all storage to the heap. Instead, you should reserve some memory for those programs. By setting DX to some value other than zero, you can tell MemInit how much memory you want to reserve for the heap. All left over memory will be available for other system (or program) use. If the value in DX is larger than the amount of available RAM, MemInit will split the available memory in half and reserve half for the heap leaving the other half unallocated. If you want to force this situation (to leave half available memory for other purposes), simply load DX with 0FFFFH before calling MemInit. There will never be this much memory available, so this will force MemInit to split the available RAM between the heap and unallocated storage. On return from MemInit, the CX register contains the number of paragraphs actually allocated. You can use this value to see if MemInit has actually allocated the number of paragraphs you requested. You can also use this value to determine how much space is available when you elect to split the free space between the heap and the unallocated portions. If all goes well, this routine returns the carry flag clear. If a DOS memory manager error occurs, this routine returns the carry flag set and the DOS error code in the AX register. Include: stdlib.a Routine: Malloc ---------------- Category: Memory Management Routine Registers on Entry: CX - number of bytes to reserve Registers on return: CX - number of bytes actually reserved by Malloc ES:DI - ptr to 1st byte of memory allocated by Malloc Flags affected: Carry=0 if no error. Carry=1 if insufficient memory. Example of Usage: mov cx, 256 Malloc jnc GoodMalloc print db "Insufficient memory to continue.",cr,lf,0 jmp Quit GoodMalloc: mov es:[di], 0 ;Init string to NULL Description: Malloc is the workhorse routine you use to allocate a block of memory. You give it the number of bytes you need and if it finds a block large enough, it will allocate the requested amount and return a pointer to that block. Most memory managers require a small amount of overhead for each block they allocate. Stdlib's (current) memory manager requires an overhead of eight bytes. Furthermore, the grainularity is 16 bytes. This means that Malloc always allocates blocks of memory in paragraph multiples. Therefore, Malloc may actually reserve more storage than you specify. Therefore, the value returned in CX may be somewhat greater than the requested value. By setting the minimum allocation size to a paragraph, however, the overhead is reduced and the speed of Malloc is improved by a considerable amount. Stdlib's memory management does not do any garbage collection. Doing so would place too many demands on Malloc's users. Therefore, it is quite possible for you to fragment memory with multiple calls to maloc, realloc, and free. You could wind up in a situation where there is enough free memory to satisfy your request, but there isn't a single contiguous block large enough for the request. Malloc treats this as an insufficient memory error and returns with the carry flag set. If Malloc cannot allocate a block of the requested size, it returns with the carry flag set. In this situation, the contents of ES:DI is undefined. Attempting to dereference this pointer will produce erratic and, perhaps, disasterous results. Include: stdlib.a Routine: Realloc ----------------- Category: Memory Management Routine Registers on Entry: CX - number of bytes to reserve ES:DI - pointer to block to reallocate. Registers on return: CX - number of bytes actually reserved by Realloc. ES:DI - pointer to first byte of memory allocated by Realloc. Flags affected: Carry = 0 if no error. Carry = 1 if insufficient memory. Example of Usage: mov cx, 1024 ;Change block size to 1K les di, CurPtr ;Get address of block into ES:DI realloc jc BadRealloc mov word ptr CurPtr, di mov word ptr CurPtr+2, es Description: Realloc lets you change the size of an allocated block in the heap. It allows you to make the block larger or smaller. If you make the block smaller, Realloc simply frees (returns to the heap) any leftover bytes at the end of the block. If you make the block larger, Realloc goes out and allocates a block of the requested size, copies the bytes form the old block to the beginning of the new block (leaving the bytes at the end of the new block uninitialized)), and then frees the old block. Include: stdlib.a Routine: Free -------------- Category: Memory Management Routine Registers on Entry: ES:DI - pointer to block to deallocate Registers on return: None Flags affected: Carry = 0 if no error. Carry = 1 if ES:DI doesn't point at a Free block. Example of Usage: les di, HeapPtr Free Description: Free (possibly) deallocates storage allocated on the heap by malloc or Realloc. Free returns this storage to heap so other code can reuse it later. Note, however, that Free doesn't always return storage to the heap. The memory manager data structure keeps track of the number of pointers currently pointing at a block on the heap (see DupPtr, below). If you've set up several pointers such that they point at the same block, Free will not deallocate the storage until you've freed all of the pointers which point at the block. Free usually returns an error code (carry flag = 1) if you attempt to Free a block which is not currently allocated or if you pass it a memory address which was not returned by malloc (or Realloc). By no means is this routine totally robust. If you start calling free with arbitrary pointers in es:di (which happen to be pointing into the heap) it is possible, under certain circumstances, to confuse Free and it will attempt to free a block it really should not. This problem could be solved by adding a large amount of extra code to the free routine, but it would slow it down considerably. Therefore, a little safety has been sacrificed for a lot of speed. Just make sure your code is correct and everything will be fine! Include: stdlib.a Routine: DupPtr ---------------- Category: Memory Manager Routine Registers on Entry: ES:DI - pointer to block Registers on return: None Flags affected: Carry = 0 if no error. Carry = 1 if es:di doesn't point at a free block. Example of Usage: les di, Ptr DupPtr Description: DupPtr increments the pointer count for the block at the specifiied address. Malloc sets this counter to one. Free decrements it by one. If free decrements the value and it becomes zero, free will release the storage to the heap for other use. By using DupPtr you can tell the memory manager that you have several pointers pointing at the same block and that it shouldn't deallocate the storage until you free all of those pointers. Include: stdlib.a Routine: IsInHeap ------------------ Category: Memory Management Routine Registers on Entry: ES:DI - pointer to a block Registers on return: None Flags affected: Carry = 0 if ES:DI is a valid pointer. Carry = 1 if not. Example of Usage: les di, MemPtr IsInHeap jc NotInHeap Description: This routine lets you know if es:di contains the address of a byte in the heap somewhere. It does not tell you if es:di contains a valid pointer returned by malloc (see IsPtr, below). For example, if es:di contains the address of some particular element of an array (not necessarily the first element) allocated on the heap, IsInHeap will return with the carry clear denoting that the es:di points somewhere in the heap. Keep in mind that calling this routine does not validate the pointer; it could be pointing at a byte which is part of the memory manager data structure rather than at actual data (since the memory manager maintains that informatnion within the bounds of the heap). This routine is mainly useful for seeing if something is allocated on the heap as opposed to somewhere else (like your code, data, or stack segment). Include: stdlib.a Routine: IsPtr --------------- Category: Memory Management Routine Registers on Entry: ES:DI - pointer to block Registers on return: None Flags affected: Carry = 0 if es:di is a valid pointer. Carry = 1 if not. Example of Usage: les di, MemPtr IsPtr jc NotAPtr Description: IsPtr is much more specific than IsInHeap. This routine returns the carry flag clear if and only if es:di contains the address of a properly allocated (and currently allocated) block on the heap. This pointer must be a value returned by Malloc, Realloc, or DupPtr and that block must be currently allocated for IsPtr to return the carry flag clear. Include: stdlib.a Character Set Routines ---------------------- The character set routines let you deal with groups of characters as a set rather than a string. A set is an unordered collection of objects where membership (presence or absence) is the only important quality. The stdlib set routines were designed to let you quickly check if an ASCII character is in a set, to quickly add characters to a set or remove characters from a set. These operations are the ones most commonly used on character sets. The other operations (like union, intersection, difference, etc.) are useful, but are not as popular as the former routines. Therefore, the data structure has been optimized for sets to handle the membership and add/delete operations at the slight expense of the others. Character sets are implemented via bit vectors. A "1" bit means that an item is present in the set and a "0" bit means that the item is absent from the set. The most common implementation of a character set is to use thirty-two consecutive bytes, eight bytes per, giving 256 bits (one bit for each char- acter in the character set). While this makes certain operations (like assignment, union, intersection, etc.) fast and convenient, other operations (membership, add/remove items) run much slower. Since these are the more important operations, a different data structure is used to represent sets. A faster approach is to simply use a byte value for each item in the set. This offers a major advantage over the thirty-two bit scheme: for operations like membership it is very fast (since all you have got to do is index into an array and test the resulting value). It has two drawbacks: first, oper- ations like set assignment, union, difference, etc., require 256 operations rather than thirty-two; second, it takes eight times as much memory. The first drawback, speed, is of little consequence. You will rarely use the the operations so affected, so the fact that they run a little slower will be of little consequence. Wasting 224 bytes is a problem, however. Especially if you have a lot of character sets. The approach used here is to allocate 272 bytes. The first eight bytes con- tain bit masks, 1, 2, 4, 8, 16, 32, 64, 128. These masks tell you which bit in the following 264 bytes is associated with the set. This facilitates putting eight sets into 272 bytes (34 bytes per character set). This provides almost the speed of the 256-byte set with only a two byte overhead. In the stdlib.a file there is a macro that lets you define a group of character sets: set. The macro is used as follows: set set1, set2, set3, ... , set8 You must supply between one and eight labels in the operand field. These are the names of the sets you want to create. The set macro automatically attaches these labels to the appropriate mask bytes in the set. The actual bit patterns for the set begin eight bytes later (from each label). There- fore, the byte corresponding to chr(0) is staggered by one byte for each set (which explains the other eight bytes needed above and beyond the 256 required for the set). When using the set manipulation routines, you should always pass the address of the mask byte (i.e., the seg/offset of one of the labels above) to the particular set manipulation routine you are using. Passing the address of the structure created with the macro above will reference only the first set in the group. Note that you can use the set operations for fast pattern matching appli- cations. The set membership operation for example, is much faster that the strspan routine found in the string package. Proper use of character sets can produce a program which runs much faster than some of the equivalent string operations. Routine: Createsets -------------------- Category: Character Set Routine Registers on Entry: no parameters passed Registers on return: ES:DI - pointer to eight sets Flags affected: Carry = 0 if no error. Carry = 1 if insufficient memory to allocate storage for sets. Example of Usage: Createsets jc NoMemory mov word ptr SetPtr, di mov word ptr SetPtr+2, es Description: Createsets allocates 272 bytes on the heap. This is sufficient room for eight character sets. It then initializes the first eight bytes of this storage with the proper mask values for each set. Location es:0[di] gets set to 1, location es:1[di] gets 2, location es:2[di] gets 4, etc. The Createsets routine also initializes all of the sets to the empty set by clearing all the bits to zero. Include: stdlib.a Routine: EmptySet ------------------ Category: Character Set Routine Registers on Entry: ES:DI - pointer to first byte of desired set Registers on return: None Flags affected: None Example of Usage: les di, SetPtr add di, 3 ; Point at 4th set in group. Emptyset Description: Emptyset clears out the bits in a character set to zero (thereby setting it to the empty set). Upon entry, es:di must point at the first byte of the character set you want to clear. Note that this is not the address returned by Createsets. The first eight bytes of a character set structure are the addresses of eight different sets. ES:DI must point at one of these bytes upon entry into Emptyset. Include: stdlib.a Routine: Rangeset ------------------ Category: Character Set Routine Registers on entry: ES:DI (contains the address of the first byte of the set) AL (contains the lower bound of the items) AH (contains the upper bound of the items) Registers on return: None Flags affected: None Example of Usage: lea di, SetPtr add di, 4 mov al, 'A' mov ah, 'Z' rangeset Description: This routine adds a range of values to a set with ES:DI as the pointer to the set, AL as the lower bound of the set, and AH as the upper bound of the set (AH has to be greater than AL, otherwise, there will an error). Include: stdlib.a Routine: Addstr (l) -------------------- Category: Character Set Routine Registers on Entry: ES:DI- pointer to first byte of desired set DX:SI- pointer to string to add to set (Addstr only) CS:RET-pointer to string to add to set (Addstrl only) Registers on Return: None Flags Affected: None Example of Usage: les di, SetPtr add di, 1 ;Point at 2nd set in group. mov dx, seg CharStr ;Pointer to string lea si, CharStr ; chars to add to set. addstr ;Union in these characters. ; les di, SetPtr ;Point at first set in group. addstrl db "AaBbCcDdEeFf0123456789",0 ; Description: Addstr lets you add a group of characters to a set by specifying a string containing the characters you want in the set. To Addstr you pass a pointer to a zero-terminated string in dx:si. Addstr will add (union) each character from this string into the set. Addstrl works the same way except you pass the string as a literal string constant in the code stream rather than via ES:DI. Include: stdlib.a Routine: Rmvstr (l) -------------------- Category: Character Set Routine Registers on entry: ES:DI contains the address of first byte of a set DX:SI contains the address of string to be removed from a set (Rmvstr only) CS:RET pointer to string to add to set (Rmvstrl only) Registers on return: None Flags affected: None Example of Usage: les di, SetPtr mov dx, seg CharStr lea si, CharStr rmvstr mov dx, seg CharStr lea si, CharStr rmvstrl db "ABCDEFG",0 Description: This routine is to remove a string from a set with ES:DI pointing to its first byte, and DX:SI pointing to the string to be removed from the set. For Rmvstrl, the string of characters to remove from the set follows the call in the code stream. Include: stdlib.a Routine: AddChar ----------------- Category: Character Set Routine Registers on Entry: ES:DI- pointer to first byte of desired set AL- character to add to the set Registers on Return: None Flags affected: None Example of Usage: les di, SetPtr add di, 1 ;Point at 2nd set in group. mov al, Ch2Add ;Character to add to set. addchar Description: AddChar lets you add a single character (passed in AL) to a set. Include: stdlib.a Routine: Rmvchar ----------------- Category: Character Set Routine Registers on entry: ES:DI (contains the address of first byte of a set) AL (contains the character to be removed) Registers on return: None Flags affected: None Example of Usage: lea di, SetPtr add di, 7 ;Point at eighth set in group. mov al, Ch2Rmv Rmvchar Description: This routine removes the character in AL from a set. ES:SI points to the set's mask byte. The corresponding bit in the set is cleared to zero. Include: stdlib.a Routine: Member ---------------- Category: Character Set Routine Registers on entry: ES:DI (contains the address of first byte of a set) AL (contains the character to be compared) Registers on return: None Flags affected: Zero flag (Zero = 1 if the character is in the set Zero = 0 if the character is not in the set) Example of Usage: les di, SetPtr add di, 1 mov al, 'H' member je IsInSet Description: Member is used to find out if the character in AL is in a set with ES:DI pointing to its mask byte. If the character is in the set, the zero flag is set to 1. If not, the zero flag is set to zero. Include: stdlib.a Routine: CopySet ----------------- Category: Character Set Routine Register on entry: ES:DI- pointer to first byte of destination set. DX:SI- pointer to first byte of source set. Register on Return: None Flags affected: None Example of Usage: les di, SetPtr add di, 7 ;Point at 8th set in group. mov dx, seg SetPtr2 ;Point at first set in group. lea si, SetPtr2 copyset Description: CopySet copies the items from one set to another. This is a straight assignment, not a union operation. After the operation, the destination set is identical to the source set, both in terms of the element present in the set and absent from the set. Include: stdlib.a Routine: SetUnion ------------------ Category: Character Set Routine Register on entry: ES:DI - pointer to first byte of destination set. DX:SI - pointer to first byte of source set. Register on return: None Flags affected: None Example of Usage: les di, SetPtr add di, 7 ;point at 8th set in group. mov dx, seg SetPtr2 ;point at 1st set in group. lea si, sSetPtr2 unionset Description: The SetUnion routine computes the union of two sets. That is, it adds all of the items present in a source set to a destination set. This operation preserves items present in the destination set before the SetUnion operation. Include: stdlib.a Routine: SetIntersect ---------------------- Category: Character Set Routine Register on entry: ES:DI - pointer to first byte of destination set. DX:SI - pointer to first byte of source set. Register on return: None Flags affected: None Example of Usage: les di, SetPtr add di, 7 ;point at 8th set in group. mov dx, seg SetPtr2 ;point at 1st set in group. lea si, SetPtr2 setintersect Description: SetIntersect computes the intersection of two sets, leaving the result in the destination set. The new set consists only of those items which previously appeared in both the source and destination sets. Include: stdlib.a Routine: SetDifference ----------------------- Category: Character Set Routine Register on entry: ES:DI - pointer to the first byte of destination set. DX:SI - pointer to the first byte of the source set. Register on return: None Flags affected: None Example of Usage: les di, SetPtr add di, 7 ;point at 8th set in group. mov dx, seg SetPtr2 ;point at 1st set in group. lea si, SetPtr2 setdifference Description: SetDifference computes the result of (ES:DI) := (ES:DI) - (DX:SI). The destination set is left with its original items minus those items which are also in the source set. Include: stdlib.a Routine: Nextitem ------------------ Category: Character Set Routine Registers on entry: ES:DI (contains the address of first byte of the set) Registers on return: AL (contains the first item in the set) Flags affected: None Example of Usage: les di, SetPtr add di, 7 ;Point at eighth set in group. nextitem Description: Nextitem is the routine to search the first character (item) in the set with ES:DI pointing to its mask byte. AL will return the character in the set. If the set is empty, AL will contain zero. Include: stdlib.a Routine: Rmvitem ----------------- Category: Character Set Routine Registers on entry: ES:DI (contains the address fo first byte of the set) Registers on return: AL (contains the first item in the set) Flags affected: None Example of Usage: les di, SetPtr add di, 7 rmvitem Description: Rmvitem locates the first available item in the set and removes it with ES:DI pointing to its mask byte. AL will return the item removed. If the set is empty, AL will return zero. Include: stdlib.a Floating Point Routines ----------------------- The floating point routines provide a basic floating point package for 80x86 assembly language users. The floating point package deals with four different floating point formats: IEEE 32-bit, 64-bit, and 80-bit formats, and an internal 81-bit format. The external formats mostly support the IEEE standard except for certain esoteric values such as denormalized numbers, NaNs, infinities, and other such cases. The package provides two "pseudo-registers", a floating point accumulator and a floating point operand. It provides routines to load and store these pseudo-registers from memory operands (using the various formats) and then all other operations apply to these two operands. All computations use the internal 81-bit floating point format. The package automatically converts between the internal format and the external format when loading and storing values. Do not write code which assumes the internal format is 81 bits. This format will change in the near future when I get a chance to add guard bits to all the computations. If your code assumes 81 bits, it will break at that point. Besides, there is no reason your code should count on the size of the internal operations anyway. Stick with the IEEE formats and you'll be much better off (since your code can be easily upgraded to deal with numeric coprocessors). WARNING: These routines have not been sufficiently tested as of 10/10/91. Use them with care. Report any problems with these routines to Randy Hyde via the electronic addresses provided in this document or by sending a written report to UC Riverside. As I get more time, I will further test these routines and add additional functions to the package. *** Randy Hyde Routine: lsfpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at a single precision (32-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue lsfpa Description: LSFPA loads a single precision floating point value into the internal floating point accumulator. It also converts the 32-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: ssfpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at a single precision (32-bit) value where this routine should store the floating point acc. Registers on return: None Flags affected: Carry set if conversion error. Example of Usage: les di, FPValue ssfpa Description: SSFPA stores the floating point accumulator into a single precision variable in memory (pointed at by ES:DI). It converts the value from the 81-bit format to the 32-bit value before storing the result. The 64-bit mantissa used by the FP package is rounded to 24 bits during the store. The exponent could be out of range. If this occurs, SSFPA returns with the carry flag set. Include: stdlib.a Routine: ldfpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at a double precision (64-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue ldfpa Description: LDFPA loads a double precision floating point value into the internal floating point accumulator. It also converts the 64-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: sdfpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at a double precision (64-bit) value where this routine should store the floating point acc. Registers on return: None Flags affected: Carry set if conversion error. Example of Usage: les di, FPValue sdfpa Description: SDFPA stores the floating point accumulator into a double precision variable in memory (pointed at by ES:DI). It converts the value from the 81-bit format to the 64-bit value before storing the result. The 64-bit mantissa used by the FP package is rounded to 51 bits during the store. The exponent could be out of range. If this occurs, SDFPA returns with the carry flag set. Include: stdlib.a Routine: lefpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at an extended precision (80-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue lefpa Description: LEFPA loads an extended precision floating point value into the internal floating point accumulator. It also converts the 80-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: lefpal ---------------- Category: Floating point Routine Registers on entry: CS:RET points at an extended precision (80-bit) value to load Registers on return: None Flags affected: None Example of Usage: lefpal dt 1.345e-3 Description: LEFPAL loads an extended precision floating point value into the internal floating point accumulator. It also converts the 80-bit format to the internal 81-bit format used by the floating point package. Unlike LEFPA, LEFPAL gets its operand directly from the code stream. You must follow the call to lefpal with a ten-byte (80-bit) floating point constant. Include: stdlib.a Routine: sefpa --------------- Category: Floating point Routine Registers on entry: ES:DI points at an extended precision (80-bit) value where this routine should store the floating point acc. Registers on return: None Flags affected: Carry set if conversion error. Example of Usage: les di, FPValue sefpa Description: SEFPA stores the floating point accumulator into an extended precision variable in memory (pointed at by ES:DI). It converts the value from the 81-bit format to the 80-bit value before storing the result. The exponent could be out of range. If this occurs, SEFPA returns with the carry flag set. Include: stdlib.a Routine: lsfpo --------------- Category: Floating point Routine Registers on entry: ES:DI points at a single precision (32-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue lsfpo Description: LSFPA loads a single precision floating point value into the internal floating point operand. It also converts the 32-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: ldfpo --------------- Category: Floating point Routine Registers on entry: ES:DI points at a double precision (64-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue ldfpo Description: LDFPO loads a double precision floating point value into the internal floating point operand. It also converts the 64-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: lefpo --------------- Category: Floating point Routine Registers on entry: ES:DI points at an extended precision (80-bit) value to load Registers on return: None Flags affected: None Example of Usage: les di, FPValue lefpo Description: LEFPO loads an extended precision floating point value into the internal floating point operand. It also converts the 80-bit format to the internal 81-bit format used by the floating point package. Include: stdlib.a Routine: lefpol ---------------- Category: Floating point Routine Registers on entry: CS:RET points at an extended precision (80-bit) value to load Registers on return: None Flags affected: None Example of Usage: lefpal dt 1.345e-3 Description: LEFPOL loads an extended precision floating point value into the internal floating point operand. It also converts the 80-bit format to the internal 81-bit format used by the floating point package. Unlike LEFPO, LEFPOL gets its operand directly from the code stream. You must follow the call to lefpal with a ten-byte (80-bit) floating point constant. Include: stdlib.a Routine: itof -------------- Category: Floating point Routine Registers on entry: AX contains a signed integer value Registers on return: None Flags affected: None Example of Usage: mov ax, -1234 itof Description: ITOF converts the 16-bit signed integer in AX to a floating point value, storing the result in the floating point accumuator. Include: stdlib.a Routine: utof -------------- Category: Floating point Routine Registers on entry: AX contains an unsigned integer value Registers on return: None Flags affected: None Example of Usage: mov ax, -1234 itof Description: UTOF converts the 16-bit unsigned integer in AX to a floating point value, storing the result in the floating point accumuator. Include: stdlib.a Routine: ultof --------------- Category: Floating point Routine Registers on entry: DX:AX contains an unsigned 32-bit integer value Registers on return: None Flags affected: None Example of Usage: mov dx, word ptr val32+2 mov ax, word ptr val32 ultof Description: ULTOF converts the 32-bit unsigned integer in DX:AX to a floating point value, storing the result in the floating point accumuator. Include: stdlib.a Routine: ltof -------------- Category: Floating point Routine Registers on entry: DX:AX contains a signed 32-bit integer value Registers on return: None Flags affected: None Example of Usage: mov dx, word ptr val32+2 mov ax, word ptr val32 ltof Description: LTOF converts the 32-bit signed integer in DX:AX to a floating point value, storing the result in the floating point accumuator. Include: stdlib.a Routine: ftoi -------------- Category: Floating point Routine Registers on entry: None Registers on return: AX contains 16-bit signed integer Flags affected: Carry is set if conversion error occurs. Example of Usage: ftoi puti ;Print AX as integer value Description: FTOI converts the floating point accumulator value to a 16-bit signed integer and returns the result in AX. If the floating point number will not fit in AX, FTOI returns with the carry flag set. Include: stdlib.a Routine: ftou -------------- Category: Floating point Routine Registers on entry: None Registers on return: AX contains 16-bit unsigned integer Flags affected: Carry is set if conversion error occurs. Example of Usage: ftou putu ;Print AX as an unsigned value Description: FTOU converts the floating point accumulator value to a 16-bit unsigned integer and returns the result in AX. If the floating point number will not fit in AX, FTOU returns with the carry flag set. Include: stdlib.a Routine: ftol -------------- Category: Floating point Routine Registers on entry: None Registers on return: DX:AX contains a 32-bit signed integer Flags affected: Carry is set if conversion error occurs. Example of Usage: ftol putl ;Print DX:AX as integer value Description: FTOL converts the floating point accumulator value to a 32-bit signed integer and returns the result in DX:AX. If the floating point number will not fit in DX:AX, FTOL returns with the carry flag set. Include: stdlib.a Routine: ftoul --------------- Category: Floating point Routine Registers on entry: None Registers on return: DX:AX contains a 32-bit unsigned integer Flags affected: Carry is set if conversion error occurs. Example of Usage: ftoul putul ;Print DX:AX as an integer value Description: FTOUL converts the floating point accumulator value to a 32-bit unsigned integer and returns the result in DX:AX. If the floating point number will not fit in DX:AX, FTOUL returns with the carry flag set. Include: stdlib.a Routine: fpadd --------------- Category: Floating point Routine Registers on entry: None Registers on return: None Flags affected: None Example of Usage: fpadd Description: FPADD adds the floating point operand to the floating point accumulator leaving the result in the floating point accumulator. Include: stdlib.a Routine: fpsub --------------- Category: Floating point Routine Registers on entry: None Registers on return: None Flags affected: None Example of Usage: fpsub Description: FPSUB subtracts the floating point operand from the floating point accumulator leaving the result in the floating point accumulator. Include: stdlib.a Routine: fpcmp --------------- Category: Floating point Routine Registers on entry: None Registers on return: AX contains result of comparison. Flags affected: As appropriate for a comparison. You can use the conditional branches to check the comparison after calling this routine. Be sure to use the *signed* conditional jumps (e.g., JG, JGE, etc.). Example of Usage: fpcmp jge FPACCgeFPOP Description: FPCMP compares the floating point accumulator to the floating point operand and sets the flags according to the result of the comparison. It also returns a value in AX as follows: AX Result -1 FPACC < FPOP 0 FPACC = FPOP 1 FPACC > FPOP Include: stdlib.a Routine: fpmul -------------- Category: Floating point Routine Registers on entry: None Registers on return: None Flags affected: None Example of Usage: fpmul Description: FPMUL multiplies the floating point accumulator by the floating point operand and leaves the result in the floating point accumulator. Include: stdlib.a Routine: fpdiv --------------- Category: Floating point Routine Registers on entry: None Registers on return: None Flags affected: None Example of Usage: fpdiv Description: FPDIV divides the floating point accumulator by the floating point operand and leaves the result in the floating point accumulator. Include: stdlib.a Routine: ftoa (2,m) -------------------- Category: Floating point Routine Registers on entry: ES:DI points at buffer to hold result (ftoa/ftoa2 only) AL- Field width for floating point value. AH- Number of positions to the right of the dec pt. Registers on return: ES:DI points at beginning of string (ftoa/ftoam only) ES:DI points at zero terminating byte (ftoa2 only) Flags affected: Carry is set if malloc error (ftoam only) Example of Usage: mov di, seg buffer mov es, di lea di, buffer mov ah, 2 ;Two digits after "." mov al, 10 ;Use a total of ten positions ftoa Description: FTOA (2,M) converts the value in the floating point accumulator to a string of characters which represent that value. These routines use a decimal representation. The value in AH is the number of digits to put after the decimal point, AL contains the total field width (including room for the sign and decimal point). The field width specification works just like Pascal or FORTRAN. If the number will not fit in the specified field width, FTOA outputs a bunch of "#" characters. FTOA stores the converted string at the address specified by ES:DI upon entry. There must be at least AL+1 bytes at this address. It returns with ES:DI pointing at the start of this buffer. FTOA2 works just like FTOA except it does not preserve DI. It returns with DI pointing at the zero terminating byte. FTOAM allocates storage for the string on the heap and returns a pointer to the converted string in ES:DI. Note: this routine preserves the value in the floating point accumulator but it wipes out the value in the floating point operand. Include: stdlib.a Routine: etoa (2,m) -------------------- Category: Floating point Routine Registers on entry: ES:DI points at buffer to hold result (etoa/etoa2 only) AL- Field width for floating point value. Registers on return: ES:DI points at beginning of string (etoa/etoam only) ES:DI points at zero terminating byte (etoa2 only) Flags affected: Carry is set if malloc error (etoam only) Example of Usage: mov al, 14 ;Use a total of 14 positions etoam puts putcr free Description: ETOA (2,M) converts the value in the floating point accumulator to a string of characters which represent that value. These routines use an exponential (scientific notation) representation. AL contains the field width. It contains the number of print position to use when outputting the number. The field width specification works just like Pascal or FORTRAN. If the number will not fit in the specified field width, ETOA outputs a bunch of "#" characters. ETOA stores the converted string at the address specified by ES:DI upon entry. There must be at least AL+1 bytes at this address. It returns with ES:DI pointing at the start of this buffer. ETOA2 works just like ETOA except it does not preserve DI. It returns with DI pointing at the zero terminating byte. ETOAM allocates storage for the string on the heap and returns a pointer to the converted string in ES:DI. Note: this routine preserves the value in the floating point accumulator but it wipes out the value in the floating point operand. Include: stdlib.a Routine: atof -------------- Category: Floating point Routine Registers on entry: ES:DI points at a string containing the representation of a floating point number in ASCII form. Registers on return: None Flags affected: None Example of Usage: les di, FPStr atof Description: ATOF converts the string pointed at by ES:DI into a floating point value and leaves this value in the floating point accumulator. Legal floating point values are described by the following regular expression: {" "}* {+ | -} ( ([0-9]+ {"." [0-9]*}) | ("." [0-9]+)} {(e | E) {+ | -} [0-9] {[0-9]*}} "{}" denote optional items. "|" denotes OR. "()" groups items together. Include: stdlib.a ****************************************************************************** File I/O Routines Featuring: - Opening and closing files - Creating new files - Deleting files - Renaming files - File "seeking" - Blocked I/O: - Reading from files using getc - Writing to files using putc and puts - File flushing ****************************************************************************** Written by: Mark Radleigh & Brian Harvey ****************************************************************************** fcreate * Creates a new file. * If a file already exists with the requested name, it will be deleted and a new one will take its place. Inputs: ES:DI- Contains address of the filename for the new file Outputs: AX- If no error occured in creating the file, it contains a filehandle number assigned to this file by DOS. If an error has occurred, it contains one of the following error codes: 3 - Path not found 4 - Too many open files 5 - Access denied Carry flag- 0 if no error occured, 1 if error Include: Stdlib.a Updated: 6/14/91 First public release This routine creates a new file on the specified pathname. If no pathname or device is specified, the file will be created in the current working directory. If the file has been successfully created (No errors occured!), then this routine returns in the ax register a number that is the DOS filehandle for this file. Don't lose this value. You will need it when to want to close the file (using fclose). Save the ax register in a variable after the routine call and move the variable back into the ax register before you call the fclose stdlib routine. See documentation for fclose for more information. FILEHANDLE NOTICE: The filehandle returned in the ax register is not the true DOS filehandle for this file. However, this filehandle is too be used when calling the file routines in stdlib. In order to get the true filehandle for a certain file, see the documentation for the stdlib routine, DOSHandle Example: print db "What do you desire to create?",0 gets ;Get filename and store in es:di fcreate ;Call routine to create file jc error ;If the carry flag is set, ;an error has occured. mov fileptr, ax ;Save the filehandle stored in ;the ax register for future ;use fopen * Opens a file for reading or writing. * File I/O depends on value in the al register. Inputs: ES:DI- Contains address of the filename for the file to be opened AL- Contains 0 if the file is to be opened for reading. Contains 1 if the file is to be opened for writing. Outputs: AX- If no error occured in opening the file, it contains a filehandle number assigned to this file by DOS. If an error has occured, it contains one of the following error codes: 2 - File not found 4 - Too many open files 5 - Access denied 12 - Invalid access Carry flag- 0 if no error occured, 1 if error Include: Stdlib.a Updated: 6/14/91 First public release This routine opens a file for reading or writing using the specified filename and directory (any standard DOS file pathway) in ES:DI. Using the stdlib gets routine is an excellent and advisable way (Not to mention an easy way!) of getting the filename in ES:DI. The user must also move one of two values into the al register before calling fopen. To open a file for reading, the al register must contain the value 0 and to open a file for writing, the al register must contain the value 1. If the file has been successfully opened, a filehandle for this file assigned by DOS. Save this filehandle in some sort of variable so you can move it back into the ax register when you call the stdlib routine fclose to close the file. See documentation for fclose for more information. Examine the examples below for a suggested way of saving the filehandle (the example uses a variable called fileptr, but the name is arbritary). FILEHANDLE NOTICE: The filehandle returned in the ax register is not the true DOS filehandle for this file. However, this filehandle is too be used when calling the file routines in stdlib. In order to get the true filehandle for a certain file, see the documentation for the stdlib routine, DOSHandle NOTICE FOR MULTIPLE OPEN FILES: fopen, along with fcreate and fclose, allows the user have up to 10 files open at the same time. In order to keep track of all the filehandles of these open files, it is suggested that a separate variable for the filehandle of each of the open files be used to keep track of the handles. Example for opening mulitple files (same theory applies with fcreate): print db "What do you desire to open?",0 gets ;Get filename and store in es:di mov al, 1 ;1 so the file will be opened ;for writing fopen ;Call routine to open file jc error ;If the carry flag is set, ;an error has occured, so quit! mov fileptr, ax ;Save the filehandle stored in ;the ax register for future ;use print db "What is the 2nd file you wish to open?",0 gets mov al, 1 fopen ;Open 2nd file for writing jc error ;Error?? mov fileptr2,ax ;Save the filehandle for the 2nd ;open file in a separate ;variable Warning: If the file the user wishes to open already exists and the user wants to open it for writing, then the data written to the file will overwrite the pre-exeisting data. See docs for fseek to overcome this problem. Example: ;Open a file for writing print db "What do you desire to open?",0 gets ;Get filename and store in es:di mov al, 1 ;1 so the file will be opened ;for writing fopen ;Call routine to open file jc error ;If the carry flag is set, ;an error has occured, so quit! mov fileptr, ax ;Save the filehandle stored in ;the ax register for future ;use ;Open a file for reading print db "What do you desire to open?",0 gets ;Get filename and store in es:di mov al, 0 ;0 so the file will be opened ;for reading fopen ;Call routine to open file jc error ;If the carry flag is set, ;an error has occured, so quit! mov fileptr, ax ;Save the filehandle stored in ;the ax register for future ;use fclose * Closes an open file * Filehandle for file to be closed needs to be in the ax register Input: AX- Contains the filehandle variable of the file to close. Outputs: AX- If carry flag is set (error occured), then ax contains an error code. If an error has occured, it contains the following error code: 6 - Invalid file handle 10 - Trouble with FREE (memory freeing routine) Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine closes an open file. Once the file is closed no I/O processes can be made on the file. Before calling the routine, fclose, the user must move into the ax register the filehandle assigned to this file when the file was opened or created. The only error that can occur is if the user moved into the ax register a filehandle that does not belong to one of the opened files. The following example demonstrates how to close a file that was opened in one of the fopen examples or the file that was created in the fcreate example, whose filehandle was saved in variable called fileptr. Example: mov ax, fileptr ;Move the DOS filehandle into ;the ax register before ;calling routine fclose ;Close the file cmp ax, 6 ;If the filehandle was an ;invalid filehandle jump to ;user's code for error's je error ;The following code is a continuation in the case that multiple files are ;open. The code close the second open file. mov ax, fileptr2 fclose cmp ax, 6 je error fwriteon * Turns on the write to file mode. * Redirects the ouput of stdlib routines putc and puts to a open file Input: AX- Contains the filehandle of which open file to write data to. Outputs: AX- If an error occurs in attempting to write to a file, ax will contain one of the following error codes: 5 - Accessed denied 6 - Invalid handle Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine turns the write to disk mode on. In other words, it redirects the output of the stdlib putc routine so that instead of writing data to the screen, the data is written to the file whose filehandle is in the ax register when fwriteon is called. The routine that replaces the output device of putc's ouput actually uses what is known as Blocked I/O. Instead of writing one character to the file each time the user calls getc, each character is stored in a buffer in memory. When the buffer contains 256 characters, that buffer is written to the file as a block. The buffer is then cleared and more characters can be read with getc. Using blocked I/O is a lot faster than one character at a time. Along with getc, the stdlib routine gets' ouput is also redirected during fwriteon mode, since in the stdlib, gets actually just calls getc many times. Example: ;This code would appear in a program after a file has been created or opened ;for "gets" mov ax, fileptr ;Move into ax filehandle of ;file to write to fwriteon ;Call function to redirect ;the output of putc and puts puts fwriteoff ;Turn off write to disk mode puts ;The puts must appear after the fwriteoff command because gets automatically ;writes whatever is in ES:DI to the screen (or in this case the file). The puts ;appearing after the writeoff, prints whatever is at ES:DI to the screen. If ;the puts were to appear in the writeoon mode, the string at ES:DI would be ;written to the file twice Example: ;This code would appear in a program after a file has been created or opened ;for "getc" mov ax, fileptr ;Move into ax filehandle of ;file to write to fwriteon ;Call function to redirect ;the output of putc and puts getc putc fwriteoff ;Unlike in the previous example, getc and putc may both appear in the writeon ;mode. The getc will get a character from the keyboard and store it in the al ;register. Putc will then write whatever is in the al register to the ;specified open file. In order for the user to see what character they typed ;in, in the previous example, a putc should appear after the fwriteoff call. ;Since fwriteoff redirects the putc ouput back to normal (See docs for fwriteoff ;for more info) the character in al will be put on the screen. fwriteoff * Turns off the write to file mode * Redirects the output of putc back to normal (the screen!) mode. Include: Stdlib.a Updated: 6/14/91 First public release This routines changes or redirects the ouput of stdlib's putc back to normal. In other words, since the routine fwriteon made the ouput go to a disk file, changing it back to normal means that after this routine is called, all putc's used will print whatever is in the al register to the screen. Example: ;This example gets a character from the keyboard, prints to a disk file and then ;prints to the screen the character in the al register that was entered. mov ax, fileptr ;Move into ax filehandle of ;file to write to fwriteon ;Call function to redirect ;the output of putc and puts getc ;Get character and store in al putc ;Print character in al to file fwriteoff ;Change ouput of putc back to ;normal putc ;Prints character in al to ;screen fflush * Flushes the buffer in an opened write file to that file Inputs: AX- Contains Stdlib filehandle of file whose buffer is to be flushed Outputs: None. Include: Stdlib.a Updated: 6/14/91 First public release This routine takes all data from the buffer associated with the Stdlib filehandle passed in AX and writes it to the file. It then clears the buffer. NOTE: This routine is automatically called on by Fclose. freadon * Turns on the read from file mode * Changes the source of the input for the stdlib function getc Input: AX- Contains the filehandle of which open file to read data from. Output: AL- Contains a character read from the specified file. AX- If an error occurs in attempting to read from a file, ax will contain one of the following error codes: 5 - Access denied 6 - Invalid handle 8 - EOF Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine turns the read from file mode on. It redirects the source from which stdlib's getc routine gets its "character" from. Instead of getting the character from the keyboard, the redirected getc reads a character from a opened file. Actually, this routine uses the blocked I/O idea discussed in the writeon documentation. This routine when called for the first time, meaning the buffer for the current file to be read from is clear, will read it 256 characters from (If there is that many) a file and store it in the buffer. The first character in the buffer is then put in the al register for the user to then use for whatever they wish. The next time the user calls getc (without calling the freadoff rotuine yet) the next character in the buffer will be stored in the al register. When the buffer is empty, another 256 bytes will be read into it. When the routine freadoff is called, any getc routines called after that will get a character from the keyboard. Example: mov ax, fileptr ;Move the filehandle of the ;file to read from into ax freadon ;Turn on read mode! mov cx, 10 ;Set up loop to read 10 ;characters from a file and ;print them to the screen loop1: getc ;Get character from buffer and ;store in al jc error ;If error in reading from file ;jump to user's code for ;handling code putc ;Print character in al to the ;screen loop loop1 freadoff ;turn read mode off from this ;file freadoff * Turns off the read from file mode * Redirects the source of the data for stdlib's getc routine back to normal This routine changes the source from which stdlib's getc routine gets its "character" from back to normal. After calling this routine, instead of reading characters from the disk, using blocked I/O, the getc routine will get it's "character" from the keyboard. For code example of how to use freadoff, see the example of code above for freadon. fseek * Moves the file pointer of a file to anywhere in the file Inputs: SI- Contains the filehandle variable of the file to be used, or "seeked" AL- Contains the offset from where to start the file seeking. 0 - Seek from the begining of the file. 1 - Seek from current pointer position 2 - Seek backwards from the end of file CX:DX- Distance to move in file, in bytes. Outputs: DX:AX- Contains the new file position if no error AX- One of the following error codes if an error occured while "seeking": 1 - Invalid function 6 - Invalid handle Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine allows the user the move the file pointer to any position within a file. You can not move backwards in a file by having a negative value in CX:DX. The value in CX:DX must be an unsigned integer. Example: mov si, fileptr ;Move the filehandle of the ;file to be seeked mov al, 0 ;Start moving pointer from ;beginning of file xor cx, cx ;Clear the cx register mov dx, 10 ;Move file pointer 10 bytes ;into file fseek ;Seek!!! jc error ;Jump to error code if error To find out where the file pointer currently is in the file, first xor cx and dx registers and call fseek. It will return in DX:AX the file pointer's position. mov si, fileptr ;Move the filehandle of the ;file to be seeked mov al, 1 ;Start moving pointer from ;the current position xor cx, cx ;Clear the cx register xor dx, dx ;Clear the dx register fseek ;Seek!!! jc error ;Jump to error code if error ;else DX:AX contains the current ;File pointer position. DOSHandle * Returns in the ax register the true DOS filehandle for a file Input: AX- Contains the filehandle for the file given to the user from stdlib routine, fopen or fcreate Ouputs: AX- Contains the true filehandle given to the requested file by DOS AX- If an error occured, it contains the following error code: 1 - Invalid pseudo-filehandle Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine returns in the ax register the true filehandle variable given by DOS for a particular file. The filehandle returned when calling the stdlib functions, fcreate and fopen, is not the true filehandle for the file used in those routines. The value returned is a value created by the routines, which stores the filehandles for multiple files in a structure in memory. The value returned from those functions is actually the index into the structure to the real filehandle for the file. This function, DOSHandle, returns from this structure in memory the actual filehandle for a file that has been opened. NOTICE: This routine is only useful to those who need to know the real filehandle of a file that has been created or opened with fopen or fcreate. For those who will only be using the File I/O routines provided in stdlib then this routine will be of no importance. It is provided only for advanced assembly language programmers who with to do other things with files and need to know their real filehandle values. Example: mov ax, fileptr ;Move into ax the filehandle ;given to the user file fopen ;or fcreate DOSHandle ;Get the true filehandle for ;a file and store it in the ;ax register mov truehandle, ax frename * Renames a file Input: DX:SI- Contains the original pathname of the file ES:DI- Contains the new pathname of the file Ouputs: AX- Contains one of the following error codes if an error occured: 2 - File not found 5 - Access denied 17 - Not the same device Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine renames the file whose name appears in a string at DX:SI with the name that appears at the string pointed at by ES:DI. If an error occurs, then an appropriate error code appears in the ax register. Example: print db "Enter the source filename: ",0 gets mov dx, es mov si, di print db cr, lf, "Enter the new filename: ",0 gets frename jc error fdel * Deletes a file Input: ES:DI- Contains the address of zero terminated pathname of file Output: AX- Contains one of the following error codes if an error occured: 2 - File not found 5 - Access denied Carry flag- 0 if no error occured, 1 if error. Include: Stdlib.a Updated: 6/14/91 First public release This routine deletes the filename that is in the string that ES:DI points to. Example: print db "Name of file to delete?",0 gets fdel ;Delete the file! jc error ;Jump to error code if an error ====================== Miscellaneous Routines ====================== This routines either defy categorization, or they haven't been properly organized yet. Mostly (like the rest of this library) they have simply been stuck here until somebody gets the time to reorganize *everything*. Routine: Random ---------------- Author: Unknown. Copied off a file on one of the networks, tweaked, and added to the library. Any info on the original author would be appreciated. Category: Miscellaneous Registers on entry: None Registers on return: AX- Contains random number Flags affected: None Example of Usage: random ;Generate random number in AX puti ;Print the random number. Description: This routine computes a 16-bit random number each time you call it. It returns the random number in the AX register. You may treat this as a signed or unsigned value as it utilizes all 16 bits. This code uses an internal table of seed values. If you are interested in producing repeatable sequences of random numbers, please look at the source listings for this file. If you are interested in producing truly random values (well, closer than you will get from this code by calling it right off the bat) look at the randomize routine which tweaks the seed table based on the current time of day clock value. Include: stdlib.a Routine: Randomize ------------------- Author: Unknown. Copied off a file on one of the networks, tweaked, and added to the library. Any info on the original author would be appreciated. Category: Miscellaneous Registers on entry: None Registers on return: None Flags affected: None Example of Usage: randomize ;Randomize the seeds. random ;Get a brand new random number puti ;Print it Description: Random's internal seed table is hard coded. It was designed to produce a sequence of random numbers with a very long period. However, each time you run a program using Random, it will generate the exact same sequence of random numbers. This could be distressing, for example, in a game where after a while the player(s) could memorize some sequence of events based on the random number generator. Randomize uses the time of day clock value to scramble the internal random seed table. If you call randomize before using random the first time, you will generally get a different sequence of random numbers each time you run the program. Note that it is dangerous to call randomize more than once inside any program. The time of day clock is not a random source when invoked fairly often. Furthermore, once the seeds are randomized, random does a pretty good job of randomizing the results. Include: stdlib.a Routine: cpuid --------------- Author: Original implementation was supplied by Intel Corp. Various modifications were made for inclusion into the UCR Standard Library. Category: Miscellaneous Registers on entry: None Registers on return: AX- Contains processor ID (86, 286, 386, or 486. Note 8088=86). BX- Contains coprocessor ID (87, 286, 387, or 487). Note that a true 486 will have an 80487 built-in, 486sx chips, however, will not. Flags affected: None Example of Usage: cpuid cmp ax, 8086 ;Is this an 8086? Description: For those programs which absolutely need to know the CPU in use, CPUID does a reasonable job (in DOS real mode) of figuring this out for you. As with all CPU identification routines, there are bound to be some problems with this one when operating in protected mode. But for normal DOS applications it appears to work great. This routine came straight from the horse's mouth (Intel Corporation) so you can place a little more faith in it than most that are floating around. Intel's blessing doesn't guarantee that this routine is perfect, though; always keep that in mind. Include: stdlib.a =================== SmartArray Routines =================== The SmartArray routines provide a consistent and easy to master interface to vectors, matrices, and higher-dimension arrays. It is a weak attempt at an abstract, encapsulated, array data type (weak because the internal structure is still visible, indeed, intended to be visible, to the main program). These routines include many operations stolen from the APL programming language. As such, they comprise a powerful set of matrix operations. On the other hand, because of their generality, they do not perform as quickly as hand-optimized code doing the same thing. These routines definitely represent a trade-off between ease of use and performance. That is not to say that these routines are all slow. Some operations, like matrix multiplication, are so slow that the overhead of dealing with arrays in this fashion pales in comparison. For other operations (e.g., extracting an element of an array), the overhead required may far exceed the actual work performed. This is why these routines do provide access to the internal data structures. The array access routines come in two basic groups: general array access and array operations. The general array access routines let you allocate arrays, access arrays, initialize arrays, and copy arrays. The array operation routines let you perform high-level operations on the arrays. SmartArrays are described by a descriptor (also called a "dope vector"). This descriptor uses the following data structure: DopeVector struc ArrayData dd ? SizeInBytes dw ? ElementSize dw ? ArrayType db ? NumDimensions db ? DimensionList dw ? ;One word for each dimension DopeVector ends The first double word is a pointer to the actual array data. This is typically (though not necessarily) allocated somewhere on the heap with malloc. The SmartArrays package stores all multi-dimensional arrays in row major order. The second field above, SizeInBytes, gives the total size of the array data. The SmartArray routines use this field for block copies and other operations where it's nice to know the actual size of the array, in bytes. Although SmartArrays are typically allocated on the heap, there is no guarantee of this. In particular, the SmartArray routines make no assumptions about free bytes immediately following the array's data. The SmartArray routines only manipulate the specified number of bytes when treating the array as a whole. The ElementSize field gives the number of bytes per array element. Any value may go here, but the SmartArrays package handles 1, 2, 4, 8, and 10 byte elements best (especially 1, 2, and 4 byte element sizes). Since most arrays use one of these sizes, you're in great shape. The ArrayType field holds the current data type for each element of the array. The NumDimensions field is an small integer which gives the number of dimen- sions in this array. The DimensionList is an array (despite its declaration) containing the number of elements specified in the NumDimensions field. Each entry is a word giving the number of array elements in that dimension. The following array element type values are currently defined: 0- Untyped element. Matches any other type. Defaults to unsigned integer if the type cannot be otherwise determined. 1- Character 2- Boolean 3- Unsigned integer 4- Signed integer 5- Floating point 6- Character String 7- SmartArray Dope Vector 8-63 Reserved for future use 64-127 User-defined types 128- Pointer to untype element 129- Pointer to character 130- Pointer to boolean 131- Pointer to unsigned integer 132- Pointer to signed integer 133- Pointer to floating point 134- Pointer to character string 135- Pointer to SmartArray Dope Vector 136-192 Reserved pointers 192-255 Pointers to user-defined types The following equates appear in the stdlib.a (& stdlib6.a) equates file: SA_untyped = 0 SA_char = 1 SA_boolean = 2 SA_unsigned = 3 SA_integer = 4 SA_float = 5 SA_string = 6 SA_dv = 7 SAp_untyped = 80h SAp_char = 81h SAp_boolean = 82h SAp_unsigned = 83h SAp_integer = 84h SAp_float = 85h SAp_string = 86h SAp_dv = 87h Note that there are two components to an element's type- the actual type field described above and the element size field. These fields must be consistent. The SmartArrays package allows the following combinations: Type Size Description ---- ---- ------------------------------------------------------- 0 >=1 Untyped data can be any size. 1 1 Character type must be one byte long or an error occurs 2 1 Boolean type must be one byte long or an error occurs 3 1,2,4 Unsigned integers must be 1, 2, or 4 bytes long. 4 1,2,4 Signed integers must be 1, 2, or 4 bytes long. 5 4, 8, 10 Floating point values must be 4, 8, or 10 bytes long. 6 >=1 Strings can be any size 7 >= sizeof dv Dope vectors have a minimum size, but not a maximum. >=80h 4 All pointers are four bytes long. The SmartArrays package currently ignores all other types. Note that the SmartArrays package is *strongly typed*. It will refuse, for example, to add the elements of a boolean array to an unsigned integer array. Except for untype arrays, you are not allowed to mix types in an operation. Affected routines return an error code should a type mismatch occur. If you prefer, you can force the SmartArrays package to abort with an error message by defining the "AryErrorAbort" symbol prior to including the stdlib.a (or stdlib6.a) file. The SmartArrays package current defines the following error codes (which also appear as equates in the stdlib.a/stdlib6.a files): AryNoError = 0 ;Should never occur AryTypeMismatch = 1 ;Array type mismatch AryOverflow = 2 ;Arithmetic overflow AryDiv0 = 3 ;Division by zero AryIllegalOp = 4 ;Illegal operation on array AryBounds = 5 ;Array index error AryMemory = 6 ;Memory allocation error AryBadDV = 7 ;Illegal dope vector AryNull = 8 ;Null pointer to array data If an error occurs, the SmartArray routines return with the carry set and the error code in AX. If no error occurs, then the SmartArray routines return with the carry flag clear. This is assuming that you have *not* defined the "AryErrorAbort" symbol before the "include stdlib.a" statement in your program. If you define the "AryErrorAbort" symbol before the include, the calls to the SmartArray routines emit some additional code which checks for any errors. If an error occurs in this case, the system will print an appropriate error message and abort the program. In addition to the array dope vector structure, the stdlib.a/stdlib6.a files also contain a macro for declaring SmartArrays within your program. Although it is perfectly possible to allocate dope vectors on the heap (and, indeed, this is a common occurrence), more often than not it is possible to allocate the dope vectors, and even the array data, in your data segment. The SmartArrays package provides a macro, "array", to specifically aid in this task. The array macro takes the following parameters: array name, element_size, type, dimension_list, opt_initial_values The name is the label you wish to attach to this smart array data structure. This must be a valid assembly language symbol. Note that the symbol must *not* appear in the normal label field. The macro does the processing of this label and it must appear as a parameter to the macro. The element_size parameter must be an integer value which is the number of bytes to allocate for each array element. The type parameter specifies the type of each array element. If the element size and type parameters are incompatible, the array macro will generate an assembly time error. The dimension_list parameter is a list of numbers, separated by commas and surrounded by "<" and ">" which list the number of elements in each array dimension. This list must not be empty and none of the dimension values should be zero. The optional initial values is another list of values surrounded by "<" and ">". This parameter is optional and need not be present. If absent, the array macro generates a dope vector *only*. It initializes the array data pointer field to NULL. If there are values present in the initial values list, the array macro will allocate storage for the array immediately following the dope vector and initializes the array elements to the value(s) in the initial value list. If there are too many items in the initial values list, the array macro ignores the extra values. If there are too few items, the array macro reuses the values from the beginning of the list (over and over again, if necessary). Some examples (no initial values): a1:array [0..1,0..1] of integer2; array a1, 2, SA_integer, <2,2> a2:array [0..7] of unsigned4; array a2, 4, SA_unsigned, <8> a3:array [0..3,0..3,0..3] of real8; array a3, 8, SA_float, <4,4,4> Some examples with initial values: array b1, 2, SA_integer, <4>, <1,2,3,4> array b2, 2, SA_unsigned, <3>, <1,2,3,4> ;ignores "4" array b3, 2, SA_unsigned, <4>, <1,2,3> ;Generates 1,2,3,1 array b4, 2, SA_unsigned, <4,4>, <1,0,0,0,0> The last example generates the following identity matrix: 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 The array macro reuses initial values once it exhausts the list. It also fills the array in row-major order (that is, it fills up the array a row at a time). Since each row in b4 is four bytes long and the initial values list contains five bytes, the first pass through the initial values list creates the follow- ing: 1 0 0 0 0 x x x x x x x x x x x Since the initialization is not complete, the second pass through the initial values list generates: 1 0 0 0 0 1 0 0 0 0 x x x x x x and so on. It is important to note that the array macro ignores row/column boundaries while initializing the array. Array simply treats each array as a one-dimensional object during initialization. The array routines themselves come in three basic forms: general array manip- ulation routines which operate on arrays of any size or dimension, vector operations which operate only on single dimension arrays, and matrix operations which operate on two-dimensional arrays. General array operations typically begin with the letters "Ary", vector operations usually begin with "vect", and matrix routines usually begin with the letters "Mat". All of these routines, despite their name, belong to the SmartArrays package. Routine: AryDVCpy (l) ---------------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray Dope Vector (DV) (AryDVCpy only). CS:IP Points at a SmartArray DV (AryDVCpyl only). Registers on return: ES:DI Points at a new SmartArray DV on the heap. AH Error code (only if error occurs). Flags affected: Carry Error if set. Possible errors: AryMemory AryBounds AryBadDV Example of Usage: les di, array1 AryDVCpy mov word ptr array1too, di mov word ptr array1too+2, es . . . AryDVCpyl DopeVector . . . AryDVCpyl DopeVector dw 2 Description: AryDVCpy duplicates an array dope vector. It allocates storage on the heap for the dope vector and copies the data from the source dope vector to the new dope vector. Note that this does not duplicate the array data. The data pointer in both DVs wind up pointing at the same array data. This routine is mostly useful for generating different "views" of the same array. For example, you could view an array as a vector, matrix, and (possibly) higher dimension array all at the same time by making duplicates of the dope vector and tweaking the array dimension information. AryDVCpyl gets its dope vector information from the code stream. The bytes which immediately follow the call must be a dope vector structure (including any necessary array bounds values). Note that the number of dimension values must exactly match the NumDimensions value. Since the DopeVector structure only provides room for one array bounds values, you must follow the DopeVector structure with additional word values if your array has more than one dimension (see the second AryDVCpyl example above). include: stdlib.a Routine: AryDVCreate --------------------- Category: SmartArray Registers on entry: AL Contains the number of dimensions for this array. Registers on return: ES:DI Points at a new SmartArray DV on the heap. AH Error code (only if error occurs). Flags affected: Carry Error if set. Possible errors: AryMemory Example of Usage: mov al, 3 ;Create a 3-D array. AryDVCreate mov word ptr MewArray, di mov word ptr NewArray+2, es Description: AryDVCreate creates an empty dope vector on the heap and returns a point in ES:DI. All fields are initialized to zero and must be set to something else before actually using the array. include: stdlib.a Routine: AryAlloc ------------------ Category: SmartArray Registers on entry: ES:DI Points at a SmartArray Dope Vector (DV) Registers on return: AH Error code (only if error occurs). Flags affected: Carry Error if set. Possible errors: AryMemory AryBadDV Example of Usage: les di, DVPtr AryAlloc jc Error Description: On entry, ES:DI points at a SmartArray dope vector. This routine goes in and deallocates the array the DV points at (if any, and if it's on the heap), allocates sufficient storage for the array on the heap, and stores the pointer to the array into the pointer field of the DV. Note that this routine returns ES:DI still pointing at the DV, not the allocated array. include: stdlib.a Routine: AryCpy ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) DX:SI Points at a SmartArray DV (dest) Registers on return: AH Error code (only if error occurs). Flags affected: Carry Error if set. Possible errors: AryMemory AryBounds AryBadDV AryNull AryTypeMismatch Example of Usage: les di, DVPtr mov dx, DV2Ptr+2 mov si, DV2Ptr AryCpy jc Error Description: AryCpy copies the data from one array to another. ES:DI points at the DV of the source array, DX:SI points at the DV of the destination array. AryCpy first checks to see if the two DVs are compatible (their types, sizes, and shapes must be the same). If not, AryCpy returns with an error. There is one exception: if the element size, type, and bounds fields all contain zeros, AryCpy will fill in the appropriate values. The NumDimensions field must be non-zero and must match or the AryCpy routine will return an error. Note that AryCpy does *not* deallocate the array storage associated with the destination DV. If it points at array data on the heap you want to dispose of, you must free that storage before calling AryCpy. The reason is simple: the destination DV might not be the only DV pointing at the array data. Freeing it up could create some problems. include: stdlib.a Routine: AryDup ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) Registers on return: ES:DI Points at new SmartArray DV AH Error code (only if error occurs). Flags affected: Carry Error if set. Possible errors: AryMemory AryBadDV AryNull Example of Usage: les di, DVPtr AryDup jc Error Description: AryDup duplicates an array. It makes a copy of the dope vector that ES:DI points at and it also duplicates the array data on the heap. It returns a pointer to the new dope vector in ES:DI. include: stdlib.a Routine: AryCmp ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) DX:SI Points at DV of array to compare against. Registers on return: AL -1, 0, 1 (for <, =, >) AH Error code (only if error occurs) Flags affected: O,S,Z Result of comparison (use signed comparisons) Carry Set if error occurs (carry is not used to test the result of the comparison. Possible errors: AryBadDV AryNull AryTypeMismatch Example of Usage: les di, DVPtr mov dx, word ptr DV2Ptr2 mov si, word ptr DV2Ptr AryCmp jc Error jg ItsBigger Description: AryCmp compares the array specified by ES:DI to the array specified by DX:SI. It returns the result of the comparison in the AL register and in the flags (the flags are set for a signed comparison, so use je, jne, jg, jge, jl, and jle to test the result). As usual the carry flag (which isn't used for signed comparisons) contains the error status. If the arrays are not the same type, size, and shape this code treats the arrays in not equal and returns a type mismatch error code. If one of the arrays is untyped, the code will assume that the arrays are comparable and ignore everything else (including size and shape). include: stdlib.a Routine: AryClr ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) Registers on return: AX Error code (only if error occurs. Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull Example of Usage: les di, DVPtr AryClr jc Error Description: AryClr stores zeros into each data byte of the array. For most data types this corresponds to the value zero (or false, in the case of booleans). include: stdlib.a Routine: VectGet (b,w,d) ------------------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) BX Index into array Registers on return: AL Contains byte value (VectGetb) AX Contains word value (VectGetw) DX:AX Contains dword value (VectGetd) AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: les di, DVPtr mov bx, i VectGetw jc Error Description: VectGet(b,w,d) extracts a single element from a one-dimensional array. It returns values for arrays whose element size is 1, 2, or 4 bytes long. If the array element size does not match the call, the routine returns an AryTypeMismatch error. If BX (containing the index) is not in the range 0..Max-1 then VectGet returns an AryBounds error. include: stdlib.a Routine: MatGet (b,w,d) ------------------------ Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) BX Row index into array CX Column index into array Registers on return: AL Contains byte value (MatGetb) AX Contains word value (MatGetw) DX:AX Contains dword value (MatGetd) AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: les di, DVPtr mov bx, i mov cx, j Matgetb jc Error Description: MatGet(b,w,d) extracts a single element from a two-dimensional array. It returns values for arrays whose element size is 1, 2, or 4 bytes long. If the array element size does not match the call, the routine returns an AryTypeMismatch error. If BX (containing the index) is not in the range 0..Dim1-1 then MatGet returns an AryBounds error. Likewise, if CX is not in the range 0..Dim2-1, you get an AryBounds error. If the array is not a two- dimensional array, MatGet returns an AryBadDV error. include: stdlib.a Routine: AryGet (b,w,d) (2) ---------------------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (source) DX:SI Points at an index list (see below) Registers on return: AL Contains byte value (AryGetb) AX Contains word value (AryGetw) DX:AX Contains dword value (AryGetd) AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: Indices dw 0,1,2,3 . . . les di, DVPtr mov dx, seg indices mov si, offset indices AryGetd jc Error . . . les di, DVPtr mov dx, word ptr indicesDV+2 mov si, word ptr indicesDV AryGetd2 jc Error Description: AryGet is used to extract an element of an arbitrary sized array (it even works for one and two dimensional arrays). On entry, ES:DI points at the dope vector for the array and DX:SI points at the array indices. If you are using AryGetb, AryGetw, or AryGetd then DX:SI must point at a word array of indices with the first word containing the the first index, the second word containing the second index, etc. Note that DX:SI does *not* contain the address of a SmartArray dope vector. It is simply the address of a simple array of values. AryGetx2 is similar to AryGetx except the indices come from a SmartArray vector (one-dimension array) rather than from a plain array. This allows you to manipulate the indices of a SmartArray using SmartArray operations. Returned error codes are the same as for VectGet and MatGet. include: stdlib.a Routine: VectPut (b,w,d) ------------------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV BX Index into array AL Contains byte value (VectPutb) AX Contains word value (VectPutw) DX:AX Contains dword value (VectPutd) Registers on return: AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: les di, DVPtr mov bx, i mov ax, 0 VectPutw jc Error Description: VectPut(b,w,d) stores a value into an element of a one-dimensional array. It works for arrays whose element size is 1, 2, or 4 bytes long. If the array element size does not match the call, the routine returns an AryTypeMismatch error. If BX (containing the index) is not in the range 0..Max-1 then VectPut returns an AryBounds error. include: stdlib.a Routine: MatPut (b,w,d) ------------------------ Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV BX Row index into array CX Column index into array AL Contains byte value (MatPutb) AX Contains word value (MatPutw) DX:AX Contains dword value (MatPutd) Registers on return: AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: les di, DVPtr mov al, 25 mov bx, i mov cx, j Matputb jc Error Description: MatPutx (x=b, w, d) stores the value in AL, AX, or DX:AX into a two- dimensional array at the indices specified by (BX,CX). The code returns all the appropriate errors in the event of a mistake. Otherwise, this routine is quite similar to the VectPutx routine. include: stdlib.a Routine: AryPut (b,w,d) ------------------------ Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV DX:SI Points at an index list (see below) AL Contains byte value (AryPutb) AX Contains word value (AryPutw) BX:AX Contains dword value (AryPutd) Registers on return: AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds AryTypeMismatch Example of Usage: Indices dw 0,1,2,3 . . . mov ax, word ptr ddval mov bx, word ptr ddval+2 les di, DVPtr mov si, offset Indices mov dx, seg Indices AryPutd jc Error Description: You use AryPut to store values into a SmartArray. This routine lets you store bytes, words, and double words into a SmartArray. On entry, ES:DI points at the dope vector for the specified SmartArray. DX:SI points at a list (simple linear array, not a SmartArray) of index values. AL, AX, or BX:AX contains the byte, word, or double word values to store at the specified array element. Note that BX:AX holds the dword value, *not* DX:AX. DX is already in use holding the segment portion of the index array. include: stdlib.a Routine: VectLEA ----------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV BX Index into vector Registers on return: ES:DI Points at specified element AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds Example of Usage: les di, AryPtr1 mov bx, i VectLEA jc Error Description: The VectGetx, MatGetx, AryGetx, VectPutx, MatPutx, and AryPutx routines all have one major drawback-- they're limited to processing array with bytes, words, and double words as elements. They do not allow access to other types. Unfortunately, it is not possible to supply routines to fetch and store every possible type of array element since these are user definable. Instead, the SmartArray package provides a routine which returns the *address* of an arbi- trary array element. Then the calling code may manipulate it as desired. VectLEA lets you obtain the address of an element in an arbitrary typed single dimension array. You pass the index of the desired element in BX and a pointer to the SmartArray DV in ES:DI. It returns a pointer to the desired element in ES:DI. include: stdlib.a Routine: MatLEA ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV BX Row index into matrix CX Column index into matrix Registers on return: ES:DI Points at specified element AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds Example of Usage: les di, AryPtr1 mov bx, i mov cx, j MatLEA jc Error Description: MatLEA lets you obtain the address of an element in an arbitrary typed two dimensional array. You pass the index of the desired element in BX and a pointer to the SmartArray DV in ES:DI. It returns a pointer to the desired element in ES:DI. include: stdlib.a Routine: AryLEA ---------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV DX:SI Pointer to index list. Registers on return: ES:DI Points at specified element AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryBounds Example of Usage: indices dw 0,2,3,1 . . . les di, AryPtr1 mov dx, seg indices mov si, offset indices AryLEA jc Error Description: AryLEA lets you obtain the address of an element in an arbitrary multi- dimensional array. DX:SI points at the index array (see AryPut & AryGet for details). AryLEA returns the address of the specified element in ES:DI. include: stdlib.a Routine: VectOuter ------------------- Category: SmartArray Registers on entry: ES:DI Points at a SmartArray DV (1st operand) DX:SI Pointer at a SmartArray DV (2nd operand) CS:IP Pointer to handler routine (if opcode is 0) AH Opcode Registers on return: ES:DI Points at result matrix AH Error code if error occurs Flags affected: Carry Set if error occurs. Possible errors: AryBadDV AryNull AryOverflow AryDiv0 AryMemory Example of Usage: les di, Vect1Ptr mov dx, seg Vect2 mov si, offset Vect2 mov ah, vopPlus VectOuter jc Error Description: VectOuter performs an outer product on two vectors. If "op" represents an operation, then the outer product of v1 and v2 is the following: v2[0] v2[1] ... v2[n-1] v1[0] v1[0] op v2[0] v1[0] op v2[1] ... v1[0] op v2[n-1] v1[1] v1[1] op v2[0] v1[1] op v2[1] ... v1[1] op v2[n-1] . . . v1[n-1] v1[n-1] op v2[0] v1[n-1] op v2[1]... v1[n-1] op v2[n-1] The actual operation performed is specified in one of two ways, either by a numeric opcode in AH upon entry to the routine or via a user-supplied routine. Currently, the following opcodes are predefined in the system: vopUser = 0 vopPlus = 2 vopMinus = 4 vopMul = 6 vopDiv = 8 vopMod = 10 vopAnd = 12 vopOr = 14 vopXor = 16 vopEQ = 18 vopNE = 20 vopGE = 22 vopGT = 24 vopLT = 26 vopLE = 28 vopMin = 30 vopMax = 32 The result produced is always an m x n matrix where m is the size of the first vector and n is the size of the second vector. If the opcode is zero (vopUser) then the call to VectOuter takes the following form: mov ah, vopUser VectOuter dd MyOperation An address must immediately follow the call to the VectOuter routine. You must supply this address (and the corresponding routine). On entry to this routine DS:SI points at the first operand and ES:DI points at the second. The user routine should perform the operation and store the result at DS:SI. Also upon entry, AL contains the element size and AH contains the element type. The user routine is responsible for error checking. If an error occurs, it should set the carry flag and return the error code in AH. Please note that the built in operations only support 1, 2, and 4 byte unsigned and signed integers. Floating point operations will follow soon. include: stdlib.a AryNoError = 0 ;Should never occur AryTypeMismatch = 1 ;Array type mismatch AryOverflow = 2 ;Arithmetic overflow AryDiv0 = 3 ;Division by zero AryIllegalOp = 4 ;Illegal operation on array AryBounds = 5 ;Array index error AryMemory = 6 ;Memory allocation error AryBadDV = 7 ;Illegal dope vector AryNull = 8 ;Null pointer to array data