EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

dosapi.htm
Enumerations
%StdCall16
Macros
DosAPI
GetArg
GetArgCount
GetEnv
StdInput
StdOutput
TerminateProgram
TerminateStayResident

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"
↑ %StdCall16
This assignments define preprocessing %variables useful to refer stack frame in 16bit StdCall calling convention.
Example
PUSH Factor3,Factor2,Factor1 CALL Multiply ; Calculate product. ; Do something with product in DX:AX. Multiply PROC1 ; Return product of three pushed factors in DX:AX. CF=overflow. PUSHAW MOV BP,SP MOV AX,[%Par1] ; AX=Factor1 MUL [%Par2],DATA=WORD ; DX:AX=Factor1 * Factor2 JC .Overflow: MUL [%Par3],DATA=WORD ; DX:AX=Factor1 * Factor2 * Factor3 .Overflow:MOV [%ReturnAX],AX MOV [%ReturnDX],DX POPAW RET 3*2 ; Discard three pushed factors. ENDPROC1 Multiply
 %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 INT=21h, reg1=value1, reg2=value2,,,
Macro DosAPI provides interaction with Disk Operation System (DOS), with the help of software-called interruptions.
Documented
[IntList]
Input
INT= is the interrupt number, if other than 0x21.
regX=valueX. Arbitrary number of keyword parameters can be specified and the corresponding 8bit or 16bit general-purpose or segment register will be loaded with its specified value before the interrupt is called.
Registers are loaded in the order as specified in the macro invocation.
Names of registers and the INT= keyword are case-sensitive but both uppercase or lowercase may be used.
Output
Values returned from interrupt service are defined in the documentation.
Error
As specified in the documentation.
Examples
LDS DX,[NewTimerHandlerFarProc] DosAPI AH=0x25,AL=8 ; Set new vector DS:DX for interrupt 8. ; DosAPI AX=0x2508 ; This equivalent invocation is 1 byte shorter.
See also
BiosAPI
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
            %IF "%key" !== "%value"
              MOV %key,%value ; Emit the instruction which loads the register %key.
            %ENDIF
          %ENDIF
        %ENDIF
    %ENDFOR k                ; Process the next keyword operand.
    INT %intNr               ; Finally emit the DOS service call.
  %ENDMACRO DosAPI
↑ GetArg   ArgNumber

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
Input
ArgNumber is ordinal number (1..254) of the required command-line parameter. It can also be provided in 16bit register or memory variable.
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.
Output
CF=0,
SI is offset of the first byte of argument in PSP segment ES,
CX is the size of argument in bytes. CX=0 when the argument is empty (white spaces only).
Error
CF=1 bad syntax - odd number of quotes.
CX=0,
SI= unchanged.
Example
CmdLine: /C "file1", "file2" --help GetArg 4: │ │ │ └SI CX=6 GetArg 3: │ │ └SI CX=7 GetArg 2: │ └SI CX=7 GetArg 1: └SI CX=2 AX=1
See also
GetArgCount
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      ; End of command-line reached?
    JNB .50:       ; If no more arguments are available.
    LODSB [ES:SI]
    CMP AL,' '
    JBE .20:       ; Ignore the separator (space).
    DEC SI
    INC CX
    MOV BX,SI      ; BX points to the brutto 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:        ; Parse the next argument.
.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
This macro counts arguments provided on the command line of the executed program.
Arguments may be separated with unquoted spaces or unquoted commas. Multiple white-space separators are treated like a single space. Single apostrophe cannot be used as a quote.
Input
ES= is paragraph address of PSP , as it was set when DOS program starts.
Output
CF=0,
CX=number of arguments on the command line which launched the program.
Error
CF=1 bad syntax of arguments,
CX=0.
Depends on
GetArg
Example
All examples of the command lines below will return ArgCount=4.
Program.exe arg1 arg2 arg3 arg4 Program.exe "arg1",arg2 "arg3" arg4 Program.exe arg1,arg2, "arg3,arg3" "arg4
GetArgCount %MACRO
     GetArg -1
   %ENDMACRO GetArgCount
