home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource4 / 256_01 / carryf.txt < prev    next >
Text File  |  1988-01-08  |  9KB  |  216 lines

  1.     SIMULATING THE USE OF THE CARRY FLAG UNDER De SMET C
  2.     ----------------------------------------------------
  3.  
  4.     It is often said that 'C' is very close to assembly language
  5.     in style, although much more frugal in its use of statements
  6.     and hence easier to maintain and to de-bug.   Where it may
  7.     miss out in comparison to assembly language is that C
  8.     functions normally only return one value, be it a 'char',
  9.     an 'int', a 'long' and so on whereas assembly language
  10.     provides (in say the case of the 8088/8086 family of chips)
  11.     for return values in more than one of the AX, BX, CX and DX
  12.     registers together with information in the setting of some
  13.     of the flags.
  14.  
  15.     The assembly language type of return values can easily be
  16.     simulated in C (in this case De Smet C) when the functions
  17.     are written in assembler (ASM88 language) and converted into
  18.     'O' files so that you can include them in the final run-time
  19.     programme with the 'bind' command.    
  20.     
  21.     As an example of the type of code required consider MS-DOS
  22.     2.x (and the later versions) where there are a great many
  23.     functions where the carry flag is set to show that an error
  24.     has occurred, then the error code itself is returned in the
  25.     AX register.   In the normal coding of these functions in the 
  26.     library included with the C compiler you just get an 'int'
  27.     return value (i.e. the return value in the AX register) and
  28.     you don't have any way of testing whether the carry flag is 
  29.     set, or not set.   
  30.  
  31.     Whilst in most cases the return value can generally be 
  32.     interpreted correctly as an error (when there has been an
  33.     error) the more elegant way of dealing with the problem is
  34.     to test for the carry flag being set, just as you would in an
  35.     assembly language function, and then examine the error value.
  36.  
  37.     A convenient way of doing this is to use the available 'extern'
  38.     register declarations which are -
  39.  
  40.          extern unsigned _rax, _rbx, _rcx, _rdx, _rsi, _rdi,
  41.                          _res, _rds;
  42.          extern char _carryf, _zerof;
  43.  
  44.     and which De Smet C has provided for use with its "_DOINT"
  45.     function.   If you do this then these values are always
  46.     available for your use when you need them later and you can
  47.     use any of the functions on this disk which use the De Smet
  48.     '_carryf' character variable.
  49.  
  50.     To illustrate how the technique works and to show how the
  51.     code needs to be written for the ASM88 language I have chosen 
  52.     the routine "FUN3CH.A" which is the "Create Handle' function
  53.     of INT 21H.
  54.  
  55.     There are a couple of things to keep in mind when studing
  56.     the code which follows.   The first is that De Smet C
  57.     pushes the variables (used in the function) onto the stack
  58.     starting from the rightmost variable.  i.e. they are in
  59.     the reverse order to the way you normally write them but,
  60.     because the stack is a "last-on, first-off" device then it
  61.     means you can extract the information from the stack in
  62.     the same order as you wrote it in the function itself.
  63.  
  64.     The second thing is that you don't actually disturb the stack
  65.     itself.   You access the information there using the Base
  66.     Pointer ('bp') and then restore the Base Pointer before you
  67.     exit the routine.   Thirdly you pass the address of the
  68.     _carryf variable to the function, not the variable itself.
  69.     In C terminology you pass a pointer to _carryf not _carryf
  70.     itself.
  71.  
  72.     The coding for FUN3CH.A now follows.   The additional comments
  73.     I have made here (not in the actual coding) are marked with
  74.     '/*' and '*/' just as they would be in a C function.
  75.  
  76.     ---------------------------------------------------------------------
  77.     ASM88 FILE:     FUN3CH.A     Create Handle
  78.     ----------
  79.     WRITTEN:        25/10/87
  80.     -------
  81.     PURPOSE:        This is one of a series of files which take
  82.     -------         advantage of INT 21H functions under MS-DOS.
  83.                     In each case the error situation is marked by
  84.                     the carry flag being set.   We use the De Smet
  85.                     external variable '_carryf' to see whether the
  86.                     carry is set on return from the function.
  87.                     If so, the error code can be used to obtain
  88.                     information about the specific error.
  89.  
  90.     USAGE:          int FUN3CH(name, attr, &_carryf)
  91.     -----           char *name;  (ASCIIZ string)
  92.                     int attr;
  93.                     char *_carryf;
  94.  
  95.     DEPENDENCIES:           De Smet C V 2.44+
  96.     ------------
  97.     Copyright 1987 - Cogar Computer Services Pty. Ltd
  98.     ---------------------------------------------------------------------
  99.  
  100.     /* 
  101.         First declare the name of the routine under the heading 'CSEG'.    
  102.         Note the underscore needed at the end of the name.
  103.     */
  104.  
  105.     CSEG
  106.     PUBLIC FUN3CH_
  107.  
  108.     /*  
  109.         The actual coding of the function follows.   Note the technique
  110.         to save the setting of the base pointer.   For the purposes of
  111.         these programmes it is not necessary to make ES common with DS,
  112.         but this is generally useful in ASM88 programmes.
  113.     */
  114.  
  115.     FUN3CH_:
  116.         push    bp    ; normal De Smet C start
  117.         mov    bp,sp    ; point to the stack
  118.         mov    ax,ds    ; and make ES common with DS
  119.         mov    es,ax
  120.     ----------------------------------------------------------------------
  121.         The unique programme follows.
  122.     ----------------------------------------------------------------------
  123.     /*
  124.         Take the values we need off the stack.   Note the first value is
  125.         located at 'bp+4' because the return address is pushed first and
  126.         then 'bp' was pushed by us as we started the programme.
  127.         The values are placed into the three registers as required by
  128.         MS-DOS so that INT 21H can be used.
  129.     */
  130.  
  131.         mov    dx,[bp+4]    ; put address of file name into DX
  132.         mov    cx,[bp+6]    ; put the file attribute into CX
  133.         mov    ah,3ch    ; put the Function No. into AH
  134.         int    21h
  135.  
  136.     /*
  137.         Now test to see whether the carry flag is set, which will tell
  138.         us that an error has occurred.   If there is an error we use
  139.         a conditional jump to the code to handle this situation.
  140.     */
  141.  
  142.         jc    FUN3CH_ERROR
  143.  
  144.     /*
  145.         If there is no error then we just jump over the error coding
  146.         to the normal return routine.
  147.     */
  148.  
  149.         jmp    FUN3CH_QUIT
  150.  
  151.     /*
  152.         If there has been an error then we get the address of the
  153.         (external) carry flag variable and send the value of one
  154.         to this address.   This is an example of the coding which
  155.         can be used to send a value to any external variable which
  156.         has previously had its address passed to the function.
  157.     */
  158.  
  159.     FUN3CH_ERROR:
  160.         mov    si,[bp+8]    ; put address of '_carryf' variable into SI
  161.         mov    byte [si],1    ; and then return with _carryf = 1
  162.  
  163.     /*
  164.         From this point the error routine just 'falls through' to the
  165.         normal programme termination where both the starting stack
  166.         conditions are restored and the starting Base Pointer is
  167.         restored.
  168.     */
  169.  
  170.     ----------------------------------------------------------------------
  171.         Normal programme termination.
  172.     ----------------------------------------------------------------------
  173.     FUN3CH_QUIT:
  174.         pop    bp    ; restore starting conditions
  175.         ret
  176.     ----------------------------------------------------------------------
  177.  
  178.  
  179.     As a side-benefit this technique allows the use of error-trapping
  180.     so that an explanatory message can be printed to the screen
  181.     explaining the nature of the error.   The file "ERRLIST.C"
  182.     is included under the sub-directory "ERRORS" to show the full
  183.     list of errors which have been included in the function -
  184.  
  185.               PRINTERR
  186.  
  187.     which is also to be found in sub-directory ERRORS.   If you
  188.     wish to use this facility in a programme just "bind" in
  189.     PRINTERR to your programme and then use the construct -
  190.  
  191.           if(_carryf)
  192.               printerr(error_return);
  193.  
  194.     where "error_return" is the value returned by the specific
  195.     function you have just used in the programme.
  196.  
  197.     If you find some (or all) of these functions useful in your
  198.     normal C programming then you should use the 'LIB88' library
  199.     creator to put them into an 'xxxx.S' file which can then be
  200.     used to bind in the required functions to the final run-time
  201.     programme.   The code is freely available for personal use
  202.     althoug