home *** CD-ROM | disk | FTP | other *** search
- /*
- * File......: CINT86.C
- * Author....: Ted Means
- * Date......: $Date: 15 Aug 1991 23:08:32 $
- * Revision..: $Revision: 1.2 $
- * Log file..: $Logfile: E:/nanfor/src/cint86.c_v $
- *
- * This function is an original work by Ted Means and is placed in the
- * public domain.
- *
- * Modification history:
- * ---------------------
- *
- * $Log: E:/nanfor/src/cint86.c_v $
- *
- * Rev 1.3 9 Jul 1993 11:17:00
- * Ted Means merged real mode source code so that both versions would be
- * reasonably consistent.
- *
- * Rev 1.3 6 Jun 1993 19:30:12
- * Anton van Straaten modified for ExoSpace;
- * this version is ExoSpace-specific.
- *
- * Rev 1.2 15 Aug 1991 23:08:32 GLENN
- * Forest Belt proofread/edited/cleaned up doc
- *
- * Rev 1.1 14 Jun 1991 03:48:42 GLENN
- * Just corrected some typos in the documentation.
- *
- * Rev 1.0 27 May 1991 13:22:36 GLENN
- * Initial revision.
- *
- *
-
- * $DOC$
- * $FUNCNAME$
- * FT_INT86X()
- * $CATEGORY$
- * DOS/BIOS
- * $ONELINER$
- * Execute a software interrupt (in protected mode using ExoSpace)
- * $SYNTAX$
- * FT_INT86X( <nInterruptNumber>, <aRegisterValues> ) -> lResult
- * $ARGUMENTS$
- * <nInterruptNumber> is the interrupt to execute.
- *
- * <aRegisterValues> is an array that contains values to be loaded
- * into the various CPU registers. The correspondence between
- * registers and array elements is as follows:
- *
- * aElement[1] == AX register
- * aElement[2] == BX register
- * aElement[3] == CX register
- * aElement[4] == DX register
- * aElement[5] == SI register
- * aElement[6] == DI register
- * aElement[7] == BP register
- * aElement[8] == DS register
- * aElement[9] == ES register
- * aElement[10] == Flags register
- * $RETURNS$
- * .T. if all parameters valid and the function was able
- * to execute the desired interrupt.
- * .F. if invalid parameters passed.
- *
- * In addition, the array elements will contain whatever values were in
- * the CPU registers immediately after the interrupt was executed. If
- * either of the string parameters were altered by the interrupt, these
- * changes will be reflected as well.
- *
- * $DESCRIPTION$
- * It is occasionally useful to be able to call interrupts directly from
- * Clipper, without having to write a separate routine in C or ASM. This
- * function allows you that capability.
- *
- * Given Clipper's high-level orientation, this function is necessarily
- * somewhat messy to use. First, declare an array of ten elements to
- * hold the eight values for the CPU registers and two string parameters.
- * Then initialize the array elements with the values that you want the
- * CPU registers to contain when the interrupt is executed. You need not
- * initialize all the elements. For example, if the interrupt requires
- * you to specify values for AX, DX, and DS, you would only need to
- * initialize elements 1, 4, and 8.
- *
- * Once you have done the required register setup, call FT_INT86(),
- * passing the interrupt number and the register array as parameters.
- * The function will load the CPU with your specified values, execute the
- * interrupt, and then store the contents of the CPU registers back into
- * your array. This will allow you to evaluate the results of the
- * interrupt.
- *
- * Some interrupt services require you to pass the address of a string in
- * a pair of registers. This function is capable of handling these sorts
- * of situations, but it will take a little work on your part. If you need
- * to pass a string that uses the DS register, store the string in element
- * 8; if you need to pass a string that uses the ES register, store the
- * string in element 9. FT_INT86() will detect that you've supplied a
- * string instead of a numeric value and will behave accordingly.
- *
- * That takes care of obtaining the segment portion of the pointer. To
- * specify which register is to contain the offset, use the values REG_DS
- * and REG_ES which are defined in the FTINT86.CH file. When one of these
- * values is found in an array element, it alerts FT_Int86() to use the
- * offset portion of a pointer instead of a numeric value. REG_DS tells
- * FT_Int86() to use the offset of the string in element 8, while REG_ES
- * tells FT_Int86() to use the offset of the string in element 9.
- *
- * All the CPU registers are sixteen bits in size. Some, however, are
- * also split into two 8-bit registers. This function is only capable of
- * receiving and returning registers that are 16 bits in size. To split
- * a 16-bit register into two 8-bit values, you can use the
- * pseudo-functions HighByte() and LowByte(), contained in the .CH file.
- *
- * To alter an 8-bit number so it will appear in the high-order byte of a
- * register when passed to the FT_INT86() function, use the MakeHI()
- * pseudo-function contained in the .CH file.
- *
- * This function is a shell for __ftint86(), which is written in assembler
- * and does the actual work of executing the interrupt. __ftint86() is
- * callable from C, so feel free to incorporate it into any C routines
- * for which it might be useful. The source for __ftint86() can be found
- * in the file AINT86.ASM.
- * $EXAMPLES$
- *
- * * This example shows how to call the DOS "create file" service. Take
- * * special note of how to set up string parameters.
- *
- * #include "FTINT86.CH"
- *
- * local aRegs[10] // Declare the register array
- * aRegs[ AX ] := makehi(60) // DOS service, create file
- * aRegs[ CX ] := 0 // Specify file attribute
- *
- * * Pay attention here, this is crucial. Note how to set up the string
- * * so it appears in DS:DX.
- *
- * aRegs[ DS ] := "C:\MISC\MYFILE.XXX"
- * aRegs[ DX ] := REG_DS
- * FT_INT86X( 33, aRegs) // Make the call to the DOS interrupt
- *
- *
- *
- * * This example shows how to call the DOS "get current directory"
- * * service. This one also uses a string parameter, but note that it
- * * uses a different offset register.
- *
- * #include "FTINT86.CH"
- *
- * local aRegs[10]
- * aRegs[ AX ] := makehi(71)
- * aRegs[ DX ] := 0 // Choose default drive
- *
- * * This service requires a 64-byte buffer whose address is in DS:SI. DOS
- * * will fill the buffer with the current directory.
- *
- * aRegs[ DS ] := space(64)
- * aRegs[ SI ] := REG_DS
- * FT_INT86X( 33, aRegs)
- *
- * ? aRegs[ DS ] // Display the directory name
- *
- *
- *
- * * For the sake of completeness, here's an example that doesn't use a
- * * string. This one changes the video mode.
- *
- * #include "FTINT86.CH"
- *
- * local aRegs[10]
- *
- * aRegs[ AX ] := 16 // Choose hi-res graphics
- * FT_INT86X( 16, aRegs)
- * $INCLUDE$
- * FTINT86.CH
- * $END$
- */
-
- #include "EXTEND.H"
- #include "CINT86X.H"
-
- // AX BX CX DX SI DI BP
- static int regOff[] = { 9, 6, 8, 7, 3, 2, 4 };
-
- CLIPPER FT_Int86X( void )
- {
- auto REGISTERS regs;
-
- auto FARPTR dsPtr; // Pointers to incoming params
- auto FARPTR esPtr;
-
- auto FARPTR dsPma; // Protected mode addresses
- auto FARPTR esPma;
-
- auto FARPTR dsRma; // Real mode addresses
- auto FARPTR esRma;
-
- auto UINT nLenDS;
- auto UINT nLenES;
- auto UINT n;
-
- dsPma.Address = NULL; dsRma.Address = NULL;
- esPma.Address = NULL; esRma.Address = NULL;
-
- if ( ( PCOUNT == 2 ) && ISNUM( 1 ) && ISARRAY( 2 ) )
- {
- if ( _parinfa( 2, 8 ) & CHARACTER )
- {
- nLenDS = _parclen( 2, 8 );
-
- _storclen( NULL, nLenDS, 2, 8 ); dsPtr.Address = _parc( 2, 8 );
-
- dsPma = _xalloclow( nLenDS );
-
- _bcopy( dsPma.Address, dsPtr.Address, nLenDS );
-
- dsRma = ExoRealPtr( dsPma ); regs.CPURegs.DS = dsRma.Pointer.Segment;
- }
- else
- regs.CPURegs.DS = _parni( 2, 8 );
-
- if ( _parinfa( 2, 9 ) & CHARACTER )
- {
- nLenES = _parclen( 2, 9 );
-
- _storclen( NULL, nLenES, 2, 9 ); esPtr.Address = _parc( 2, 9 );
-
- esPma = _xalloclow( nLenES );
-
- _bcopy( esPma.Address, esPtr.Address, nLenES );
-
- esRma = ExoRealPtr( esPma ); regs.CPURegs.ES = esRma.Pointer.Segment;
- }
- else
- regs.CPURegs.ES = _parni( 2, 9 );
-
- for ( n = 1; n <= 7; n++ )
- {
- if ( _parinfa( 2, n ) & LOGICAL )
- if ( _parl( 2, n ) )
- regs.registers[ regOff[ n - 1 ] ] = dsRma.Pointer.Offset;
- else
- regs.registers[ regOff[ n - 1 ] ] = esRma.Pointer.Offset;
- else
- regs.registers[ regOff[ n - 1 ] ] = _parni( 2, n );
- }
-
- _storni( ExoRMInterrupt( _parni( 1 ), ®s, ®s ), 2, 10 );
-
- for ( n = 1; n <= 7; n++ )
- _storni( regs.registers[ regOff[ n - 1 ] ], 2, n );
-
- if ( dsPma.Address == NULL )
- _storni( regs.CPURegs.DS, 2, 8 );
- else
- {
- _bcopy( dsPtr.Address, dsPma.Address, nLenDS );
-
- _xfreelow( dsPma.Address );
- }
-
- if ( esPma.Address == NULL )
- _storni( regs.CPURegs.ES, 2, 9 );
- else
- {
- _bcopy( esPtr.Address, esPma.Address, nLenES );
-
- _xfreelow( esPma.Address );
- }
-
- _retl( TRUE );
- }
- else
- _retl( FALSE );
-
- return;
- }
-
-