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, 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 EBP,ESP MOV EDI,[%Param1] ; %theFile. SUB ESP,SIZE# STAT64 MOV ECX,ESP ; STAT32 or STAT64 LEA EBX,[EDI+FILE.Name] LinAPI stat,EBX,ECX,Fastmode=Yes ; Try old 32bit fstat first. MOV EDX,[ECX+STAT32.st_size] TEST EAX JZ .90: CMP EAX,-EOVERFLOW JNE .80: ; 32bit application is run on 64bit Linux, it may fail due to kernel mess when inode number exceeds 4G. MOV ECX,EBX ; ^FILE.Name. MOV EDX,ESP ; ^STAT64. XOR ESI,ESI ; flags. MOV EBX,AT_FDCWD ; Obey the current directory for relative path. LinAPI fstatat64,EBX,ECX,EDX,ESI,Fastmode=Yes MOV EDX,[EDX+STAT64.st_size] TEST EAX JZ .90: .80:MOV EDX,EAX STC .90:MOV [%ReturnEAX],EDX MOV ESP,EBP POPAD RET 1*4 ENDPROC1 FileGetSize@RT:: %ENDMACRO FileGetSize
FileOpen %MACRO theFile PUSHD %theFile CALL FileOpen@RT:: FileOpen@RT:: PROC1 PUSHAD MOV EDI,[ESP+36] ; 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+28],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: LEA ECX,[EDI+FILE.NameOffs] SUB ECX,EDI SHR ECX,2 XOR EAX,EAX REP STOSD ; Clear the FILE object except for Name and Offs. 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 theFile, CallbackProc PUSHD %CallbackProc, %theFile CALL FileEach@RT:: FileEach@RT:: PROC1 %FileEachBufSize %SETA 40 ; 512 ; Local buffer for DIRENT records. PUSHAD MOV EBP,ESP MOV ECX,(SIZE# FILE.Name + 3) & ~3 SUB ESP,ECX %FileEachMask$ %SET EBP-(SIZE#FILE.Name+3&~3) MOV EBX,[%Param1] ; theFile. SUB EAX,EAX MOV [%ReturnEAX],EAX ADD EAX,[EBX+FILE.NameOffs] ; ZF indicates the absence of path. LEA ESI,[EAX+EBX+FILE.Name] MOV EDI,ESP REP MOVSB ; Copy the ASCIIZ mask without path to LocalVar %FileEachMask$. JNZ .10: ; Test if FILE.NameOffs=0. ; The mask was specified without path, e.g.doc*.txt. ; Default path . will be injected to FILE.Name, e.g../doc*.txt. MOV ECX,SIZE#FILE.Name-2 LEA ESI,[ECX+EBX+FILE.Name-1] LEA EDI,[ESI+2] STD REP MOVSB CLD DEC EDI MOVW [EDI],'./' MOVB [EDI+SIZE#FILE.Name-1],0 FileNameParse EDI SUB EAX,EDI SUB ECX,EDI MOV [EBX+FILE.NameOffs],EAX MOV [EBX+FILE.ExtOffs],ECX .10: LEA EDI,[EBX+FILE.Name] ; EAX=FILE.NameOffs. MOVB [EDI+EAX-1],0 ; Temporary replace / with NULL. LinAPI open,EDI,O_RDONLY+O_DIRECTORY+O_NOATIME,0,Fastmode=Yes MOV EBX,[%Param1] ; Restore theFile. MOV EDX,[EBX+FILE.NameOffs] MOVB [EDI+EDX-1],'/' ; Replace temporary NULL back with slash in the mask name. MOV ECX,%FileEachBufSize SUB ESP,ECX ; LocalVar for DIRENT records. %FileEachBuf %SET %FileEachMask$-%FileEachBufSize PUSH EAX ; LocalVar for fd (directory file descriptor). CMP EAX,-ERR_MAX JNC .Abort: MOV EBX,EAX ; fd. .20: LEA ESI,[%FileEachBuf] LinAPI getdents,EBX,ESI,%FileEachBufSize,Fastmode=Yes TEST EAX JZ .Abort: ; No more dir entries. CMP EAX,-ERR_MAX JNC .Abort: LEA EDX,[ESI+EAX] ; End of DIRENT records in %FileEachBuf. .30: CMP ESI,EDX JNB .20: CALL .DirEnt: ; Process the DIRENT record ESI. JC .Abort: MOVZX EAX,[ESI+DIRENT.d_reclen] ADD ESI,EAX JMP .30: .DirEnt:PROC1 ; If the resolved name [ESI+DIRENT.d_name] complies with %FileEachMask$, ; update FILE.Name [%Param1] with the DIRENT.d_name and then callback [%Param2]. PUSHAD LEA EDI,[ESI+DIRENT.d_name] MOVZX ECX,[ESI+DIRENT.d_reclen] MOV ESI,EDI SUB ECX,DIRENT.d_name XOR EAX,EAX REPNE SCASB DEC EDI MOV ECX,EDI ; ECX=Pointer to the end of DIRENT.d_name ( NUL). MOV EDI,ESI ; EDI..ECX is a filename in DIRENT. LEA ESI,[%FileEachMask$] LEA EDX,[ESI+SIZE#FILE.Name] XOR EBX,EBX .40: CMP ESI,EDX ; Test on end-of-mask. JNB .80: LODSB ; Byte from the mask. MOV AH,[EDI] ; Byte from dir entry. INC EDI Dispatch AL,0x00, 0x3F, 0x2A ; Wildcards NUL, '?', '*' CMP AL,AH ; Ordinary character/byte. JE .40: CLC JMP .90: ; Mask does not comply. .0x00: CMP AH,0 JE .80: JMP .90: ; Mask does not comply. .0x3F: CMP AH,0 ; Question mark in mask complies with one not-nul UTF8 character. JE .90: NOT EAX ; Invert bits in UTF8 AH. BSR BX,AX ; Scan AH. SUB EBX,15 JZ .40: INC EBX SUB EDI,EBX ; Advance EDI by the size of UTF8 character - 1. JMP .40: .0x2A: ; Asterix '*' in mask complies with zero or more UTF8 characters. LODSB ; The mask character/byte following '*'. CMP AL,0 JE .80: CMP AL,'?' JE .0x2A: CMP AL,'*' JE .0x2A: DEC EDI PUSH ECX ; Temporary save the end of name in dir entry. SUB ECX,EDI REPNE SCASB ; Search for the character which follows '*'. POP ECX CLC JNE .90: JMP .40: .80: ; Mask complies. MOV ESI,[ESP+04] ; Restore ^DIRENT. MOV EBX,[%Param1] ; Restore theFile. MOV EAX,[EBX+FILE.NameOffs] LEA ECX,[EBX+FILE.Name+SIZE#FILE.Name] LEA EDI,[EAX+EBX+FILE.Name] ADD ESI,DIRENT.d_name SUB ECX,EDI PUSH EDI REP MOVSB POP ESI MOV EAX,[%Param2] ; CallbackProc. PUSH EBP MOV EBP,[%ReturnEBP] ; Parent's stack frame. CALL EAX ; Perform the callback. POP EBP MOV [%ReturnEAX],EAX ; Value returned from callback. .90: POPAD RET ENDPROC1 .DirEnt: .Abort:POP EBX LinAPI close,EBX, Fastmode=On MOV ESP,EBP POPAD RET 2*4 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+36] ; theFile. FileOpen EDI .Err:MOV [ESP+28],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 ADD EAX,[EDI+FILE.Size] MOV [EDI+FILE.Top],EAX SetSt [EDI+FILE.Status],fileStMapped+fileStMapOpened .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