| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# linf32.htm
Class
FILE
Encoding
FileStatusEnc
Macros
FileAppend
FileAssign
FileClose
FileCreate
FileDelete
FileEach
FileEnclose
FileEnclose$
FileEncloseLn
FileExists?
FileFlush
FileGetSize
FileLoad
FileMapCreate
FileMapOpen
FileMkDir
FileMove
FileNameParse
FileOpen
FileRead
FileReset
FileStore
FileStreamAppend
FileStreamCreate
FileStreamOpen
FileStreamRead
FileStreamReadByte
FileStreamReadLn
FileStreamWrite
FileStreamWriteByte
FileStreamWriteWord
FileStreamWriteDword
FileStreamWrite$
FileStreamWriteLn
FileWrite
FileWrite$
FileWriteLn

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:

[.bss] InpFile DS FILE OutFile DS FILE Record: DB 512 * BYTE [.text] FileAssign InpFile, ="Input.dat" FileAssign OutFile, ="Output.dat" FileOpen InpFile JC .InpErr: FileCreate OutFile JC .OutErr: .Next: FileRead InpFile, Record, SIZE# Record JC .InpErr: JZ .EOF: CALL ModifyRecord FileWrite OutFile, Record, SIZE# Record JC .OutErr: JMP .Next: .InpErr: StdOutput ="Error reading ",InpFile.Name JMP .EOF: .OutErr: StdOutput ="Error writing ",OutFile.Name .EOF: FileClose OutFile, InpFile TerminateProgram

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:

FileAssign InpFile, ="Input.txt" FileAssign OutFile, ="Output.txt" FileStreamOpen InpFile JC .Error: FileStreamCreate OutFile JC .Error: .Next:FileStreamReadLn InpFile JC .Error: JZ .EOF: MOV ECX,EAX ; EAX=Line size, ESI=pointer to the line in buffer. MOV EDI,WorkLine REP MOVSB CALL ModifyWorkLine FileStreamWrite OutFile, WorkLine, EAX JC .Error: JMP .Next: .EOF: FileClose OutFile, InpFile

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
  structure keeps information about the file status. Variable with FILE structure should be defined for each file used in program, either statically (in .data segment) or cleared when defined on stack or .bss. Pointer to a FILE structured variable is passed as the first parameter to all macros in this library.

    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

FileStatusEnc
  Definition of flags which describe `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 FileNamePtr, Size= -1, Unicode=%^UNICODE
  FileNameParse will analyze string with complete FileName, which may contain path, name, extension. It returns pointers to the name without path and to the file extension.
  Name starts behind the last slash `/`, backslash `\` or colon`:`. If no such characters exists, the whole input string is the name.
  File extension starts at the last point `.` in the name. If there is no point in name, the extension is empty.
Input
  FileNamePtr is pointer to a string of characters.
  Size=-1 is the size of input string in bytes. By default it is unlimited and the string must be zero terminated in this case.
  Unicode=%^UNICODE is ignored.
Output
  EAX is pointer to the start of the name without path.
  ECX is pointer to the start of extension.
  EDX points behind the last FileName character.
  Path starts at %FileNamePtr, size=EAX - OFFSET#FileNamePtr
  Name starts at EAX, size=ECX - EAX
  Extension starts at ECX, size=EDX - ECX
Error
  -
Examples
  %FileNamePtr │ │ │ │ "D:\path.ext\nam.part1.txt" "\plain" "./.profile" "name" │ │ │ │ │ │ │ │ │ EAX │ │ EAX │ EAX │ EAX │ ECX │ ECX ECX │ ECX EDX EDX EDX EDX

    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

FileAssign theFile, Name$1, Name$2,,,Size=-1, Unicode=%^UNICODE
  Macro FileAssign associates file name with the FILE data object. Name of the file is copied to `theFile.Name` member.
  The file must be assigned with file name before it is created or opened. FileAssign can concatenate the filename from several input strings, e.g. path, name, extension.
Input
  theFile is pointer to a FILE structured memory variable.
  Name$* is pointer to a zero terminated string with the file name or its part. It needs not be zero terminated when Size= is expicitly specified. Filename will be concatenated when more than one string is provided.
  Name$1 may also be 0 or pointer to an empty string. The file is then assigned to standard input or output.
  Device name may be assigned instead of a disk file.
  Size= applies to all input strings. Size is unlimited by default and the strings must be zero terminated in this case.
  Unicode=%^UNICODE is ignored in Linux
Output
  Members of theFile `.Name, .NameOffs, .ExtOffs, .Status:fileStUnicode` of `theFile` are set.
Error
  CF=1 if the concatenated name length exceeds `SIZE# FILE.Name`, i.e. NAME_MAX=260 characters.
