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.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_INT86()
- * $CATEGORY$
- * DOS/BIOS
- * $ONELINER$
- * Execute a software interrupt
- * $SYNTAX$
- * FT_INT86( <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_INT86( 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_INT86( 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_INT86( 16, aRegs)
- * $INCLUDE$
- * FTINT86.CH
- * $END$
- */
-
- #include "extend.h"
- #include "cint86.h"
-
- CLIPPER FT_Int86(void)
- {
- auto struct CPUREGS regs;
- auto unsigned int i;
- auto char * dsptr = NULL;
- auto char * esptr = NULL;
-
- if ( (PCOUNT == 2) && ISNUM(1) && ISARRAY(2) )
- {
- if ( _parinfa(2, 8) & CHARACTER )
- {
- _storclen(NULL, _parclen(2, 8), 2, 8);
- dsptr = _parc(2, 8);
- regs.ds = *((unsigned int *)(&dsptr) + 1);
- }
- else
- regs.ds = _parni(2, 8);
-
- if ( _parinfa(2, 9) & CHARACTER )
- {
- _storclen(NULL, _parclen(2, 9), 2, 9);
- esptr = _parc(2, 9);
- regs.es = *((unsigned int *)(&esptr) + 1);
- }
- else
- regs.es = _parni(2, 9);
-
- for (i = 1; i <= 7; i++)
- {
- if ( _parinfa(2, i) & LOGICAL )
- if ( _parl(2, i) )
- *(((unsigned int *)(®s)) + i - 1) = *(unsigned int *)&dsptr;
- else
- *(((unsigned int *)(®s)) + i - 1) = *(unsigned int *)&esptr;
- else
- *(((unsigned int *)(®s)) + i - 1) = _parni(2, i);
- }
-
- __ftint86( _parni(1), ®s);
-
- for (i = 1; i <= 7; i++)
- _storni(*(((unsigned int *)(®s)) + i - 1), 2, i);
-
- _storni(regs.flags, 2, 10);
-
- if ( dsptr == NULL )
- _storni(regs.ds, 2, 8);
-
- if ( esptr == NULL )
- _storni(regs.es, 2, 9);
-
- _retl(TRUE);
- }
- else
- _retl(FALSE);
-
- return;
- }
-