home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / clipper / int86x.zip / CINT86X.C next >
C/C++ Source or Header  |  1993-07-10  |  10KB  |  278 lines

  1. /*
  2.  * File......: CINT86.C
  3.  * Author....: Ted Means
  4.  * Date......: $Date:   15 Aug 1991 23:08:32  $
  5.  * Revision..: $Revision:   1.2  $
  6.  * Log file..: $Logfile:   E:/nanfor/src/cint86.c_v  $
  7.  * 
  8.  * This function is an original work by Ted Means and is placed in the
  9.  * public domain.
  10.  *
  11.  * Modification history:
  12.  * ---------------------
  13.  *
  14.  * $Log:   E:/nanfor/src/cint86.c_v  $
  15.  * 
  16.  *    Rev 1.3    9 Jul 1993 11:17:00
  17.  * Ted Means merged real mode source code so that both versions would be
  18.  * reasonably consistent.
  19.  *
  20.  *    Rev 1.3    6 Jun 1993 19:30:12
  21.  * Anton van Straaten modified for ExoSpace;
  22.  * this version is ExoSpace-specific.
  23.  *
  24.  *    Rev 1.2   15 Aug 1991 23:08:32   GLENN
  25.  * Forest Belt proofread/edited/cleaned up doc
  26.  * 
  27.  *    Rev 1.1   14 Jun 1991 03:48:42   GLENN
  28.  * Just corrected some typos in the documentation.
  29.  * 
  30.  *    Rev 1.0   27 May 1991 13:22:36   GLENN
  31.  * Initial revision.
  32.  *  
  33.  *
  34.  
  35.  *  $DOC$
  36.  *  $FUNCNAME$
  37.  *      FT_INT86X()
  38.  *  $CATEGORY$
  39.  *      DOS/BIOS
  40.  *  $ONELINER$
  41.  *      Execute a software interrupt (in protected mode using ExoSpace)
  42.  *  $SYNTAX$
  43.  *      FT_INT86X( <nInterruptNumber>, <aRegisterValues> ) -> lResult
  44.  *  $ARGUMENTS$
  45.  *      <nInterruptNumber> is the interrupt to execute.
  46.  *
  47.  *      <aRegisterValues> is an array that contains values to be loaded
  48.  *      into the various CPU registers.  The correspondence between
  49.  *      registers and array elements is as follows:
  50.  *
  51.  *               aElement[1]  ==  AX register
  52.  *               aElement[2]  ==  BX register
  53.  *               aElement[3]  ==  CX register
  54.  *               aElement[4]  ==  DX register
  55.  *               aElement[5]  ==  SI register
  56.  *               aElement[6]  ==  DI register
  57.  *               aElement[7]  ==  BP register
  58.  *               aElement[8]  ==  DS register
  59.  *               aElement[9]  ==  ES register
  60.  *               aElement[10] ==  Flags register
  61.  *  $RETURNS$
  62.  *      .T. if all parameters valid and the function was able
  63.  *          to execute the desired interrupt.
  64.  *      .F. if invalid parameters passed.
  65.  *
  66.  *     In addition, the array elements will contain whatever values were in
  67.  *     the CPU registers immediately after the interrupt was executed.  If
  68.  *     either of the string parameters were altered by the interrupt, these
  69.  *     changes will be reflected as well.
  70.  *
  71.  *  $DESCRIPTION$
  72.  *     It is occasionally useful to be able to call interrupts directly from
  73.  *     Clipper, without having to write a separate routine in C or ASM.  This
  74.  *     function allows you that capability.
  75.  *
  76.  *     Given Clipper's high-level orientation, this function is necessarily
  77.  *     somewhat messy to use.  First, declare an array of ten elements to
  78.  *     hold the eight values for the CPU registers and two string parameters.
  79.  *     Then initialize the array elements with the values that you want the
  80.  *     CPU registers to contain when the interrupt is executed.  You need not
  81.  *     initialize all the elements.  For example, if the interrupt requires
  82.  *     you to specify values for AX, DX, and DS, you would only need to
  83.  *     initialize elements 1, 4, and 8.
  84.  *
  85.  *     Once you have done the required register setup, call FT_INT86(),
  86.  *     passing the interrupt number and the register array as parameters.
  87.  *     The function will load the CPU with your specified values, execute the
  88.  *     interrupt, and then store the contents of the CPU registers back into
  89.  *     your array.  This will allow you to evaluate the results of the
  90.  *     interrupt.
  91.  *
  92.  *     Some interrupt services require you to pass the address of a string in
  93.  *     a pair of registers.  This function is capable of handling these sorts
  94.  *     of situations, but it will take a little work on your part.  If you need
  95.  *     to pass a string that uses the DS register, store the string in element
  96.  *     8;  if you need to pass a string that uses the ES register, store the
  97.  *     string in element 9.  FT_INT86() will detect that you've supplied a
  98.  *     string instead of a numeric value and will behave accordingly.
  99.  *
  100.  *     That takes care of obtaining the segment portion of the pointer.  To
  101.  *     specify which register is to contain the offset, use the values REG_DS
  102.  *     and REG_ES which are defined in the FTINT86.CH file.  When one of these
  103.  *     values is found in an array element, it alerts FT_Int86() to use the
  104.  *     offset portion of a pointer instead of a numeric value.  REG_DS tells
  105.  *     FT_Int86() to use the offset of the string in element 8, while REG_ES
  106.  *     tells FT_Int86() to use the offset of the string in element 9.
  107.  *
  108.  *     All the CPU registers are sixteen bits in size.  Some, however, are
  109.  *     also split into two 8-bit registers.  This function is only capable of
  110.  *     receiving and returning registers that are 16 bits in size.  To split
  111.  *     a 16-bit register into two 8-bit values, you can use the
  112.  *     pseudo-functions HighByte() and LowByte(), contained in the .CH file.
  113.  *
  114.  *     To alter an 8-bit number so it will appear in the high-order byte of a
  115.  *     register when passed to the FT_INT86() function, use the MakeHI()
  116.  *     pseudo-function contained in the .CH file.
  117.  *
  118.  *     This function is a shell for __ftint86(), which is written in assembler
  119.  *     and does the actual work of executing the interrupt.  __ftint86() is
  120.  *     callable from C, so feel free to incorporate it into any C routines
  121.  *     for which it might be useful.  The source for __ftint86() can be found
  122.  *     in the file AINT86.ASM.
  123.  *  $EXAMPLES$
  124.  *
  125.  *     * This example shows how to call the DOS "create file" service.  Take
  126.  *     * special note of how to set up string parameters.
  127.  *
  128.  *     #include "FTINT86.CH"
  129.  *
  130.  *     local aRegs[10]              // Declare the register array
  131.  *     aRegs[ AX ] := makehi(60)    // DOS service, create file
  132.  *     aRegs[ CX ] := 0             // Specify file attribute
  133.  *
  134.  *     * Pay attention here, this is crucial.  Note how to set up the string
  135.  *     * so it appears in DS:DX.
  136.  *
  137.  *     aRegs[ DS ] := "C:\MISC\MYFILE.XXX"
  138.  *     aRegs[ DX ] := REG_DS
  139.  *     FT_INT86X( 33, aRegs)        // Make the call to the DOS interrupt
  140.  *
  141.  *
  142.  *
  143.  *     * This example shows how to call the DOS "get current directory"
  144.  *     * service.  This one also uses a string parameter, but note that it
  145.  *     * uses a different offset register.
  146.  *
  147.  *     #include "FTINT86.CH"
  148.  *
  149.  *     local aRegs[10]
  150.  *     aRegs[ AX ] := makehi(71)
  151.  *     aRegs[ DX ] := 0           // Choose default drive
  152.  *
  153.  *     * This service requires a 64-byte buffer whose address is in DS:SI.  DOS
  154.  *     * will fill the buffer with the current directory.
  155.  *
  156.  *     aRegs[ DS ] := space(64)
  157.  *     aRegs[ SI ] := REG_DS
  158.  *     FT_INT86X( 33, aRegs)
  159.  *
  160.  *     ? aRegs[ DS ]       // Display the directory name
  161.  *
  162.  *
  163.  *
  164.  *     * For the sake of completeness, here's an example that doesn't use a
  165.  *     * string.  This one changes the video mode.
  166.  *
  167.  *     #include "FTINT86.CH"
  168.  *
  169.  *     local aRegs[10]
  170.  *
  171.  *     aRegs[ AX ] := 16          // Choose hi-res graphics
  172.  *     FT_INT86X( 16, aRegs)
  173.  *  $INCLUDE$
  174.  *     FTINT86.CH
  175.  *  $END$
  176. */
  177.  
  178. #include "EXTEND.H"
  179. #include "CINT86X.H"
  180.  
  181. //                      AX BX CX DX SI DI BP
  182. static int regOff[] = {  9, 6, 8, 7, 3, 2, 4 };
  183.  
  184. CLIPPER FT_Int86X( void )
  185. {
  186.    auto REGISTERS regs;
  187.  
  188.    auto FARPTR dsPtr;            // Pointers to incoming params
  189.    auto FARPTR esPtr;
  190.  
  191.    auto FARPTR dsPma;            // Protected mode addresses
  192.    auto FARPTR esPma;
  193.  
  194.    auto FARPTR dsRma;            // Real mode addresses
  195.    auto FARPTR esRma;
  196.  
  197.    auto UINT nLenDS;
  198.    auto UINT nLenES;
  199.    auto UINT n;
  200.  
  201.    dsPma.Address = NULL;   dsRma.Address = NULL;
  202.    esPma.Address = NULL;   esRma.Address = NULL;
  203.  
  204.    if ( ( PCOUNT == 2 ) && ISNUM( 1 ) && ISARRAY( 2 ) )
  205.    {
  206.       if ( _parinfa( 2, 8 ) & CHARACTER )
  207.       {
  208.          nLenDS = _parclen( 2, 8 );
  209.          
  210.          _storclen( NULL, nLenDS, 2, 8 ); dsPtr.Address = _parc( 2, 8 );
  211.  
  212.          dsPma = _xalloclow( nLenDS );
  213.  
  214.          _bcopy( dsPma.Address, dsPtr.Address, nLenDS );
  215.  
  216.          dsRma = ExoRealPtr( dsPma ); regs.CPURegs.DS = dsRma.Pointer.Segment;
  217.       }
  218.       else
  219.          regs.CPURegs.DS = _parni( 2, 8 );
  220.  
  221.       if ( _parinfa( 2, 9 ) & CHARACTER )
  222.       {
  223.          nLenES = _parclen( 2, 9 );
  224.          
  225.          _storclen( NULL, nLenES, 2, 9 ); esPtr.Address = _parc( 2, 9 );
  226.  
  227.          esPma = _xalloclow( nLenES );
  228.  
  229.          _bcopy( esPma.Address, esPtr.Address, nLenES );
  230.  
  231.          esRma = ExoRealPtr( esPma ); regs.CPURegs.ES = esRma.Pointer.Segment;
  232.       }
  233.       else
  234.          regs.CPURegs.ES = _parni( 2, 9 );
  235.  
  236.       for ( n = 1; n <= 7; n++ )
  237.       {
  238.          if ( _parinfa( 2, n ) & LOGICAL )
  239.             if ( _parl( 2, n ) )
  240.                regs.registers[ regOff[ n - 1 ] ] = dsRma.Pointer.Offset;
  241.             else
  242.                regs.registers[ regOff[ n - 1 ] ] = esRma.Pointer.Offset;
  243.          else
  244.             regs.registers[ regOff[ n - 1 ] ] = _parni( 2, n );
  245.       }
  246.  
  247.       _storni( ExoRMInterrupt( _parni( 1 ), ®s, ®s ), 2, 10 );
  248.  
  249.       for ( n = 1; n <= 7; n++ )
  250.          _storni( regs.registers[ regOff[ n - 1 ] ], 2, n );
  251.  
  252.       if ( dsPma.Address == NULL )
  253.          _storni( regs.CPURegs.DS, 2, 8 );
  254.       else
  255.       {
  256.          _bcopy( dsPtr.Address, dsPma.Address, nLenDS );
  257.  
  258.          _xfreelow( dsPma.Address );
  259.       }
  260.  
  261.       if ( esPma.Address == NULL )
  262.          _storni( regs.CPURegs.ES, 2, 9 );
  263.       else
  264.       {
  265.          _bcopy( esPtr.Address, esPma.Address, nLenES );
  266.  
  267.          _xfreelow( esPma.Address );
  268.       }
  269.  
  270.       _retl( TRUE );
  271.    }
  272.    else
  273.       _retl( FALSE );
  274.  
  275.    return;
  276. }
  277.  
  278.