Post by T. MentI'm working on STDMAC.INC from MS-DOS Developer's Guide now. It's almost
20 pages.
I soon discovered STDMAC.INC depends on STDLIB.ASM. which is another 18
pages. Converting all that took some time. Glad to have it done.
I assembled STDMAC.INC in a skeleton wrapper to check for syntax errors,
found a few, and fixed them. I've not tested the code so I don't know if
any of it works, But FWIW, here it is.
;----------------------------------------------------------------
; MACRO DEFINITIONS INCLUDE FILE
;----------------------------------------------------------------
; STANDARD EQUATES:
;
TRUE EQU 0FFFFh ; TRUE
FALSE EQU 0 ; FALSE
;
; Standard nonprintable ASCII characters:
NUL EQU 00000000b ; null
BEL EQU 00000111b ; bell
BS EQU 00001000b ; backspace
HT EQU 00001001b ; horizontal tab
LF EQU 00001010b ; line feed
FF EQU 00001100b ; form feed
CR EQU 00001101b ; carriage return
SUBST EQU 00011010b ; substitute
ESCAPE EQU 00011011b ; escape
SPACE EQU 00100000b ; space
COLON EQU 00111010b ; colon
SCOLON EQU 00111011b ; semicolon
; IBM Extended characters:
SLINE EQU 11000100b ; horizontal line
;
;----------------------------------------------------------------
.XLIST ; suppress listing macro defs.
;;.LALL ; list everything
;;
;;
;;** @Model *************************** GENERAL PURPOSE MACRO **
;; Set up segments according to memory model.
;; This macro emulates the MASM 5.X .MODEL
;; directive for use with earlier versions of
;; of MASM.
IF1 ;; assemble only during Pass 1
@Model MACRO memory_model,code_name,stack_size
;; NOTE: "code_name" is used only with medium,
;; large, and huge memory models.
IFNB <memory_model> ;; was memory model specified?
;;
IF memory_model EQ 0
@TinyModel stack_size
ELSE
IF memory_model EQ 1
@SmallModel stack_size
ELSE
IF memory_model EQ 2
@MediumModel code_name,stack_size
ELSE
IF memory_model EQ 3
@CompactModel stack_size
ELSE
IF memory_model EQ 4
@LargeModel code_name,stack_size
ELSE
IF memory_model EQ 5
@LargeModel code_name,stack_size
ELSE
.ERR
%OUT @Model macro: unknown memory model
ENDIF ;; end of huge model check
ENDIF ;; end of large model check
ENDIF ;; end of compact model check
ENDIF ;; end of medium model check
ENDIF ;; end of small model check
ENDIF ;; end of tiny model check
;;
ELSE ;; memory model was not specified
.ERR ;; terminate with error message
%OUT @Model macro error: Memory model not specified.
ENDIF ;; end of memory-model parameter check
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Tiny **************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up TINY memory model (.COM type programs)
;; (This macro is called via "@Model 0".
;; This macro may also be called directly.)
;; Note that this macro, unlike the other memory-model macros,
;; does not make use of the @Stack macro, since alternate
;; stacks in .COM programs must be defined at the end of
;; of the program. To define an alternate stack in a .COM
;; program, execute the @Stack macro at the appropriate position
;; in the source code.
IF1 ;; assemble only during Pass 1
@TinyModel MACRO
MEMODEL = 0
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
;; Assign physical segments:
ASSUME cs:_TEXT, ds:_TEXT, ss:_TEXT, es:_TEXT
;;-----------------------------------------------
;; Insert the following code manually after @Model 0:
;;
;; _TEXT SEGMENT
;; main PROC near
;; entry: ORG 0100h
;; jmp start
;; ; <insert data here if desired>
;; start:
;; ; <insert program code here>
;; main ENDP
;; ; <insert routines here>
;; ; <insert optional stack here>
;; ; <insert data at the end if desired>
;; _TEXT ENDS
;; END entry
;;------------------------------------------------
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Small *************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up SMALL memory model
;; (This macro is called via "@Model small".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@SmallModel MACRO stack_size
MEMODEL = 1
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA' ; data seg. (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Medium ************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up MEDIUM memory model
;; (This macro is called via "@Model medium".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@MediumModel MACRO code_name,stack_size
MEMODEL = 2
code_name_TEXT SEGMENT BYTE PUBLIC 'CODE' ; named code
code_name_TEXT ENDS ; ... segment
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Compact ************************* GENERAL PURPOSE MACRO **
;; Direct macro to set up COMPACT memory model
;; (This macro is called via "@Model compact".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@CompactModel MACRO stack_size
MEMODEL = 3
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
FAR_DATA SEGMENT PARA 'FAR_DATA' ; private far data
FAR_DATA ENDS ; ... segment (DGROUP)
FAR_BSS SEGMENT PARA 'FAR_BSS' ; private far uninitialized
FAR_BSS ENDS ; ... data seg. (DGROUP)
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Large *************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up LARGE memory model
;; (This macro is called via "@Model large".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@LargeModel MACRO code_name,stack_size
MEMODEL = 4
code_name_TEXT SEGMENT BYTE PUBLIC 'CODE' ; named code seg.
code_name_TEXT ENDS
FAR_DATA SEGMENT PARA 'FAR_DATA' ; private far data
FAR_DATA ENDS ; ... segment (DGROUP)
FAR_BSS SEGMENT PARA 'FAR_BSS' ; private far uninitialized
FAR_BSS ENDS ; ... data seg. (DGROUP)
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Huge **************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up HUGE memory model
;; (This macro is called via "@Model huge".
;; This macro may also be called directly.)
;; The HUGE memory model is currently set up the
;; same as the LARGE memory model.
IF1 ;; assemble only during Pass 1
@HugeModel MACRO code_name,stack_size
MEMODEL = 5
@LargeModel code_name,stack_size
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Stack *************************** GENERAL PURPOSE MACRO **
;; Direct macro to establish the size of the stack
IF1 ;; assemble only during Pass 1
@Stack MACRO stack_size,prog_type
;;
IFB <prog_type> ;; if prog_type parameter is blank ...
IF MEMODEL EQ 0
PROGTYPE = 0
ELSE
IF MEMODEL EQ 1
PROGTYPE = 1
ELSE
IF MEMODEL EQ 2
PROGTYPE = 1
ELSE
IF MEMODEL EQ 3
PROGTYPE = 1
ELSE
IF MEMODEL EQ 4
PROGTYPE = 1
ELSE
IF MEMODEL EQ 5
PROGTYPE = 1
ELSE
.ERR
%OUT @Stack macro: The memory model or
%OUT program type was not established.
ENDIF ;; end of huge model check
ENDIF ;; end of large model check
ENDIF ;; end of compact model check
ENDIF ;; end of medium model check
ENDIF ;; end of small model check
ENDIF ;; end of tiny model check
ELSE ;; prog_type parameter was specified
IF prog_type EQ 0 ;; set up for .COM type program
PROGTYPE = 0
ELSE
IF prog_type EQ 1
PROGTYPE = 1
ELSE
.ERR ;; exit with error message
%OUT @Stack macro: Incorrect prog. type specified.
ENDIF ;; end of .EXE type check
ENDIF ;; end of .COM type check
ENDIF ;; end of "prog_type" parameter check
;;
IFNB <stack_size>
;;
IF PROGTYPE EQ 0
; Optional stack. CAUTION! You MUST use
; function 4Ch to terminate the program
; when using a local stack!
db stack_size DUP ('stack ')
top_of_stack EQU $
ELSE ;; prog. type is .EXE
STACK SEGMENT
db stack_size DUP ('stack ')
STACK ENDS
ENDIF ;; end of PROGTYPE check
;;
ELSE ;; "stack_size" parameter wasn't specified
;;
IF PROGTYPE EQ 0
; Optional stack. CAUTION! You MUST use
; function 4Ch to terminate the program
; when using a local stack!
db 32 DUP ('stack ')
top_of_stack EQU $
ELSE ;; prog. type is .EXE
STACK SEGMENT
db 32 DUP ('stack ')
STACK ENDS
ENDIF ;; end of PROGTYPE check
ENDIF ;; end of "stack_size" check
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @SwapNewStack ******************** GENERAL PURPOSE MACRO **
;; Switch stack to a new stack
IF1 ;; assemble only during Pass 1
@SwapNewStack MACRO tos
LOCAL bypass
;;
jmp bypass ;; skip data area
old_stk_seg dw ;; space for caller's stack segment
old_stk_ptr dw ;; space for caller's stack pointer
new_stk_seg dw ;; space for new stack segment
new_stk_ptr dw offset tos ;; space for new stack pointer
;;
bypass:
mov cs:new_stk_seg,cs ;; set new stack segment
mov cs:old_stk_seg,ss ;; save old stack values
mov cs:old_stk_ptr,sp ;; save old stack pointer
mov ss,cs:new_stk_seg ;; get new stack values
mov sp,cs:new_stk_ptr ;; get new stack pointer
@PushAll ;; save flags and all registers
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @SwapOldStack ******************** GENERAL PURPOSE MACRO **
;; Switch from new stack to the original stack.
IF1 ;; assemble only during Pass 1
@SwapOldStack MACRO
@PopAll ;; restore flags and all regs.
mov ss,cs:old_stk_seg ;; restore old stack values
mov sp,cs:old_stk_ptr
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DosCall ************************* GENERAL PURPOSE MACRO **
;; Call an MS-DOS function
IF1 ;; assemble only during Pass 1
@DosCall MACRO
int 21h
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DirConCharIO ******************** GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@DirConCharIO MACRO ; check keyboard status & read
push dx ; save DX
mov dl,0FFh ; no character to output
mov ah,06h
@DosCall
pop dx ; restore DX
ENDM
ENDIF ;; end of pass execution
;;
;;** @ReadCon_NoEcho ****************** GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@ReadCon_NoEcho MACRO
mov ah,08h ; read keyboard without echo
aDosCall
ENDM
ENDIF ;; end of pass execution
;;
;;** @ReadBufflnput ******************* GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@ReadBufflnput MACRO buffname ; read buffered keyboard input
mov dx,offset bufname
mov ah,0Ah
@DosCall
ENDM
ENDIF ;; end of pass execution
;;
;;** @DisChr ************************** GENERAL PURPOSE MACRO **
;; Display an immediate character
IF1 ;; assemble only during Pass 1
@DisChr MACRO char
IFNB <char> ;; was character argument specified?
;; yes, so insert code
push ax ;; save registers used
push dx
mov dl,char ;; load character
mov ah,02h ;; load func. number
@DosCall ;; call MS-DOS
pop dx ;; restore registers
pop ax
ELSE ;; otherwise
.ERR ;; generate error and output message
%OUT @DisChr macro: "char" argument not supplied.
ENDIF
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr ************************** GENERAL PURPOSE MACRO **
;; Display a string from memory with default "$"
;; end-of-string terminator or with a specified
;; terminator.
;; (Calls @DisStr1 or cDisStr2 internal macros.)
IF1 ;; assemble only during Pass 1
@DisStr MACRO string,terminator
IFNB <string> ;; was string argument specified?
;; yes, so ...
IFB <terminator> ;; was terminator specified?
;; no, so insert default code for "$" terminator
@DisStr1 string
ELSE ;; otherwise, a terminator was specified
@DisStr2 string,terminator
ENDIF ;; end "terminator" check
ELSE ;; otherwise, "string" was not specified
.ERR ;; generate error and output message
%OUT @DisStr macro: "string" argument not supplied.
ENDIF
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr1 ********************************* SUPPORT MACRO **
;; Called by @DisStr to display a string from memory with
;; default "$" end-of-string terminator.
IF1 ;; assemble only during Pass 1
@DisStr1 MACRO string
push ax ;;save registers used
push dx
mov dx,offset ds:string ;; point to string
;; in memory
mov ah,09h ;; load func. number
@DosCall ;; call MS-DOS
pop dx ;; restore registers used
pop ax
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr2 ********************************* SUPPORT MACRO **
;; Called by @DisStr to display a string from memory with a
;; specified end-of-string terminator.
IF1 ;; assemble only during Pass 1
@DisStr2 MACRO string,terminator
LOCAL strloop,strloopdone ;; create local labels
push si ;; save registers
push ax
push bx
push dx
xor bh,bh ;; clear BX
mov bl,terminator ;; get the terminator
mov si,offset string ;; point to string
xor dx,dx
strloop:
mov dl,byte ptr [si] ;; get next char.
cmp dl,bl ;; is it the terminator?
je strloopdone ;; yes, we're done
mov ah,02h ;; load output-char. function
@DosCall ;; and call DOS
inc si ;; point to next char.
jmp short strloop ;; and go thru again
strloopdone:
pop dx ;; restore registers
pop bx
pop ax
pop si
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;** @TypeStr ************************* GENERAL PURPOSE MACRO **
;; Display an immediate string (string defined on the fly)
;; NOTE: "string" must be presented within quotes so that
;; it is treated as a single argument to the macro and to
;; ensure that the data is encoded correctly.
IF1 ;; assemble only during Pass 1
@TypeStr MACRO string ;; define and display a string
LOCAL TypeStrAddr ;; set up a local label
;;
IF MEMODEL NE 0 ;; if not .COM type
_TEXT ENDS ;; end code segment
_DATA SEGMENT ;; change to data segment
ENDIF
TypeStrAddr DB string,'$' ;; define string in data segment
IF MEMODEL NE 0 ;; if not .COM type
_DATA ENDS ;; end data segment
_TEXT SEGMENT ;; return to code segment
ENDIF
;;
@DisStr TypeStrAddr ;; display string
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @TypeStrCR *********************** GENERAL PURPOSE MACRO **
;; Display an immediate string terminated with a CR/LF
;; "string" must be presented within quotes so that it is
;; treated as a single argument to the macro.
IF1 ;; assemble only during Pass 1
@TypeStrCR MACRO string
@TypeStr string ;; define and display string
@NewLine ;; terminate with a CR/LF
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @NewLine ************************* GENERAL PURPOSE MACRO **
;; Display a carriage return and linefeed
IF1 ;; assemble only during Pass 1
@NewLine MACRO
IFNDEF EXT_NEWLINE ;; was EXT_NEWLINE symbol defined?
EXTRN newline:NEAR ;; no, insert EXTRN only once
EXT_NEWLINE EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call newline ;; call NEWLINE procedure
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisNum ************************** GENERAL PURPOSE MACRO **
;; Display a binary number in ASCII decimal or hexadecimal
IF1 ;; assemble only during Pass 1
@DisNum MACRO number,type,digits,sign
;; Test for required parameters first
IFB <number> ;; was number parameter specified?
.ERR ;; no, exit with error message
%OUT @DisNum macro: "number" parameter not specified.
ELSE
IFB <type> ;; was type of output specified?
.ERR ;; no, exit with error message
%OUT @DisNum macro: "type" parameter not specified.
ELSE
IF type NE 10 AND type NE 16
.ERR
%OUT @DisNum Macro: Illegal "type" specified.
ELSE ;; parameters OK
IF type EQ 10 ;; decimal conversion specified?
IFNDEF EXT_BIN2DEC ;; was EXT_BIN2DEC defined?
EXTRN bin2dec:NEAR ;; no, insert EXTRN declaration
EXT_BIN2DEC EQU 0 ;; and equate only once
ENDIF
ELSE ;; hex. conversion specified
IFNDEF EXT_BIN2HEX ;; was EXT_BIN2HEX defined?
EXTRN bin2hex:NEAR ;; no, insert EXTRN declaration
EXT_BIN2HEX EQU 0 ;; and equate only once
ENDIF
ENDIF
;;
;; Begin code insertion
push ax ;; save registers
push cx
push dx
;;
mov ax,number ;; put number in AX
;;
IFNB <digits> ;; was digits argument specified?
mov ch,digits ;; yes, put value in CH
ELSE ;; otherwise
mov ch,1 ;; default to disp. at least 1 digit
ENDIF
;;
IFNB <sign> ;; was the sign argument specified?
mov dx,sign ;; yes, so put it in DX
ELSE ;; otherwise
mov dx,0 ;; default to unsigned
ENDIF
;;
IF type EQ 10 ;; decimal conversion specified?
call bin2dec
ELSE ;; hex. conversion specified
call bin2hex
ENDIF
;;
pop dx ;; restore registers
pop cx
pop ax
;;
ENDIF ;; parameters OK
ENDIF
ENDIF
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetDate ************************* GENERAL PURPOSE MACRO **
;; Get the system date
IF1 ;; assemble only during Pass 1
@GetDate MACRO
mov ah,2Ah ;; load func. number
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetTime ************************* GENERAL PURPOSE MACRO **
;; Get the system time
IF1 ;; assemble only during Pass 1
@GetTime MACRO
mov ah,2Ch ;; load func. number
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DiskRead ************************ GENERAL PURPOSE MACRO **
;; Read from logical sector(s)
IF1 ;; assemble only during Pass 1
@DiskRead MACRO
int 25h ;; execute absolute disk-read interrupt
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DiskWrite *********************** GENERAL PURPOSE MACRO **
;; Write to logical sector(s)
IF1 ;; assemble only during Pass 1
@DiskWrite MACRO
int 26h ;; execute absolute disk-write interrupt
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetDOSVersion ******************* GENERAL PURPOSE MACRO **
;; Get DOS Version number
IF1 ;; assemble only during Pass 1
@GetDOSVersion MACRO
push bx ;; save registers destroyed
push cx
mov ah,30h ;; load func. number
@DosCall ;; call MS-DOS
pop cx ;; restore registers
pop bx
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** GetDOSVer ********************** GENERAL PURPOSE MACRO **
;; Get DOS Version number
IF1 ;; assemble only during Pass 1
@GetDOSVer MACRO
IFNDEF EXT_GDOSV ;; was symbol defined?
EXTRN GETDOSV:NEAR ;; no, insert EXTRN only once
EXT_GDOSV EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call dosver ;; call library routine
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisDOSVer ********************** GENERAL PURPOSE MACRO **
;; Get and display DOS Version number
IF1 ;; assemble only during Pass 1
@DisDOSVer MACRO
IFNDEF EXT_DDOSV ;; was symbol defined?
EXTRN DOSV2CON:NEAR ;; no, insert EXTRN only once
EXT_DDOSV EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call dosv2con ;; call library routine
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @ChangeCase ********************** GENERAL PURPOSE MACRO **
;; Change case of character
IF1 ;; execute only on pass 1
@ChangeCase MACRO char,type
IFB <char> ;; was char to be converted specified?
.ERR ;; no, generate error and output message
%OUT @ChangeCase macro: "char" parameter not defined!
ELSE ;; otherwise
mov al,char ;; load char into AL
ENDIF
;;
IFB <type> ;; was type of conversion specified?
mov ah,0 ;; no, so Load 0 into AH
ELSE
mov ah,type ;; load type of conversion into AH
ENDIF
;;
IFNDEF EXT_CHGCASE ;; was EXT_CHGCASE symbol defined?
EXTRN CHGCASE:NEAR ;; no, insert EXTRN only once
EXT_CHGCASE EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
;;
call chgcase ;; call change-case library procedure
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Case **************************** GENERAL PURPOSE MACRO **
;; CASE macro for assembly language
@Case MACRO key,case_list,jmp_labels
??tmp_1 = 0
IRP match,<&case_list> ;; sequence through cases
??tmp_1 = ??tmp_1 + 1 ;; set index number
cmp key,&&match ; case match?
??tmp_2 = 0
IRP retl,<&jmp_labels> ;; sequence through jumps
??tmp_2 = ??tmp_2 + 1 ;; ... until index matches
IF (??tmp_1 EQ ??tmp_2)
je &&&retl ; yes!
EXITM
ENDIF ;; end condition check
ENDM ;; end 2nd IRP block
ENDM ;; end 1st IRP block
ENDM ;; end macro definition
;;
;;***************************************************************
;; Use the @PushAll and @PopAll macros instead of the
;; PUSHA and POPA instructions supported by the
;; 80186/80188/80286/80386 processors to maintain
;; compatibility with the 8086/8088 processors.
;;
;;** @PushAll ************************* GENERAL PURPOSE MACRO **
;; Push all registers
IF1 ;; execute only during pass 1
@PushAll MACRO ;; save all registers onto the stack
push ax
push bx
push cx
push dx
push bp
push di
push si
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @PopALL ************************** GENERAL PURPOSE MACRO **
;; Pop all registers
IF1 ;; execute only during pass 1
@PopAll MACRO ;; restore all registers off of the stack
pop si
pop di
pop bp
pop dx
pop cx
pop bx
pop ax
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @ExitToDos *********************** GENERAL PURPOSE MACRO **
;; Terminate process with optional ERRORLEVEL settings
IF1 ;; execute only during pass 1
@ExitToDOS MACRO errorcode
IFB <errorcode> ;; was an errorcode specified?
mov ax,4C0Oh ;; no, load func. & errorlevel 0 into AX
ELSE ;; otherwise
mov ah,4Ch ;; load function
mov al,errorcode ;; and errorlevel separately
ENDIF
;;
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;***************************************************************
;; END OF MACRO DEFINITIONS
;;***************************************************************
.LIST ; restore listing back to normal
; End of macro definitions include file.