Depends on
  FileNameParse
Examples
  File1 DS FILE Path$ DB "C:\Text\",0 Name$ DB "Some",0 Ext$ DB ".txt",0 [.text] FileAssign File1,Path$,Name$,Ext$ FileAssign File1,0 ; Standard output, by default redirected to console. FileAssign File1,="/dev/prn" ; Output to a line printer.

    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

FileExists? theFile
  will test if the given file with assigned name exists on disk. File may be opened or closed. Wildcard characters `* ?` are allowed in the file name.
  This macro can test the presence of a directory, too.
Input
  theFile is pointer to FILE object which was assigned with the name of file or directory.
Output
  CF=1 if the file | directory does not exist.
  CF=0 ZF=1 if the file exists.
  CF=0 ZF=0 if the directory exists.
Example
  FileExists? =".\Config.ini" JC ErrorIniNotFound

    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 theFile
  will parse the file name and create all directories in its path if they didn't exist.
  The last portion of assigned name is treated as directory only if
  it is terminated with slash.
Input
  theFile is pointer to FILE object with assigned name.
Output
  CF=0
  EAX=0 if the directory was created or if it existed before.
Error
  CF=1
  EAX=last error if CreateDirectory failed.
Example
  FileAssign SomeFile, ="/var/lib/mydir/file.txt" FileMkDir SomeFile ; will create folders /var/lib/ and /var/lib/mydir/. FileAssign SomeFile, ="/var/lib/mydir/file.txt/" FileMkDir SomeFile ; will create folders /var/lib/, /var/lib/mydir/, /var/lib/mydir/file.txt/.

    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 theFile
  is a service macro used internally in FileOpen, FileCreate, FileMap* to get the size of opened/closed file.
  Then it may be obtained faster as FILE.Size.
Input
  theFile is pointer to an assigned FILE object.
Output
  CF=0
  EAX= file size in bytes.
Error
  CF=1
  EAX= error code.

    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 theFile
  opens the assigned file for reading.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  EAX= file size.
Error
  CF=1
  EAX= is errorCode.

    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 theFile
  is a service macro used internally in FileClose, FileStreamWrite* to write the contents of file buffer on disk. There is no reason to invoke this macro explicitly by the programmer.
Output
  CF=0
  EAX= number of flushed bytes.
Error
  CF=1
  EAX= errorCode or EAX=0 (file not created for write).

    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 theFile1, theFile2,,,
  Macro FileClose will flush and deallocate the buffer, close file mapping, close the file, clear pointers in the FILE structure.
  FileClose does not clear the name assignment, so the closed file may be reopen with the same name without invoking FileAssign again.
Input
  theFile is pointer to a FILE object. More than one file may be specified simultaneously.
Output
  -
Error
  -
Depends on
  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 SourceFile, DestinationFile
  FileMove renames directory on the same volume or moves the source file to the destination. Files will be closed first, if necessarry. The destination file will be erased if it existed before.
  Directories in the destination file name will be maked, if necessarry. Both files must have been assigned.
Input
  SourceFile and DestinationFile are pointers to assigned FILE objects.
Output
  CF=0
  EAX=0
Error
  CF=1
  EAX= error.
Depends on
  FileClose, FileMkDir

    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 theFile1, theFile2,,,
  will close and erase the disk file(s).
  FileDelete does not clear the name assignment, so the deleted file may be reopen with the same name without invoking FileAssign again.
