(*********************************************************************** Name: CtlCTrap.Pas Version: 1.0 ABSTRACT: Provides reliable CTRL/C trapping for TURBO Pascal programs running under MS-DOS and PC-DOS. ENVIRONMENT: MS-DOS or PC-DOS, compiled with TURBO Pascal. Tested combinations: MS-DOS V2.11 with TURBO Pascal V3.01A (MS-DOS generic) MS-DOS V2.11 with TURBO Pascal V3.02A (MS-DOS generic) PC-DOS V2.10 with TURBO Pascal V3.00B (PC-DOS specific) PC-DOS V2.10 with TURBO Pascal V3.01A (PC-DOS specific) PC-DOS V2.10 with TURBO Pascal V3.02A (MS-DOS generic) PC-DOS V2.10 with TURBO Pascal V3.02A (PC-DOS specific) AUTHOR: Brian Hetrick EDIT HISTORY: Brian Hetrick, 12 December 1986: Version 1.0 000 - Original creation of module. ACKNOWLEDGMENTS: This is an enhanced version of the CTRLC.PAS public domain program, discovered on the MARKET public access bulletin board, author un- known. ***********************************************************************) {.PA} (* * TYPE DECLARATIONS: *) TYPE CtrlCPtr = ^ CHAR; (* * CONSTANT DECLARATIONS: *) CONST CtrlCCount : INTEGER = 0; CtrlCFlag : BOOLEAN = FALSE; (* * VARIABLE DECLARATIONS: *) VAR CtrlCVect : CtrlCPtr; {.PA} PROCEDURE CtrlCHandler; (*********************************************************************** FUNCTIONAL DESCRIPTION: THIS ROUTINE MUST NOT BE CALLED BY THE CLIENT PROGRAM. THIS ROUTINE MUST BE DEFINED AT THE OUTERMOST LEVEL (i.e., not nested inside an- other routine). Control/C interrupt handler. Called by MS-DOS when a Control/C is detected in the input stream. Sets the Control/C flag and dismisses the Control/C interrupt. Ray Duncan's book "Advanced MS-DOS" documents the possible actions that could be taken by a Control/C handler as any one of: o Take any appropriate action and execute an IRET. The MS-DOS function in progress will be restarted and return normally. o Take any appropriate action and execute a far RETURN. If carry is set, MS-DOS will abort the application and otherwise "will continue in the normal manner". o Keep control and never return. The first alternative is chosen here. Although any MS-DOS function call can by used an a Control/C interrupt handler, a TURBO function may have been occurring and so no TURBO functions may be used. FORMAL PARAMETERS: None. RETURN VALUE: None. IMPLICIT INPUTS: None. IMPLICIT OUTPUTS: CtrlCFlag - The Control/C flag. SIDE EFFECTS: None. ***********************************************************************) BEGIN (* * Standard TURBO procedure entry for routines at the outermost * level. A different entry sequence is used for routines that are * within other routines (it must ensure addressability of the * outer routine's variables), and this other sequence is NOT legal * for interrupt routines *) { PUSH BP } { MOV BP,SP } { PUSH BP } { JMP procedure body } (* * Recommended TURBO interrupt procedure entry *) InLine ($50/ { PUSH AX } $53/ { PUSH BX } $51/ { PUSH CX } $52/ { PUSH DX } $56/ { PUSH SI } $57/ { PUSH DI } $1E/ { PUSH DS } $06/ { PUSH ES } $FB); { STI } (* * Note CTRL/C occurrence. As the data segment is not addressable * at this point, only CONST variables may be used *) CtrlCFlag := TRUE; (* * Recommended TURBO interrupt procedure exit *) InLine ($07/ { POP ES } $1F/ { POP DS } $5F/ { POP DI } $5E/ { POP SI } $5A/ { POP DX } $59/ { POP CX } $5B/ { POP BX } $58/ { POP AX } $8B/$E5/ { MOV SP,BP } $5D/ { POP BP } $CF) { IRET } END; {.PA} FUNCTION CtrlCOccurred : BOOLEAN; (*********************************************************************** FUNCTIONAL DESCRIPTION: Tests whether a Control/C has occurred. This function MUST be used rather than just checking the CtrlCFlag variable, as Control/Cs are detected only at MS-DOS function calls. FORMAL PARAMETERS: None. RETURN VALUE: TRUE - There is an unhandled Ctrl/C present. FALSE - There is no unhandled Ctrl/C present. IMPLICIT INPUTS: CtrlCCount - The count of outstanding enables of the Control/C pack- age. CtrlCFlag - The Control/C pending flag. IMPLICIT OUTPUTS: CtrlCFlag - The Control/C pending flag. SIDE EFFECTS: May issue an MS-DOS function call permitting Control/C detection. ***********************************************************************) TYPE RegisterPackage = RECORD AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : INTEGER END; VAR Registers : RegisterPackage; BEGIN (* * If the Control/C package is not initialized, then it cannot * detect Control/Cs. *) IF CtrlCCount = 0 THEN CtrlCOccurred := FALSE ELSE BEGIN (* * If there is no Control/C pending, issue MS-DOS function call *) IF NOT CtrlCFlag THEN BEGIN Registers . AX := $0B00; MsDos (Registers) END; (* * Return Control/C status and reset pending flag *) CtrlCOccurred := CtrlCFlag; CtrlCFlag := FALSE; END END; {.PA} PROCEDURE CtrlCSetup; (*********************************************************************** FUNCTIONAL DESCRIPTION: Initializes the Control/C package. FORMAL PARAMETERS: None. RETURN VALUE: None. IMPLICIT INPUTS: CtrlCCount - The count of outstanding enables of the Control/C pack- age. Interrupt vector 23 (Control/C trap). IMPLICIT OUTPUTS: CtrlCCount - The count of outstanding enables of the Control/C pack- age. Interrupt vector 23 (Control/C trap). CtrlCVect - The original Control/C trap vector. SIDE EFFECTS: None. ***********************************************************************) TYPE RegisterPackage = RECORD AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : INTEGER END; VAR Registers : RegisterPackage; BEGIN (* * If necessary, set up the Control/C vector *) IF CtrlCCount = 0 THEN BEGIN (* * Initialize the CtrlCFlag *) CtrlCFlag := FALSE; (* * Save the old Control/C vector *) Registers . AX := $3523; MsDos (Registers); CtrlCVect := Ptr (Registers . ES, Registers . BX); (* * Install the new Control/C vector *) Registers . AX := $2523; Registers . DS := Cseg; Registers . DX := Ofs (CtrlCHandler); MsDos (Registers) END; (* * Increment the installation count *) CtrlCCount := CtrlCCount + 1 END; {.PA} PROCEDURE CtrlCTearDown; (*********************************************************************** FUNCTIONAL DESCRIPTION: Tears down the Control/C package. FORMAL PARAMETERS: None. RETURN VALUE: None. IMPLICIT INPUTS: CtrlCCount - The count of outstanding enables of the Control/C pack- age. CtrlCVect - The original Control/C trap vector. IMPLICIT OUTPUTS: CtrlCCount - The count of outstanding enables of the Control/C pack- age. Interrupt vector 23 (Control/C trap). SIDE EFFECTS: None. ***********************************************************************) TYPE RegisterPackage = RECORD AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : INTEGER END; VAR Registers : RegisterPackage; BEGIN (* * Decrement the installation count *) CtrlCCount := CtrlCCount - 1; (* * If necessary, remove handler *) IF CtrlCCount = 0 THEN BEGIN (* * Restore old Control/C routine *) Registers . AX := $2523; Registers . DS := Seg (CtrlCVect ^); Registers . DX := Ofs (CtrlCVect ^); MsDos (Registers); (* * Ignore any Control/Cs that were captured *) CtrlCCount := 0 END END;