home *** CD-ROM | disk | FTP | other *** search
- ;----------------------------------
- ;
- ; EXTENDA.MAC
- ;
- ; by Ralph Davis
- ;
- ; Placed in the public domain.
- ;
- ; Assembly language macros for Clipper interface
- ;
- ;----------------------------------
-
- ; Declare all Clipper internal functions
-
- EXTRN _PARINFO:FAR
- EXTRN _PARC:FAR
- EXTRN _PARNI:FAR
- EXTRN _PARNL:FAR
- EXTRN _PARND:FAR
- EXTRN _PARDS:FAR
- EXTRN _PARL:FAR
-
- EXTRN _RETC:FAR
- EXTRN _RETNI:FAR
- EXTRN _RETNL:FAR
- EXTRN _RETND:FAR
- EXTRN _RETDS:FAR
- EXTRN _RETL:FAR
-
-
- ; Equates from EXTEND.H
-
- UNDEF EQU 0
- CHARACTER EQU 1
- NUMERIC EQU 2
- LOGICAL EQU 4
- DATE EQU 8
- ALIAS EQU 16
-
- TRUE EQU 1
- FALSE EQU 0
-
-
- ;--------------------------------------
- ;
- ; _PAR functions
- ;
- ;-----------------
-
- ; get number of parms passed--returned in AX
-
- GET_PCOUNT MACRO
- XOR AX,AX
- PUSH AX
- CALL _PARINFO
- ADD SP,2
- ENDM
-
-
- ; get type of requested parm--returned in AX
-
- GET_PTYPE MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARINFO
- ADD SP,2
- ENDM
-
-
- ; get requested parm as string--returns segment and offset in AX:BX
-
- GET_CHAR MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARC
- ADD SP,2
- ENDM
-
-
- ; get requested parm as integer--returned in AX
-
- GET_INT MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARNI
- ADD SP,2
- ENDM
-
-
- ; get requested parm as long integer--returned in AX:BX
-
- GET_LONG MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARNL
- ADD SP,2
- ENDM
-
-
- ; get requested parm as double--returned in AX:BX:CX:DX
-
- GET_DBL MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARND
- ADD SP,2
- ENDM
-
-
- ; get requested parm as date string
- ; returns segment and offset as AX:BX
-
- GET_DATESTR MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARDS
- ADD SP,2
- ENDM
-
-
- ; get requested parm as logical true or false--returned in AX
-
- GET_LOGICAL MACRO N
- MOV AX,N
- PUSH AX
- CALL _PARL
- ADD SP,2
- ENDM
-
-
- ;--------------------------------------
- ;
- ; _RET functions
- ;
- ;---------------
- ; return char pointer in REG1:REG2
-
- RET_CHAR MACRO REG1,REG2
- IRP X,<REG1,REG2>
- PUSH X
- ENDM
- CALL _RETC
- ADD SP,4
- ENDM
-
-
- ; return integer in REG1
-
- RET_INT MACRO REG1
- PUSH REG1
- CALL _RETNI
- ADD SP,2
- ENDM
-
-
- ; return long integer in REG1:REG2
-
- RET_LONG MACRO REG1,REG2
- IRP X,<REG1,REG2>
- PUSH X
- ENDM
- CALL _RETNL
- ADD SP,4
- ENDM
-
-
- ; return 8-byte floating-point number in REG1:REG2:REG3:REG4
-
- RET_DBL MACRO REG1,REG2,REG3,REG4
- IRP X,<REG1,REG2,REG3,REG4>
- PUSH X
- ENDM
- CALL _RETND
- ADD SP,8
- ENDM
-
-
- ; return date string pointed to by REG1:REG2
-
- RET_DATESTR MACRO REG1,REG2 ; return pointer to date string
- ; in REG1:REG2
- IRP X,<REG1,REG2>
- PUSH X
- ENDM
- CALL _RETDS
- ADD SP,4
- ENDM
-
-
- ; return logical true (1) or false (0) in REG1
-
- RET_LOGICAL MACRO REG1 ; return 1 or 0 in REG1
- PUSH REG1
- CALL _RETL
- ADD SP,2
- ENDM
-
- ; EOF: EXTENDA.MAC
-
-
-
- Notice that all the Clipper extend system functions must be
-
-
-
- declared as FAR symbols in EXTRN statements. The assembler does
-
-
-
- not care what kind of values the functions return; it only needs
-
-
-
- to know that it will be generating FAR CALLs to reach them. The
-
-
-
- EQUates come directly from the #define statements at the
-
-
-
- beginning of EXTEND.H, and translate only the statements we will
-
-
-
- need.
-
- The first two macros, GET_PCOUNT and GET_PTYPE, use
-
-
-
- _parinfo(). As I mentioned earlier, this is a very useful
-
-
-
- function, and deserves some special attention.
-
- Here are some of the statements in EXTEND.H having to do
-
-
-
- with _parinfo() (also on page 62 of January 1986 DBA):
-
-
- #define PCOUNT (_parinfo(0))
- #define ISCHAR(n) (_parinfo(n) & CHARACTER)
- #define ISNUM(n) (_parinfo(n) & NUMERIC)
- #define ISLOG(n) (_parinfo(n) & LOGICAL)
- #define ISDATE(n) (_parinfo(n) & DATE)
-
-
- _parinfo() gives us the very important ability to pass a variable
-
-
-
- number of parameters to a user-defined function, and also to pass
-
-
-
- parameters of varying types. If we are writing C code, we simply
-
-
-
- include these macros to check the number of parameters passed,
-
-
-
- and their type, and then execute the appropriate section of code.
-
-
-
- To apply _parinfo() to assembler code, we have to look at these
-
-
-
- macro definitions closely to understand what they mean, then
-
-
-
- express them accordingly. PCOUNT, for instance, is defined as
-
-
-
- _parinfo(0). The macro GET_PCOUNT simply PUSHes a zero in AX
-
-
-
- onto the stack, then calls _PARINFO. Clipper returns the number
-
-
-
- of parameters passed in AX. ISCHAR(n) is defined as (_parinfo(n)
-
-
-
- & CHARACTER). So to obtain the type of the nth parameter, we
-
-
-
- PUSH n onto the stack and CALL _PARINFO. This is what the macro
-
-
-
- GET_PTYPE does. _PARINFO returns a numeric code in AX
-
-
-
- corresponding to the type of the variable, as defined in EXTEND.H
-
-
-
- and EXTENDA.MAC. As the definition of ISCHAR tells us, to
-
-
-
- determine if the variable is of CHARACTER type, we AND AX with
-
-
-
- the CHARACTER constant we have defined, i.e. 1. If we are left
-
-
-
- with a zero, the parameter is NOT character data. Otherwise, it
-
-
-
- is. The code would look like this.
-
-
- GET_PTYPE 1 ; Get type of first parameter
- AND AX,CHARACTER ; Is it character?
- JZ NOT_CHAR ; No, branch
-
- ; Code for character parameter follows here
-
-
- The GET and RET macros perform the tasks I described above:
-
-
-
- the GETs PUSH a number onto the stack and call Clipper to
-
-
-
- retrieve the corresponding variable; the RETs PUSH the computed
-
-
-
- values onto the stack and call Clipper to return them. All the
-
-
-
- macros are courteous enough to restore the stack pointer (SP).
-
-
-
- Before I present the code for an assembly-language function
-
-
-
- which uses these macros, there are a couple of subtleties I want
-
-
-
- to mention.
-
- Remember that _parc() and _pards() are declared as returning
-
-
-
- pointers to character data. This would seem to suggest that they
-
-
-
- pass us the address of the corresponding variable. For instance,
-
-
-
- suppose we have a user-defined function CAPITALS() which converts
-
-
-
- letters to upper-case. It does not return a value, it simply
-
-
-
- takes the character string passed and converts all the letters.
-
-
-
- What would we expect the following Clipper code to produce?
-
-
- m_string1 = 'data-based advisor'
- ? CAPITALS( m_string1 )
- ? m_string1
-
-
- We would expect that because our function does not return a
-
-
-
- value, the second statement would not output anything, and the
-
-
-
- third one would output DATA-BASED ADVISOR. In fact, the third
-
-
-
- outputs data-based advisor. This is because _parc() and _pards()
-
-
-
- pass a character pointer, yes, but NOT a pointer to the actual
-
-
-
- variable--only a pointer to a temporary copy of that variable.
-
-
-
- Essentially, Clipper passes all parameters to functions by value,
-
-
-
- not by reference. This may seem like a silly design at first
-
-
-
- sight, but it is quite consistent with the role most high-level
-
-
-
- languages assign to functions: to return a value. They use
-
-
-
- procedures to alter variables or perform significant tasks.
-
-
-
- Clipper's CALL statement DOES pass the address of the actual
-
-
-
- variable.
-
- I have come across some situations where this was an
-
-
-
- inconvenience, for example when I wanted to write functions
-
-
-
- returning the segment and offset addresses of a variable. I
-
-
-
- wanted the syntactical brevity of a function call, but I also had
-
-
-
- to have the address of the actual variable. The solution is to
-
-
-
- write a little Clipper function which does the CALL, and pass it
-
-
-
- the name of the variable as a character string. The function
-
-
-
- then issues the CALL statement using macro expansion with the
-
-
-
- string passed to it. Here is the function SEG() from Tom
-
-
-
- Rettig's and my Clip-On library:
-
-
-
- .cp13
- *************
- *
- * SEG() FUNCTION
- *
- * SYNTAX: SEG( <expC> )
- *
- * PARAMETERS: <expC> = name of memory variable
- * as a character string
- *
- * RETURNS: segment address of memory variable
- * as a hexadecimal string
- *
- *************
-
- FUNCTION SEG
- PARAMETERS m_var_in
- PRIVATE m_var_out
- m_var_out = SPACE(4)
-
- * Note use of &m_var_in
- CALL segment WITH &m_var_in, m_var_out
- RETURN m_var_out
-
- * End of function: SEG()
-
-