This library contains wrapper macros which encapsulate LinABI calls for most typical file operations in 64bit Linux . See also equivalent homonymous macroinstructions in linf32.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 RAX. 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 FILE64 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 ABI 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 LinABI, Dispatch, status32.htm.
linf64 HEAD INCLUDEHEAD1 lins.htm, linsfile.htm, linabi.htm, cpuext.htm, status32.htm
FILE64 STRUC .Ptr DQ Q ; Pointer to the current data content in memory-mapped|buffered data. .Top DQ Q ; Pointer to the end of the memory-mapped|buffered data. .BufPtr DQ Q ; Address of the start of memory-map|allocated buffer. .BufSize DQ Q ; Size of memory map|buffer. .Pos DQ Q ; Zero based offset of the current file position: lseek(.Handle,.Pos,SEEK_SET). .Size DQ Q ; File size in bytes. .Handle DQ Q ; File descriptor. .MapHandle DQ Q ; 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 FILE64
FILE64.Status.fi64StFound EQU 0x00000010 ; File was once succesfully opened. fi64StAppend EQU 0x00100000 ; Created file should move its pointer to the end. fi64StStdIO EQU 0x00200000 ; FILE64.Handle is standard input|output. fi64StAllocated EQU 0x00400000 ; FILE64.BufPtr is pointer to the allocated memory. fi64StUnicode EQU 0x00800000 ; FILE64.Name is in WIDE characters (not used in Linux). fi64StMapCreated EQU 0x01000000 ; FILE64.MapHandle is valid for writing. fi64StMapOpened EQU 0x02000000 ; FILE64.MapHandle is valid for reading. fi64StMapped EQU 0x04000000 ; FILE64.Ptr is pointer to the mapped memory. fi64StCreated EQU 0x10000000 ; FILE64.Handle is valid for writing. fi64StOpened EQU 0x20000000 ; FILE64.Handle is valid for reading.
FileNameParse %MACRO FileNamePtr,Size=-1, Unicode=%^UNICODE
PUSHQ %Size,%FileNamePtr
CALL FileNameParse@RT::
FileNameParse@RT:: PROC1
PUSH RBX,RSI
SUB EBX,EBX ; Prepare returned value of RAX.
SUB ECX,ECX ; Prepare returned value of RCX.
MOV RSI,[RSP+3*8] ; %FileNamePtr.
MOV RDX,[RSP+4*8] ; %Size.
TEST RDX
JS .NextChar:
ADD RDX,RSI ; End of input string or -1.
.NextChar:
CMP RSI,RDX
JNB .End:
LODSB
Dispatch AL,47,46,0,58,92 ; slash, dot, null, colon, backslash.
; Ordinary character.
LEA RAX,[RSI-1]
TEST RBX
JNZ .NextChar:
MOV RBX,RAX
JMP .NextChar:
.46: ; dot .
LEA RCX,[RSI-1]
JMP .NextChar:
.47: ; colon, slash, backslash
.58:
.92: MOV RBX,RSI
JMP .NextChar:
.0: DEC RSI ; Byte NULL.
.End:MOV RDX,RSI
TEST RCX
JNZ .E1:
MOV RCX,RSI
.E1: TEST RBX
JNZ .E2:
MOV RBX,RSI
.E2: MOV RAX,RBX
POP RSI,RBX
RET 2*8
ENDPROC1 FileNameParse@RT::
%ENDMACRO FileNameParse
theFile.Name member.
.Name, .NameOffs, .ExtOffs, of theFile are set.SIZE# FILE64.Name, i.e. NAME_MAX=260 bytes.
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
PUSHQ 0 ; End-of-arguments marker.
ArgNr %FOR %#..2,STEP=-1
PUSHQ %*{%ArgNr} ; Pointers to strings, start with the last one.
%ENDFOR ArgNr
PUSHQ %Size, %theFile, RSP
ADDQ [RSP],(2+%#)*8
CALL FileAssign@RT::
POP RSP ; Restore stack to equilibrum.
FileAssign@RT:: PROC1
PUSH RAX,RBX,RCX,RDX,RBP,RSI,RDI
MOV RBX,[RSP+9*8] ; %theFile
LEA RBP,[RSP+11*8] ; Pointer to the 1st namepointer.
LEA RDI,[RBX+FILE64.Name]
LEA RDX,[RDI+SIZE#FILE64.Name] ; End of reserved room.
.10:XCHG RBP,RSI
LODSQ ; Load pointer to namestring.
MOV RBP,RAX
XCHG RSI,RBP
TEST RAX ; Check the end of pointers.
JZ .50:
MOV RCX,[RSP+10*8] ; Parameter %Size=.
.20:LODSB
CMP AL,0
JE .10:
CMP RDI,RDX
JNB .40:
STOSB
DEC RCX
JNZ .20:
JMP .10:
.40:SUB EAX,EAX
STC ; Overflow.
.50:MOV RCX,RDI
STOSB
LEA RDX,[RBX+FILE64.Name]
PUSHF
SUB RCX,RDX
FileNameParse RDX,Size=RCX
LEA RDX,[RBX+FILE64.Name]
SUB RAX,RDX
SUB RCX,RDX
MOV [RBX+FILE64.NameOffs],EAX
MOV [RBX+FILE64.ExtOffs],ECX
POPF
POP RDI,RSI,RBP,RDX,RCX,RBX,RAX
RET
ENDPROC1 FileAssign@RT::
%ENDMACRO FileAssign
* ? are allowed in the file name.
FileExists? %MACRO theFile
PUSHQ %theFile
CALL FileExists?@RT::
FileExists?@RT:: PROC1
PUSH RAX,RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+8*8] ; theFile.
LEA RDI,[RBX+FILE64.Name]
MOV ESI,O_RDONLY+O_DIRECTORY
XOR EDX,EDX
LinABI open,RDI,RSI,RDX, Fastmode=Yes ; Try to open a directory.
MOV RDI,RAX ; Returned fd or error.
SAL RAX ; Copy SF to CF.
JNC .80: ; Return with CF=0,ZF=0 if the directory exists.
MOV ESI,O_RDONLY
LEA RDI,[RBX+FILE64.Name]
LinABI open,RDI,RSI,RDX, Fastmode=Yes ; Try to open a file.
MOV RDI,RAX ; Returned fd or error.
SAL RAX ; Copy SF to CF.
JC .90:
SetSt [RBX+FILE64.Status],fi64StFound
XOR EDX,EDX ; Set CF=0, ZF=1 if the file exists.
.80: PUSHFQ
LinABI close,RDI,Fastmode=Yes
POPFQ
.90:POP R11,RDI,RSI,RDX,RCX,RBX,RAX
RET 1*8
ENDPROC1 FileExists?@RT::
%ENDMACRO FileExists?
FileMkDir %MACRO theFile
PUSHQ %theFile
CALL FileMkDir@RT::
FileMkDir@RT:: PROC1
PUSH RBX,RCX,RBP,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
LEA RBX,[RBX+FILE64.Name]
SUB ECX,ECX
MOV RDI,RBX
DEC RCX
XOR EAX,EAX
REPNE SCASB
MOV RBP,RDI ; ASCIIZ FileName is now RBX..RBP.
MOV RDI,RBX
.20: MOV RCX,RBP
MOV AL,'/'
CMP [RDI],AL
JNE .30:
INC RDI
.30: SUB RCX,RDI
REPNE SCASB ; Search for the next slash.
MOV AL,0
CLC
JNE .90: ; Done when no more slashes left in FileName.
MOV [RDI-1],AL ; Temporarily replace slash with NULL.
MOV ESI,00777q
XCHG RBX,RDI
LinABI mkdir,RDI,RSI,Fastmode=Yes
XCHG RDI,RBX
MOVB [RDI-1],'/' ; Restore original slash.
TEST EAX
JZ .20:
CMP EAX,-EEXIST ; EEXIST=17 is the only tolerated error.
JE .20:
.80: STC
.90:POP R11,RDI,RSI,RBP,RCX,RBX
RET 1*8
ENDPROC1 FileMkDir@RT::
%ENDMACRO FileMkDir
FileGetSize %MACRO FileHandle
PUSHQ %FileHandle
CALL FileGetSize@RT::
FileGetSize@RT:: PROC1
PUSH RCX,RBP,RSI,RDI,R11
MOV RBP,RSP
MOV RDI,[RBP+6*8] ; FileHandle.
MOV ECX,SIZE# STAT
ADD ECX,7
AND ECX,~7
SUB RSP,RCX
MOV RSI,RSP ; STAT
LinABI fstat,RDI,RSI,Fastmode=Yes
MOV RCX,[RSI+STAT.st_size]
MOV RSP,RBP
CMP RAX,-ERR_MAX
CMC
JC .90:
MOV RAX,RCX
.90:POP R11,RDI,RSI,RBP,RCX
RET 1*8
ENDPROC1 FileGetSize@RT::
%ENDMACRO FileGetSize
FileOpen %MACRO theFile
PUSHQ %theFile
CALL FileOpen@RT::
FileOpen@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
LEA RDI,[RBX+FILE64.Name]
XOR EDX,EDX
MOV [RBX+FILE64.Size],RDX
MOV [RBX+FILE64.Pos],RDX
MOV [RBX+FILE64.Ptr],RDX
MOV [RBX+FILE64.Top],RDX
LinABI open,RDI,O_RDONLY,RDX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
SetSt [RBX+FILE64.Status],fi64StOpened+fi64StFound
MOV [RBX+FILE64.Handle],RAX
FileGetSize RAX
JC .90:
MOV [RBX+FILE64.Size],RAX
MOV [RBX+FILE64.Top],RAX
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileOpen@RT::
%ENDMACRO FileOpen
FileCreate %MACRO theFile
PUSHQ %theFile
CALL FileCreate@RT::
FileCreate@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; ^theFile.
XOR EAX,EAX
MOV [RBX+FILE64.Ptr],RAX
MOV [RBX+FILE64.Top],RAX
LEA RDI,[RBX+FILE64.Name]
MOV ESI,O_CREAT|O_WRONLY|O_TRUNC
JNSt [RBX+FILE64.Status],fi64StAppend,.10:
MOV ESI,O_CREAT|O_RDWR|O_APPEND ; The macro is used by FileAppend.
.10: LinABI open,RDI,RSI,777q,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
SetSt [RBX+FILE64.Status],fi64StCreated
MOV [RBX+FILE64.Handle],RAX
FileGetSize RAX
JC .90:
MOV [RBX+FILE64.Size],RAX
MOV [RBX+FILE64.Pos],RAX
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileCreate@RT::
%ENDMACRO FileCreate
FileAppend %MACRO theFile
PUSHQ %theFile
CALL FileAppend@RT::
FileAppend@RT:: PROC1
PUSH RBX
MOV RBX,[RSP+2*8] ; ^theFile
SetSt [RBX+FILE64.Status],fi64StAppend
FileCreate RBX
POP RBX
RET 1*8
ENDPROC1 FileAppend@RT::
%ENDMACRO FileAppend
FileFlush %MACRO theFile
PUSHQ %theFile
CALL FileFlush@RT::
FileFlush@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
MOV RAX,-EBADFD ; Error: file is not open for write.
JNSt [RBX+FILE64.Status],fi64StAllocated,.80:
JNSt [RBX+FILE64.Status],fi64StCreated, .80:
MOV RSI,[RBX+FILE64.BufPtr] ; Start of buffer.
MOV RDX,[RBX+FILE64.Ptr] ; Next free position in buffer.
MOV [RBX+FILE64.Ptr],RSI
SUB RDX,RSI
MOV RAX,RDX
JZ .90: ; If nothing to flush.
MOV RDI,[RBX+FILE64.Handle]
LinABI write,RDI,RSI,RDX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JNC .90:
.80: STC
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileFlush@RT::
%ENDMACRO FileFlush
FileClose %MACRO theFile
ArgNr %FOR 1..%#
PUSHQ %*{%ArgNr}
CALL FileClose@RT::
%ENDFOR ArgNr
FileClose@RT:: PROC1
PUSH RAX,RBX,RCX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile
JSt [RBX+FILE64.Status],fi64StMapped,.10:
FileFlush RBX
JMPS .20:
.10: LinABI munmap,[RBX+FILE64.MapHandle],[RBX+FILE64.Size],Fastmode=Yes
.20: JNSt [RBX+FILE64.Status],fi64StAllocated,.30:
LinABI munmap,[RBX+FILE64.BufPtr],[RBX+FILE64.BufSize],Fastmode=Yes
.30: JNSt [RBX+FILE64.Status],fi64StOpened|fi64StCreated, .40:
LinABI close,[RBX+FILE64.Handle],Fastmode=Yes
.40: LEA RCX,[RBX+FILE64.NameOffs]
SUB RCX,RBX
SHR ECX,2
XOR EAX,EAX
MOV RDI,RBX
REP STOSD ; Clear the FILE object except for Name and Offs.
POP R11,RDI,RSI,RCX,RBX,RAX
RET 1*8
ENDPROC1 FileClose@RT::
%ENDMACRO FileClose
FileMove %MACRO SourceFile, DestinationFile
PUSHQ %DestinationFile, %SourceFile
CALL FileMove@RT::
FileMove@RT:: PROC1
PUSH RCX,RSI,RDI,R11
MOV RSI,[RSP+5*8] ; SourceFile.
MOV RDI,[RSP+6*8] ; DestinationFile.
FileClose RSI,RDI
FileMkDir RDI
JC .90:
LEA RSI,[RSI+FILE64.Name]
LEA RDI,[RDI+FILE64.Name]
XCHG RSI,RDI
LinABI rename,RDI,RSI,Fastmode=Yes
MOV ECX,EAX
SAL ECX,1 ; Copy SF to CF.
.90: POP R11,RDI,RSI,RCX
RET 2*8
ENDPROC1 FileMove@RT::
%ENDMACRO FileMove
FileDelete %MACRO theFile
ArgNr %FOR 1..%#
PUSHQ %*{%ArgNr}
CALL FileDelete@RT::
%ENDFOR ArgNr
FileDelete@RT:: PROC1
PUSH RCX,RDI,R11
MOV RDI,[RSP+4*8] ; theFile.
FileClose RDI
LEA RDI,[RDI+FILE64.Name]
LinABI unlink,RDI,Fastmode=Yes
MOV ECX,EAX
SAL ECX,1 ; Copy SF to CF.
POP R11,RDI,RCX
RET 1*8
ENDPROC1 FileDelete@RT::
%ENDMACRO FileDelete
FILE64.Name is replaced
with the resolved file name found in directory. The file is not open.
FileEach %MACRO theFile, CallbackProc
PUSHQ %CallbackProc, %theFile
CALL FileEach@RT::
FileEach@RT:: PROC1
%FileEachMaskSize %SETA (SIZE# FILE64.Name + 7) & ~7 ; Local buffer for the filename mask.
%FileEachBufSize %SETA (SIZE# DIRENT64 + 7) & ~7 ; Local buffer for DIRENT64 records.
PUSH RAX,RBX,RCX,RDX,RSI,RDI,R9,R11
MOV RBX,[RSP+9*8] ; RBX=^theFile.
MOV ECX,%FileEachMaskSize
SUB EAX,EAX
MOV [RSP+7*8],RAX ; Initialize returned RAX with NULL.
SUB RSP,RCX
ADD EAX,[RBX+FILE64.NameOffs]
MOV RDI,RSP
LEA RSI,[RAX+RBX+FILE64.Name]
REP MOVSB ; Copy the ASCIIZ mask without path to LocalVar %FileEachMask$.
JNZ .10: ; Test if theFile.NameOffs=0.
; The mask was specified without path, e.g. doc*.txt
.
; Default path ./ will be injected to FILE64.Name, i.e. ./doc*.txt
.
MOV ECX,SIZE#FILE64.Name-2
LEA RSI,[RCX+RBX+FILE64.Name-1]
LEA RDI,[RSI+2]
STD
REP MOVSB
CLD
DEC RDI
MOVW [RDI],'./'
MOVB [RDI+SIZE#FILE64.Name-1],0
FileNameParse RDI
SUB RAX,RDI
SUB RCX,RDI
MOV [RBX+FILE64.NameOffs],EAX
MOV [RBX+FILE64.ExtOffs],ECX
.10: LEA RDI,[RBX+FILE64.Name] ; RAX=FILE64.NameOffs.
MOVB [RDI+RAX-1],0 ; Temporary replace / with NULL.
MOV R9,RDI
;; LinABI open,RDI,O_RDONLY+O_DIRECTORY+O_NOATIME,0,Fastmode=Yes ; With O_NOATIME 'open' returned -1.
LinABI open,RDI,O_RDONLY+O_DIRECTORY, 0, Fastmode=Yes
MOV EDX,[RBX+FILE64.NameOffs]
MOVB [R9+RDX-1],'/' ; Replace temporary NULL back with slash in the mask name.
MOV EDX,%FileEachBufSize
SUB RSP,RDX ; RDX=Size of temporary buffer.
MOV RDI,RAX ; Directory descriptor (or error code from sys_open).
.20: MOV RSI,RSP ; Pointer to temporary buffer for DIRENT64 records.
LinABI getdents64,RDI,RSI,RDX,Fastmode=Yes
TEST EAX
JZ .End: ; When there are no more dir entries.
CMP RAX,-ERR_MAX
JNC .End: ; When error occured.
LEA RCX,[RSI+RAX] ; End of DIRENT64 records in buffer.
.30: CMP RSI,RCX
JNB .20: ; Go to read the next portion of dir entries.
CALL .DirEnt: ; Process the DIRENT64 record at RSI. Keep all GPR.
JC .End:
MOVZX EAX,[RSI+DIRENT64.d_reclen]
ADD RSI,RAX
JMP .30:
.DirEnt:PROC ; If the resolved name [RSI+DIRENT64.d_name] complies with %FileEachMask$,
; update FILE64.Name at [%Param1] with the resolved name and then call [%Param2].
; Input: RSI=^DIRENT64
; RBX=^FILE64
; Output:CF and RAX as returned from callback. Other registers are unchanged.
PUSH RBX,RCX,RDX,RBP,RSI,RDI
CMP [RSI+DIRENT64.d_type],DT_REG
JNE .NoMatch: ; Skip sockets, pipes, devices and other nonregular files.
LEA RDI,[RSI+DIRENT64.d_name] ; ^name from the directory.
MOV RDX,RDI
LEA RSI,[RSP+7*8+%FileEachBufSize] ; ^file mask without path.
.D1: LODSB ; Byte from file mask.
MOV AH,[RDI] ; Byte from file name.
INC RDI
Dispatch AL,0x00,0x2A,0x3F; Test on end-of-mask and wildcard.
CMP AL,AH ; Ordinary character match?
JE .D1:
JMP .NoMatch:
.0x00: CMP AH,0
JE .Match:
JMP .NoMatch:
.0x3F: CMP AH,0 ; Question mark '?' in mask complies with one not-nul UTF8 character.
JE .NoMatch:
NOT EAX ; Invert bits in UTF8 AH.
SUB ECX,ECX
BSR CX,AX ; Scan AH, start with MSbit.
SUB RCX,15
JZ .D1:
INC RCX
SUB RDI,RCX ; Advance RDI by the size of UTF8 character - 1.
JMP .D1:
.0x2A: ; Asterix '*' complies with zero or more UTF8 characters.
LODSB ; The mask character/byte which follows '*'.
Dispatch AL,0x2A,0x3F,0n00
.D3: CMP AH,0
JE .NoMatch:
CMP AL,AH
JE .D1:
MOV AH,[RDI]
INC RDI
JMP .D3:
.NoMatch: CLC
JMP .D9:
.Match: ; File name at RDX complies with the file mask. Perform callback.
.0n00: MOV RSI,RDX
MOV ECX,SIZE# FILE64.Name
MOV EAX,[RBX+FILE64.NameOffs]
SUB ECX,EAX
JNA .NoMatch:
LEA RDI,[RBX+FILE64.Name+RAX]
MOV RDX,RDI
REP MOVSB
MOV RSI,RDX ; Pointer to resolved file name without path.
MOV RAX,[RSP+17*8+%FileEachBufSize+%FileEachMaskSize] ; ^CallbackProc.
CALL RAX ; Perform the callback.
MOV [RSP+14*8+%FileEachMaskSize+%FileEachBufSize],RAX ; Pass the returned RAX.
.D9: POP RDI,RSI,RBP,RDX,RCX,RBX
RET
ENDP .DirEnt:
.End: LinABI close,RDI, Fastmode=On
ADD RSP,%FileEachMaskSize+%FileEachBufSize
POP R11,R9,RDI,RSI,RDX,RCX,RBX,RAX
RET 2*8
ENDPROC1 FileEach@RT:
%ENDMACRO FileEach
FileLoad %MACRO theFile
PUSHQ %theFile
CALL FileLoad@RT::
FileLoad@RT:: PROC1
PUSH RBX,RCX,RDX,RDI,R8,R9,R10,R11
MOV RBX,[RSP+9*8] ; ^theFile.
FileOpen RBX ; Returns CF=0,RAX=file size.
JC .80:
MOV [RBX+FILE64.BufSize],RAX
TEST RAX ; Zero-sized files are not supported.
JZ .80:
MOV RSI,RAX
LinABI mmap,0,RSI,PROT_READ+PROT_WRITE,MAP_PRIVATE+MAP_ANONYMOUS,-1,0,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .80:
MOV [RBX+FILE64.BufPtr],RAX
MOV [RBX+FILE64.Ptr],RAX
ADD [RBX+FILE64.Top],RAX
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV RSI,RAX
LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
.80: PUSHFQ ; Save CF.
PUSH RAX
LinABI close,[RBX+FILE64.Handle]
RstSt [RBX+FILE64.Status],fi64StCreated+fi64StOpened
POP RAX
POPFQ ; Restore CF.
POP R11,R10,R9,R8,RDI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileLoad@RT::
%ENDMACRO FileLoad
FileStore %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileStore@RT::
FileStore@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; ^theFile.
FileCreate RBX
JC .90:
MOV RSI,[RSP+8*8] ; DataPtr.
MOV RDX,[RSP+9*8] ; DataSize.
LinABI write,[RBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
MOV [RBX+FILE64.Size],RAX
ADD [RBX+FILE64.Pos],RAX
FileClose RBX
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 3*8
ENDPROC1 FileStore@RT::
%ENDMACRO FileStore
FileReset %MACRO theFile, Position
%IF "%Position" === ""
PUSHQ 0
%ELSE
PUSHQ %Position
%ENDIF
PUSHQ %theFile
CALL FileReset@RT::
FileReset@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
MOV RSI,[RSP+8*8] ; Position.
MOV RAX,-EBADF ; Error code "file is not opened".
JNSt [RBX+FILE64.Status],fi64StOpened,.90:
LinABI lseek,[RBX+FILE64.Handle],RSI,SEEK_SET,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
MOV [RBX+FILE64.Pos],RAX
MOV RSI,[RBX+FILE64.BufPtr]
ADD RSI,RAX
MOV [RBX+FILE64.Ptr],RSI
JSt [RBX+FILE64.Status],fi64StMapOpened,.90:
MOV [RBX+FILE64.Top],RSI
.90: POP R11,RDI,RSI,RDX,RCX,RBX
RET 2*8
ENDPROC1 FileReset@RT::
%ENDMACRO FileReset
FileRead %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileRead@RT::
FileRead@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
MOV RAX, -EBADFD ; Error code: file is not open.
TEST [RBX+FILE64.Status],fi64StOpened
STC
JZ .90:
MOV RSI,[RSP+8*8] ; DataPtr.
MOV RDX,[RSP+9*8] ; DataSize.
LinABI read,[EBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
ADD [RBX+FILE64.Pos],RAX
TEST RAX ; Check ZF=EOF.
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 3*8
ENDPROC1 FileRead@RT::
%ENDMACRO FileRead
FileWriteRT %MACRO theFile, DataPtr1, DataSize1,,, ; Common runtime procedure declaration for macros FileWrite*
%IF %# & 1 = 0
%ERROR ID=5946, 'Macro FileWrite expects odd number of arguments.'
%EXITMACRO FileWriteRT
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile,RSP
ADDQ [RSP],(%#+1)*8
CALL FileWrite@RT::
POP RSP
FileWrite@RT::PROC1
PUSH RBX,RCX,RDX,RBP,RSI,RDI,R11
MOV RBX,[RSP+9*8] ; theFile.
MOV RAX,-EBADFD ; File was not opened.
TESTD [RBX+FILE64.Status],fi64StCreated
STC
JZ .90:
PUSHQ 0 ; Returned RAX will accumulate written size.
LEA RBP,[RSP+11*8] ; Pointer to the first DataPtr.
.20: XCHG RBP,RSI
LODSQ ; DataPtr.
MOV RBP,RAX
TEST RAX ; Test if it's the end of pointers.
JZ .80:
LODSQ ; DataSize.
XCHG RSI,RBP
MOV RDX,RAX
INC RAX
JNZ .30:
MOV RCX,RDX ; DataSize=-1, let's find the actual size.
MOV RDI,RSI
REPNE SCASB
SUB RDI,RSI
LEA RDX,[RDI-1]
.30: LinABI write,[RBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
CMP RAX,-ERR_MAX
JC .40: ; Jump when no error.
STC
LEA RSP,[RSP+2*8] ; Keep CF and RAX=error code.
JMP .90:
.40: ADD [RBX+FILE64.Size],RAX
ADD [RBX+FILE64.Pos],RAX
ADD [RSP+0*8],RAX ; Accumulate total written size.
JMP .20:
.80: POP RAX
.90:POP R11,RDI,RSI,RBP,RDX,RCX,RBX
RET
ENDP1 FileWrite@RT
%ENDMACRO FileWriteRT
FileWrite %MACRO theFile,DataPtr,DataSize,,,,
FileWriteRT %*
%ENDMACRO FileWrite
FileWriteLn %MACRO theFile,DataPtr,DataSize,,,
FileWrite %*, =B 0x0A, 1
%ENDMACRO FileWriteLn
FileWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
%ArgList %SET %theFile
ArgNr %FOR 2..%#
%ArgList %SET %ArgList,%*{%ArgNr},-1
%ENDFOR ArgNr
FileWriteRT %ArgList
%ENDMACRO FileWrite$
FileEnclose %MACRO theFile,DataPtr,DataSize,,,,
FileAppend %theFile
JC FileEnclose%.Abort:
FileWrite %*
JC FileEnclose%.Abort:
FileClose %theFile
FileEnclose%.Abort:
%ENDMACRO FileEnclose
FileEncloseLn %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
FileAppend %theFile
JC FileEncloseLn%.Abort:
FileWriteLn %*
JC FileEncloseLn%.Abort:
FileClose %theFile
FileEncloseLn%.Abort:
%ENDMACRO FileEncloseLn
FileEnclose$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
FileAppend %theFile
JC FileEnclose$%.Abort:
FileWrite$ %*
JC FileEnclose$%.Abort:
FileClose %theFile
FileEnclose$%.Abort:
%ENDMACRO FileEnclose$
FileMapOpen %MACRO theFile
PUSHQ %theFile
CALL FileMapOpen@RT::
FileMapOpen@RT:: PROC1
PUSH RBX,RCX,RDX,RDI,R8,R9,R10,R11
MOV RBX,[RSP+9*8] ; theFile.
XOR ESI,ESI
FileOpen RBX
JC .End:
TEST EAX
JZ .End: ; If the file has size=0.
LinABI mmap,0,RAX,PROT_READ+PROT_EXEC,MAP_SHARED,[RBX+FILE64.Handle],0,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .End:
MOV RSI,RAX
MOV [RBX+FILE64.Ptr],RAX
MOV [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.BufPtr],RAX
MOV [RBX+FILE64.MapHandle],RAX
MOV RAX,[RBX+FILE64.Size]
MOV [RBX+FILE64.BufSize],RAX
ADD [RBX+FILE64.Top],RAX
SetSt [RBX+FILE64.Status],fi64StMapped+fi64StMapOpened
DEC EBX ; Set ZF=0.
.End:POP R11,R10,R9,R8,RDI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileMapOpen@RT::
%ENDMACRO FileMapOpen
FileMapCreate %MACRO theFile,FileSize
%IF %# > 1
PUSHQ %FileSize
%ELSE
PUSHQ 0
%ENDIF
PUSHQ %theFile
CALL FileMapCreate@RT::
FileMapCreate@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,R8,R9,R10,R11
MOV RBX,[RSP+9*8] ; theFile.
FileAppend RBX
JC .90:
MOV RSI,RAX ; Current file size.
MOV RCX,[RSP+10*8] ; Requested FileSize.
JRCXZ .10:
MOV RSI,RCX
.10: LinABI ftruncate,[RBX+FILE64.Handle],RSI,Fastmode=Yes
TEST EAX
STC
JNZ .90:
LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_SHARED,[RBX+FILE64.Handle],RAX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
SetSt [RBX+FILE64.Status],fi64StMapCreated+fi64StMapped+fi64StAllocated+fi64StCreated
MOV RDI,RAX
MOV [RBX+FILE64.Size],RSI
MOV [RBX+FILE64.MapHandle],RAX
MOV [RBX+FILE64.BufPtr],RAX
ADD RAX,RSI
MOV [RBX+FILE64.Ptr],RAX
MOV [RBX+FILE64.Top],RAX
XCHG RAX,RSI
.90: POP R11,R10,R9,R8,RSI,RDX,RCX,RBX
RET 2*8
ENDPROC1 FileMapCreate@RT::
%ENDMACRO FileMapCreate
FileStreamOpen %MACRO theFile,BufSize=16K
PUSHQ %BufSize,%theFile
CALL FileStreamOpen@RT::
FileStreamOpen@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
MOV RBX,[RSP+10*8] ; theFile.
FileOpen RBX
JC .90:
MOV RSI,[RSP+11*8] ; BufSize.
MOV [RBX+FILE64.BufSize],RSI
XOR EDI,EDI
LinABI mmap,RDI,RSI,PROT_READ+PROT_WRITE,MAP_PRIVATE+MAP_ANONYMOUS,-1,RDI,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV [RBX+FILE64.MapHandle],RAX
MOV [RBX+FILE64.BufPtr],RAX
MOV [RBX+FILE64.Ptr],RAX
MOV [RBX+FILE64.Top],RAX
MOV RAX,[RBX+FILE64.Size]
.90: POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
RET 2*8
ENDPROC1 FileStreamOpen@RT::
%ENDMACRO FileStreamOpen
FileStreamRead %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileStreamRead@RT::
FileStreamRead@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
SUB EDX,EDX
MOV RBX,[RSP+7*8] ; theFile.
MOV RAX,-EBADFD ; Error: file is not open.
TESTD [RBX+FILE64.Status],fi64StOpened
STC
JZ .90:
TESTD [RBX+FILE64.Status],fi64StAllocated
STC
JZ .90:
MOV RDI,[RSP+8*8] ; DataPtr.
.10: MOV RSI,[RBX+FILE64.Ptr]
.20: MOV RCX,[RBX+FILE64.Top]
SUB RCX,RSI ; How many bytes is left in buffer.
JNA .50:
CMP RCX,[RSP+9*8] ; Is it enough for the requested DataSize?
JA .60:
SUB [RSP+9*8],RCX
ADD RDX,RCX
REP MOVSB
MOV [RBX+FILE64.Ptr],RSI
JMP .20:
.50: MOV RSI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
ADD [RBX+FILE64.Top],RAX
JMP .20:
.60: MOV RCX,[RSP+9*8] ; DataSize.
ADD RDX,RCX
REP MOVSB
MOV [RBX+FILE64.Ptr],RSI
.70: MOV RAX,RDX
ADD [RBX+FILE64.Pos],RDX
TEST RAX
.90: POP R11,RDI,RSI,RDX,RCX,RBX
RET 3*8
ENDPROC1 FileStreamRead@RT::
%ENDMACRO FileStreamRead
FileStreamReadLn %MACRO theFile
PUSHQ %theFile
CALL FileStreamReadLn@RT::
FileStreamReadLn@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R11
MOV RBX,[RSP+7*8] ; theFile.
MOV RAX,-EBADFD ; Error: file is not open.
TESTD [RBX+FILE64.Status],fi64StOpened
STC
JZ .90:
TESTD [RBX+FILE64.Status],fi64StAllocated
STC
JZ .90:
.10: MOV RDI,[RBX+FILE64.Ptr]
MOV RCX,[RBX+FILE64.Top]
MOV [RSP+2*8],RDI ; Returned ESI.
MOV RDX,RDI
SUB RCX,RDI
JNA .30:
MOV AL,10 ; Search for LineFeed.
REPNE SCASB
JE .50:
CMP RDX,[RBX+FILE64.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 RCX,RDX
SUB RCX,RDI
LinABI lseek,[RBX+FILE64.Handle],RCX,SEEK_CUR,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
.30: MOV RSI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
TEST RAX
JZ .90: ; End of file.
ADD RAX,RSI
MOV [RBX+FILE64.Top],RAX
JMP .10:
.50: MOV [RBX+FILE64.Ptr],RDI
MOV RAX,RDI
SUB RAX,RDX
ADD [RBX+FILE64.Pos],RAX
.90:POP R11,RDI,RSI,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileStreamReadLn@RT::
%ENDMACRO FileStreamReadLn
FileStreamReadByte %MACRO theFile
PUSHQ %theFile
CALL FileStreamReadByte@RT::
FileStreamReadByte@RT:: PROC1
PUSH RBX,RCX,RDX,RBP,RSI,RDI,R11
MOV RBX,[RSP+8*8] ; theFile.
.10: MOV RSI,[RBX+FILE64.Ptr]
CMP RSI,[RBX+FILE64.Top]
JB .50:
MOV RSI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
MOV RBP,RAX
LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
ADD [RBX+FILE64.Top],RAX
TEST RAX
MOV RAX,RBP
JZ .90:
JMP .10: ; This time it will not fail.
.50: LODSB
MOV [RBX+FILE64.Ptr],RSI
INCQ [RBX+FILE64.Pos]
CLC
.90: POP R11,RDI,RSI,RBP,RDX,RCX,RBX
RET 1*8
ENDPROC1 FileStreamReadByte@RT::
%ENDMACRO FileStreamReadByte
FileStreamCreate %MACRO theFile,BufSize=16K
PUSHQ %BufSize,%theFile
CALL FileStreamCreate@RT::
FileStreamCreate@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
MOV RBX,[RSP+10*8] ; theFile.
RstSt [RBX+FILE64.Status],fi64StAppend
FileCreate RBX
JC .90:
MOV RSI,[RSP+11*8] ; BufSize.
XOR EAX,EAX
LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_PRIVATE+MAP_ANONYMOUS,-1,RAX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
MOV [RBX+FILE64.BufSize],RSI
MOV [RBX+FILE64.BufPtr],RAX
MOV [RBX+FILE64.Ptr],RAX
ADD RAX,RSI
MOV [RBX+FILE64.Top],RAX
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV RAX,[RBX+FILE64.Size]
.90:POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
RET 2*8
ENDPROC1 FileStreamCreate@RT::
%ENDMACRO FileStreamCreate
FileStreamAppend %MACRO theFile,BufSize=16K
PUSHQ %BufSize,%theFile
CALL FileStreamAppend@RT::
FileStreamAppend@RT:: PROC1
PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
MOV RBX,[RSP+10*8] ; theFile.
SetSt [RBX+FILE64.Status],fi64StAppend
FileCreate RBX
JC .90:
MOV RSI,[RSP+11*8] ; BufSize.
XOR EAX,EAX
LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_PRIVATE+MAP_ANONYMOUS,-1,RAX,Fastmode=Yes
CMP RAX,-ERR_MAX
CMC
JC .90:
MOV [RBX+FILE64.BufSize],RSI
MOV [RBX+FILE64.BufPtr],RAX
MOV [RBX+FILE64.Ptr],RAX
ADD RAX,RSI
MOV [RBX+FILE64.Top],RAX
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV RAX,[RBX+FILE64.Size]
.90:POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
RET 2*8
ENDPROC1 FileStreamAppend@RT::
%ENDMACRO FileStreamAppend
FileStreamWriteByte %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteByte@RT::
FileStreamWriteByte@RT:: PROC1
PUSH RAX,RBX,RDI
MOV RBX,[RSP+4*8] ; theFile.
.10: MOV RDI,[RBX+FILE64.Ptr]
CMP RDI,[RBX+FILE64.Top]
JB .50
FileFlush RBX ; Write the buffer if it is full.
JNC .10:
MOV [RSP+2*8],RAX ; Returned RAX on error.
JMP .90:
.50: STOSB
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
INC RAX
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90: POP RDI,RBX,RAX
RET 1*8
ENDPROC1 FileStreamWriteByte@RT::
%ENDMACRO FileStreamWriteByte
FileStreamWriteWord %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteWord@RT::
FileStreamWriteWord@RT:: PROC1
PUSH RAX,RBX,RCX,RDI
MOV RBX,[RSP+5*8] ; theFile.
.10: MOV RDI,[RBX+FILE64.Ptr]
LEA RCX,[RDI+1]
CMP RCX,[RBX+FILE64.Top]
JB .50:
FileFlush RBX ; Write the buffer if it is full.
JNC .10:
MOV [RSP+3*8],RAX ; Returned RAX on error.
JMP .90:
.50: STOSW
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
ADD EAX,2
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90: POP RDI,RCX,RBX,RAX
RET 1*8
ENDPROC1 FileStreamWriteWord@RT::
%ENDMACRO FileStreamWriteWord
FileStreamWriteDword %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteDword@RT::
FileStreamWriteDword@RT:: PROC1
PUSH RAX,RBX,RCX,RDI
MOV RBX,[RSP+5*8] ; the File.
.10: MOV RDI,[RBX+FILE64.Ptr]
LEA RCX,[RDI+3]
CMP RCX,[RBX+FILE64.Top]
JB .50
FileFlush RBX ; Write the buffer if it is full.
JNC .10:
MOV [RSP+3*8],RAX ; Returned RAX on error.
JMP .90:
.50: STOSD
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
ADD EAX,4
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90: POP RDI,RCX,RBX,RAX
RET 1*8
ENDPROC1 FileStreamWriteDword@RT::
%ENDMACRO FileStreamWriteDword
FileStreamWriteRT %MACRO ; Common runtime procedure for macros FileStreamWrite*
%IF %# & 1 = 0
%ERROR ID=5946, 'Macro FileStreamWrite expects odd number of arguments.'
%EXITMACRO FileStreamWriteRT
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile,RSP
ADDQ [RSP],(%#+1)*8
CALL FileStreamWrite@RT::
POP RSP
FileStreamWrite@RT::PROC1
PUSH RBX,RCX,RDX,RBP,RSI,RDI
MOV RBX,[RSP+8*8] ; theFile.
MOV RAX,-EBADFD ; File was not opened.
TESTD [RBX+FILE64.Status],fi64StCreated
STC
JZ .90:
TESTD [RBX+FILE64.Status],fi64StAllocated
STC
JZ .90:
PUSHQ 0 ; Returned RAX will accumulate written size.
LEA RBP,[RSP+10*8] ; Pointer to the first DataPtr.
.20: XCHG RBP,RSI
LODSQ ; DataPtr.
MOV RBP,RAX
TEST RAX ; Test if it's the end of pointers.
JZ .80:
LODSQ ; DataSize.
XCHG RSI,RBP
MOV RDX,RAX
INC RAX
JNZ .30:
MOV RCX,RDX ; DataSize=-1, let's find the actual size.
MOV RDI,RSI
REPNE SCASB
SUB RDI,RSI
LEA RDX,[RDI-1]
.30: MOV RDI,[RBX+FILE64.Ptr] ; RDX is DataSize.
MOV RCX,[RBX+FILE64.Top]
SUB RCX,RDI
JA .40:
FileFlush RBX
JNC .30:
LEA RSP,[RSP+1*8] ; Keep CF and RAX=error code.
JMP .90:
.40: SUB RDX,RCX
JAE .50:
ADD RCX,RDX
.50: ADD [RBX+FILE64.Pos],RCX
ADD [RBX+FILE64.Size],RCX
ADD [RSP+0*8],RCX ; Accumulate total written size.
REP MOVSB
MOV [RBX+FILE64.Ptr],RDI
CMP RDX,RCX
JG .30
JMP .20:
.80: POP RAX
.90:POP RDI,RSI,RBP,RDX,RCX,RBX
RET
ENDP1 FileStreamWrite@RT::
%ENDMACRO FileStreamWriteRT
FileStreamWrite %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
FileStreamWriteRT %*
%ENDMACRO FileStreamWrite
FileStreamWriteLn %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
FileStreamWriteRT %*, =B 0x0A, 1
%ENDMACRO FileStreamWriteLn
FileStreamWrite$ %MACRO theFile,DataPtr$1,DataPtr$2,DataPtr$3,,,
%ArgList %SET %theFile
ArgNr %FOR 2..%#
%ArgList %SET %ArgList,%*{%ArgNr},-1
%ENDFOR ArgNr
FileStreamWriteRT %ArgList
%ENDMACRO FileStreamWrite$
ENDHEAD linf64