unit TDos;

{$O+,F+,S-}

interface

const

  ReadOnly  = $01;
  Hidden    = $02;
  SysFile   = $04;
  VolumeID  = $08;
  Directory = $10;
  Archive   = $20;
  AnyFile   = $3F;

type

  PathStr = string[79];
  DirStr  = string[67];
  NameStr = string[8];
  ExtStr  = string[4];

  SearchRec = record
    Fill: array[1..21] of Byte;
    Attr: Byte;
    Time: Longint;
    Size: Longint;
    Name: string[12];
  end;

  DateTime = record
    Year,Month,Day,Hour,Min,Sec: Word;
  end;

function  FOpen(Path: PathStr; Mode: Word): Integer;
procedure FClose(Handle: Integer);
function  FRead(Handle: Integer; var Buf; Count: Integer): Integer;
function  FWrite(Handle: Integer; var Buf; Count: Integer): Integer;
function  FSeek(Handle: Integer; Pos: Longint; Mode: Word): Longint;
function  GetFTime(Handle: Integer): Longint;
procedure SetFTime(Handle: Integer; Time: Longint);
function  FDelete(Path: PathStr): Integer;
function  GetFileTime(Path: PathStr): Longint;
function  FileExists(Path: PathStr): Boolean;
function  GetFileAttr(Path: PathStr): Integer;
function  FindFirst(Path: PathStr; Attr: Word; var F: SearchRec): Integer;
function  FindNext(var F: SearchRec): Integer;
function  FSearch(Path: PathStr; DirList: string): PathStr;
procedure FExpand(Path: PathStr; var Result: PathStr);
procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr;
  var Ext: ExtStr);
function  FRename(Path, NewName: PathStr): Integer;
function  GetCurDir(Drive: Char): DirStr;
function  ChDir(Path: PathStr): Integer;
function  GetCurDrive: Char;
procedure SetCurDrive(Drive: Char);
function  DriveValid(Drive: Char): Boolean;
procedure UnpackTime(P: Longint; var T: DateTime);
function  GetDateTime: Longint;
function  GetEnv(EnvVar: string): string;

implementation

procedure Pas2C; near; assembler;
asm
        MOV     DX,DI
        PUSH    SS
        POP     ES
        CLD
        LODSB
        XOR     AH,AH
        XCHG    AX,CX
        REP     MOVSB
        XCHG    AX,CX
        STOSB
        PUSH    ES
        POP     DS
end;

procedure C2Pas; assembler;
asm
        PUSH    DS
        PUSH    ES
        POP     DS
        XOR     AL,AL
        MOV     CX,256
        CLD
        REPNZ   SCASB
        NOT     CL
        MOV     AL,CL
        DEC     DI
        MOV     SI,DI
        DEC     SI
        STD
        REP     MOVSB
        STOSB
        POP     DS
end;

function FOpen(Path: PathStr; Mode: Word): Integer; assembler;
var
  PathC: array[0..79] of Char;
asm
        PUSH    DS
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AX,Mode
        CMP     AL,3
        ADC     AH,3CH
        XOR     CX,CX
        INT     21H
        JNC     @@1
        NEG     AX
@@1:    POP     DS
end;

procedure FClose(Handle: Integer); assembler;
asm
        MOV     AH,3EH
        MOV     BX,Handle
        INT     21H
end;

function FRead(Handle: Integer; var Buf; Count: Integer): Integer; assembler;
asm
        PUSH    DS
        MOV     AH,3FH
        MOV     BX,Handle
        MOV     CX,Count
        LDS     DX,Buf
        INT     21H
        JNC     @@1
        MOV     AX,-1
@@1:    POP     DS
end;

function FWrite(Handle: Integer; var Buf; Count: Integer): Integer; assembler;
asm
        PUSH    DS
        MOV     AH,40H
        MOV     BX,Handle
        MOV     CX,Count
        LDS     DX,Buf
        INT     21H
        JNC     @@1
        MOV     AX,-1
@@1:    POP     DS
end;

function FSeek(Handle: Integer; Pos: Longint; Mode: Word): Longint; assembler;
asm
        MOV     AH,42H
        MOV     AL,Mode.Byte
        MOV     BX,Handle
        MOV     DX,Pos.Word[0]
        MOV     CX,Pos.Word[2]
        INT     21H
        JNC     @@1
        MOV     AX,-1
        CWD
@@1:
end;

function GetFTime(Handle: Integer): Longint; assembler;
asm
        MOV     AX,5700H
        MOV     BX,Handle
        INT     21H
        XCHG    AX,CX
end;

