home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / nfsrc21.zip / CINT86.C < prev    next >
Text File  |  1991-08-16  |  9KB  |  230 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.2   15 Aug 1991 23:08:32   GLENN
  17.  * Forest Belt proofread/edited/cleaned up doc
  18.  * 
  19.  *    Rev 1.1   14 Jun 1991 03:48:42   GLENN
  20.  * Just corrected some typos in the documentation.
  21.  * 
  22.  *    Rev 1.0   27 May 1991 13:22:36   GLENN
  23.  * Initial revision.
  24.  *  
  25.  *
  26.  
  27.  *  $DOC$
  28.  *  $FUNCNAME$
  29.  *      FT_INT86()
  30.  *  $CATEGORY$
  31.  *      DOS/BIOS
  32.  *  $ONELINER$
  33.  *      Execute a software interrupt
  34.  *  $SYNTAX$
  35.  *      FT_INT86( <nInterruptNumber>, <aRegisterValues> ) -> lResult
  36.  *  $ARGUMENTS$
  37.  *      <nInterruptNumber> is the interrupt to execute.
  38.  *
  39.  *      <aRegisterValues> is an array that contains values to be loaded
  40.  *      into the various CPU registers.  The correspondence between
  41.  *      registers and array elements is as follows:
  42.  *
  43.  *               aElement[1]  ==  AX register
  44.  *               aElement[2]  ==  BX register
  45.  *               aElement[3]  ==  CX register
  46.  *               aElement[4]  ==  DX register
  47.  *               aElement[5]  ==  SI register
  48.  *               aElement[6]  ==  DI register
  49.  *               aElement[7]  ==  BP register
  50.  *               aElement[8]  ==  DS register
  51.  *               aElement[9]  ==  ES register
  52.  *               aElement[10] ==  Flags register
  53.  *  $RETURNS$
  54.  *      .T. if all parameters valid and the function was able
  55.  *          to execute the desired interrupt.
  56.  *      .F. if invalid parameters passed.
  57.  *
  58.  *     In addition, the array elements will contain whatever values were in
  59.  *     the CPU registers immediately after the interrupt was executed.  If
  60.  *     either of the string parameters were altered by the interrupt, these
  61.  *     changes will be reflected as well.
  62.  *  $DESCRIPTION$
  63.  *     It is occasionally useful to be able to call interrupts directly from
  64.  *     Clipper, without having to write a separate routine in C or ASM.  This
  65.  *     function allows you that capability.
  66.  *
  67.  *     Given Clipper's high-level orientation, this function is necessarily
  68.  *     somewhat messy to use.  First, declare an array of ten elements to
  69.  *     hold the eight values for the CPU registers and two string parameters.
  70.  *     Then initialize the array elements with the values that you want the
  71.  *     CPU registers to contain when the interrupt is executed.  You need not
  72.  *     initialize all the elements.  For example, if the interrupt requires
  73.  *     you to specify values for AX, DX, and DS, you would only need to
  74.  *     initialize elements 1, 4, and 8.
  75.  *
  76.  *     Once you have done the required register setup, call FT_INT86(),
  77.  *     passing the interrupt number and the register array as parameters.
  78.  *     The function will load the CPU with your specified values, execute the
  79.  *     interrupt, and then store the contents of the CPU registers back into
  80.  *     your array.  This will allow you to evaluate the results of the
  81.  *     interrupt.
  82.  *
  83.  *     Some interrupt services require you to pass the address of a string in
  84.  *     a pair of registers.  This function is capable of handling these sorts
  85.  *     of situations, but it will take a little work on your part.  If you need
  86.  *     to pass a string that uses the DS register, store the string in element
  87.  *     8;  if you need to pass a string that uses the ES register, store the
  88.  *     string in element 9.  FT_INT86() will detect that you've supplied a
  89.  *     string instead of a numeric value and will behave accordingly.
  90.  *
  91.  *     That takes care of obtaining the segment portion of the pointer.  To
  92.  *     specify which register is to contain the offset, use the values REG_DS
  93.  *     and REG_ES which are defined in the FTINT86.CH file.  When one of these
  94.  *     values is found in an array element, it alerts FT_Int86() to use the
  95.  *     offset portion of a pointer instead of a numeric value.  REG_DS tells
  96.  *     FT_Int86() to use the offset of the string in element 8, while REG_ES
  97.  *     tells FT_Int86() to use the offset of the string in element 9.
  98.  *
  99.  *     All the CPU registers are sixteen bits in size.  Some, however, are
  100.  *     also split into two 8-bit registers.  This function is only capable of
  101.  *     receiving and returning registers that are 16 bits in size.  To split
  102.  *     a 16-bit register into two 8-bit values, you can use the
  103.  *     pseudo-functions HighByte() and LowByte(), contained in the .CH file.
  104.  *
  105.  *     To alter an 8-bit number so it will appear in the high-order byte of a
  106.  *     register when passed to the FT_INT86() function, use the MakeHI()
  107.  *     pseudo-function contained in the .CH file.
  108.  *
  109.  *     This function is a shell for __ftint86(), which is written in assembler
  110.  *     and does the actual work of executing the interrupt.  __ftint86() is
  111.  *     callable from C, so feel free to incorporate it into any C routines
  112.  *     for which it might be useful.  The source for __ftint86() can be found
  113.  *     in the file AINT86.ASM.
  114.  *  $EXAMPLES$
  115.  *
  116.  *     * This example shows how to call the DOS "create file" service.  Take
  117.  *     * special note of how to set up string parameters.
  118.  *
  119.  *     #include "FTINT86.CH"
  120.  *
  121.  *     local aRegs[10]              && Declare the register array
  122.  *     aRegs[ AX ] := makehi(60)    && DOS service, create file
  123.  *     aRegs[ CX ] := 0             && Specify file attribute
  124.  *
  125.  *     * Pay attention here, this is crucial.  Note how to set up the string
  126.  *     * so it appears in DS:DX.
  127.  *
  128.  *     aRegs[ DS ] := "C:\MISC\MYFILE.XXX"
  129.  *     aRegs[ DX ] := REG_DS
  130.  *     FT_INT86( 33, aRegs)         && Make the call to the DOS interrupt
  131.  *
  132.  *
  133.  *     * This example shows how to call the DOS "get current directory"
  134.  *     * service.  This one also uses a string parameter, but note that it
  135.  *     * uses a different offset register.
  136.  *
  137.  *     #include "FTINT86.CH"
  138.  *
  139.  *     local aRegs[10]
  140.  *     aRegs[ AX ] := makehi(71)
  141.  *     aRegs[ DX ] := 0           // Choose default drive
  142.  *
  143.  *     * This service requires a 64-byte buffer whose address is in DS:SI.  DOS
  144.  *     * will fill the buffer with the current directory.
  145.  *
  146.  *     aRegs[ DS ] := space(64)
  147.  *     aRegs[ SI ] := REG_DS
  148.  *     FT_INT86( 33, aRegs)
  149.  *
  150.  *     ? aRegs[ DS ]       // Display the directory name
  151.  *
  152.  *
  153.  *
  154.  *     * For the sake of completeness, here's an example that doesn't use a
  155.  *     * string.  This one changes the video mode.
  156.  *
  157.  *     #include "FTINT86.CH"
  158.  *
  159.  *     local aRegs[10]
  160.  *
  161.  *     aRegs[ AX ] := 16          && Choose hi-res graphics
  162.  *     FT_INT86( 16, aRegs)
  163.  *  $INCLUDE$
  164.  *     FTINT86.CH
  165.  *  $END$
  166. */
  167.  
  168. #include "extend.h"
  169. #include "cint86.h"
  170.  
  171. CLIPPER FT_Int86(void)
  172. {
  173.    auto struct CPUREGS regs;
  174.    auto unsigned int i;
  175.    auto char * dsptr = NULL;
  176.    auto char * esptr = NULL;
  177.  
  178.    if ( (PCOUNT == 2) && ISNUM(1) && ISARRAY(2) )
  179.    {
  180.       if ( _parinfa(2, 8) & CHARACTER )
  181.       {
  182.          _storclen(NULL, _parclen(2, 8), 2, 8);
  183.          dsptr = _parc(2, 8);
  184.          regs.ds = *((unsigned int *)(&dsptr) + 1);
  185.       }
  186.       else
  187.          regs.ds = _parni(2, 8);
  188.  
  189.       if ( _parinfa(2, 9) & CHARACTER )
  190.       {
  191.          _storclen(NULL, _parclen(2, 9), 2, 9);
  192.          esptr = _parc(2, 9);
  193.          regs.es = *((unsigned int *)(&esptr) + 1);
  194.       }
  195.       else
  196.          regs.es = _parni(2, 9);
  197.  
  198.       for (i = 1; i <= 7; i++)
  199.       {
  200.          if ( _parinfa(2, i) & LOGICAL )
  201.             if ( _parl(2, i) )
  202.                *(((unsigned int *)(®s)) + i - 1) = *(unsigned int *)&dsptr;
  203.             else
  204.                *(((unsigned int *)(®s)) + i - 1) = *(unsigned int *)&esptr;
  205.          else
  206.             *(((unsigned int *)(®s)) + i - 1) = _parni(2, i);
  207.       }
  208.  
  209.       __ftint86( _parni(1), ®s);
  210.  
  211.       for (i = 1; i <= 7; i++)
  212.          _storni(*(((unsigned int *)(®s)) + i - 1), 2, i);
  213.  
  214.       _storni(regs.flags, 2, 10);
  215.  
  216.       if ( dsptr == NULL )
  217.          _storni(regs.ds, 2, 8);
  218.  
  219.       if ( esptr == NULL )
  220.          _storni(regs.es, 2, 9);
  221.  
  222.       _retl(TRUE);
  223.    }
  224.    else
  225.       _retl(FALSE);
  226.  
  227.    return;
  228. }
  229. 
  230.