;
; Macro file for MSDOS.
;

SUBTTL BREAK a listing into pages and give new subtitles
PAGE
BREAK   MACRO   subtitle
        SUBTTL  subtitle
        PAGE
ENDM

BREAK <I_NEED: declare a variable external, if necessary, and allocate a size>

;
; declare a variable external and allocate a size
;
I_NEED  MACRO   sym,len
    CODE    ENDS
    DATA    SEGMENT BYTE PUBLIC 'DATA'

    IFIDN   <len>,<WORD>
        EXTRN   &sym:WORD
    ELSE
        IFIDN   <len>,<DWORD>
            EXTRN   &sym:DWORD
        ELSE
           EXTRN   &sym:BYTE
        ENDIF
    ENDIF

    DATA    ENDS
    CODE    SEGMENT BYTE PUBLIC 'CODE'
ENDM

;
; call a procedure that may be external.  The call will be short.
;
invoke  MACRO   name
&.xcref
    add_ext name,near
&.cref
    CALL    name
ENDM

PAGE
;
; jump to a label that may be external.  The call will be near.
;
transfer    MACRO   name
&.xcref
    add_ext name,near
&.cref
    JUMP    name
ENDM

;
; get a short address in a word
;
short_addr  MACRO   name
    IFDIF   <name>,<?>
&.xcref
        add_ext name,near
&.cref
        DW  OFFSET DOSGROUP:name
    ELSE
        DW  ?
    ENDIF
ENDM

;
; get a long address in a dword
;
long_addr   MACRO   name
&.xcref
    add_ext name,far
&.cref
    DD  name
ENDM

;
; declare a PROC near or far but PUBLIC nonetheless
;
procedure   MACRO   name,distance
        PUBLIC  name
name    PROC    distance
ENDM

PAGE
;
; define a data item to be public and of an appropriate size/type
;
I_AM    MACRO   name,size
    PUBLIC  name

    IFIDN <size>,<WORD>
        name    DW  ?
    ELSE
        IFIDN <size>,<DWORD>
            name    DD  ?
        ELSE
            IFIDN <size>,<BYTE>
                name    DB  ?
            ELSE
                name    DB  size DUP (?)
            ENDIF
        ENDIF
    ENDIF
ENDM

PAGE
;
; play games with a possible external.  Create a new
; macro for the symbol and text, and string it together
; with a central invoker
;

.xcref
.xcref  ?i
.xcref def_mac
.xcref  ?z0
.xcref  add_ext
.cref

IF1
    ?i=0
ENDIF

?z0 macro
endm

;
; add an external declaration to s with type t if it is not defined
;
add_ext macro   s,t
&.xcref
&.xcref ?&s
&.cref
    IFNDEF   ?&s
        ?i = ?i + 1
        def_mac     ?z&%?i,?z&%(?i-1),s,t
    ENDIF
endm

;
; define a macro called that possibly externals s:t and then calls macro n
;
def_mac macro   m,n,s,t
&.xcref
&.xcref  ?&s
&.xcref  m
&.cref
m   macro
    ifndef s
        extrn s:&t
    endif
    purge m
    purge ?&s
    n
endm
?&s macro
&endm
endm

;
; call the macro chain
;
do_ext  macro
&.xcref
    expand_mac  ?z%?i
&.cref
endm

PAGE
expand_mac macro m
    m
endm

;
; define an entry in a procedure
;
entry macro name
    PUBLIC  name
name:
endm

BREAK <ERROR - print a message and then jump to a label>

error macro code
    local a
.xcref
    MOV AL,code
    transfer    SYS_RET_ERR
.cref
ENDM

BREAK <JUMP - real jump that links up shortwise>
;
; given a label <lbl> either 2 byte jump to another label <lbl>_J
; if it is near enough or 3 byte jump to <lbl>
;

jump    macro lbl
    local a
.xcref
    a:
    ifndef lbl&_J                       ; is this the first invocation
        JMP lbl
    ELSE
        IF lbl&_J GE $
            JMP lbl
        ELSE
            IF ($-lbl&_J) GT 126            ; is the jump too far away?
                JMP lbl
            ELSE                            ; do the short one...
                JMP lbl&_J
            ENDIF
        ENDIF
    ENDIF
endm

BREAK <RETURN - return from a function>

return  macro
    local a
.xcref
a:
    RET
ret_l = a
endm

BREAK <CONDRET - conditional return>

makelab macro l,cc,ncc
    j&ncc   a                           ; j<NCC> a:
    return                              ; return
    a:                                  ; a:
    ret_&cc = ret_l                     ; define ret_<CC> to be ret_l
endm

condret macro   cc,ncc
    local   a,b
    ifdef   ret_l                       ; if ret_l is defined
        if (($ - ret_l) le 126) and ($ gt ret_l)
                                        ;     if ret_l is near enough then
            a:  j&cc    ret_l           ;         a: j<CC> to ret_l
            ret_&cc = a                 ;         define ret_<CC> to be a:
        else
            makelab a,cc,ncc
        endif
    else
        ifdef   ret_&cc                     ; if ret_<CC> defined
            if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
                                            ;     if ret_<CC> is near enough
                a:  j&cc    ret_&cc         ;         a: j<CC> to ret_<CC>
                ret_&cc = a                 ;         define ret_<CC> to be a:
            else
                makelab a,cc,ncc
            endif
        else
            makelab a,cc,ncc
        endif
    endif
endm
;condret macro   cc,ncc
;    local   a,b
;    ifdef   ret_l                       ; if ret_l is defined
;        if (($ - ret_l) le 126) and ($ gt ret_l)
;                                        ;     if ret_l is near enough then
;            a:  j&cc    ret_l           ;         a: j<CC> to ret_l
;            ret_&cc = a                 ;         define ret_<CC> to be a:
;            exitm
;        endif
;    endif
;    ifdef   ret_&cc                     ; if ret_<CC> defined
;        if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
;                                        ;     if ret_<CC> is near enough
;            a:  j&cc    ret_&cc         ;         a: j<CC> to ret_<CC>
;            ret_&cc = a                 ;         define ret_<CC> to be a:
;            exitm
;        endif
;    endif
;    j&ncc   a                           ; j<NCC> a:
;    return                              ; return
;    a:                                  ; a:
;    ret_&cc = ret_l                     ; define ret_<CC> to be ret_l
;endm

BREAK <RETZ - return if zero, links up shortwise if necessary>

retz    macro
    condret z,nz
endm

BREAK <RETNZ - return if not zero, links up shortwise if necessary>

retnz   macro
    condret nz,z
endm

BREAK <RETC - return if carry set, links up shortwise if necessary>

retc    macro
    condret c,nc
endm

BREAK <RETNC - return if not carry, links up shortwise if necessary>

retnc   macro
    condret nc,c
endm