procedure SetFTime(Handle: Integer; Time: Longint); assembler;
asm
        MOV     AX,5701H
        MOV     BX,Handle
        MOV     CX,Time.Word[0]
        MOV     DX,Time.Word[2]
        INT     21H
end;

function FDelete(Path: PathStr): Integer; assembler;
var
  PathC: array[0..79] of Char;
asm
        PUSH    DS
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AH,41H
        INT     21H
        JC      @@1
        XOR     AX,AX
@@1:    NEG     AX
        POP     DS
end;

function GetFileTime(Path: PathStr): Longint; assembler;
var
  PathC: array[0..79] of Char;
  DTA: array[0..47] of Byte;
asm
        PUSH    DS
        MOV     AH,1AH
        LEA     DX,DTA
        PUSH    SS
        POP     DS
        INT     21H
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AH,4EH
        XOR     CX,CX
        INT     21H
        MOV     AX,DTA.SearchRec.Time.Word[0]
        MOV     DX,DTA.SearchRec.Time.Word[2]
        JNC     @@1
        MOV     AX,-1
        CWD
@@1:    POP     DS
end;

function FileExists(Path: PathStr): Boolean; assembler;
asm
        LES     DI,Path
        PUSH    ES
        PUSH    DI
        CALL    GetFileTime
        AND     AX,DX
        INC     AX
        JZ      @@1
        MOV     AL,1
@@1:
end;

procedure DTAName; near; assembler;
asm
        INT     21H
        JC      @@1
        ADD     DI,SearchRec.Name
        CALL    C2Pas
        XOR     AX,AX
@@1:    NEG     AX
end;

function FindFirst(Path: PathStr; Attr: Word; var F: SearchRec): Integer;
  assembler;
var
  PathC: array[0..79] of Char;
asm
        PUSH    DS
        MOV     AH,1AH
        LDS     DX,F
        INT     21H
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AH,4EH
        MOV     CX,Attr
        LES     DI,F
        CALL    DTAName
        POP     DS
end;

function FindNext(var F: SearchRec): Integer; assembler;
asm
        PUSH    DS
        MOV     AH,1AH
        LDS     DX,F
        INT     21H
        MOV     AH,4FH
        LES     DI,F
        CALL    DTAName
        POP     DS
end;

function FSearch(Path: PathStr; DirList: string): PathStr; assembler;
asm
        PUSH    DS
        LDS     SI,DirList
        CLD
        LODSB
        MOV     BL,AL
        XOR     BH,BH
        ADD     BX,SI
        LES     DI,@Result
        INC     DI
@@1:    PUSH    SI
        PUSH    DS
        LDS     SI,Path
        LODSB
        MOV     CL,AL
        XOR     CH,CH
        REP     MOVSB
        XOR     AL,AL
        STOSB
        DEC     DI
        MOV     AX,4300H
        LDS     DX,@Result
        INC     DX
        INT     21H
        POP     DS
        POP     SI
        JC      @@2
        TEST    CX,VolumeID+Directory
        JZ      @@5
@@2:    LES     DI,@Result
        INC     DI
        CMP     SI,BX
        JE      @@5
        XOR     AX,AX
@@3:    LODSB
        CMP     AL,';'
        JE      @@4
        STOSB
        MOV     AH,AL
        CMP     SI,BX
        JNE     @@3
@@4:    CMP     AH,':'
        JE      @@1
        CMP     AH,'\'
        JE      @@1
        MOV     AL,'\'
        STOSB
        JMP     @@1
@@5:    MOV     AX,DI
        LES     DI,@Result
        SUB     AX,DI
        DEC     AX
        STOSB
        POP     DS
end;

function GetFileAttr(Path: PathStr): Integer; assembler;
var
  PathC: array[0..79] of Char;
  DTA: array[0..47] of Byte;
asm
        PUSH    DS
        MOV     AH,1AH
        LEA     DX,DTA
        PUSH    SS
        POP     DS
        INT     21H
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AH,4EH
        MOV     CX,Directory
        INT     21H
        MOV     AL,DTA.SearchRec.Attr
        MOV     AH,0
        JNC     @@1
        MOV     AX,-1
        CWD
@@1:    POP     DS
end;

procedure FExpand(Path:PathStr;var Result:PathStr);assembler;
var
  PathC, ResultC: array[0..79] of Char;
asm
        PUSH    DS
        LDS     SI,Path
        CLD
        LODSB
        XOR     AH,AH
        XCHG    AX,CX
        ADD     CX,SI
        LEA     DI,ResultC
        PUSH    SS
        POP     ES
        LODSW
        CMP     SI,CX
        JA      @@1
        CMP     AH,':'
        JNE     @@1
        CMP     AL,'a'
        JB      @@2
        CMP     AL,'z'
        JA      @@2
        SUB     AL,20H
        JMP     @@2
