Technical Notes
OverviewIf a miscellaneous DOS function returns an error code, it does so through the global e_code variable. This allows functions to maintain a smaller profile, and it allows error conditions to be ignored or dealt with at a later time. Symbolic equates are defined for each error code in the ECODES.H header file. A list of these codes, their symbolic constants, and their meanings can be found in Appendix A. These equates use an E_... naming convention.
The error code can be accessed directly or it can be retrieved by calling _get_ecode.
Most programs require a minimum DOS version in order to function properly. (The Spontaneous Assembly Library functions only support DOS 2.0 or greater.) To check the active DOS version, the program should call _chk_version or _chk_version2 immediately after program start up. _chk_version is called with the required DOS version number; _chk_version2 assumes DOS 2.0 is the required version number. If the actual DOS version number is less than the required version number, the function writes a DOS-like error message to the standard output device (STDOUT), exits the program, and returns control to DOS using the appropriate exit method for the active DOS version; otherwise, the function returns normally. To ensure that a program can always be exited gracefully, _chk_version and _chk_version2 are compatible with DOS 1.0 and above.
_cmp_version is designed to be used to conditionally execute code which depends on the DOS version number. _cmp_version is called with the required DOS version number and compares the required version number with the actual version number stored in _osmajor and _osminor. 1, 0 or -1 ("greater than", "equal", or "less than") is returned depending on the result of the comparison. _osmajor and _osminor must be initialized before this function is called. (Using _cmp_version is more efficient than using _get_version and then comparing the returned version number.)
Note that the _dos_msize function has no DOS counterpart. It examines DOS Memory Control Blocks directly in order to determine the size of a given block.
typedef struct {
int cntry_dtformat; /* date format */
char cntry_curstr[5]; /* currency symbol (ASCIIZ) */
char cntry_thdelim[2]; /* thousand delimiter (ASCIIZ) */
char cntry_decdelim[2]; /* decimal delimiter (ASCIIZ) */
char cntry_dtdelim[2]; /* date delimiter (ASCIIZ) */
char cntry_tmdelim[2]; /* time delimiter (ASCIIZ) */
char cntry_curloc; /* currency symbol location */
char cntry_cdigits; /* digits after decimal point */
/* for currency */
char cntry_tmformat; /* time format 12/24 hour */
long cntry_case; /* case map */
char cntry_datadelim[2]; /* data delimiter (ASCIIZ) */
char cntry_reserved[10]; /* DOS (reserved) */
} dcountry;
The following symbolic constants may be used to check or modify the information in the cntry_dtformat field (these equates are defined in MISCDOS.H):
_osmajor must be properly initialized prior to calling either of these functions. Both functions use _osmajor internally because: 1) DOS version 2.x returns the country information in a different format than DOS version 3.0 and above, and 2) the DOS country cannot be set using DOS version 2.x. When using Spontaneous Assembly for C/C++, this variable is supplied and initialized by the compiler instead of the Spontaneous Assembly library.
_dta_save and _dta_restore allow the DTA to be saved, manipulated in some way, and then restored. These are particularly useful in TSR start up and exit routines. Since the DTA is restored by DOS when a program terminates, these functions do not need to be called at the beginning and end of a non-TSR program.
The DTA functions work in harmony with the _find_first and _find_next functions. Specifically, these functions keep track of the current DTA in an internal variable. The _find... functions then check this variable to see if the DTA needs to be changed prior to issuing a DOS Find First or Find Next function call. This simplifies the interface to the _find... functions without slowing them down with unnecessary DOS calls. However, it imposes the restriction that the DTA should never be modified directly if the _find... functions are being used. To be safe, the ...dta... functions should always be used to access the DTA if other Spontaneous Assembly library functions are being used. If this rule is followed, the DTA may be modified at will without interfering with any other Spontaneous Assembly library functions.
_get_cdfree, _get_cdinfo and _get_cdsize provide parallel functionality to _get_dfree, _get_dinfo and _get_dsize. The _get_cd... functions return information about the current drive and the _get_d... functions return information about a specified drive.
Functions which expect a drive specifier as an input expect an ASCII alphabetic character in either upper or lower case. Functions which return a drive specifier return an ASCII uppercase letter. For example, the following code obtains the free disk space on drive A:
long int dfree;
dfree = _get_dfree ('A');
When verify is off, disk writes are not verified; when verify in on, all disk writes are verified to assure that data is properly written.
_verify_save and _verify_restore allow the verify state to be saved, changed at will, and restored. These functions are designed to be used at the beginning and end of a program which modifies the state of the verify flag.
Zortech C compilers do not support interrupt functions. To avoid error messages, the _get_vect and _set_vect functions are not defined when using this compiler. See the MISCDOS.H header file for more details.
Note that the _get_vec and _set_vec functions in the miscellaneous hardware unit provide a faster and more flexible method of manipulating interrupt vectors. However, some semi-compatible PC's (i.e., the DEC Rainbow) don't support direct manipulation of system interrupt vectors. In these rare cases, _get_vect and _set_vect must be used.
The _get_cbrk, _set_cbrk, _cbrk_save, and _cbrk_restore functions all deal with the DOS ctrl-break flag. These functions get, set, save, and restore the flag status, respectively. _cbrk_save and _cbrk_restore make it easy to save the initial state of the ctrl-break flag, modify it, and then restore it to its original state. Note that if a program modifies the DOS ctrl-break flag it must restore it before it terminates or it will modify the BREAK state for subsequent programs.
_cbrk_install installs a new ctrl-break handler which replaces the currently-installed handler. DOS passes control to the ctrl-break handler whenever a ctrl-break event is detected and the ctrl-break flag is set. The ctrl-break handler supports an assembly language interface and may perform any action including making DOS function calls and/or terminating the program. The handler may also return via a far return (RETF) as long as it preserves all of the registers. In this case, the carry flag is used to indicate whether or not program execution should continue or be terminated (if the carry flag is set, the program terminates immediately; if the carry flag is clear, the program continues where execution left off).
_cbrk_remove removes the current ctrl-break handler by setting the ctrl-break address to the address which was active when the program first began execution (this address is obtained from the Program Segment Prefix).
Since DOS only processes pending ctrl-break events whenever a DOS function call is issued, it is possible for a program to execute for long periods of time without ever checking for ctrl-break events. _cbrk_check is provided to allow unresponsive code to check for ctrl-break events. If the DOS ctrl-break flag is set and a ctrl-break event is pending when _cbrk_check is called, then DOS will pass control to the active ctrl-break handler.
Unfortunately, clearing the DOS ctrl-break flag does not completely disable DOS control ctrl-break checking. If the flag is set, DOS checks for ctrl-break events whenever almost any DOS function call is issued; when the flag is clear, DOS still checks for ctrl-break events when I/O is performed using a standard I/O function. Furthermore, these standard I/O functions treat ctrl-C events exactly like ctrl-break events.
For the reasons mentioned above, _cbrk_disable must be used any time ctrl-break checking must be completely disabled. This function installs a temporary BIOS break (INT 0x1B) handler, preventing DOS from being notified of ctrl-break events. A temporary ctrl-break (INT 0x23) handler is also installed to trap any ctrl-C events which are detected by DOS standard I/O functions. Note that DOS function calls 9 and 0xA are always affected by ctrl-C events (^C and a new line are output to the display and I/O resumes from the beginning of the line). This occurs even after _cbrk_disable has been called. Calling _cbrk_disable will, however, prevent the ctrl-break handler from receiving control. _cbrk_disable has no effect on the state of the DOS ctrl-break flag.
While _cbrk_disable is in effect, the variable cbrk_pending keeps track of trapped ctrl-break events; it is set to one (1) if any ctrl-break or ctrl-C events are trapped; otherwise, it is zero (0). _cbrk_enable may then be called to re-enable ctrl-break checking. _cbrk_enable first restores the original INT 0x1B and INT 0x23 vectors. Then, if cbrk_pending was non-zero on entry, _cbrk_enable notifies DOS of the pending ctrl-break event by issuing an INT 0x1B. _cbrk_check is then called to allow DOS to process the pending ctrl-break event if the DOS ctrl-break flag is set. _cbrk_enable has no effect on the state of the DOS ctrl-break flag.
_ce_install installs a custom DOS critical error handler in place of the current critical error handler. The installed critical error handler receives control whenever a critical error occurs during a DOS function call. See a DOS Technical Reference Manual for information about how to write a custom critical error handler. In most cases, _cem_install is preferable to _ce_install. Zortech C compilers do not support interrupt functions. To avoid error messages, the _ce_install function is not defined when using this compiler. See the MISCDOS.H header file for more details.
_cem_install installs the Critical Error Manager in place of the current critical error handler. The Critical Error Manager is a predefined critical error handler which provides a simplified, DOS version-independent interface for writing custom critical error routines. When the Critical Error Manager is installed, a user function address may be specified. If a user function is provided, the Critical Error Manager passes control to this user function each time a critical error occurs. After the user function has examined information about the critical error, it may 1) direct the Critical Error Manager to abort the program immediately, 2) retry the operation which caused the error, 3) ignore the error and continue as if no error had occurred, 4) fail the function call which caused the error, or 5) quit the program by passing control to a specified exit address. If no user function is provided, the Critical Error Manager fails the DOS call, returns an appropriate error code, and passes control to the instruction following the DOS call. This eliminates "Abort, Retry, Ignore?" messages, allowing corrective action to be taken in the program (i.e., use a different floppy disk drive or display a descriptive error message). See the entry for _cem_install in the Reference Section for detailed information about user functions and their interaction with the Critical Error Manager.
_ce_remove removes the current critical error handler by setting the critical error handler address to the address which was active when the program first began execution (this address is obtained from the Program Segment Prefix). _ce_remove may be used to remove the Critical Error Manager. This is not necessary, however, since DOS automatically replaces the critical error handler when the program terminates.