↑ GetEnv   EnvNamePtr, Size=-1

Macro GetEnv retrieves value of environment-variable with specified name EnvName at run-time. The zero-terminated value is returned in ES:SI,CX.
Requested name should be in upper case and either zero-terminated, or its EnvNameSize= explicitly specified.

Environment variables in DOS are stored in segment identified by current process' PSP at PSP.EnvSeg in the format EnvName=EnvValue where each definition is zero-terminated and one more zero (NULL character) terminates the whole array of ASCIIZ environment strings.
Remember that most DOS versions convert all environment names to uppercase.
In TINY COM programs are all segment registers permanently set to PSP. In DOS programs are DS and ES set to PSP when the executable MZ program starts, this value should be provided to the macro GetEnv in register ES.
Input
DS= is segment (paragraph address) of EnvName.
ES= is segment (paragraph address) of PSP , as it was set when DOS program started.
EnvNamePtr offset in DS of environment-variable name (in upper case).
Size=-1 netto size of EnvName in bytes. If this keyword argument is omitted, EnvName must be zero-terminated.
Output
CF=0
ES=segment of environment strings (different from PSP),
SI=offset in ES of environment variable value, NULL-terminated,
CX=size of environment variable value in bytes without the terminating NULL,
Error
CF=1 when the variable EnvName was not found in environment.
ES=segment of environment strings (different from PSP),
SI=0,
CX=0.
Example
; SMALL MZ program to show environment variable specified as argument %1: ShowEnv PROGRAM Format=MZ,Entry=Start: INCLUDE dosapi.htm Start: GetArg 1 ; Return 1st argument (EnvName) in ES:SI,CX. JCXZ .NotFound: ; If no EnvName was specified on command-line. StdOutput SI,Size=CX,Eol=Yes ; Echo the argument (EnvName). Assume DS=SEGMENT# PSP. GetEnv SI,Size=CX ; Value of EnvName ES:SI,CX is returned in ES:SI,CX. JC .NotFound: PUSH ES POP DS ; Load DS with environment segment ES. StdOutput SI,Eol=Yes ; Display ASCIIZ string DS:SI (env.value) on console. TerminateProgram Errorlevel=0 .NotFound:PUSH PARA# [DATA] ; Segment of data (literals). POP DS StdOutput =B" was not found in environment.",Eol=Yes TerminateProgram Errorlevel=4 ENDPROGRAM ShowEnv
Tested by
tdosapi.htm
GetEnv %MACRO EnvNamePtr, Size= -1
         PUSHW %Size, %EnvNamePtr
         CALL GetEnvDos16@RT::
GetEnvDos16@RT:: PROC1
          PUSHAW
           MOV BP,SP
           MOV ES,[ES:0x002C]  ; PSP.EnvSeg.
           MOV SI,[%Par1]      ; EnvNamePtr.
           MOV DX,[%Par2]      ; EnvNameSize.
           MOV BX,SI
           SUB DI,DI
           SUB AX,AX           ; AL=NULL.
           CLD
           JMPS .20:
.10:       MOV CX,-1           ; Try the next string.
           REPNE SCASB [ES:DI] ; Search for the terminating NULL.
           CMP AL,[ES:DI]      ; Second NULL terminates the whole set of environment strings.
           MOV CX,AX           ; Zero in case that EnvName was not found.
           MOV [%ReturnSI],AX  ; Zero in case that EnvName was not found.
           STC
           JZ .90:             ; End of the set of strings, CX=SI=0, CF=1, nothing found.
.20:       MOV SI,BX           ; EnvNamePtr.
           MOV CX,DX           ; EnvName Size. DS:SI is EnvName, max CX bytes or terminated with NULL.
           REPE CMPSB          ; ES:DI is name=value, perhaps the desired one.
           JCXZ .30:           ; If EnvNameSize was specified, omit the check on terminating NULL.
           DEC DI
           CMP [DS:SI-1],AL