@@1:    DEC     SI
        DEC     SI
        MOV     AH,19H
        INT     21H
        ADD     AL,'A'
        MOV     AH,':'
@@2:    STOSW
        CMP     SI,CX
        JE      @@3
        CMP     [SI].Byte,'\'
        JE      @@4
@@3:    SUB     AL,'A'-1
        MOV     DL,AL
        MOV     AL,'\'
        STOSB
        PUSH    SI
        PUSH    DS
        MOV     AH,47H
        MOV     SI,DI
        PUSH    ES
        POP     DS
        INT     21H
        POP     DS
        POP     SI
        JC      @@4
        CMP     ES:[DI].Byte,0
        JE      @@4
        PUSH    CX
        MOV     CX,-1
        XOR     AL,AL
        REPNZ   SCASB
        DEC     DI
        MOV     AL,'\'
        STOSB
        POP     CX
@@4:    SUB     CX,SI
        REP     MOVSB
        XOR     AL,AL
        STOSB
        LEA     DI,ResultC
        MOV     SI,DI
        PUSH    ES
        POP     DS
        MOV     CX,-1
@@5:    LODSB
        OR      AL,AL
        JZ      @@8
        CMP     AL,'\'
        JE      @@8
        CMP     AL,'.'
        JE      @@7
        JCXZ    @@5
        DEC     CX
        CMP     AL,'a'
        JB      @@6
        CMP     AL,'z'
        JA      @@6
        SUB     AL,20H
@@6:    STOSB
        JMP     @@5
@@7:    MOV     CX,3
        JMP     @@6
@@8:    CMP     [DI-2].Word,'.\'
        JNE     @@9
        DEC     DI
        DEC     DI
        JMP     @@11
@@9:    CMP     [DI-2].Word,'..'
        JNE     @@11
        CMP     [DI-3].Byte,'\'
        JNE     @@11
        SUB     DI,3
        CMP     [DI-1].Byte,':'
        JE      @@11
@@10:   DEC     DI
        CMP     [DI].Byte,'\'
        JNE     @@10
@@11:   MOV     CX,8
        OR      AL,AL
        JNZ     @@6
        CMP     [DI-1].Byte,':'
        JNE     @@12
        MOV     AL,'\'
        STOSB
@@12:   LEA     SI,ResultC
        MOV     AX,DI
        SUB     AX,SI
        CMP     AL,79
        JB      @@13
        MOV     AL,79
@@13:   LES     DI,Result
        STOSB
        CBW
        XCHG    AX,CX
        REP     MOVSB
        POP     DS
end;

procedure SMove; near; assembler;
asm
        SUB     DX,BX
        CMP     AX,BX
        JB      @@1
        MOV     AX,BX
@@1:    STOSB
        MOV     CX,AX
        ADD     BX,SI
        REP     MOVSB
        MOV     SI,BX
end;

procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr;
  var Ext: ExtStr); assembler;
asm
        PUSH    DS
        LDS     SI,Path
        CLD
        LODSB
        MOV     DL,AL
        XOR     DH,DH
        MOV     BX,DX
        OR      BX,BX
        JZ      @@2
@@1:    CMP     [BX+SI-1].Byte,'\'
        JE      @@2
        CMP     [BX+SI-1].Byte,':'
        JE      @@2
        DEC     BX
        JNZ     @@1
@@2:    MOV     AX,67
        LES     DI,Dir
        CALL    SMove
        XOR     BX,BX
        JMP     @@4
@@3:    CMP     [BX+SI].Byte,'.'
        JE      @@5
        INC     BX
@@4:    CMP     BX,DX
        JNE     @@3
@@5:    MOV     AX,8
        LES     DI,Name
        CALL    SMove
        MOV     BX,DX
        MOV     AX,4
        LES     DI,Ext
        CALL    SMove
        POP     DS
end;

function FRename(Path, NewName: PathStr): Integer; assembler;
var
  NewNameC, PathC: array[0..79] of Char;
asm
        PUSH    DS
        LDS     SI,NewName
        LEA     DI,NewNameC
        CALL    Pas2C
        PUSH    DS
        PUSH    DX
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        POP     DI
        POP     ES
        MOV     AH,56H
        INT     21H
        JNC     @@1
        NEG     AX
        JMP     @@2
@@1:    XOR     AX,AX
@@2:    POP     DS
end;