Input
  theFile* is pointer to a FILEobject. More than one file may be specified simultaneously.
Output
  CF=0,
  EAX=0 if the last file was succesfully deleted.
Error
  CF=1
  EAX= error.
Depends on
  FileClose

    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

FileEach MaskFile, CallbackProc
  Macro FileEach expects the file object assigned with file name which may have wildcard characters `*` and `?`. FileEach will resolve the mask and performs callback procedure with each such filename. If no file matches the mask, CallbackProc is never called.
Input
  MaskFile is a pointer to FILE object which must have assigned the requested file path and (optionally) file name mask.
  CallbackProc is the address of a callback procedure.
Output
  EAX=content of EAX at the last CallbackProc exit, or 0 if the CallbackProc was never called.
CallbackProc
  is called with register calling convention. CallbackProc should return CF=0 to let FileEach continue with the next file, otherwise FileEach stops searching.
  CallbackProc input registers:
    EBX=%theFile where the mask in `FILE.Name` is replaced with the resolved file name found in directory. The file is not open.
    ESI=pointer to the file name without path without wildcards inside the [EBX+FILE.Name].
    EBP=EBP at FileEach macro entry. This allows to access local stack variables of the procedure which invoked FileEach.
    Other registers are undefined at CallbackProc entry.
  CallbackProc output registers:
    EAX is passed through. FileEach returns EAX value from the last called CallbackProc, or 0 if it was never called.
    CF=0 to continue with the next file
    CF=1 to break further searching.
    CallbackProc may destroy any GP register.
Depends on
  FileNameParse
Example
  MyFile DS FILE FileAssign MyFile,="/var/lib/t??_*.txt" FileEach MyFile, ListFile TerminateProgram ListFile PROC StdOutput ESI,Eol=Yes RET ENDP ListFile

    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 theFile
  will allocate memory buffer from OS, open the file, read entire file content to a block of memory allocated by FileLoad and then close the file.
  Although the file handle is closed immediately, you should always use FileClose to free allocated buffer when the file content is no longer needed.
Input
  theFile is pointer to an assigned existing FILE object.
Output
  CF=0
  EAX= file size,
  ESI= pointer to the file contents in allocated memory.
Error
  CF=1
  EAX= errorCode.
  ESI= is undefined.
Depends on
  FileOpen

    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 theFile, DataPtr, DataSize
  Macro FileStore will open the file, write data and close the file.
Input
  theFile is pointer to an assigned unopened FILE object,
  DataPtr is pointer to the data to be written,
  DataSize is size of the data in bytes, i.e. future file size.
Output
  CF=0
  EAX= is the data size of written data.
Error
  CF=1
  EAX= is error code.
Example
  FileStore File1, MyDataPtr, MyDataEnd-MyDataPtr

    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 theFile, Position
  Macro FileReset will reset internal file pointers to a new Position in the file.
Input
  theFile is pointer to a FILE object, which must have been opened with FileOpen, FileMapOpen or FileStreamOpen.
  Position specifies the number of bytes from the beginning of theFile. Zero is used if omitted.
Output
  CF=0
  EAX=Position
Error
  CF=1
  EAX= error code.

    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 theFile, DataPtr, DataSize
  reads from an opened file to the memory provided by caller.
Input
  theFile is pointer to a FILE object opened for reading.
  DataPtr is pointer where the data will be read,
  DataSize is requested number of bytes (<2GB).
Output
  CF=0
  ZF=0
  EAX= the actually read size (may be less than DataSize if the file is not large enough).
End of file
  CF=0
  ZF=1
  EAX=0 if all data have been read from the file (EOF).
Error
  CF=1
  EAX= errorCode.
Example
  FileRead InpFile,aLine,80 JC .ErrorReadingFile JZ .EOF

    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 theFile
  creates a new file or rewrites an existing file for writing.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  EAX=0 (size of just rewritten file).
Error
  CF=1
  EAX=errorCode.

    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 theFile
  Macro FileAppend creates a new file or opens an existing file for writing and sets file pointer to its end.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  EAX= file size.
Error
  CF=1
  EAX=errorCode as returned from GetLastError.
