Contributor: ANDREW EIGUS { I'm very glad to be useful and to post the enhanced DOS unit for Turbo Pascal 7.0. It includes lots of nice routines written on inline asm, combined with short comments and explanations. All you have in standard DOS unit you may find in EnhDOS as well except of Exec and SwapVectors. Sure, the full source code! What is good? ----------------- 1. Fast! (because of the asm) 2. Flexible! (less procedures, more functions, lots of parameters) 3. Good error-handling routines. (don't need to care to check errors at all) 4. _Strong_ file service. (lots of file functions) 5. Lots of additional DOS service functions that can't be found in any standard or non-standard Pascal, C,... library. 6. Windows (tm) compatible (means you may use these routines when developing Windows (tm) applications. 7. Own memory allocate/release routines. (used DOS memory allocation) 8. Free. Released to a Public Domain. What is bad? ----------------- 1. Requires Borland Turbo Pascal version 7.0 or later (7.01) 2. Requires DOS 3.1 or later. Sorry guys, wanna cool service - need later DOS. 3. Won't run on XT personal computers. (uses 286 instructions) 4. No more strings. (all string-type names are of PChar type) 5. Exec and SwapVectors not implemented. If you'd like this code, I will continue modifying this unit and will eventually add the above functions too. Well, routines were checked on IBM PS/2 386SX, seems like work fine! Greetingz to ----------------- Bas van Gaalen (cool asm programmer and my PASCAL area friend ;) Dj Murdoch (best explainer ;) Gayle Davis (SWAG live forever) Feel free to place it into a next SWAG bundle. Ralph Brown (brilliant idea to make the interrupt list) Alex Grischenko (whose asm help was very appreciated) ...and all of you, guys! Material used ----------------- Borland Pascal 7.0 Runtime Library source code Ralph Brown's Interrupt List Tech Help 4.0 You may use this source-code-software in ANY purpose. Code may be changed. If some of the routines won't work, please send me a message. If you don't mind, please leave my copyright strings as they are.} Unit EnhDOS; (* Turbo Pascal 7.0 - ENHDOS.PAS Enhanced DOS interface unit for DOS 3.1+ *** Version 1.1 April, 1994. Copyright (c) 1994 by Andrew Eigus Fidonet 2:5100/33 Runtime Library Portions Copyright (c) 1991,92 Borland International } THIS UNIT SOURCE IS FREE *) interface {$X+} { Enable extended syntax } {$G+} { Enable 286+ instructions } const { My copyright information } Copyright : PChar = 'Portions Copyright (c) 1994 by Andrew Eigus'; { GetDriveType return values } dtError = $00; { Bad drive } dtFixed = $01; { Fixed drive } dtRemovable = $02; { Removable drive } dtRemote = $03; { Remote (network) drive } { Handle file open modes (om) constants } omRead = $00; { Open file for input only } omWrite = $01; { Open file for output only } omReadWrite = $02; { Open file for input or/and output (both modes) } omShareCompat = $00; { Modes used when SHARE.EXE loaded } omShareExclusive = $10; omShareDenyWrite = $20; omShareDenyRead = $30; omShareDenyNone = $40; { Maximum file name component string lengths } fsPathName = 79; fsDirectory = 67; fsFileSpec = 12; fsFileName = 8; fsExtension = 4; { FileSplit return flags } fcExtension = $0001; fcFileName = $0002; fcDirectory = $0004; fcWildcards = $0008; { File attributes (fa) constants } faNormal = $00; faReadOnly = $01; faHidden = $02; faSysFile = $04; faVolumeID = $08; faDirectory = $10; faArchive = $20; faAnyFile = $3F; { Seek start offset (sk) constants } skStart = 0; { Seek position relative to the beginning of a file } skPos = 1; { Seek position relative to a current file position } skEnd = 2; { Seek position relative to the end of a file } { Error handler function (fr) result codes } frOk = 0; { Continue program } frRetry = 1; { Retry function once again } { Function codes (only passed to error handler routine) (fn) constants } fnGetDPB = $3200; fnGetDiskSize = $3600; fnGetDiskFree = $3601; fnGetCountryInfo = $3800; fnSetDate = $2B00; fnSetTime = $2D00; fnIsFixedDisk = $4408; fnIsNetworkDrive = $4409; fnCreateDir = $3900; fnRemoveDir = $3A00; fnGetCurDir = $4700; fnSetCurDir = $3B00; fnDeleteFile = $4100; fnRenameFile = $5600; fnGetFileAttr = $4300; fnSetFileAttr = $4301; fnFindFirst = $4E00; fnFindNext = $4F00; fnCreateFile = $5B00; fnCreateTempFile = $5A00; fnOpenFile = $3D00; fnRead = $3F00; fnWrite = $4000; fnSeek = $4200; fnGetFDateTime = $5700; fnSetFDateTime = $5701; fnCloseFile = $3E00; fnMemAlloc = $4800; fnMemFree = $4900; { DOS 3.x+ errors/return codes } dosrOk = 0; { Success } dosrInvalidFuncNumber = 1; { Invalid DOS function number } dosrFileNotFound = 2; { File not found } dosrPathNotFound = 3; { Path not found } dosrTooManyOpenFiles = 4; { Too many open files } dosrFileAccessDenied = 5; { File access denied } dosrInvalidFileHandle = 6; { Invalid file handle } dosrNotEnoughMemory = 8; { Not enough memory } dosrInvalidEnvment = 10; { Invalid environment } dosrInvalidFormat = 11; { Invalid format } dosrInvalidAccessCode = 12; { Invalid file access code } dosrInvalidDrive = 15; { Invalid drive number } dosrCantRemoveDir = 16; { Cannot remove current directory } dosrCantRenameDrives = 17; { Cannot rename across drives } dosrNoMoreFiles = 18; { No more files } type TPathStr = array[0..fsPathName] of Char; TDirStr = array[0..fsDirectory] of Char; TNameStr = array[0..fsFileName] of Char; TExtStr = array[0..fsExtension] of Char; TFileStr = array[0..fsFileSpec] of Char; { Disk information block structure } PDiskParamBlock = ^TDiskParamBlock; TDiskParamBlock = record Drive : byte; { Disk drive number (0=A, 1=B, 2=C...) } SubunitNum : byte; { Sub-unit number from driver device header } SectSize : word; { Number of bytes per sector } SectPerClust : byte; { Number of sectors per cluster -1 (max sector in cluster) } ClustToSectShft : byte; { Cluster-to-sector shift } BootSize : word; { Reserved sectors (boot secs; start of root dir} FATCount : byte; { Number of FATs } MaxDir : word; { Number of directory entries allowed in root } DataSect : word; { Sector number of first data cluster } Clusters : word; { Total number of allocation units (clusters) +2 (number of highest cluster) } FATSectors : byte; { Sectors needed by first FAT } RootSect : word; { Sector number of start of root directory } DeviceHeader : pointer; { Address of device header } Media : byte; { Media descriptor byte } AccessFlag : byte; { 0 if drive has been accessed } NextPDB : pointer { Address of next DPB (0FFFFh if last) } end; { Disk allocation data structure } PDiskAllocInfo = ^TDiskAllocInfo; TDiskAllocInfo = record FATId : byte; { FAT Id } Clusters : word; { Number of allocation units (clusters) } SectPerClust : byte; { Number of sectors per cluster } SectSize : word { Number of bytes per sector } end; { Country information structure } PCountryInfo = ^TCountryInfo; TCountryInfo = record DateFormat : word; { Date format value may be one of the following: 0 - Month, Day, Year (USA) 1 - Day, Month, Year (Europe) 2 - Year, Month, Day (Japan) } CurrencySymbol : array[0..4] of Char; { Currency symbol string } ThousandsChar : byte; { Thousands separator character } reserved1 : byte; DecimalChar : byte; { Decimal separator character } reserved2 : byte; DateChar : byte; { Date separator character } reserved3 : byte; TimeChar : byte; { Time separator character } reserved4 : byte; CurrencyFormat : byte; { Currency format: $XXX.XX XXX.XX$ $ XXX.XX XXX.XX $ XXX$XX } Digits : byte; { Number of digits after decimal in currency } TimeFormat : byte; { Time format may be one of the following: bit 0 = 0 if 12 hour clock 1 if 24 hour clock } MapRoutine : pointer; { Address of case map routine FAR CALL, AL - character to map to upper case [>=80h] } DataListChar : byte; { Data-list separator character } reserved5 : byte; reserved6 : array[1..10] of Char end; THandle = Word; { Handle type (file handle and memory handle functions) } { Error handler function } TErrorFunc = function(ErrCode : integer; FuncCode : word) : byte; { Search record used by FindFirst and FindNext } TSearchRec = record Fill : array[1..21] of Byte; Attr : byte; Time : longint; Size : longint; Name : TFileStr end; { Date and time record used by PackTime and UnpackTime } TDateTime = record Year, Month, Day, Hour, Min, Sec : word end; var DOSResult : integer; { Error status variable } TempStr : array[0..High(String)] of Char; function SetErrorHandler(Handler : TErrorFunc) : pointer; function Pas2PChar(S : string) : PChar; function GetInDOSFlag : boolean; function GetDOSVersion : word; function GetSwitchChar : char; function SetSwitchChar(Switch : char) : byte; function GetCountryInfo(var Info : TCountryInfo) : integer; procedure GetDate(var Year : word; var Month, Day, DayOfWeek : byte); function SetDate(Year : word; Month, Day : byte) : boolean; procedure GetTime(var Hour, Minute, Second, Sec100 : byte); function SetTime(Hour, Minute, Second, Sec100 : byte) : boolean; function GetCBreak : boolean; function SetCBreak(Break : boolean) : boolean; function GetVerify : boolean; function SetVerify(Verify : boolean) : boolean; function GetArgCount : integer; function GetArgStr(Dest : PChar; Index : integer; MaxLen : word) : PChar; function GetEnvVar(VarName : PChar) : PChar; function GetIntVec(IntNo : byte; var Vector : pointer) : pointer; function SetIntVec(IntNo : byte; Vector : pointer) : pointer; function GetDTA : pointer; function GetCurDisk : byte; function SetCurDisk(Drive : byte) : byte; procedure GetDriveAllocInfo(Drive : byte; var Info : TDiskAllocInfo); function GetDPB(Drive : byte; var DPB : TDiskParamBlock) : integer; function DiskSize(Drive : byte) : longint; function DiskFree(Drive : byte) : longint; function IsFixedDisk(Drive : byte) : boolean; function IsNetworkDrive(Drive : byte) : boolean; function GetDriveType(Drive : byte) : byte; function CreateDir(Dir : PChar) : integer; function RemoveDir(Dir : PChar) : integer; function GetCurDir(Drive : byte; Dir : PChar) : integer; function SetCurDir(Dir : PChar) : integer; function DeleteFile(Path : PChar) : integer; function RenameFile(OldPath, NewPath : PChar) : integer; function ExistsFile(Path : PChar) : boolean; function GetFileAttr(Path : PChar) : integer; function SetFileAttr(Path : PChar; Attr : word) : integer; function FindFirst(Path : PChar; Attr: word; var F : TSearchRec) : integer; function FindNext(var F : TSearchRec) : integer; procedure UnpackTime(P : longint; var T : TDateTime); function PackTime(var T : TDateTime) : longint; function h_CreateFile(Path : PChar) : THandle; function h_CreateTempFile(Path : PChar) : THandle; function h_OpenFile(Path : PChar; Mode : byte) : THandle; function h_Read(Handle : THandle; var Buffer; Count : word) : word; function h_Write(Handle : THandle; var Buffer; Count : word) : word; function h_Seek(Handle : THandle; SeekPos : longint; Start : byte) : longint; function h_FilePos(Handle : THandle) : longint; function h_FileSize(Handle : THandle) : longint; function h_Eof(Handle : THandle) : boolean; function h_GetFTime(Handle : THandle) : longint; function h_SetFTime(Handle : THandle; DateTime : longint) : longint; function h_CloseFile(Handle : THandle) : integer; function MemAlloc(Size : longint) : pointer; function MemFree(P : pointer) : integer; function FileSearch(Dest, Name, List : PChar) : PChar; function FileExpand(Dest, Name : PChar) : PChar; function FileSplit(Path, Dir, Name, Ext : PChar) : word; implementation {$IFDEF Windows} {$DEFINE ProtectedMode} {$ENDIF} {$IFDEF DPMI} {$DEFINE ProtectedMode} {$ENDIF} {$IFDEF Windows} uses WinTypes, WinProcs, Strings; {$ELSE} uses Strings; {$ENDIF} const DOS = $21; { DOS interrupt number } var ErrorHandler : TErrorFunc; Function SetErrorHandler; { Sets the new error handler to hook all errors returned by EnhDOS functions, and returns the pointer to an old interrupt handler routine } Begin SetErrorHandler := @ErrorHandler; ErrorHandler := Handler End; { SetErrorHandler } Function Pas2PChar(S : string) : PChar; { Returns PChar type equivalent of the S variable. Use this function to convert strings to PChars } Begin Pas2PChar := StrPCopy(TempStr, S) End; { Pas2PChar } {$IFDEF Windows} procedure AnsiDosFunc; assembler; asm PUSH DS PUSH CX PUSH AX MOV SI,DI PUSH ES POP DS LEA DI,TempStr PUSH SS POP ES MOV CX,fsPathName CLD @@1: LODSB OR AL,AL JE @@2 STOSB LOOP @@1 @@2: XOR AL,AL STOSB LEA DI,TempStr PUSH SS PUSH DI PUSH SS PUSH DI CALL AnsiToOem POP AX POP CX LEA DX,TempStr PUSH SS POP DS INT DOS POP DS end; { AnsiDosFunc /Windows } {$ELSE} procedure AnsiDosFunc; assembler; asm PUSH DS MOV DX,DI PUSH ES POP DS INT DOS POP DS end; { AnsiDosFunc } {$ENDIF} Function GetInDOSFlag; assembler; { GETINDOSFLAG - DOS service function Description: Returns the current state of InDOS flag; fn=34h Returns: True if a DOS operation is being performed, False if there is no DOS command that currently is running } Asm MOV AH,34h INT DOS MOV AL,BYTE PTR [ES:BX] End; { GetInDOSFlag } Function GetDOSVersion; assembler; { GETDOSVERSION - DOS service function Description: Retrieves DOS version number; fn=30h Returns: Major DOS version number in low-order byte, minor version number in high-order byte of word } Asm MOV AH,30h INT DOS End; { GetDOSVersion } Function GetSwitchChar; assembler; { GETSWITCHCHAR - DOS service function Description: Retrieves DOS command line default switch character; fn=37h Returns: Switch character ('/', '-', ...) or FFh if unsupported subfunction } Asm MOV AH,37h XOR AL,AL INT DOS CMP AL,0FFh JE @@1 MOV AL,DL @@1: End; { GetSwitchChar } Function SetSwitchChar; assembler; { SETSWITCHCHAR - DOS service function Description: Sets new DOS command line switch character; fn=37h Returns: FFh if unsupported subfunction, any other value success } Asm MOV AX,3701h MOV DL,Switch INT DOS End; { SetSwitchChar } Function GetCountryInfo; assembler; { GETCOUNTRYINFO - DOS service function Description: Retrieves country information; fn=38h Returns: Country code if successful, negative DOS error code otherwise } Asm @@1: PUSH DS MOV AH,38h XOR AL,AL LDS DX,Info INT DOS POP DS JC @@2 MOV AX,BX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnGetCountryInfo { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { GetCountryInfo } Procedure GetDate; assembler; { GETDATE - DOS service function Description: Retrieves the current date set in the operating system. Ranges of the values returned are: Year 1980-2099, Month 1-12, Day 1-31 and DayOfWeek 0-6 (0 corresponds to Sunday) } Asm MOV AH,2AH INT DOS XOR AH,AH LES DI,DayOfWeek STOSB MOV AL,DL LES DI,Day STOSB MOV AL,DH LES DI,Month STOSB XCHG AX,CX LES DI,Year STOSW End; { GetDate } Function SetDate; assembler; { SETDATE - DOS service function Description: Sets the current date in the operating system. Valid parameter ranges are: Year 1980-2099, Month 1-12 and Day 1-31 Returns: True if the date was set, False if the date is not valid } Asm MOV CX,Year MOV DH,Month MOV DL,Day MOV AH,2BH INT DOS CMP AL,0 JE @@1 MOV DOSResult,AX PUSH AX PUSH fnSetDate CALL ErrorHandler MOV AL,True @@1: NOT AL End; { SetDate } Procedure GetTime; assembler; { GETTIME - DOS service function Description: Returns the current time set in the operating system. Ranges of the values returned are: Hour 0-23, Minute 0-59, Second 0-59 and Sec100 (hundredths of seconds) 0-99 } Asm MOV AH,2CH INT DOS XOR AH,AH MOV AL,DL LES DI,Sec100 STOSB MOV AL,DH LES DI,Second STOSB MOV AL,CL LES DI,Minute STOSB MOV AL,CH LES DI,Hour STOSB End; { GetTime } Function SetTime; assembler; { SETTIME - DOS service function Description: Sets the time in the operating system. Valid parameter ranges are: Hour 0-23, Minute 0-59, Second 0-59 and Sec100 (hundredths of seconds) 0-99 Returns: True if the time was set, False if the time is not valid } Asm MOV CH,Hour MOV CL,Minute MOV DH,Second MOV DL,Sec100 MOV AH,2DH INT DOS CMP AL,0 JE @@1 MOV DOSResult,AX PUSH AX PUSH fnSetTime CALL ErrorHandler MOV AL,True @@1: NOT AL End; { SetTime } Function GetCBreak; assembler; { GETCBREAK - DOS service function Description: Retrieves Control-Break state; fn=3300h Returns: Current Ctrl-Break state } Asm MOV AX,3300h INT DOS MOV AL,DL End; { GetCBreak } Function SetCBreak; assembler; { SETCBREAK - DOS service function Description: Sets new Control-Break state; fn=3300h Returns: Old Ctrl-Break state } Asm CALL GetCBreak PUSH AX MOV AX,3301h MOV DL,Break INT DOS POP AX End; { SetCBreak } Function GetVerify; assembler; { GETVERIFY - DOS service function Description: Returns the state of the verify flag in DOS. When off (False), disk writes are not verified. When on (True), all disk writes are verified to insure proper writing; fn=54h Returns: State of the verify flag } Asm MOV AH,54H INT DOS End; { GetVerify } Function SetVerify; assembler; { SETVERIFY - DOS service function Description: Sets the state of the verify flag in DOS; fn=2Eh Returns: Previous state of the verify flag } Asm CALL GetVerify PUSH AX MOV AL,Verify MOV AH,2EH INT DOS POP AX End; { SetVerify } {$IFDEF Windows} Procedure ArgStrCount; assembler; Asm LDS SI,CmdLine CLD @@1: LODSB OR AL,AL JE @@2 CMP AL,' ' JBE @@1 @@2: DEC SI MOV BX,SI @@3: LODSB CMP AL,' ' JA @@3 DEC SI MOV AX,SI SUB AX,BX JE @@4 LOOP @@1 @@4: End; { ArgStrCount /Windows } Function GetArgCount; assembler; { GETARGCOUNT - DOS service function Description: Returns the number of parameters passed to the program on the command line Returns: Actual number of command line parameters } Asm PUSH DS XOR CX,CX CALL ArgStrCount XCHG AX,CX NEG AX POP DS End; { GetArgCount /Windows } Function GetArgStr; assembler; { GETARGSTR - DOS service function Description: Returns the specified parameter from the command line Returns: ASCIIZ parameter, or an empty string if Index is less than zero or greater than GetArgCount. If Index is zero, GetArgStr returns the filename of the current module. The maximum length of the string returned in Dest is given by the MaxLen parameter. The returned value is Dest } Asm MOV CX,Index JCXZ @@2 PUSH DS CALL ArgStrCount MOV SI,BX LES DI,Dest MOV CX,MaxLen CMP CX,AX JB @@1 XCHG AX,CX @@1: REP MOVSB XCHG AX,CX STOSB POP DS JMP @@3 @@2: PUSH HInstance PUSH WORD PTR [Dest+2] PUSH WORD PTR [Dest] MOV AX,MaxLen INC AX PUSH AX CALL GetModuleFileName @@3: MOV AX,WORD PTR [Dest] MOV DX,WORD PTR [Dest+2] End; { GetArgStr /Windows } {$ELSE} Procedure ArgStrCount; assembler; Asm MOV DS,PrefixSeg MOV SI,80H CLD LODSB MOV DL,AL XOR DH,DH ADD DX,SI @@1: CMP SI,DX JE @@2 LODSB CMP AL,' ' JBE @@1 DEC SI @@2: MOV BX,SI @@3: CMP SI,DX JE @@4 LODSB CMP AL,' ' JA @@3 DEC SI @@4: MOV AX,SI SUB AX,BX JE @@5 LOOP @@1 @@5: End; { ArgStrCount } Function GetArgCount; assembler; { GETARGCOUNT - DOS service function Description: Returns the number of parameters passed to the program on the command line Returns: Actual number of command line parameters } Asm PUSH DS XOR CX,CX CALL ArgStrCount XCHG AX,CX NEG AX POP DS End; { GetArgCount } Function GetArgStr; assembler; { GETARGSTR - DOS service function Description: Returns the specified parameter from the command line Returns: ASCIIZ parameter, or an empty string if Index is less than zero or greater than GetArgCount. If Index is zero, GetArgStr returns the filename of the current module. The maximum length of the string returned in Dest is given by the MaxLen parameter. The returned value is Dest } Asm PUSH DS MOV CX,Index JCXZ @@1 CALL ArgStrCount MOV SI,BX JMP @@4 @@1: MOV AH,30H INT DOS CMP AL,3 MOV AX,0 JB @@4 MOV DS,PrefixSeg MOV ES,DS:WORD PTR 2CH XOR DI,DI CLD @@2: CMP AL,ES:[DI] JE @@3 MOV CX,-1 REPNE SCASB JMP @@2 @@3: ADD DI,3 MOV SI,DI PUSH ES POP DS MOV CX,256 REPNE SCASB XCHG AX,CX NOT AL @@4: LES DI,Dest MOV CX,MaxLen CMP CX,AX JB @@5 XCHG AX,CX @@5: REP MOVSB XCHG AX,CX STOSB MOV AX,WORD PTR [Dest] MOV DX,WORD PTR [Dest+2] POP DS End; { GetArgStr } {$ENDIF} Function GetEnvVar; { GETENVVAR - DOS service function Description: Retrieves a specified DOS environment variable Returns: A pointer to the value of a specified variable, i.e. a pointer to the first character after the equals sign (=) in the environment entry given by VarName. VarName is case insensitive. GetEnvVar returns NIL if the specified environment variable does not exist } var L : word; P : PChar; Begin L := StrLen(VarName); {$IFDEF Windows} P := GetDosEnvironment; {$ELSE} P := Ptr(Word(Ptr(PrefixSeg, $2C)^), 0); {$ENDIF} while P^ <> #0 do begin if (StrLIComp(P, VarName, L) = 0) and (P[L] = '=') then begin GetEnvVar := P + L + 1; Exit; end; Inc(P, StrLen(P) + 1) end; GetEnvVar := nil End; { GetEnvVar } Function GetIntVec; assembler; { GETINTVEC - DOS service function Description: Retrieves the address stored in the specified interrupt vector Returns: A pointer to this address } Asm MOV AL,IntNo MOV AH,35H INT DOS MOV AX,ES LES DI,Vector CLD MOV DX,BX XCHG AX,BX STOSW XCHG AX,BX STOSW XCHG AX,DX End; { GetIntVec } Function SetIntVec; assembler; { SETINTVEC - DOS Service function Description: Sets the address in the interrupt vector table for the specified interrupt Returns: The old address of the specified interrupt vector } Asm LES DI,Vector PUSH WORD PTR IntNo PUSH ES PUSH DI PUSH CS CALL GetIntVec PUSH DX PUSH AX PUSH DS LDS DX,Vector MOV AL,IntNo MOV AH,25H INT DOS POP DS POP AX POP DX End; { SetIntVec } Function GetDTA; assembler; { GETDTA - DOS service function Description: Retrieves a pointer address to a DOS data exchange buffer (DTA). By default, DTA address has the offset PSP+80h and the size of 128 bytes. DTA is used to access files with the FCB method; fn=2Fh Returns: A pointer address to DTA } Asm MOV AH,2Fh INT DOS MOV DX,BX { store offset } MOV AX,ES { store segment } End; { GetDTA } Function GetCurDisk; assembler; { GETCURDISK - DOS disk service function Description: Retrieves number of disk currently being active; fn=19h Returns: Default (current, active) disk number } Asm MOV AH,19h INT DOS End; { GetCurDisk } Function SetCurDisk; assembler; { SETCURDISK - DOS disk service function Description: Sets current (default/active) drive; fn=0Eh Returns: Number of disks in the system } Asm MOV AH,0Eh MOV DL,Drive INT DOS End; { SetCurDisk } Procedure GetDriveAllocInfo; assembler; { GETDRIVEALLOCINFO - DOS disk service function Description: Retrieves disk allocation information; fn=1Ch Retrieves Info structure } Asm PUSH DS MOV AH,1Ch MOV DL,Drive INT DOS MOV AH,BYTE PTR [DS:BX] LES DI,Info MOV BYTE PTR ES:[DI],AH { Info.FATId } MOV WORD PTR ES:[DI+1],DX { Info.Clusters } MOV BYTE PTR ES:[DI+3],AL { Info.SectorsPerCluster } MOV WORD PTR ES:[DI+4],CX { Info.BytesPerSector } POP DS End; { GetDriveAllocInfo } Function GetDPB; assembler; { GETDPB - DOS disk service function (undocumented) Description: Returns a block of information that is useful for applications which perform sector-level access of disk drives supported by device drivers; fn=32h Returns: 0 if successful, negative dosrInvalidDrive error code otherwise Remarks: Use 0 for default drive } Asm MOV DOSResult,dosrOk PUSH DS MOV AH,32h MOV DL,Drive INT DOS MOV WORD PTR [DPB],DS MOV WORD PTR [DPB+2],BX POP DS XOR AH,AH CMP AL,0FFh JNE @@1 MOV DOSResult,dosrInvalidDrive PUSH DOSResult PUSH fnGetDPB CALL ErrorHandler MOV AX,DOSResult NEG AX @@1: End; { GetDPB } Function DiskSize; assembler; { DISKSIZE - DOS disk service function Description: Retrieves total disk size; fn=36h Returns: Total disk size in bytes if successful, negative dosrInvalidDrive error code otherwise Remarks: Use 0 for default drive } Asm @@1: MOV AH,36h MOV DL,Drive INT DOS CMP AX,0FFFFh JE @@2 MOV BX,DX IMUL CX IMUL BX JMP @@3 @@2: MOV DOSResult,dosrInvalidDrive PUSH DOSResult PUSH fnGetDiskSize CALL ErrorHandler CMP AL,frRetry JE @@1 MOV AX,DOSResult NEG AX XOR DX,DX @@3: End; { DiskSize } Function DiskFree; assembler; { DISKFREE - DOS disk service function Description: Retrieves amount of free disk space; fn=36h Returns: Amount of free disk space in bytes if successful, negative dosrInvalidDrive error code otherwise Remarks: Use 0 for default drive } Asm @@1: MOV AH,36h MOV DL,Drive INT DOS CMP AX,0FFFFh JE @@2 IMUL CX IMUL BX JMP @@3 @@2: MOV DOSResult,dosrInvalidDrive PUSH DOSResult PUSH fnGetDiskFree CALL ErrorHandler CMP AL,frRetry JE @@1 MOV AX,DOSResult NEG AX XOR DX,DX @@3: End; { DiskFree } Function IsFixedDisk; assembler; { ISFIXEDDISK - DOS disk service function Description: Ensures whether the specified disk is fixed or removable; fn=4408h Returns: True, if the disk is fixed, False - otherwise Remarks: Use 0 for default (current) drive } Asm MOV AX,4408h MOV BL,Drive INT DOS JNC @@1 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnIsFixedDisk { store function code } CALL ErrorHandler @@1: End; { IsFixedDisk } Function IsNetworkDrive; assembler; { ISNETWORKDRIVE - DOS disk service function Description: Ensures whether the specified disk drive is a network drive; fn=4409h Returns: True if drive is a network drive, False if it's a local drive Remarks: Use 0 for detecting the default (current) drive } Asm MOV AX,4409h MOV BL,Drive INT DOS JNC @@1 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnIsNetworkDrive { store function code } CALL ErrorHandler @@1: End; { IsNetworkDrive } Function GetDriveType(Drive : byte) : byte; assembler; { GETDRIVETYPE - Disk service function Description: Detects the type of the specified drive. Uses IsFixedDisk and IsNetworkDrive functions to produce a result value Returns: One of (dt) constants (see const section) Remarks: Use 0 for detecting the default (current) drive } Asm PUSH WORD PTR Drive CALL IsNetworkDrive XOR BL,BL CMP DOSResult,dosrOk JNE @@3 CMP AL,True JNE @@1 MOV BL,dtRemote JMP @@3 @@1: PUSH WORD PTR Drive CALL IsFixedDisk XOR BL,BL CMP DOSResult,dosrOk JNE @@3 CMP AL,True JNE @@2 MOV BL,dtFixed JMP @@3 @@2: MOV BL,dtRemovable @@3: MOV AL,BL End; { GetDriveType } Function CreateDir; assembler; { CREATEDIR - DOS directory function Description: Creates a directory; fn=39h Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Dir MOV AH,39h INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnCreateDir { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { CreateDir } Function RemoveDir; assembler; { REMOVEDIR - DOS directory function Description: Removes (deletes) a directory; fn=3Ah Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Dir MOV AH,3Ah INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnRemoveDir { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { RemoveDir } Function GetCurDir; assembler; { GETCURDIR - DOS directory function Description: Retrieves current (active) directory name; fn=47h Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS SI,Dir MOV DL,Drive MOV AH,47h INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnGetCurDir { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { GetCurDir } Function SetCurDir; assembler; { SETCURDIR - DOS directory function Description: Sets current (active) directory; fn=3Bh Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Dir MOV AH,3Bh INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,AX JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnSetCurDir { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { SetCurDir } Function DeleteFile; assembler; { DELETEFILE - DOS file function Description: Deletes a file; fn=41h Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Path MOV AH,41h INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnDeleteFile { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { DeleteFile } Function RenameFile; assembler; { RENAMEFILE - DOS file function Description: Renames/moves a file; fn=56h Returns: 0 if successful, negative error code otherwise } Asm @@1: PUSH DS LDS DX,OldPath LES DI,NewPath MOV AH,56h INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnRenameFile { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { RenameFile } Function ExistsFile; assembler; { EXISTSFILE - DOS file function Description: Determines whether the file exists; fn=4Eh Returns: TRUE if the file exists, FALSE - otherwise } Asm PUSH DS LDS DX,Path MOV AH,4Eh INT DOS POP DS JNC @@1 XOR AL,AL JMP @@2 @@1: MOV AL,True @@2: End; { ExistsFile } Function GetFileAttr; assembler; { GETFILEATTR - DOS file function Description: Gets file attributes; fn=43h,AL=0 Returns: File attributes if no error, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Path MOV AX,4300h INT DOS POP DS JC @@2 MOV AX,CX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnGetFileAttr { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { GetFileAttr } Function SetFileAttr; assembler; { SETFILEATTR - DOS file function Description: Sets file attributes; fn=43h,AL=1 Returns: 0 if no error, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,Path MOV CX,Attr MOV AX,4301h INT DOS POP DS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnSetFileAttr { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { GetFileAttr } Function FindFirst; assembler; { FINDFIRST - DOS file service function Description: Searches the specified (or current) directory for the first entry that matches the specified filename and attributes; fn=4E00h Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,F MOV AH,1AH INT DOS POP DS LES DI,Path MOV CX,Attr MOV AH,4EH CALL AnsiDosFunc MOV DOSResult,dosrOk JC @@2 {$IFDEF Windows} LES DI,F ADD DI,OFFSET TSearchRec.Name PUSH ES PUSH DI PUSH ES PUSH DI CALL OemToAnsi {$ENDIF} XOR AX,AX JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnFindFirst { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX @@3: NEG AX End; { FindFirst } Function FindNext; assembler; { FINDNEXT - DOS file service function Description: Returs the next entry that matches the name and attributes specified in a previous call to FindFirst. The search record must be one passed to FindFirst Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: PUSH DS LDS DX,F MOV AH,1AH INT DOS POP DS MOV AH,4FH MOV DOSResult,dosrOk INT DOS JC @@2 {$IFDEF Windows} LES DI,F ADD DI,OFFSET TSearchRec.Name PUSH ES PUSH DI PUSH ES PUSH DI CALL OemToAnsi {$ENDIF} XOR AX,AX JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnFindNext { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX @@3: NEG AX End; { FindNext } Procedure UnpackTime; assembler; { UNPACKTIME - Service function Description: Converts a 4-byte packed date/time returned by FindFirst, FindNext or GetFTime into a TDateTime record } Asm LES DI,T CLD MOV AX,WORD PTR [P+2] MOV CL,9 SHR AX,CL ADD AX,1980 STOSW MOV AX,WORD PTR [P+2] MOV CL,5 SHR AX,CL AND AX,15 STOSW MOV AX,WORD PTR [P+2] AND AX,31 STOSW MOV AX,P.Word[0] MOV CL,11 SHR AX,CL STOSW MOV AX,WORD PTR [P+2] MOV CL,5 SHR AX,CL AND AX,63 STOSW MOV AX,WORD PTR [P] AND AX,31 SHL AX,1 STOSW End; { UnpackTime } Function PackTime; assembler; { PACKTIME - Service function Decription: Converts a TDateTime record into a 4-byte packed date/time used by SetFTime Returns: 4-byte long integer corresponding to packed date/time } Asm PUSH DS LDS SI,T CLD LODSW SUB AX,1980 MOV CL,9 SHL AX,CL XCHG AX,DX LODSW MOV CL,5 SHL AX,CL ADD DX,AX LODSW ADD DX,AX LODSW MOV CL,11 SHL AX,CL XCHG AX,BX LODSW MOV CL,5 SHL AX,CL ADD BX,AX LODSW SHR AX,1 ADD AX,BX POP DS End; { PackTime } Function h_CreateFile; assembler; { H_CREATEFILE - DOS Handle file function Description: Creates a file; fn=3Ch Returns: File handle if successful, 0 if unsuccessful } Asm @@1: PUSH DS LDS DX,Path MOV CX,0 MOV AH,5Bh INT DOS POP DS JC @@2 MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnCreateFile { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 XOR AX,AX @@3: End; { h_CreateFile } Function h_CreateTempFile; assembler; { H_CREATETEMPFILE - DOS Handle file function Description: Creates a temporary file; fn=5Ah Returns: File handle if successful, 0 if unsuccessful } Asm @@1: PUSH DS LDS DX,Path MOV CX,0 { file attribute here, 0 used for normal } MOV AH,5Ah INT DOS POP DS JC @@2 MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnCreateTempFile { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 XOR AX,AX @@3: End; { h_CreateTempFile } Function h_OpenFile; assembler; { H_OPENFILE - DOS Handle file function Description: Opens a file for input, output or input/output; fn=3Dh Returns: File handle if successful, 0 if unsuccessful } Asm @@1: PUSH DS LDS DX,Path MOV AH,3Dh MOV AL,Mode INT DOS POP DS JC @@2 MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnOpenFile { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 XOR AX,AX @@3: End; { h_OpenFile } Function h_Read; assembler; { H_READ - DOS Handle file function Description: Reads a memory block from file; fn=3Fh Returns: Actual number of bytes read } Asm @@1: PUSH DS LDS DX,Buffer MOV CX,Count MOV BX,Handle MOV AH,3Fh INT DOS POP DS MOV DOSResult,dosrOk JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnRead { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 @@2: End; { h_Read } Function h_Write; assembler; { H_WRITE - DOS Handle file function Description: Writes a memory block to file; fn=40h Returns: Actual number of bytes written } Asm @@1: PUSH DS LDS DX,Buffer MOV CX,Count MOV BX,Handle MOV AH,40h INT DOS POP DS MOV DOSResult,dosrOk JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnWrite { store function code } CALL ErrorHandler CMP AL,frRetry JE @@1 @@2: End; { h_Write } Function h_Seek; assembler; { H_SEEK - DOS Handle file function Description: Seeks to a specified file position; fn=42h Start is one of the (sk) constants and points to a relative seek offset position Returns: Current file position if successful, 0 - otherwise } Asm @@1: MOV CX,WORD PTR [SeekPos+2] MOV DX,WORD PTR [SeekPos] MOV BX,Handle MOV AL,Start MOV AH,42h MOV DOSResult,dosrOk INT DOS JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnSeek { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 @@2: End; { h_Seek } Function h_FilePos; { H_GETPOS - DOS Handle file function Description: Calls h_Seek to determine file active position Returns: Current file (seek) position number in long integer } Begin h_FilePos := h_Seek(Handle, 0, skPos) End; { h_FilePos } Function h_FileSize; { H_FILESIZE - DOS Handle file function Description: Determines file size Returns: File size in bytes } var SavePos, Size : longint; Begin SavePos := h_FilePos(Handle); h_FileSize := h_Seek(Handle, 0, skEnd); h_Seek(Handle, SavePos, skStart) End; { h_FileSize } Function h_Eof; assembler; { H_EOF - DOS Handle file function Description: Checks if the current file position is equal to file size and then returns True Returns: True if end of file detected, False - otherwise } var Size : longint; Asm PUSH Handle CALL h_FileSize { Get file size in AX:DX } MOV WORD PTR [Size],AX { Store high word } MOV WORD PTR [Size+2],DX { Store low word } PUSH Handle CALL h_FilePos { Get current file position } XOR CL,CL CMP AX,WORD PTR [Size] JNE @@1 CMP DX,WORD PTR [Size+2] JNE @@1 MOV CL,True @@1: MOV AL,CL End; { h_GetPos } Function h_GetFTime; assembler; { H_GETFTIME - DOS Handle file function Description: Returns file update date and time values; fn=5700h Returns: Date and time values in long integer or negative DOS error code if an error occured } Asm @@1: MOV BX,Handle MOV AX,5700h { read date and time } MOV DOSResult,dosrOk INT DOS JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnGetFDateTime { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@2: End; { h_GetFTime } Function h_SetFTime; assembler; { H_SETFTIME - DOS Handle file function Description: Sets file date and time; fn=5701h Returns: New date and time values in long integer or negative DOS error code if an error occured } Asm @@1: MOV CX,WORD PTR [DateTime] MOV DX,WORD PTR [DateTime+2] MOV BX,Handle MOV AX,5701h { read date and time } MOV DOSResult,dosrOk INT DOS JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnSetFDateTime { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@2: End; { h_SetFTime } Function h_CloseFile; assembler; { H_CLOSEFILE - DOS Handle file function Description: Closes open file; fn=3Eh Returns: 0 if successful, negative DOS error code otherwise } Asm @@1: MOV BX,Handle MOV AH,3Eh INT DOS JC @@2 XOR AX,AX MOV DOSResult,dosrOk JMP @@3 @@2: MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnCloseFile { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 POP AX NEG AX @@3: End; { h_CloseFile } Function MemAlloc; assembler; Asm @@1: MOV DOSResult,dosrOk MOV AX,WORD PTR [Size] MOV DX,WORD PTR [Size+2] MOV CX,16 DIV CX INC AX MOV BX,AX MOV AH,48h INT DOS JNC @@2 MOV DOSResult,AX { save error code in global variable } PUSH AX { store error code } PUSH fnMemAlloc { store function number } CALL ErrorHandler CMP AL,frRetry JE @@1 XOR AX,AX @@2: MOV DX,AX XOR AX,AX End; { MemAlloc } Function MemFree; assembler; Asm MOV DOSResult,dosrOk MOV ES,WORD PTR [P+2] MOV AH,49h INT DOS JNC @@1 MOV DOSResult,AX PUSH AX PUSH fnMemFree CALL ErrorHandler @@1: MOV AX,DOSResult NEG AX End; { MemFree } Function FileSearch; assembler; { FileSearch searches for the file given by Name in the list of } { directories given by List. The directory paths in List must } { be separated by semicolons. The search always starts with the } { current directory of the current drive. If the file is found, } { FileSearch stores a concatenation of the directory path and } { the file name in Dest. Otherwise FileSearch stores an empty } { string in Dest. The maximum length of the result is defined } { by the fsPathName constant. The returned value is Dest. } Asm PUSH DS CLD LDS SI,List LES DI,Dest MOV CX,fsPathName @@1: PUSH DS PUSH SI JCXZ @@3 LDS SI,Name @@2: LODSB OR AL,AL JE @@3 STOSB LOOP @@2 @@3: XOR AL,AL STOSB LES DI,Dest MOV AX,4300H CALL AnsiDosFunc POP SI POP DS JC @@4 TEST CX,18H JE @@9 @@4: LES DI,Dest MOV CX,fsPathName XOR AH,AH LODSB OR AL,AL JE @@8 @@5: CMP AL,';' JE @@7 JCXZ @@6 MOV AH,AL STOSB DEC CX @@6: LODSB OR AL,AL JNE @@5 DEC SI @@7: JCXZ @@1 CMP AH,':' JE @@1 MOV AL,'\' CMP AL,AH JE @@1 STOSB DEC CX JMP @@1 @@8: STOSB @@9: MOV AX,WORD PTR [Dest] MOV DX,WORD PTR [Dest+2] POP DS End; { FileSearch } Function FileExpand; assembler; { FileExpand fully expands the file name in Name, and stores } { the result in Dest. The maximum length of the result is } { defined by the fsPathName constant. The result is an all } { upper case string consisting of a drive letter, a colon, a } { root relative directory path, and a file name. Embedded '.' } { and '..' directory references are removed, and all name and } { extension components are truncated to 8 and 3 characters. The } { returned value is Dest. } Asm PUSH DS CLD LDS SI,Name LEA DI,TempStr PUSH SS POP ES LODSW OR AL,AL JE @@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 DOS ADD AL,'A' MOV AH,':' @@2: STOSW CMP [SI].Byte,'\' JE @@3 SUB AL,'A'-1 MOV DL,AL MOV AL,'\' STOSB PUSH DS PUSH SI MOV AH,47H MOV SI,DI PUSH ES POP DS INT DOS POP SI POP DS JC @@3 XOR AL,AL CMP AL,ES:[DI] JE @@3 {$IFDEF Windows} PUSH ES PUSH ES PUSH DI PUSH ES PUSH DI CALL OemToAnsi POP ES {$ENDIF} MOV CX,0FFFFH XOR AL,AL CLD REPNE SCASB DEC DI MOV AL,'\' STOSB @@3: MOV CX,8 @@4: LODSB OR AL,AL JE @@7 CMP AL,'\' JE @@7 CMP AL,'.' JE @@6 JCXZ @@4 DEC CX {$IFNDEF Windows} CMP AL,'a' JB @@5 CMP AL,'z' JA @@5 SUB AL,20H {$ENDIF} @@5: STOSB JMP @@4 @@6: MOV CL,3 JMP @@5 @@7: CMP ES:[DI-2].Word,'.\' JNE @@8 DEC DI DEC DI JMP @@10 @@8: CMP ES:[DI-2].Word,'..' JNE @@10 CMP ES:[DI-3].Byte,'\' JNE @@10 SUB DI,3 CMP ES:[DI-1].Byte,':' JE @@10 @@9: DEC DI CMP ES:[DI].Byte,'\' JNE @@9 @@10: MOV CL,8 OR AL,AL JNE @@5 CMP ES:[DI-1].Byte,':' JNE @@11 MOV AL,'\' STOSB @@11: LEA SI,TempStr PUSH SS POP DS MOV CX,DI SUB CX,SI CMP CX,79 JBE @@12 MOV CX,79 @@12: LES DI,Dest PUSH ES PUSH DI {$IFDEF Windows} PUSH ES PUSH DI {$ENDIF} REP MOVSB XOR AL,AL STOSB {$IFDEF Windows} CALL AnsiUpper {$ENDIF} POP AX POP DX POP DS End; { FileExpand } {$W+} Function FileSplit; { FileSplit splits the file name specified by Path into its } { three components. Dir is set to the drive and directory path } { with any leading and trailing backslashes, Name is set to the } { file name, and Ext is set to the extension with a preceding } { period. If a component string parameter is NIL, the } { corresponding part of the path is not stored. If the path } { does not contain a given component, the returned component } { string is empty. The maximum lengths of the strings returned } { in Dir, Name, and Ext are defined by the fsDirectory, } { fsFileName, and fsExtension constants. The returned value is } { a combination of the fcDirectory, fcFileName, and fcExtension } { bit masks, indicating which components were present in the } { path. If the name or extension contains any wildcard } { characters (* or ?), the fcWildcards flag is set in the } { returned value. } var DirLen, NameLen, Flags : word; NamePtr, ExtPtr : PChar; begin NamePtr := StrRScan(Path, '\'); if NamePtr = nil then NamePtr := StrRScan(Path, ':'); if NamePtr = nil then NamePtr := Path else Inc(NamePtr); ExtPtr := StrScan(NamePtr, '.'); if ExtPtr = nil then ExtPtr := StrEnd(NamePtr); DirLen := NamePtr - Path; if DirLen > fsDirectory then DirLen := fsDirectory; NameLen := ExtPtr - NamePtr; if NameLen > fsFilename then NameLen := fsFilename; Flags := 0; if (StrScan(NamePtr, '?') <> nil) or (StrScan(NamePtr, '*') <> nil) then Flags := fcWildcards; if DirLen <> 0 then Flags := Flags or fcDirectory; if NameLen <> 0 then Flags := Flags or fcFilename; if ExtPtr[0] <> #0 then Flags := Flags or fcExtension; if Dir <> nil then StrLCopy(Dir, Path, DirLen); if Name <> nil then StrLCopy(Name, NamePtr, NameLen); if Ext <> nil then StrLCopy(Ext, ExtPtr, fsExtension); FileSplit := Flags; End; { FileSplit } {$W-} Function StdErrorProc(ErrCode : integer; FuncCode : word) : byte; far; assembler; { Default error handler procedure called from EnhDOS functions } Asm MOV AL,frOk { Return zero } End; { StdErrorProc } const WrongDOSVersion : PChar = 'DOS 3.1 or greater required.'#13#10'$'; Begin asm MOV AH,30h { Get DOS version } INT DOS CMP AL,3 JGE @@continue { if greater than or equal to 3 then continue else exit } PUSH DS LDS DX,WrongDOSVersion MOV AH,09h INT DOS MOV AH,4Ch INT DOS @@continue: LES DI,Copyright end; DOSResult := dosrOk; SetErrorHandler(StdErrorProc) End. { EnhDOS+ } { ------------------------------------- DEMO ------------------ } { ***** ENHDDEMO.PAS ***** } Program DemoEnhDOS; { Copyright (c) 1994 by Andrew Eigus Fido Net 2:5100/33 } { EnhDOS+ (Int21) demo program } {$M 8192,0,0} { no heap size, couz using own memeory allocation } (* Simple copy file program *) uses EnhDOS, Strings; const BufSize = 65535; { may be larger; you may allocate more } var Buffer : pointer; InputFile, OutputFile : array[0..63] of Char; Handle1, Handle2 : THandle; BytesRead : word; Function Int21ErrorHandler(ErrCode : integer; FuncCode : word) : byte; far; var fn : array[0..20] of Char; Begin case FuncCode of fnOpenFile: StrCopy(fn, 'h_OpenFile'); fnCreateFile: StrCopy(fn, 'h_CreateFile'); fnRead: StrCopy(fn, 'h_Read'); fnWrite: StrCopy(fn, 'h_Write'); fnSeek: StrCopy(fn, 'h_Seek'); fnCloseFile: StrCopy(fn, 'h_CloseFile'); fnMemAlloc: StrCopy(fn, 'MemAlloc'); fnDeleteFile: Exit; else fn[0] := #0 end; WriteLn('DOS Error ', ErrCode, ' in function ', FuncCode, ' (', fn, ')'); { actually for function return code see fr consts in the EnhDOS const section } End; { Int21ErrorHandler } Begin SetErrorHandler(Int21ErrorHandler); WriteLn('EnhDOS+ demo program: copies one file to another'); repeat if ParamCount > 0 then StrPCopy(InputFile, ParamStr(1)) else begin Write('Enter file name to read from: '); ReadLn(InputFile) end; if ParamCount > 1 then StrPCopy(OutputFile, ParamStr(2)) else begin Write('Enter file name to write to: '); ReadLn(OutputFile) end; WriteLn until (StrLen(InputFile) > 0) and (StrLen(OutputFile) > 0); if not ExistsFile(InputFile) then begin WriteLn('File not found: ', InputFile); Halt(1) end; Buffer := MemAlloc(BufSize); Write('Copying... '); Handle1 := h_OpenFile(InputFile, omRead); if Handle1 <> 0 then begin DeleteFile(OutputFile); Handle2 := h_CreateFile(OutputFile); if Handle2 <> 0 then begin BytesRead := 1; while (BytesRead > 0) and (DOSResult = dosrOk) do begin BytesRead := h_Read(Handle1, Buffer^, BufSize); if DOSResult <> dosrOk then { read error then } WriteLn('Error reading from input file'); if h_Write(Handle2, Buffer^, BytesRead) <> BytesRead then { write error then } begin WriteLn('Error writing to output file'); DOSResult := $FF end end; if DOSResult = dosrOk then WriteLn('File copied OK'); h_CloseFile(Handle2) end; h_CloseFile(Handle1) end; MemFree(Buffer) End. { DemoEnhDOS }