function GetCurDir(Drive: Char): DirStr; assembler;
asm
        MOV     AL,Drive
        OR      AL,AL
        JNZ     @@1
        MOV     AH,19H
        INT     21H
        ADD     AL,'A'
@@1:    MOV     DL,AL
        LES     DI,@Result
        MOV     AH,':'
        CLD
        STOSW
        MOV     AL,'\'
        STOSB
        PUSH    DS
        MOV     AH,47H
        SUB     DL,'A'-1
        MOV     SI,DI
        PUSH    ES
        POP     DS
        INT     21H
        JNC     @@2
        MOV     [SI].Byte,0
@@2:    POP     DS
        LES     DI,@Result
        CALL    C2Pas
end;

function ChDir(Path: PathStr): Integer; assembler;
var
  PathC: array[0..79] of Char;
asm
        PUSH    DS
        LDS     SI,Path
        LEA     DI,PathC
        CALL    Pas2C
        MOV     AH,3BH
        INT     21H
        JC      @@1
        XOR     AX,AX
@@1:    POP     DS
end;

function GetCurDrive: Char; assembler;
asm
        MOV     AH,19H
        INT     21H
        ADD     AL,'A'
end;

procedure SetCurDrive(Drive: Char); assembler;
asm
        MOV     AH,0EH
        MOV     DL,Drive
        SUB     DL,'A'
        INT     21H
end;

function DriveValid(Drive: Char): Boolean; assembler;
asm
        MOV     DL,Drive
        MOV     AH,36H
        SUB     DL,'A'-1
        INT     21H
        INC     AX
        JZ      @@1
        MOV     AL,1
@@1:
end;

procedure UnpackTime(P: Longint; var T: DateTime); assembler;
asm
        LES     DI,T
        CLD
        MOV     AX,P.Word[2]
        MOV     CL,9
        SHR     AX,CL
        ADD     AX,1980
        STOSW
        MOV     AX,P.Word[2]
        MOV     CL,5
        SHR     AX,CL
        AND     AX,0FH
        STOSW
        MOV     AX,P.Word[2]
        AND     AX,1FH
        STOSW
        MOV     AX,P.Word[0]
        MOV     CL,11
        SHR     AX,CL
        STOSW
        MOV     AX,P.Word[0]
        MOV     CL,5
        SHR     AX,CL
        AND     AX,3FH
        STOSW
        MOV     AX,P.Word[0]
        AND     AX,1FH
        SHL     AX,1
        STOSW
end;

function GetDateTime: Longint; assembler;
asm
        MOV     AH,2AH
        INT     21H
        XCHG    AX,CX
        SUB     AX,1980
        MOV     CL,9
        SHL     AX,CL
        XOR     BX,BX
        MOV     BL,DH
        MOV     CL,5
        SHL     BX,CL
        OR      AX,BX
        OR      AL,DL
        PUSH    AX
        MOV     AH,2CH
        INT     21H
        XOR     AX,AX
        MOV     BX,CX
        XCHG    AL,BH
        MOV     CL,11
        SHL     AX,CL
        XOR     BH,BH
        MOV     CL,5
        SHL     BX,CL
        OR      AX,BX
        SHR     DH,1
        OR      AL,DH
        POP     DX
end;

function GetEnv(EnvVar: string): string; assembler;
var
  EnvVarC: array[0..31] of Char;
asm
        PUSH    DS
        CLD
        LDS     SI,EnvVar
        LEA     DI,EnvVarC
        PUSH    SS
        POP     ES
        LODSB
        CMP     AL,31
        JBE     @@1
        MOV     AL,31
@@1:    CBW
        MOV     CX,AX
        INC     AX
        MOV     DX,AX
        JCXZ    @@4
@@2:    LODSB
        CMP     AL,'a'
        JB      @@3
        CMP     AL,'z'
        JA      @@3
        SUB     AL,20H
@@3:    STOSB
        LOOP    @@2
@@4:    MOV     AL,'='
        STOSB
        POP     DS
        PUSH    DS
        MOV     DS,PrefixSeg
        MOV     DS,DS:2CH
        XOR     SI,SI
@@5:    CMP     [SI].Byte,0
        JE      @@7
        LEA     DI,EnvVarC
        MOV     CX,DX
        REPE    CMPSB
        JE      @@7
        DEC     SI
@@6:    LODSB
        OR      AL,AL
        JNZ     @@6
        JMP     @@5
@@7:    MOV     DI,SI
        PUSH    DS
        POP     ES
        XOR     AL,AL
        MOV     CX,256
        REPNZ   SCASB
        NOT     CL
        LES     DI,@Result
        MOV     AL,CL
        STOSB
        REP     MOVSB
        POP     DS
end;

end.
