This file can be included to 16bit DOS programs written in EuroAssembler.
It declares macroinstructions for interaction with
Disk Operation System - DOS.
DOS services run in 16bit real CPU mode.
dosapi HEAD ; Start of interface block includable to other programs. INCLUDEHEAD1 "cpuext.htm", "status16.htm"
%Par4 %SET BP+24 %Par3 %SET BP+22 %Par2 %SET BP+20 %Par1 %SET BP+18 %ReturnAX %SET BP+14 %ReturnCX %SET BP+12 %ReturnDX %SET BP+10 %ReturnBX %SET BP+08 %ReturnSP %SET BP+06 %ReturnBP %SET BP+04 %ReturnSI %SET BP+02 %ReturnDI %SET BP+00
DosAPI %MACRO INT=21h, \ AL=,AH=,CL=,CH=,DL=,DH=,BL=,BH=,AX=,CX=,DX=,BX=,BP=,SP=,SI=,DI=,DS=,ES=, \ al=,ah=,cl=,ch=,dl=,dh=,bl=,bh=,ax=,cx=,dx=,bx=,bp=,sp=,si=,di=,ds=,es= %intNr %SET 0x21 ; Interrupt 0x21 will be used if not specified otherwise. %kwlength %SETA %=# ; %kwlength is now the number of keyword operands in DosAPI invocation. k %FOR 1..%kwlength ; Loop through all keyword operands in DosAPI invocation. %kw %SET %=*{%k} ; %kw is now something like AH=5 or INT=21h. %kwsize %SETS %kw ; Number of characters in keyword operand %kw. %key %SET ; Split the operand by = to %key and %value. Start with empty %key. %i %SETA 1 ; Start with the 1st character. %REPEAT %IF "%kw[%i]" === "=" %EXITREPEAT ; Equal-sign found, the split is done. %ELSE %key %SET %key%kw[%i] ; Append the %i-th character and continue. %i %SETA %i + 1 %ENDIF %UNTIL %i > %kwsize %value %SET %kw[%i+1..%&] %IF "%key" == "INT" %intNr %SET %value ; Save the interrupt number for later to the variable %intNr. %ELSE %IF "%key"==="" || "%value"==="" %ERROR ID=5910,'Bad parameter "%key=%value", ignored.' %ELSE MOV %key,%value ; Emit the instruction which loads the register %key. %ENDIF %ENDIF %ENDFOR k ; Process the next keyword operand. INT %intNr ; Finally emit the DOS service call. %ENDMACRO DosAPI
Macro GetArg retrieves ArgNumber-th parameter provided on command line.
Parameters on the command line may be separated with unquoted
white spaces or unquoted commas. Single aphostrophe cannot be used as quote.
The returned argument is not zero terminated. Quotes surrounding the argument are returned, too, but separating white spaces and commas are stripped off.
Runtime procedure GetArg@RT is also used in macro GetArgCount , its functionality is controlled by the ArgNumber parameter.
Dump of PSP:80h when the DOS program launched with parameters
/1 "2"
:
07 20 2F 31 20 22 32 22 0D / 1 " 2 " CR
Dump of PSP:80h when the DOS program launched without parameters:
00 0D CR
ArgNumber=-1 is a special case when this macro is used by GetArgCount and it returns number of arguments in AX instead of argument string in ES:SI,CX.ES= is paragraph address of PSP , as it was set when DOS program starts.
GetArg %MACRO ArgNumber PUSHW %ArgNumber CALL GetArgDos16@RT GetArgDos16@RT:: PROC1 PUSHAW MOV BP,SP SUB AX,AX ; AL will be the parsed character. SUB CX,CX ; CX is argument counter. MOV [%ReturnCX],CX MOV SI,0x80 ; Offset of PSP.CmdArgSize byte. CLD LODSB [ES:SI] ; ES is paragraph address of PSP. MOV DX,SI MOV BX,SI ADD DX,AX ; ES:DX now points to the CR which terminates command-line parameters. .10:MOV DI,SI CMP CX,[%Par1] ; %Par1 is the number of requested argument. JAE .50: .20:CMP SI,DX JNB .50: ; If no more arguments are available. LODSB [ES:SI] CMP AL,' ' JBE .20: DEC SI INC CX MOV BX,SI ; BX points to the brutton begining of CX-th argument. MOV DI,SI ; DI points to the brutto end of current argument. .30:CMP SI,DX JNB .10: LODSB [ES:SI] CMP AL,'"' JNE .40: .35:CMP SI,DX CMC JC .90: ; CF signalizes syntax error - unpaired quotes. LODSB [ES:SI] CMP AL,'"' JNE .35: ; Inside the quoted string. JMP .30: .40:CMP AL,',' JE .10: CMP AL,' ' JA .30: .45:CMP SI,DX JNB .10: LODSB [ES:SI] CMP AL,' ' JNA .45: CMP AL,',' JE .10: DEC SI JMP .10: .50:CMPW [%Par1],-1 ; Test if invoked from GetArgCount with ArgNr= -1. JNE .60: MOV [%ReturnCX],CX JMP .80: .60:CMP CX,[%Par1] STC JNE .90: MOV SI,BX ; Brutto CX-th argument found at SI..DI. Trim spaces and commas. .65:CMP SI,DI JNB .75: LODSB [ES:SI] CMP AL,' ' JBE .65: CMP AL,',' JE .65: DEC SI .70:DEC DI MOV AL,[ES:DI] CMP AL,' ' JBE .70: CMP AL,',' JE .70: INC DI ; Netto argument is now at SI..DI. .75 MOV [%ReturnSI],SI SUB DI,SI JC .80: ; Return CX=0 when the netto size is not positive. MOV [%ReturnCX],DI .80:CLC .90:POPAW RET 2 ENDPROC1 GetArgDos16@RT:: %ENDMACRO GetArg
GetArgCount %MACRO GetArg -1 %ENDMACRO GetArgCount
Macro StdOutput writes one or more concatenated strings to the standard output or to other equipment identified by the DOS device Handle number.
Strings are either zero-terminated, or the keyword
Size=
must specify their size in bytes. The terminating NUL character is never written.
If keyword Eol=Yes
, macro writes CR+LF after all strings.
StdOutput %MACRO String1,String2,,,Size=-1, Handle=1, Eol=No OpNr %FOR 1..%#, STEP=1 PUSHW %Handle, %Size, %1 CALL StdOutputDos16@RT: %SHIFT 1 %ENDFOR OpNr %IF %Eol PUSHW %Handle, 2, -1 CALL StdOutputDos16@RT: %ENDIF StdOutputDos16@RT:: PROC1 ; StdCalled with %Par1=StringPtr,%Par2=Size,%Par3=Handle. PUSHAW MOV BP,SP PUSH ES,DS POP ES MOV DI,[%Par1] ; Pointer to String. MOV CX,[%Par2] ; String maximal size. MOV BX,[%Par3] ; Standard handle. JCXZ .90: CMP DI,-1 ; This sginalizes Eol request. JE .Eol: MOV DX,DI SUB AX,AX CLD REPNE SCASB JNE .50: DEC DI .50: SUB DI,DX DosAPI AH=0x40,BX=BX,CX=DI,DX=DX ; WRITE TO FILE OR DEVICE. .80: JC .90: CMP AX,CX ; Set CF in not all characters have been written. .90:POP ES POPAW RET 3*2 .Eol:PUSH DS PUSH SS POP DS PUSHW 0x0A0D ; Temporary store CR+LF on stack. DosAPI AH=0x40,BX=BX,CX=CX,DX=SP ; WRITE TO FILE OR DEVICE. INC SP,SP ; Discard CR+LF, preserve CF. POP DS JMPS .80: ENDPROC1 StdOutputDos16@RT:: %ENDMACRO StdOutput
Macro StdInput reads a line terminated with CR (ASCII 13) from standard input or from other equipment identified by the DOS device Handle number.
StdInput %MACRO Buffer, Size=, Handle=0 %IF "%Size" === "" PUSHW %Handle, SIZE# %Buffer, %Buffer %ELSE PUSHW %Handle, %Size, %Buffer %ENDIF CALL StdInputDos16@RT StdInputDos16@RT:: PROC1 ; StdCalled with %Par1=Buffer,%Par2=Size,%Par3=Handle. PUSHAW MOV BP,SP DosAPI AH=0x3F,BX=[%Par3],DX=[%Par1],CX=[%Par2] ; READ FROM FILE OR DEVICE. MOV [%ReturnCX],AX POPAW RET 3*2 ENDP1 StdInputDos16@RT:: %ENDMACRO StdInput
RETN
if registers CS, SS, SP have the same value as they had at the program entry.Errorlevel=
, this value may also be specified as an ordinal operand.
DosAPI AH=0x4C,AL=Errorlevel
.TerminateProgram %MACRO Errorlevel=0 %IF %# = 1 ; If ordinal provided. %IF "%1" !== "AL" MOV AL,%1 %ENDIF %ELSE ; Errorlevel is specified as keyword. %IF "%Errorlevel" !== "AL" MOV AL,%Errorlevel %ENDIF %ENDIF DosAPI AH=0x4C,AL=AL ; TERMINATE WITH RETURN CODE. %ENDMACRO TerminateProgram
Errorlevel=
, this value may also be specified as an ordinal operand.
DosAPI AH=0x31,AL=Errorlevel,DX=ResidentParagraphs
.TerminateStayResident %MACRO ResidentParagraphs, Errorlevel=0 %IF "%1" !== "DX" MOV DX,%1 %ENDIF %IF %# = 2 ; If two ordinals provided. MOV AL,%2 %ELSE MOV AL,%Errorlevel %ENDIF DosAPI AH=0x31,AL=AL,DX=DX ; TERMINATE AND STAY RESIDENT. %ENDMACRO TerminateStayResident
ENDHEAD dosapi ; End of interface block.