| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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
  - 1=StdOutput (console screen),
  - 2=StdError (nonredirectable console screen),
  - 3=StdAux (auxilliary output, serial port COM1),
  - 4=StdPrn (line printer, paralel port LPT1).
  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
  - 0=StdInput (keyboard),
  - 3=StdAux (auxilliary input, serial port COM1).
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▲