.30:       JNE .10:
           CMPB [ES:DI],'='
           JNE .10:
           INC DI
           MOV [%ReturnSI],DI  ; EnvName was found, ES:DI is pointer to its value.
           MOV CX,-1
           REPNE SCASB [ES:DI] ; Find the size of ASCIIZ value ES:DI.
           NOT CX
           DEC CX
.90:       MOV [%ReturnCX],CX
          POPAW
          RET 2*2
         ENDP1 GetEnvDos16@RT::
       %ENDMACRO GetEnv
↑ StdOutput String1, String2,,, Size=-1, Handle=1, Eol=No

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 NULL character is never written.

If keyword Eol=Yes, macro writes CR+LF after all strings.

Input
DS= segment of all strings.
StringX is offset of (ASCIIZ) string of 8byte characters. Its segment is DS.
Size=-1 is the maximal possible string size. If its left to -1 (default), strings must be zero-terminated. This parameter applies to all ordinal operads.
Handle=1 is the number of device handle for the output. Standard output handles are Eol=No. If Yes, two additional characters CR and LF will be written on output after all strings have been written.
Output
CF=0
Error
CF=1
Depends on
DosAPI
Examples
StdOutput Message, Eol=Yes StdOutput Eol=Yes ; Write new line (CR+LF) only. StdOutput =B"Page header",=B(12),Handle=4 ; Print header and then eject page from the printer at LPT1.
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
↑ StdInput Buffer, Size=, Handle=0

Macro StdInput reads a line terminated with CR (ASCII 13) from standard input or from other equipment identified by the DOS device Handle number.

Input
Buffer is offset of memory where the input line will be stored.
DS= segment of the Buffer.
Size= is the Buffer size. If omitted (default), macro will use SIZE# attribute of the Buffer.
Handle=0 is the number of device handle for the input. Standard input handles are
Output
CF=0,
CX=number of bytes actually read and stored to Buffer.
Error
CF=1,
CX=DOS error code.
Depends on
DosAPI
Remark
Input from keyboard is terminated with the Enter key. CR+LF are stored to Buffer, too.
See also
DosAPI AX=0x3301 how to abort the input by Ctrl-Break.
BiosAPI INT=0x16 for keyboard functions.
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
↑ TerminateProgram Errorlevel=0
This macro exits from the running DOS program and returns to DOS.
It also specifies the Errorlevel (plain number 0..255) which can be used to inform the batch script which launched the program whether the it terminated normally or with some error condition.
Programs in COM format can alternatively terminate with a simple instruction RETN if registers CS, SS, SP have the same value which they had at the program entry.
Documented
[IntList]
Input
Errorlevel=0 is immediate byte or 8bit register or memory operand.
Beside the keyword Errorlevel=, this value may also be specified as an ordinal operand.
When this argument is omitted, it defaults to 0.
Output
is not applicable.
Depends on
DosAPI
See also
TerminateStayResident
Remark
This macro is equivalent to DosAPI AH=0x4C,AL=Errorlevel.
Examples
TerminateProgram Errorlevel=[WorstErrLevel] ; Keyword value (from memory). TerminateProgram [WorstErrLevel] ; Ordinal value (from memory). TerminateProgram 8 ; Immediate value.
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
↑ TerminateStayResident   ResidentParagraphs, Errorlevel=0
This macro exits the running DOS program and returns to DOS, but leaves part of its memory allocated (resident).
It also specifies the Errorlevel (plain number 0..255) which can be used to inform the batch script which launched the program whether it terminated normally or due to some error.
Documented
[IntList]
Input
ResidentParagraphs is the size of resident memory in 16byte paragraphs (OWORDs).
It may be immediate value or 16bit memory variable or register (preferably DX).
Errorlevel=0 is immediate byte or 8bit register other than DL,DH, or memory operand.
Beside the keyword Errorlevel=, this value may also be specified as an ordinal operand.
When this argument is omitted, it defaults to 0.
Output
is not applicable.
Depends on
DosAPI
See also
TerminateProgram
Remark
This macro is equivalent to DosAPI AH=0x31,AL=Errorlevel,DX=ResidentParagraphs.
Examples
TerminateStayResident DX,0 ;
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.

▲Back to the top▲