Depends on
  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
  is a runtime definition macro used internally by FileWrite, FileWriteLn, FileWrite$.

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened for writing with FileCreate or FileAppend.
  Multiple data may be written in one macro invocation.
Input
  theFile is pointer to an open FILE object,
  DataPtr* points to the data to be written,
  DataSize* is the size of data in bytes.
Output
  CF=0
  EAX=total written size in bytes.
Error
  CF=1
  EAX=errorCode.
Depends on
  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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  Macro FileWriteLn writes data to the file previously opened for writing with FileCreate or FileAppend.
  Multiple data may be written in one macro invocation. End of line LF character is written in the end.
Input
  theFile is pointer to an open FILE object,
  DataPtr* points to the data to be written,
  DataSize* is size of data in bytes.
Output
  CF=0
  EAX= is the total written size including LF.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileWriteRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes zero terminated ANSI string(s) to the file previously opened for writing with FileCreate or FileAppend.
  More than one string may be written in one macro invocation. The terminating zeros are not written to the file.
Input
  theFile is pointer to an open FILE object,
  DataPtr$* are pointers to zero terminated strings to be written.
Output
  CF=0
  EAX= total written size in bytes.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileWriteRT

    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
  is a runtime defining macro used internally by FileEnclose, FileEncloseLn, FileEnclose$.
Input stack
  ReturnEIP,ReturnESP,theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,0
Depends on
  FileCreate, FileClose.

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data at the end of existing file or creates a new one and then closes the file.
  Multiple data can be appended with one invocation.
  The file should be assigned but not open.
Input
  theFile is pointer to FILE object with assigned name,
  DataPtr is pointer to the data to be written,
  DataSize is size of the data in bytes.
Output
  CF=0
  EAX= it total written size in bytes.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileEncloseRT
Example
  FileEnclose LogFile,Datum,SIZE#Datum

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data at the end of existing file or creates a new one and then closes the file.
  More than one data item can be appended with one invocation.
  When all data have been written, it appends end-of-line character LF to the file.
  The file should be assigned but not open.
Input
  theFile is pointer to FILE object with assigned name,
  DataPtr is pointer to the data to be written,
  DataSize is size of the data in bytes.
Output
  CF=0
  EAX= it total written size in bytes, including CR+LF.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileEncloseRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes one or more zero-terminated data strings at the end of existing file or it creates a new one and then closes the file.
  The file should be assigned but not open.
  More than one string can be appended with one invocation. The terminating NULL is not written.
Input
  theFile is pointer to FILE object with assigned name,
  DataPtr$* are pointers to zero-terminated ANSI strings. Terminating zeroes are not written to the file.
Output
  CF=0
  EAX= total written size.
Error
  CF=1
  EAX= is errorCode.
Depends on
  FileEncloseRT
Example
  FileEnclose$ LogFile, Time$, =" Job started"

    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 theFile
  opens an existing regular file for reading and creates file mapping to memory.
  Content of the file will be available for reading and pointed to with ESI.
  The file cannot be assigned with device, pipe or empty name.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  EAX= file size,
  ESI= pointer to the memory-mapped file contents.
Error
  CF=1
  ESI=0
  EAX= errorCode.
Depends on
  FileOpen

    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 theFile, FileSize
  Macro FileMapCreate will create or rewrite an existing file for writing and create file mapping. Size of the file being created should be specified with FileSize.
  File content can be copied to the mapped memory returned in EDI but not more than FileSize bytes.
  The file cannot be assigned with device, pipe or empty name.
Input
  theFile is pointer to a FILE object with assigned name.
  FileSize is the size of memory mapped file. It may be omitted when FileMapCreate opens an existing file.
Output
  CF=0
  EAX=FileSize
  EDI= is pointer to the memory mapped file content.
Error
  CF=1
  EDI=0
  EAX= errorCode as returned from GetLastError.

    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 theFile, BufSize=16K
  This macro opens an existing file for reading and allocates memory buffer from OS heap. Buffer will be read from file on the FileStreamRead* request.
