This library contains wrapper macros which encapsulate LinAPI calls for most typical file operations in 32bit Linux . See also equivalent homonymous macroinstructions in linf64.htm, winf32.htm, winf64.htm.
| File Access method | Open | Data transfer | Close |
|---|---|---|---|
| read file at once | - | FileLoad | FileClose |
| write file at once | - | FileStore | - |
| standard read | FileOpen | FileRead | FileClose |
| standard write | FileCreate | FileWrite, FileWriteLn, FileWrite$ | FileClose |
| standard write at the end of file | FileAppend | FileWrite, FileWriteLn, FileWrite$ | FileClose |
| memory mapped read | FileMapOpen | - | FileClose |
| memory mapped write | FileMapCreate | - | FileClose |
| buffered read | FileStreamOpen | FileStreamReadByte, FileStreamRead, FileStreamReadLn | FileClose |
| buffered write | FileStreamCreate | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose |
| buffered write at end of file | FileStreamAppend | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose |
| append to file | - | FileEnclose, FileEncloseLn, FileEnclose$ | - |
| special functions | FileReset | FileAssign, FileExists?, FileNameParse, FileMove, FileMkDir, FileEach | FileDelete |
Macros return the results in registers, usually EAX. Other registers do not change. CF is set when error occurs, ZF is set at the end of file, DF must be always reset. Other flags are undefined.
Association of the FILE object with the name of file is provided separately, using the macro FileAssign. File must be assigned before opening.
Macro names suffixed with ~Ln write LineFeed character after the data. Macro names suffixed with ~$ expect NULL-terminated input data.
Acces methods at once, stream, memory-map allocate dynamic virtual memory. It will be freed in FileClose.
| Access method | Virtual memory | |
|---|---|---|
| reserved | comitted | |
| At once load | filesize | filesize |
| At once store | none | none |
| Standard | none | none |
| MemoryMapped | filesize | pagesize |
| Streamed | buffersize | buffersize |
File access method at once loads entire file content into comitted memory, so it is suitable for small files only. The loaded/stored file doesn't need explicit opening nor closing.
This access method is equivalent to PHP functions file_get_contents, file_put_contents.
Access method enclose opens the file at its end for writing, appends the data and closes file in one operation.
Standard read/write methods only encapsulate API functions read/write and they can process files of any size. Example:
Memory mapped file access reserves memory for the entire file contents virtually loaded to memory.
Streamed (buffered) file access method allocates its own memory buffer to accelerate reading/writing of small pieces of data. This method is also suitable for processing text files line by line. Example:
Common limitations: This library cannot be used if special requirements are required, such as overlapped file access, other than normal file attributes, nonstandard share disposition, files bigger than 2 GB, filename longer than 260 characters.
Runtime procedures defined in this library use macros LinAPI, Dispatch, status32.htm.
linf32 HEAD INCLUDEHEAD1 lins.htm, linsfile.htm, linapi.htm, cpuext.htm, string32.htm, status32.htm
FILE STRUC .Ptr DD D ; Pointer to the current data content in memory-mapped|buffered data. .Top DD D ; Pointer to the end of the memory-mapped|buffered data. .BufPtr DD D ; Address of the start of memory-map|allocated buffer. .BufSize DD D ; Size of memory map|buffer. .Pos DD D ; Zero based offset of the current file position: lseek(.Handle,.Pos,SEEK_SET). .Size DD D ; File size in bytes. .Handle DD D ; File descriptor. .MapHandle DD D ; Pointer to the start of mapped memory, identical with .BufPtr. .Status DD D ; File status flags, see FileStatusEnc. .NameOffs DD D ; Offset of the filename without path inside the .Name. Zero if no path in .Name. .ExtOffs DD D ; Offset of the file extension inside the .Name. .Name D NAME_MAX * B ; Zero terminated file name. ENDSTRUC FILE
FILE.Status.fileStFound EQU 0x00000010 ; File was once succesfully opened. fileStAppend EQU 0x00100000 ; Created file should move its pointer to the end. fileStStdIO EQU 0x00200000 ; FILE.Handle is standard input|output. fileStAllocated EQU 0x00400000 ; FILE.BufPtr is pointer to the allocated memory. fileStUnicode EQU 0x00800000 ; FILE.Name is in WIDE characters (not used in Linux). fileStMapCreated EQU 0x01000000 ; FILE.MapHandle is valid for writing. fileStMapOpened EQU 0x02000000 ; FILE.MapHandle is valid for reading. fileStMapped EQU 0x04000000 ; FILE.Ptr is pointer to the mapped memory. fileStCreated EQU 0x10000000 ; FILE.Handle is valid for writing. fileStOpened EQU 0x20000000 ; FILE.Handle is valid for reading.
FileNameParse %MACRO FileNamePtr,Size=-1, Unicode=%^UNICODE
PUSHD %Size,%FileNamePtr
CALL FileNameParse@RT:
FileNameParse@RT: PROC1
PUSHAD
MOV EBP,ESP
MOV ESI,[%Param1] ; %FileNamePtr.
MOV EDX,[%Param2] ; %Size.
SUB ECX,ECX
TEST EDX
JS .UnlimitedSize:
ADD EDX,ESI ; End of input string.
.UnlimitedSize:
MOV [%ReturnEAX],ECX
MOV [%ReturnECX],ECX
MOV [%ReturnEDX],ECX
.NextChar:
CMP ESI,EDX
JNB .E0:
LODSB
Dispatch AL,58,92,47,46,0 ; colon, backslash, slash, dot, NULL.
; Ordinary character
LEA EAX,[ESI-1]
CMP [%ReturnEAX],ECX
JNZ .NextChar:
MOV [%ReturnEAX],EAX
JMP .NextChar:
.46: ; dot .
LEA EAX,[ESI-1]
MOV [%ReturnECX],EAX
CMP [%ReturnEAX],ECX
JNE .NextChar:
MOV [%ReturnEAX],EAX
JMP .NextChar:
.47: ; colon, slash, backslash
.58:
.92: MOV [%ReturnEAX],ESI
MOV [%ReturnECX],ECX
JMP .NextChar:
.0: DEC ESI ; Byte NULL.
.E0:MOV [%ReturnEDX],ESI
CMP [%ReturnECX],ECX
JNE .E1:
MOV [%ReturnECX],ESI
.E1:CMP [%ReturnEAX],ECX
JNE .E2:
MOV EAX,[%ReturnECX]
MOV [%ReturnEAX],EAX
.E2:POPAD
RET 8
ENDPROC1 FileNameParse@RT:
%ENDMACRO FileNameParse
theFile.Name member.
.Name, .NameOffs, .ExtOffs, .Status:fileStUnicode of theFile are set.SIZE# FILE.Name, i.e. NAME_MAX=260 characters.
FileAssign %MACRO theFile,Name$1,Name$2,,, Size=-1, Unicode=%^UNICODE
%IF %#<2 ; >
%ERROR ID=5941, 'File name missing in macro "FileAssign".'
%EXITMACRO FileAssign
%ENDIF
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-1
PUSHD %*{%ArgNr}
%ENDFOR ArgNr
PUSHD %Size, %theFile, ESP
ADDD [ESP],4*(%#+2)
CALL FileAssign@RT:
FileAssign@RT: PROC1
PUSHAD
MOV EBX,[ESP+40] ; %theFile
LEA EBP,[ESP+48] ; %Name$1
LEA EDI,[EBX+FILE.Name]
RstSt [EBX+FILE.Status],fileStUnicode
LEA EDX,[EDI+NAME_MAX]
.10:XCHG EBP,ESI
LODSD ; Offset of source string.
MOV EBP,EAX
XCHG ESI,EBP
TEST EAX
JZ .50:
MOV ECX,[ESP+44] ; %Size.
.20:LODSB
CMP AL,0
JE .10:
CMP EDI,EDX
JNB .40:
STOSB
LOOP .20:
JMP .10:
.40:SUB EAX,EAX
STC ; Overflow.
.50:MOV ECX,EDI
STOSB
LEA EDX,[EBX+FILE.Name]
PUSHFD
SUB ECX,EDX
FileNameParse EDX,Size=ECX
LEA EDX,[EBX+FILE.Name]
SUB EAX,EDX
SUB ECX,EDX
MOV [EBX+FILE.NameOffs],EAX
MOV [EBX+FILE.ExtOffs],ECX
POPFD
POPAD
RET
ENDPROC1 FileAssign@RT:
POP ESP
%ENDMACRO FileAssign
* ? are allowed in the file name.
FileExists? %MACRO theFile
PUSHD %theFile
CALL FileExists?@RT:
FileExists?@RT: PROC1
PUSHAD
MOV EBP,[ESP+36] ; theFile.
LEA EBX,[EBP+FILE.Name]
MOV ECX,O_RDONLY+O_PATH+O_DIRECTORY
XOR EDX,EDX
LinAPI open,EBX,ECX,EDX, Fastmode=Yes ; Try to open a directory.
MOV EDI,EAX ; Returned fd or error.
SAL EAX ; Copy SF to CF.
JNC .80: ; Return with CF=0,ZF=0 if directory exists.
MOV ECX,O_RDONLY+O_PATH
LinAPI open,EBX,ECX,EDX, Fastmode=Yes ; Try to open a file.
MOV EDI,EAX ; Returned fd or error.
SAL EAX ; Copy SF to CF.
JC .80:
SetSt [EBP+FILE.Status],fileStFound
XOR EDX,EDX ; Set CF=0, ZF=1 if file exists.
.80: PUSHFD
JC .90: ; Do not close if EDI is invalid handle.
LinAPI close,EDI,Fastmode=Yes
.90: POPFD
POPAD
RET 1*4
ENDPROC1 FileExists?@RT:
%ENDMACRO FileExists?
FileMkDir %MACRO theFile
PUSHD %theFile
CALL FileMkDir@RT:
FileMkDir@RT: PROC1
PUSHAD
MOV EBP,[ESP+36] ; theFile.
LEA EBX,[EBP+FILE.Name]
SUB ECX,ECX
MOV EDI,EBX
DEC ECX
SUB EAX,EAX
REPNE SCASB
MOV EBP,EDI ; ASCIIZ FileName is now EBX..EBP.
MOV EDI,EBX
.20: MOV ECX,EBP
MOV EAX,'/'
CMP [EDI],AL
JNE .30:
INC EDI
.30: SUB ECX,EDI
REPNE SCASB ; Search for the next slash.
MOV AL,0
JNE .80: ; Done when no more slashes left in FileName.
MOV [EDI-1],AL ; Temporarily replace slash with NULL.
MOV ECX,00777q
LinAPI mkdir,EBX,ECX,Fastmode=Yes
MOVB [EDI-1],'/' ; Restore original slash.
TEST EAX
JZ .20:
CMP EAX,-17 ; EEXIST is the only tolerated error.
JE .20:
.80: MOV [ESP+28],EAX ; Returned EAX.
SAL EAX,1 ; Copy SF to CF.
POPAD
RET 1*4
ENDPROC1 FileMkDir@RT:
%ENDMACRO FileMkDir
FileGetSize %MACRO theFile
PUSHD %theFile
CALL FileGetSize@RT:
FileGetSize@RT: PROC1
PUSHAD
MOV EDI,[ESP+9*4] ; %theFile.
SUB ESP,SIZE# STAT64 ; STAT64
MOV ECX,ESP
LEA EBX,[EDI+FILE.Name]
LinAPI stat64,EBX,ECX,Fastmode=Yes
MOV EDX,[ECX+STAT64.st_size]
ADD ESP,SIZE# STAT64
TEST EAX
STC
JNZ .90:
MOV EAX,EDX
CLC
.90:MOV [ESP+7*4],EAX ; Value returned in EAX.
POPAD
RET 1*4
ENDPROC1 FileGetSize@RT:
%ENDMACRO FileGetSize
FileOpen %MACRO theFile
PUSHD %theFile
CALL FileOpen@RT:
FileOpen@RT: PROC1
PUSHAD
MOV EDI,[ESP+9*4] ; theFile.
LEA EBX,[EDI+FILE.Name]
XOR EDX,EDX
MOV [EDI+FILE.Size],EDX
MOV [EDI+FILE.Pos],EDX
MOV [EDI+FILE.Ptr],EDX
MOV [EDI+FILE.Top],EDX
LinAPI open,EBX,O_RDONLY,EDX,Fastmode=Yes
TEST EAX
STC
JS .90:
SetSt [EDI+FILE.Status],fileStOpened+fileStFound
MOV [EDI+FILE.Handle],EAX
FileGetSize EDI
JC .90:
MOV [EDI+FILE.Size],EAX
MOV [EDI+FILE.Top],EAX
.90: MOV [ESP+7*4],EAX ; Returned EAX.
POPAD
RET 1*4
ENDPROC1 FileOpen@RT:
%ENDMACRO FileOpen
FileFlush %MACRO theFile
PUSHD %theFile
CALL FileFlush@RT:
FileFlush@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
MOV EAX,-EBADFD ; Error: file is not open for write.
JNSt [EDI+FILE.Status],fileStAllocated,.Err:
JNSt [EDI+FILE.Status],fileStCreated, .Err:
MOV ECX,[EDI+FILE.BufPtr] ; Start of buffer.
MOV EDX,[EDI+FILE.Ptr] ; Next free position in buffer.
MOV [EDI+FILE.Ptr],ECX
SUB EDX,ECX
MOV EAX,EDX
JZ .80:
LinAPI write,[EDI+FILE.Handle],ECX,EDX,Fastmode=Yes
CMP EAX,-ERR_MAX
CMC
JNC .80:
.Err:STC
.80: MOV [ESP+28],EAX ; Returned EAX.
.90:POPAD
RET 1*4
ENDPROC1 FileFlush@RT:
%ENDMACRO FileFlush
FileClose %MACRO theFile1
ArgNr %FOR 1..%#
PUSHD %*{%ArgNr}
CALL FileClose@RT:
%ENDFOR ArgNr
FileClose@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile
JSt [EDI+FILE.Status],fileStMapped,.10:
FileFlush EDI
JMPS .20:
.10: LinAPI munmap,[EDI+FILE.MapHandle],[EDI+FILE.Size],Fastmode=Yes
.20: JNSt [EDI+FILE.Status],fileStAllocated,.30:
LinAPI munmap,[EDI+FILE.BufPtr],[EDI+FILE.BufSize],Fastmode=Yes
.30: JNSt [EDI+FILE.Status],fileStOpened|fileStCreated, .40:
LinAPI close,[EDI+FILE.Handle],Fastmode=Yes
.40: RstSt [EDI+FILE.Status],fileStOpened|fileStCreated|fileStAppend|fileStMapCreated|fileStMapOpened|fileStMapped|fileStAllocated
MOVD [EDI+FILE.MapHandle],-1
MOVD [EDI+FILE.Handle],-1
POPAD
RET 1*4
ENDPROC1 FileClose@RT:
%ENDMACRO FileClose
FileMove %MACRO SourceFile, DestinationFile
PUSHD %DestinationFile, %SourceFile
CALL FileMove@RT:
FileMove@RT: PROC1
PUSHAD
MOV ESI,[ESP+36] ; SourceFile.
MOV EDI,[ESP+40] ; DestinationFile.
FileClose ESI,EDI
FileMkDir EDI
JC .EndWithEAX:
LEA EBX,[ESI+FILE.Name]
LEA ECX,[EDI+FILE.Name]
LinAPI rename,EBX,ECX,Fastmode=Yes
.EndWithEAX:
MOV [ESP+28],EAX ; ReturnEAX.
SAL EAX,1 ; Copy SF to CF.
POPAD
RET 2*4
ENDPROC1 FileMove@RT:
%ENDMACRO FileMove
FileDelete %MACRO theFile
ArgNr %FOR 1..%#
PUSHD %*{%ArgNr}
CALL FileDelete@RT:
%ENDFOR ArgNr
FileDelete@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
FileClose EDI
LEA ESI,[EDI+FILE.Name]
LinAPI unlink,ESI,Fastmode=Yes
MOV [ESP+28],EAX ; ReturnEAX.
SAL EAX,1 ; Copy SF to CF.
POPAD
RET 4
ENDPROC1 FileDelete@RT:
%ENDMACRO FileDelete
FILE.Name is replaced
with the resolved file name found in directory. The file is not open.
FileEach %MACRO MaskFile, CallbackProc
PUSHD %CallbackProc, %MaskFile
CALL FileEach@RT:
FileEach@RT: PROC1
PUSHAD
MOV EBP,ESP
%FileEachDirentSize %SETA NAME_MAX+16
%FileEachDirEntries %SET EBP-%FileEachDirentSize
%FileEachStat64 %SET EBP-%FileEachDirentSize-SIZE#STAT64
%FileEachMask %SET EBP-%FileEachDirentSize-SIZE#STAT64-NAME_MAX
%FileEachDirFd %SET EBP-%FileEachDirentSize-SIZE#STAT64-NAME_MAX-4
SUB ESP,%FileEachDirentSize+SIZE#STAT64+NAME_MAX+4
MOVD [EBP+7*4],0 ; Returned EAX.
MOV EBX,[EBP+9*4] ; MaskFile.
LEA ESI,[EBX+FILE.Name]
LEA EDI,[%FileEachMask]
MOVW [EDI],'*' ; Use %FileEachMask='*' in case when the entire MaskFile.Name is a directory.
LEA EDX,[%FileEachStat64]
LinAPI stat64,ESI,EDX
TESTW [EDX+STAT64.st_mode],S_IFDIR
JZ .10:
GetLength$ ESI ; Entire assigned MaskFile.Name is a directory. Perhaps it does not end with '/'?
CMPB [ESI+ECX-1],'/'
JE .30:
MOVW [ESI+ECX],'/'
JMP .30: ; MaskFile.Name is a directory terminated with '/',0. %FileEachMask is '*',0.
.10:FileNameParse ESI ; ESI is path+name.
MOV ECX,EDX
MOV ESI,EAX
SUB ECX,EAX ; ECX is the mask size without path.
INC ECX ; Include the terminating 0.
REP MOVSB ; Copy the mask without path to %FileEachMask. It may be "doc??.txt", "*", "" etc.
MOVB [EAX],0 ; End of the directory name. It may be empty.
LEA ESI,[EBX+FILE.Name]
CMP EAX,ESI
JA .30:
MOVD [ESI],'./'
ADD [EBX+FILE.NameOffs],2
ADD [EBX+FILE.ExtOffs],2
.30:LEA ESI,[EBX+FILE.Name] ; FILE %MaskFile is now assigned with its directory. Mask (file name) is in %FileEachMask.
LinAPI open,ESI,O_RDONLY+O_DIRECTORY+O_NOATIME,0,Fastmode=Yes ; Open the directory.
CMP EAX,-ERR_MAX
JNC .80:
MOV [%FileEachDirFd],EAX
.40:MOV EDX,[%FileEachDirFd] ; Directory handle.
LEA EBX,[%FileEachDirEntries] ; A buffer for directory entries.
MOV ECX,%FileEachDirentSize ; Size of the buffer.
LinAPI getdents64,EDX,EBX,ECX ; Load a portion of DirEnt records.
CMP EAX,-ERR_MAX
JNC .70:
TEST EAX
JZ .70: ; No more records when EAX=0.
LEA EDX,[EBX+EAX] ; End of directory entries in this buffer.
.50:CMP EBX,EDX
JNB .40:
CMPB [EBX+DIRENT64.d_type],DT_REG ; Accept regular files only.
JNE .60:
LEA EDI,[EBX+DIRENT64.d_name] ; Zero-terminated regular file name without path.
PUSH EBX,EDX,ESI
MOV EBX,[EBP+9*4] ; MaskFile.
LEA ESI,[EBX+FILE.Name]
FileNameParse ESI
SUB EAX,ESI
MOV [EBX+FILE.NameOffs],EAX
MOVB [ESI+EAX],0
CALL .OneFilename:
POP ESI,EDX,EBX
JC .70:
.60:MOVZXW EAX,[EBX+DIRENT64.d_reclen]
ADD EBX,EAX
JMP .50:
.70:LinAPI close,[%FileEachDirFd]
.80:MOV ESP,EBP
POPAD
RET 2*4
.OneFilename: ; EDI is pointer to one filename from the given directory, without path, without wildcards, zero-terminated.
; If the filename complies the mask, perform callback [EBP+10*4] and return EAX from the callback and CF=0.
LEA ESI,[%FileEachMask]
MOV EDX,EDI ; Save the pointer to filename into EDX.
.100: LODSB ; A byte from the mask.
MOV AH,[EDI] ; A byte from the filename.
INC EDI
Dispatch AL,0x3F, 0x2A, 0x00 ; Wildcards '?', '*', NULL.
CMP AL,AH ; Otherwise it's an ordinary character, perhaps in UTF-8.
JE .100: ; Comply so far.
JMP .NotC: ; ZF=0. The mask does not match.
.0x3F:CMP AH,0 ; Question mark in mask complies with one not-nul UTF8 character.
JE .NotC: ; ZF=0.
.150: NOT EAX ; Invert bits in UTF8 AH.
XOR EBX,EBX
BSR BX,AX ; Scan AH.
SUB EBX,15 ; Decrease the bit number.
JZ .100: ; If it is ASCII character below 0x80, test the next character.
INC EBX
SUB EDI,EBX ; Advance EDI by the size of UTF8 character - 1.
JMP .100:
.0x2A: ; Asterix '*' in mask complies with zero or more UTF8 characters.
LODSB ; The mask character/byte following '*'.
CMP AL,0
JE .Cply:
CMP AL,'?'
JE .0x2A:
CMP AL,'*'
JE .0x2A:
DEC ESI
SUB ECX,ECX
.200: LODSB
CMP AL,0
JE .300:
INC ECX
JMP .200:
.0x00:CMP AH,0
JE .Cply:
JMP .NotC:
.300: SUB ESI,ECX
MOV EBX,ECX
DEC ESI ; ESI,EDX is the end of string which should match the same end of filename.
XOR EAX,EAX
MOV ECX,-1
REPNE SCASB
SUB EDI,EBX
DEC EDI
MOV ECX,EBX
REPE CMPSB
JNE .NotC: ; ZF=0.
.Cply:; Filename matches the mask. Assign it to MaskFile and then call Callback.
MOV ESI,EDX ; Restore saved filename.
MOV EBX,[EBP+9*4] ; Pointer to MaskFile.
LEA EDI,[EBX+FILE.Name]
GetLength$ EDI
ADD EDI,ECX
PUSH EDI ; Save pointer to filename without path.
.500: LODSB
STOSB
CMP AL,0
JNE .500:
POP ESI
MOV EDX,[EBP+10*4] ; Pointer to the callback procedure.
PUSH EBP
MOV EBP,[EBP+2*4] ; ReturnEBP
CALL EDX
JC .600:
XOR ECX,ECX ; ZF=1.
.600: POP EBP
MOV [EBP+7*4],EAX
RET ; ZF=1 or CF=1 on abort.
.NotC:CLC
RET ; ZF=0.
ENDPROC1 FileEach@RT:
%ENDMACRO FileEach
FileLoad %MACRO theFile
PUSHD %theFile
CALL FileLoad@RT:
FileLoad@RT: PROC1
PUSHAD
MOV EDI,[ESP+9*4] ; theFile.
FileOpen EDI ; Returns CF=0,EAX=file size.
JC .80:
MOV [EDI+FILE.BufSize],EAX
TEST EAX
JZ .80: ; Zero-sized files are not supported.
PUSHD 0,-1,MAP_PRIVATE+MAP_ANONYMOUS,PROT_READ+PROT_WRITE,EAX,0
MOV EBX,ESP
LinAPI mmap,EBX,Fastmode=Yes
ADD ESP,6*4
CMP EAX,-ERR_MAX
CMC
JC .80:
MOV [EDI+FILE.BufPtr],EAX
MOV [EDI+FILE.Ptr],EAX
ADD [EDI+FILE.Top],EAX
MOV [ESP+1*4],EAX ; Returned ESI.
SetSt [EDI+FILE.Status],fileStAllocated
MOV EDX,[EDI+FILE.Size]
LinAPI read,[EDI+FILE.Handle],EAX,EDX,Fastmode=Yes
CMP EAX,-ERR_MAX
CMC
.80:MOV [ESP+7*4],EAX ; Returned EAX.
PUSHFD ; Save CF.
JNSt [EDI+FILE.Status],fileStOpened,.90:
LinAPI close,[EDI+FILE.Handle],Fastmode=Yes
.90: RstSt [EDI+FILE.Status],fileStOpened
MOVD [EDI+FILE.Handle],-1
POPFD ; Restore CF.
POPAD
RET 1*4
ENDPROC1 FileLoad@RT:
%ENDMACRO FileLoad
FileStore %MACRO theFile,DataPtr,DataSize
PUSHD %DataSize,%DataPtr,%theFile
CALL FileStore@RT:
FileStore@RT: PROC1
PUSHAD
MOV EBP,[ESP+36] ; theFile.
MOV EAX,[ESP+40] ; DataPtr.
MOV ECX,[ESP+44] ; DataSize.
LEA EDI,[EBP+FILE.Name]
MOV [EBP+FILE.Ptr],EAX
MOV [EBP+FILE.Top],EAX
MOV [EBP+FILE.Size],ECX
ADD [EBP+FILE.Top],ECX
MOV [ESP+28],ECX ; Returned EAX.
SUB EAX,EAX
MOV [EBP+FILE.Pos],EAX
LEA EBX,[EBP+FILE.Name]
LinAPI open,EBX,O_WRONLY+O_CREAT+O_TRUNC,777q,Fastmode=Yes
TEST EAX
JNS .OK:
.ErrorEAX: STC
JMP .EndWithEAX:
.OK:MOV EBX,EAX ; File descriptor.
LinAPI write,EBX,[EBP+FILE.Ptr],[EBP+FILE.Size],Fastmode=Yes
TEST EAX
JS .ErrorEAX:
LinAPI close,EBX,Fastmode=Yes
MOV EAX,[EBP+FILE.Size]
ADD [EBP+FILE.Pos],EAX
.EndWithEAX:
MOV [ESP+28],EAX ; Returned EAX.
POPAD
RET 3*4
ENDPROC1 FileStore@RT:
%ENDMACRO FileStore
FileReset %MACRO theFile, Position
%IF "%Position" === ""
PUSHD 0
%ELSE
PUSHD %Position
%ENDIF
PUSHD %theFile
CALL FileReset@RT:
FileReset@RT: PROC1
PUSHAD
MOV EBP,ESP
MOV EDI,[%Param1] ; theFile.
MOV ESI,[%Param2] ; Position.
MOV EAX,EBADF ; Error code file is not opened.
JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX:
LinAPI lseek,[EDI+FILE.Handle],ESI,SEEK_SET,Fastmode=Yes
TEST EAX
JNS .50:
.ErrorEAX: STC
JMP .EndWithEAX:
.50: MOV [EDI+FILE.Pos],EAX
MOV ESI,[EDI+FILE.BufPtr]
ADD ESI,EAX
MOV [EDI+FILE.Ptr],ESI
JSt [EDI+FILE.Status],fileStMapOpened,.EndWithEAX:
MOV [EDI+FILE.Top],ESI
.EndWithEAX:
MOV [%ReturnEAX],EAX
.90: POPAD
RET 2*4
ENDPROC1 FileReset@RT:
%ENDMACRO FileReset
FileRead %MACRO theFile,DataPtr,DataSize
PUSHD %DataSize,%DataPtr,%theFile
CALL FileRead@RT:
FileRead@RT: PROC1
PUSHAD
MOV EBP,ESP
MOV EDI,[%Param1] ; theFile.
MOV EAX, -EBADFD ; Error code: file is not open.
TEST [EDI+FILE.Status],fileStOpened
STC
JZ .EndWithEAX:
LinAPI read,[EDI+FILE.Handle],[%Param2],[%Param3],Fastmode=Yes
TEST EAX
STC
JS .EndWithEAX:
ADD [EDI+FILE.Pos],EAX
TEST EAX ; Check EOF.
.EndWithEAX:
MOV [%ReturnEAX],EAX
POPAD
RET 3*4
ENDPROC1 FileRead@RT:
%ENDMACRO FileRead
FileCreate %MACRO theFile
PUSHD %theFile
CALL FileCreate@RT:
FileCreate@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
LEA EBX,[EDI+FILE.Name]
SUB ESI,ESI
MOV [EDI+FILE.Size],ESI
MOV [EDI+FILE.Pos],ESI
MOV [EDI+FILE.Ptr],ESI
MOV [EDI+FILE.Top],ESI
MOV ECX,O_CREAT|O_WRONLY|O_TRUNC
JNSt [EDI+FILE.Status],fileStAppend,.10:
MOV ECX,O_CREAT|O_WRONLY|O_APPEND
.10:LinAPI open,EBX,ECX,777q,Fastmode=Yes
CMP EAX,-ERR_MAX
CMC
JC .Error:
SetSt [EDI+FILE.Status],fileStCreated
MOV [EDI+FILE.Handle],EAX
FileGetSize EDI
JC .Error:
MOV [ESP+28],EAX ; Returned EAX.
MOV [EDI+FILE.Size],EAX
MOV [EDI+FILE.Pos],EAX
.Error:
MOV [ESP+28],EAX
POPAD
RET 1*4
ENDPROC1 FileCreate@RT:
%ENDMACRO FileCreate
FileAppend %MACRO theFile
PUSHD %theFile
CALL FileAppend@RT:
FileAppend@RT: PROC1
PUSH EBX
MOV EBX,[ESP+8] ; theFile
SetSt [EBX+FILE.Status],fileStAppend
FileCreate EBX
POP EBX
RET 1*4
ENDPROC1 FileAppend@RT:
%ENDMACRO FileAppend
FileWriteRT %MACRO ; Common runtime procedure declaration for macros FileWrite*
FileWrite@RT: PROC1
PUSHAD
MOV EDI,[ESP+40] ; theFile
LEA ESI,[ESP+44] ; 1st string ptr.
MOV EAX,-EBADFD ; File is not opened.
JNSt [EDI+FILE.Status],fileStCreated, .ErrorEAX:
SUB EAX,EAX
MOV [ESP+28],EAX ; %Return EAX.
.10: LODSD ; DataPtr.
MOV ECX,EAX
JECXZ .90 ; End of data.
LODSD ; DataSize.
LinAPI write,[EDI+FILE.Handle],ECX,EAX,Fastmode=Yes
TEST EAX
JS .ErrorEAX:
ADD [ESP+28],EAX ; %ReturnEAX
ADD [EDI+FILE.Pos],EAX
ADD [EDI+FILE.Size],EAX
JMP .10:
.ErrorEAX: STC
MOV [%ReturnEAX],EAX
.90:POPAD
RET
FileWrite$size@RT:
PUSH EAX,ECX,EDI
SUB ECX,ECX
SUB EAX,EAX
DEC ECX
MOV EDI,[ESP+16] ; DataPtr.
REPNE SCASB
SUB EAX,ECX
SUB EAX,2
MOV [ESP+20],EAX ; DataSize.
POP EDI,ECX,EAX
RET
ENDPROC1 FileWrite@RT:
%ENDMACRO FileWriteRT
FileWrite %MACRO theFile,DataPtr,DataSize,,,,
%IF %# & 1 = 0
%ERROR ID=5944, 'Macro "%0" expects odd number of arguments.'
%EXITMACRO FileWrite
%ENDIF
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],(%#+1)*4
CALL FileWrite@RT:
POP ESP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWrite
FileWriteLn %MACRO theFile,DataPtr,DataSize,,,
%IF %# & 1 = 0
%ERROR ID=5945, 'Macro "%0" expects odd number of arguments.'
%EXITMACRO FileWriteLn
%ENDIF
PUSHD 0x0A ; CR+LF.
PUSHD 0 ; Mark the end of arguments.
PUSHD 1 ; Size of LF.
PUSHD ESP
ADDD [ESP],2*4 ; Pointer to LF.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],(%#+4)*4
CALL FileWrite@RT:
POP ESP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWriteLn
FileWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-1
PUSHD EAX,%*{%ArgNr}
CALL FileWrite$size@RT:
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],2 * %# * 4
CALL FileWrite@RT:
POP ESP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWrite$
FileEncloseRT %MACRO ; Common RT procedure declaration for macros FileEnclose*
FileEnclose@RT: PROC1
PUSHAD
MOV EDI,[ESP+40] ; theFile
SetSt [EDI+FILE.Status],fileStAppend
FileCreate EDI
JC .Error:
LEA ESI,[ESP+44] ; Pointer to 1st string pointer.
SUB EAX,EAX
MOV [ESP+28],EAX ; %ReturnEAX.
.10: LODSD ; DataPtr.
MOV ECX,EAX
JECXZ .90 ; End of data pointers.
LODSD ; DataSize.
LinAPI write,[EDI+FILE.Handle],ECX,EAX,Fastmode=Yes
TEST EAX
JS .Error:
ADD [ESP+28],EAX ; %ReturnEAX.
ADD [EDI+FILE.Pos],EAX
ADD [EDI+FILE.Size],EAX
JMP .10:
.Error:STC
MOV [ESP+28],EAX ; %ReturnEAX.
.90: PUSHFD ; Save CF.
FileClose EDI
POPFD ; Restore CF.
POPAD
RET
FileEnclose$size@RT: ; Subprocedure for zero-terminated strings.
PUSH EAX,ECX,EDI
SUB ECX,ECX
SUB EAX,EAX
DEC ECX
MOV EDI,[ESP+16] ; DataPtr.
REPNE SCASB
SUB EAX,ECX
SUB EAX,2
MOV [ESP+20],EAX ; DataSize.
POP EDI,ECX,EAX
RET
ENDPROC1 FileEnclose@RT:
%ENDMACRO FileEncloseRT
FileEnclose %MACRO theFile,DataPtr,DataSize,,,,
%IF %# & 1 = 0
%ERROR ID=5942, 'Macro "%0" expects odd number of arguments.'
%EXITMACRO FileEnclose
%ENDIF
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],(%#+1)*4
CALL FileEnclose@RT
POP ESP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEnclose
FileEncloseLn %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5943, 'Macro "FileEncloseLn" expects odd number of arguments.'
%EXITMACRO FileEncloseLn
%ENDIF
PUSHD 0x0A ; LF.
PUSHD 0 ; Mark the end of arguments.
PUSHD 1 ; Size of LF.
PUSHD ESP
ADDD [ESP],2*4 ; Pointer to LF.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],(%#+4)*4
CALL FileEnclose@RT
POP ESP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEncloseLn
FileEnclose$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-1
PUSHD EAX,%*{%ArgNr}
CALL FileEnclose$size@RT ; Using subprocedure in FileEncloseRT get datasize to EAX.
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],2 * %# * 4
CALL FileEnclose@RT
POP ESP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEnclose$
FileMapOpen %MACRO theFile
PUSHD %theFile
CALL FileMapOpen@RT:
FileMapOpen@RT: PROC1
PUSHAD
MOV EDI,[ESP+9*4] ; theFile.
FileOpen EDI
.Err:MOV [ESP+7*4],EAX ; Return EAX.
JC .End:
MOV [EDI+FILE.Size],EAX
MOV EDX,[EDI+FILE.Handle]
PUSHD 0,EDX,MAP_SHARED,PROT_READ+PROT_EXEC,EAX,0
MOV EBX,ESP
LinAPI mmap,EBX,Fastmode=Yes
ADD ESP,6*4
CMP EAX,-ERR_MAX
CMC
JC .Err:
MOV [ESP+4],EAX ; Return ESI=Pointer to the mapped memory.
MOV [EDI+FILE.Ptr],EAX
MOV [EDI+FILE.BufPtr],EAX
MOV [EDI+FILE.MapHandle],EAX
MOV EAX,[EDI+FILE.Size]
MOV [EDI+FILE.BufSize],EAX
ADD EAX,[EDI+FILE.Ptr]
MOV [EDI+FILE.Top],EAX
SetSt [EDI+FILE.Status],fileStMapped+fileStMapOpened+fileStFound
.End:POPAD
RET 1*4
ENDPROC1 FileMapOpen@RT:
%ENDMACRO FileMapOpen
FileMapCreate %MACRO theFile,FileSize
%IF %# > 1
PUSHD %FileSize
%ELSE
PUSHD 0
%ENDIF
PUSHD %theFile
CALL FileMapCreate@RT:
FileMapCreate@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
LEA EBX,[EDI+FILE.Name]
LinAPI open,EBX,O_RDWR|O_CREAT,777q,Fastmode=Yes
TEST EAX
JNS .10:
.Error:MOVD [ESP+0],0 ; Returned EDI.
MOV [ESP+28],EAX ; Returned EAX.
STC
JMP .90:
.10: MOV [EDI+FILE.Handle],EAX
MOV ESI,EAX
MOV ECX,[ESP+40] ; Requested file size.
LinAPI ftruncate,ESI,ECX,Fastmode=Yes
TEST EAX
JNZ .Error:
PUSHD EAX,ESI,MAP_SHARED+MAP_32BITS,PROT_READ+PROT_WRITE+PROT_EXEC,ECX,EAX
MOV EBX,ESP
LinAPI mmap,EBX, Fastmode=Yes
ADD ESP,6*4
CMP EAX,-ERR_MAX
JNC .Error:
MOV [ESP+0],EAX ; Returned EDI=Pointer to mapped memory.
SetSt [EDI+FILE.Status],fileStMapCreated+fileStMapped+fileStCreated
MOV [EDI+FILE.MapHandle],EAX
MOV [EDI+FILE.Ptr],EAX
MOV [EDI+FILE.BufPtr],EAX
ADD EAX,[EDI+FILE.Size]
MOV [EDI+FILE.Top],EAX
.90: POPAD
RET 2*4
ENDPROC1 FileMapCreate@RT:
%ENDMACRO FileMapCreate
FileStreamOpen %MACRO theFile,BufSize=16K
PUSHD %BufSize,%theFile
CALL FileStreamOpen@RT:
FileStreamOpen@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
MOV ECX,[ESP+40] ; BufSize.
MOV [EDI+FILE.BufSize],ECX
XOR EAX,EAX
PUSHD EAX,-1,MAP_PRIVATE+MAP_ANONYMOUS,PROT_READ+PROT_WRITE,ECX,EAX
MOV EBX,ESP
LinAPI mmap,EBX,Fastmode=Yes
ADD ESP,6*4
CMP EAX,-ERR_MAX
CMC
JC .90:
SetSt [EDI+FILE.Status],fileStAllocated
MOV [EDI+FILE.MapHandle],EAX
MOV [EDI+FILE.BufPtr],EAX
MOV EBX,EAX
FileOpen EDI
MOV [EDI+FILE.Ptr],EBX
MOV [EDI+FILE.Top],EBX
.90: MOV [ESP+28],EAX ; Returned EAX.
POPAD
RET 2*4
ENDPROC1 FileStreamOpen@RT:
%ENDMACRO FileStreamOpen
FileStreamRead %MACRO theFile,DataPtr,DataSize
PUSHD %DataSize,%DataPtr,%theFile
CALL FileStreamRead@RT:
FileStreamRead@RT: PROC1
PUSHAD
SUB EDX,EDX
MOV EBX,[ESP+36] ; theFile.
MOV EAX,-EBADFD ; Error: file is not open.
JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX:
JNSt [EBX+FILE.Status],fileStAllocated,.ErrorEAX:
MOV EDI,[ESP+40] ; DataPtr.
.10: MOV ESI,[EBX+FILE.Ptr]
.20: MOV ECX,[EBX+FILE.Top]
SUB ECX,ESI ; How many bytes is left in buffer.
JNA .50:
CMP ECX,[ESP+44] ; Is it enough for the requested DataSize?
JA .60:
SUB [ESP+44],ECX
ADD EDX,ECX
REP MOVSB
MOV [EBX+FILE.Ptr],ESI
JMP .20:
.50: MOV ESI,[EBX+FILE.BufPtr]
MOV [EBX+FILE.Ptr],ESI
MOV [EBX+FILE.Top],ESI
PUSH EBX
LinAPI read,[EBX+FILE.Handle],ESI,[EBX+FILE.BufSize],Fastmode=Yes
POP EBX
CMP EAX,-ERR_MAX
CMC
JC .80:
ADD [EBX+FILE.Top],EAX
JMP .20:
.60: MOV ECX,[ESP+44] ; DataSize.
ADD EDX,ECX
REP MOVSB
MOV [EBX+FILE.Ptr],ESI
.70: MOV EAX,EDX
ADD [EBX+FILE.Pos],EDX
TEST EAX
.80: MOV [ESP+28],EAX ; Returned EAX.
.90: POPAD
RET 3*4
ENDPROC1 FileStreamRead@RT:
%ENDMACRO FileStreamRead
FileStreamReadLn %MACRO theFile
PUSHD %theFile
CALL FileStreamReadLn@RT:
FileStreamReadLn@RT: PROC1
PUSHAD
MOV EBP,[ESP+36] ; theFile.
MOV EAX,-EBADFD ; Error: file is not open.
JNSt [EBP+FILE.Status],fileStOpened, .Err:
JNSt [EBP+FILE.Status],fileStAllocated, .Err:
MOV EDI,[EBP+FILE.Ptr]
.10: MOV ECX,[EBP+FILE.Top]
MOV [ESP+4],EDI ; Returned ESI.
MOV EDX,EDI
SUB ECX,EDI
JNA .30:
MOV AL,10 ; Search for LineFeed.
REPNE SCASB
JE .50:
CMP EDX,[EBP+FILE.BufPtr]
JE .50:
; When EOL is out of buffer and start of line is not
; at buffer's beginning, the buffer will be reloaded with the current line.
MOV ECX,EDX
SUB ECX,EDI
LinAPI lseek,[EBP+FILE.Handle],ECX,SEEK_CUR,Fastmode=Yes
CMP EAX,-ERR_MAX
JNC .Err:
.30: MOV EDI,[EBP+FILE.BufPtr]
MOV [EBP+FILE.Ptr],EDI
MOV [EBP+FILE.Top],EDI
LinAPI read,[EBP+FILE.Handle],EDI,[EBP+FILE.BufSize],Fastmode=Yes
CMP EAX,-ERR_MAX
JNC .Err:
TEST EAX
JZ .Eof:
ADD EAX,EDI
MOV [EBP+FILE.Top],EAX
JMP .10:
.Err: STC
JMP .80:
.Eof: SUB EAX,EAX
JMP .80:
.50: MOV [EBP+FILE.Ptr],EDI
MOV EAX,EDI
SUB EAX,EDX
ADD [EBP+FILE.Pos],EAX
.80: MOV [ESP+28],EAX ; Returned EAX.
POPAD
RET 4
ENDPROC1 FileStreamReadLn@RT:
%ENDMACRO FileStreamReadLn
FileStreamReadByte %MACRO theFile
PUSHD %theFile
CALL FileStreamReadByte@RT:
FileStreamReadByte@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
.10: MOV ESI,[EDI+FILE.Ptr]
CMP ESI,[EDI+FILE.Top]
JB .50:
MOV EAX,-EBADFD ; Error: file is not open.
JNSt [EDI+FILE.Status],fileStOpened,.Error:
JNSt [EDI+FILE.Status],fileStAllocated,.Error:
MOV ECX,[EDI+FILE.BufPtr]
MOV [EDI+FILE.Ptr],ECX
MOV [EDI+FILE.Top],ECX
LinAPI read,[EDI+FILE.Handle],ECX,[EDI+FILE.BufSize],Fastmode=Yes
CMP EAX,-ERR_MAX
JNC .Error:
TEST EAX
JZ .80:
ADD [EDI+FILE.Top],EAX
JMP .10: ; This time it will not fail.
.Error:STC
JMP .80:
.50: MOV EAX,[ESP+28] ; Do not clobber other bytes in EAX but AL.
LODSB
MOV [EDI+FILE.Ptr],ESI
INCD [EDI+FILE.Pos]
CLC
.80: MOV [ESP+28],EAX ; Returned EAX.
POPAD
RET 4
ENDPROC1 FileStreamReadByte@RT:
%ENDMACRO FileStreamReadByte
FileStreamCreate %MACRO theFile,BufSize=16K
PUSHD %BufSize,%theFile
CALL FileStreamCreate@RT:
FileStreamCreate@RT: PROC1
PUSHAD
MOV EDI,[ESP+36] ; theFile.
FileCreate EDI
JC .80:
MOV ECX,[ESP+40] ; BufSize.
PUSH 0,-1,MAP_PRIVATE+MAP_ANONYMOUS,PROT_READ+PROT_WRITE+PROT_EXEC,ECX,0
MOV EBX,ESP
LinAPI mmap,EBX,Fastmode=Yes
ADD ESP,6*4
CMP EAX,-ERR_MAX
CMC
JC .80:
MOV [EDI+FILE.BufSize],ECX
MOV [EDI+FILE.BufPtr],EAX
MOV [EDI+FILE.Ptr],EAX
ADD EAX,ECX
MOV [EDI+FILE.Top],EAX
SetSt [EDI+FILE.Status],fileStAllocated
MOV EAX,[EDI+FILE.Size]
.80: MOV [ESP+28],EAX ; Returned EAX.
POPAD
RET 2*4
ENDPROC1 FileStreamCreate@RT:
%ENDMACRO FileStreamCreate
FileStreamAppend %MACRO theFile,BufSize=16K
PUSHD %BufSize,%theFile
CALL FileStreamAppend@RT:
FileStreamAppend@RT: PROC1
PUSH EBX,ECX
MOV EBX,[ESP+12] ; theFile
MOV ECX,[ESP+16] ; BufSize
SetSt [EBX+FILE.Status],fileStAppend
FileStreamCreate EBX,ECX
POP ECX,EBX
RET 2*4
ENDPROC1 FileStreamAppend@RT:
%ENDMACRO FileStreamAppend
FileStreamWriteByte %MACRO theFile
PUSHD %theFile
CALL FileStreamWriteByte@RT:
FileStreamWriteByte@RT: PROC1
PUSHAD
MOV EBX,[ESP+36] ; theFile.
.10: MOV EDI,[EBX+FILE.Ptr]
CMP EDI,[EBX+FILE.Top]
JB .50
FileFlush EBX ; Write the buffer if it is full.
JNC .10:
MOV [ESP+28],EAX ; Returned EAX on error.
JMP .90:
.50: STOSB
MOV EAX,[EBX+FILE.Pos]
MOV [EBX+FILE.Ptr],EDI
ADD EAX,1
MOV [EBX+FILE.Pos],EAX
MOV [EBX+FILE.Size],EAX
.90: POPAD
RET 4
ENDPROC1 FileStreamWriteByte@RT:
%ENDMACRO FileStreamWriteByte
FileStreamWriteWord %MACRO theFile
PUSHD %theFile
CALL FileStreamWriteWord@RT:
FileStreamWriteWord@RT: PROC1
PUSHAD
MOV EBX,[ESP+36] ; theFile.
.10: MOV EDI,[EBX+FILE.Ptr]
LEA EDX,[EDI+1]
CMP EDX,[EBX+FILE.Top]
JB .50:
FileFlush EBX ; Write the buffer if it is full.
JNC .10:
MOV [ESP+28],EAX ; Returned EAX on error.
JMP .90:
.50: STOSW
MOV EAX,[EBX+FILE.Pos]
MOV [EBX+FILE.Ptr],EDI
ADD EAX,2
MOV [EBX+FILE.Pos],EAX
MOV [EBX+FILE.Size],EAX
CLC
.90: POPAD
RET 4
ENDPROC1 FileStreamWriteWord@RT:
%ENDMACRO FileStreamWriteWord
FileStreamWriteDword %MACRO theFile
PUSHD %theFile
CALL FileStreamWriteDword@RT:
FileStreamWriteDword@RT: PROC1
PUSHAD
MOV EBX,[ESP+36] ; the File.
.10: MOV EDI,[EBX+FILE.Ptr]
LEA EDX,[EDI+3]
CMP EDX,[EBX+FILE.Top]
JB .50
FileFlush EBX ; Write the buffer if it is full.
JNC .10:
MOV [ESP+28],EAX ; Returned EAX on error.
JMP .90:
.50: STOSD
MOV EAX,[EBX+FILE.Pos]
MOV [EBX+FILE.Ptr],EDI
ADD EAX,4
MOV [EBX+FILE.Pos],EAX
MOV [EBX+FILE.Size],EAX
CLC
.90: POPAD
RET 4
ENDPROC1 FileStreamWriteDword@RT:
%ENDMACRO FileStreamWriteDword
FileStreamWriteRT %MACRO ; Common runtime procedure for macros FileStreamWrite*
FileStreamWrite@RT: PROC1
PUSHAD
MOV EBX,[ESP+40] ; theFile
LEA ESI,[ESP+44] ; 1st string pointer.
MOV EAX,-EBADFD ; File was not opened.
JNSt [EBX+FILE.Status],fileStCreated,.Err:
JNSt [EBX+FILE.Status],fileStAllocated,.Err:
SUB EAX,EAX
MOV [ESP+28],EAX ; %Returned EAX is accumulator of written size.
.10: LODSD ; DataPtr.
MOV EBP,EAX
TEST EAX
JZ .90 ; End of data.
LODSD ; DataSize.
MOV EDX,EAX
ADD [ESP+28],EAX ; %Returned EAX.
PUSH ESI
MOV ESI,EBP
ADD [EBX+FILE.Size],EDX
ADD [EBX+FILE.Pos],EDX
.20: TEST EDX
JZ .70
.30: MOV ECX,[EBX+FILE.Top]
MOV EDI,[EBX+FILE.Ptr]
SUB ECX,EDI ; Remaining free room in Buf.
JNZ .40:
FileFlush EBX ; Flush will reset FILE.Ptr to FILE.BufPtr.
JNC .30:
JC .70:
.40: CMP ECX,EDX
JBE .50:
MOV ECX,EDX
.50: SUB EDX,ECX
REP MOVSB
MOV [EBX+FILE.Ptr],EDI
JA .20:
.70: POP ESI
JNC .10
.Err:STC
MOV [ESP+28],EAX
.90:POPAD
RET
FileStreamWrite$size@RT:
PUSH EAX,ECX,EDI
SUB ECX,ECX
SUB EAX,EAX
DEC ECX
MOV EDI,[ESP+16] ; DataPtr.
REPNE SCASB
SUB EAX,ECX
SUB EAX,2
MOV [ESP+20],EAX ; DataSize.
POP EDI,ECX,EAX
RET
ENDPROC1 FileStreamWrite@RT:
%ENDMACRO FileStreamWriteRT
FileStreamWrite %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5946, 'Macro "%0" expects odd number of arguments.'
%EXITMACRO FileStreamWrite
%ENDIF
PUSHD 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],4*(%#+1)
CALL FileStreamWrite@RT
POP ESP
FileStreamWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileStreamWrite
FileStreamWriteLn %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5947, 'Macro "FileStreamWriteLn" expects odd number of arguments.'
%EXITMACRO FileStreamWriteLn
%ENDIF
PUSHD 0x0000000A ; LF.
PUSHD 0 ; Mark the end of arguments.
PUSHD 1
PUSHD ESP
ADDD [ESP],8 ; Pointer to the LF on stack.
ArgNr %FOR %#..2,STEP=-2
PUSHD %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],4*(%#+4)
CALL FileStreamWrite@RT
POP ESP
FileStreamWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileStreamWriteLn
FileStreamWrite$ %MACRO theFile,DataPtr$1,DataPtr$2,DataPtr$3,,,
PUSHD 0 ; mark end of arguments
ArgNr %FOR %#..2,STEP=-1
PUSHD EAX,%*{%ArgNr}
CALL FileStreamWrite$size@RT
%ENDFOR ArgNr
PUSHD %theFile
PUSH ESP
ADDD [ESP],8*%#
CALL FileStreamWrite@RT
POP ESP
FileStreamWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileStreamWrite$
ENDHEAD linf32