Miscellaneous DOS

Technical Notes

Overview
Handling DOS Error Messages
Checking the DOS Version
Managing System Memory
DOS Country Information
Manipulating the DTA
Getting Disk Drive Information
Manipulating the Verify Flag
Managing the Interrupt Vectors
Handling Control-Break Events
Handling Critical Errors

Overview

This unit consists of functions which handle DOS error messages, check the DOS version, manage system memory, manage DOS country information, manipulate the DTA, get disk drive information, manipulate the verify flag, manage interrupt vectors, handle control-break events, handle critical errors. These functions present a uniform, DOS version-independent interface to existing DOS functions, and in most cases provide enhanced functionality.

If 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.

Handling DOS Error Messages

_dos_errmsg
Returns the offset of a DOS error message string.
_dos_errmsge
Returns the offset of the DOS error message string describing the most recent DOS error.
e_code
(Variable) Contains the most recent error code.
_get_ecode
Returns the value of e_code.
These functions get an error code and provide pointers to appropriate error messages. The global variable e_code holds the most recent error code. When any of the DOS interface functions returns an error code it does so through this global variable. The address of the corresponding DOS error message can be obtained by calling _dos_errmsg or _dos_errmsge. _dos_errmsg is called with the DOS error code, while _dos_errmsge gets the error code directly from e_code.

The error code can be accessed directly or it can be retrieved by calling _get_ecode.

Checking the DOS Version

_chk_version
Terminates program execution immediately if the current DOS version is unacceptable.
_chk_version2
Terminates program execution immediately if the current DOS version is 1.0 or 1.1.
_get_version
Gets the current DOS version number.
_cmp_version
Compares the required DOS version number with the current version.
These functions check and get the DOS version number. The global variables _osmajor and _osminor are defined in most C libraries, and therefore, to avoid conflicts, are not defined in the C version of the Spontaneous Assembly libraries. _osmajor and _osminor hold the major and minor portions of the current DOS version number, respectively. These variables are automaticallyinitialized any time _chk_version, _chk_version2, or _get_version is called. Since DOS versions 1.0 and 1.x cannot be easily distinguished, any 1.x version is assumed to be version 1.0.

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.)

Managing System Memory

_dos_malloc
Allocates a block of DOS memory.
_dos_mavail
Gets the size of the largest block of allocable DOS memory.
_dos_mfree
Frees a block of allocated DOS memory.
_dos_mset
Modifies the size of a block of DOS memory.
_dos_msize
Gets the size of a block of DOS memory.
These functions allocate, manipulate, and free blocks of conventional memory. They are low-level in nature and are usually used only in programs that do not need the higher level heap management functionality provided in the memory management unit.

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.

DOS Country Information

_get_countryinfo
Gets the current DOS country information.
_set_country
Sets the current DOS country code (DOS 3.0 or above).
_get_countryinfo gets the DOS country information for the current or a specified country. The DOS country information is returned in dcountry structure format. The dcountry structure follows the standard DOS country information format and is defined in MISCDOS.H as follows:

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):
CDATE_MDY
(0x0000) For USA (MONTH/DAY/YEAR)
CDATE_DMY
(0x0001) For European (DAY/MONTH/YEAR)
CDATE_YMD
(0x0002) For Japanese (YEAR/MONTH/DAY)
The following symbolic constants may be used to check or modify the information in the cntry_curloc field (these equates are defined in MISCDOS.H):
CURR_PN
(0x00) Currency symbol precedes the value. No spaces are between the currency symbol and the value.
CURR_FN
(0x01) Currency symbol follows the value. No spaces are between the currency symbol and the value.
CURR_P1
(0x02) Currency symbol precedes the value. One space is between the currency symbol and the value.
CURR_F1
(0x03) Currency symbol follows the value. One space is between the currency symbol and the value.
CURR_R
(0x04) Currency symbol replaces the decimal delimiter.
The following symbolic constants may be used to check or modify the information in the cntry_tmformat field (these equates are defined in MISCDOS.H):
CTIME_12HR
(0x00) For 12-hour clock.
CTIME_24HR
(0x01) For 24-hour clock.
_set_country specifies a new "current DOS country." After calling this function, other functions which query DOS for information about the current DOS country will recognize the specified country as the default country. A list of valid DOS country codes may be found in the DOS user manuals for DOS 4.x and above and in many programming reference manuals.

_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.

Manipulating the DTA

_get_dta
Gets the disk transfer address (DTA).
_dta_restore
Restores the Disk Transfer Address (DTA).
_dta_save
Saves the current Disk Transfer Address (DTA).
_set_dta
Sets the disk transfer address (DTA).
These functions get, set, save and restore the DTA (Disk Transfer Address).

_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.

Getting Disk Drive Information

_get_cdfree
Gets the amount of free disk space on the current drive.
_get_cdinfo
Gets File Allocation Table (FAT) information for the current drive.
_get_cdsize
Gets the disk size for the current drive.
_get_dfree
Gets the free disk space on a specified drive.
_get_dinfo
Gets File Allocation Table (FAT) information about the specified drive.
_get_dsize
Gets the disk size for a specified drive.
_get_lastdrive
Gets the total number of logical drives.
These functions get disk drive information.

_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');

Manipulating the Verify Flag

_get_verify
Gets the state of the DOS verify flag.
_set_verify
Sets or clears the DOS verify flag.
_verify_off
Disables DOS write verification.
_verify_on
Enables DOS write verification.
_verify_restore
Restores the original state of the DOS verify flag.
_verify_save
Saves the current state of the DOS verify flag.
These functions get, set, save, and restore the state of the DOS verify flag.

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.

Managing the Interrupt Vectors

_get_vect
Gets an interrupt handler address.
_set_vect
Sets an interrupt handler address.
These functions issue DOS calls to get and set interrupt vector addresses. They allow user interrupt handlers to be installed and removed as needed.

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.

Handling Control-Break Events

_cbrk_check
Allows a ctrl-break event to be processed if one is pending and the DOS ctrl-break flag is set.
_cbrk_disable
Disables all DOS ctrl-break checking
_cbrk_enable
Enables DOS ctrl-break after _cbrk_disable has been called.
_cbrk_install
Installs a DOS ctrl-break handler.
cbrk_pending
(Variable) Indicates whether or not ctrl-break events occurred while _cbrk_disable was in effect.
_cbrk_remove
Removes an installed DOS ctrl-break handler.
_cbrk_restore
Restores the original state of the DOS ctrl-break flag.
_cbrk_save
Saves the current state of the DOS ctrl-break flag.
_get_cbrk
Returns the state of the DOS ctrl-break flag.
_set_cbrk
Sets or clears the DOS ctrl-break flag.
These functions get, set, save, and restore the state of the DOS ctrl-break flag. The global variable cbrk_pending holds the most recent control break state. Functions are also provided which install and remove ctrl-break handlers, disable and enable ctrl-break checking, and check for pending ctrl-break events.

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.

Handling Critical Errors

_ce_install
Installs a critical error handler.
_ce_remove
Removes an installed DOS critical error handler.
_cem_install
Installs the Critical Error Manager.
These functions manage critical errors and install and remove custom critical error handlers.

_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.