Input
  theFile is pointer to a FILE object with assigned name.
  BuffSize= specifies the buffer size.
Output
  CF=0
  EAX= file size.
Error
  CF=1
  EAX= errorCode
Depends on
  FileOpen

    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 theFile, DataPtr, DataSize
  reads data from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE object.
  DataPtr points to a memory area allocated by the caller,
  DataSize is amount of bytes to read.
Output
  CF=0
  ZF=0
  EAX= how many bytes was read (may be less the DataSize).
End of file
  CF=0
  ZF=1
  EAX= 0 when there are no more bytes in the file (EOF).
error
  CF=1
  EAX= errorCode.

    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 theFile
  reads one LineFeed-terminated physical line from the file opened with FileStreamOpen.
  When the size of physical line exceeds the size of buffer allocated with FileStreamOpen, returned data may not terminate with `0x0A` (LineFeed) and FileStreamReadLn should be invoked again - per partes reading.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  ZF=0
  EAX= line size (never bigger than theFILE.BufSize)
  ESI= pointer to the line in buffer.
End of file
  CF=0
  ZF=1
  EAX=0 when there are no more data in file (EOF).
  ESI= undefined
Error
  CF=1
  EAX= errorCode.
  ESI= undefined.

    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 theFile
  reads one byte from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE object.
Output
  CF=0
  ZF=0
  AL= the byte read from file. Upper 3 bytes in EAX are preserved.
End of file
  CF=0
  ZF=1
  AL=0 when there are no more bytes in the file (EOF).
Error
  CF=1
  EAX= errorCode.

    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 theFile, BufSize=16K
  This macro creates a new file or rewrites an existing file for writing and allocates memory buffer from OS heap. The buffer will be automatically written to the file whenever it is completely filled with FileStreamWrite*.
Input
  theFile is pointer to a FILE object with assigned filename.
  BuffSize= specifies the buffer size.
Output
  CF=0
  EAX=0 (size of just rewritten file).
Error
  CF=1
  EAX= errorCode.
Depends on
  FileCreate

    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 theFile, BufSize=16K
  This macro creates a new file or rewrites an existing file for writing at its end and allocates memory buffer from heap. Buffer will be written to file every time it is completely filled with FileStreamWrite*.
Input
  theFile is pointer to a FILE object,
  BuffSize= specifies the buffer size.
Output
  CF=0
  EAX= is the old file size.
Error
  CF=1
  EAX= errorCode.
Depends on
  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 theFile
  This macro writes one byte from AL to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE object,
  AL contains the data byte to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileFlush

    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 theFile
  This macro writes one word from AX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE object,
  AX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileFlush

    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 theFile
  This macro writes one doubleword from EAX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE object,
  EAX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  EAX= errorCode .
Depends on
  FileFlush

    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
  is a runtime defining macro used internally by FileStreamWrite*.
  Macro returns CF=0, EAX=total written size, or CF=error
Depends on
  FileFlush

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple data portions may be written in one macro invocation.
Input
  theFile is pointer to an open FILE object,
  DataPtr* is pointer to the data to be written,
  DataSize* is the size of the data in bytes to be written. It may be bigger than the buffer size specified on opening the file.
Output
  CF=0
  EAX= Total written size in bytes.
Error
  CF=1
  EAX= errorCode.
Depends on
  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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple data portions may be written in one macro invocation. End of line LF character is written in the end.
Input
  theFile is pointer to an open FILE object,
  DataPtr* is pointer to the data to be written,
  DataSize* is the size of the data to be written, including the LF. It may be bigger than the buffer size specified on opening the file.
Output
  CF=0
  EAX= total written size including LF.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileStreamWriteRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes zero terminated ANSI string(s) to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple strings may be written in one macro invocation. The terminating zeros are not written to the file.
Input
  theFile is pointer to an open FILE object,
  DataPtr$* are pointers to the zero terminated strings to be written.
Output
  CF=0
  EAX= total written size.
Error
  CF=1
  EAX= errorCode.
Depends on
  FileStreamWriteRT

    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

▲Back to the top▲