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

# linf64.htm
Class
FILE64
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
FileStreamWrite$
FileStreamWriteDword
FileStreamWriteLn
FileStreamWriteRT
FileStreamWriteWord
FileWrite
FileWrite$
FileWriteLn
FileWriteRT

This library contains wrapper macros which encapsulate LinABI calls for most typical file operations in 64bit Linux . See also equivalent homonymous macroinstructions in linf32.htm, winf32.htm, winf64.htm.

File Access method | Open | Data transfer | Close
--- | --- | --- | ---
read file at once | - | FileLoad | FileClose
write file at once | - | FileStore | -
standard read | FileOpen | FileRead | FileClose
standard write | FileCreate | FileWrite, FileWriteLn, FileWrite$ | FileClose
standard write at the end of file | FileAppend | FileWrite, FileWriteLn, FileWrite$ | FileClose
memory mapped read | FileMapOpen | - | FileClose
memory mapped write | FileMapCreate | - | FileClose
buffered read | FileStreamOpen | FileStreamReadByte, FileStreamRead, FileStreamReadLn | FileClose
buffered write | FileStreamCreate | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose
buffered write at end of file | FileStreamAppend | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose
append to file | - | FileEnclose, FileEncloseLn, FileEnclose$ | -
special functions | FileReset | FileAssign, FileExists?, FileNameParse, FileMove, FileMkDir, FileEach | FileDelete

Macros return the results in registers, usually RAX. Other registers do not change. CF is set when error occurs, ZF is set at the end of file, DF must be always reset. Other flags are undefined.

Association of the FILE64 object with the name of file is provided separately, using the macro FileAssign. File must be assigned before opening.

Macro names suffixed with ~Ln write LineFeed character after the data. Macro names suffixed with ~$ expect NULL-terminated input data.

Acces methods at once, stream, memory-map allocate dynamic virtual memory. It will be freed in FileClose.

Access method | Virtual memory
--- | ---
reserved | comitted
At once load | filesize | filesize
At once store | none | none
Standard | none | none
MemoryMapped | filesize | pagesize
Streamed | buffersize | buffersize

File access method at once loads entire file content into comitted memory, so it is suitable for small files only. The loaded/stored file doesn't need explicit opening nor closing.

> This access method is equivalent to PHP functions file_get_contents, file_put_contents.

Access method enclose opens the file at its end for writing, appends the data and closes file in one operation.

Standard read/write methods only encapsulate ABI functions read/write and they can process files of any size. Example:

[.bss] InpFile DS FILE64 OutFile DS FILE64 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 ; RAX=Line size, RSI=pointer to the line in buffer. LEA RDI,[WorkLine] REP MOVSB CALL ModifyWorkLine FileStreamWrite OutFile, WorkLine, RAX 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 LinABI, Dispatch, status32.htm.

    linf64 HEAD
     INCLUDEHEAD1 lins.htm, linsfile.htm, linabi.htm, cpuext.htm, status32.htm

FILE64
  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 FILE64 structured variable is passed as the first parameter to all macros in this library.

    FILE64    STRUC
     .Ptr       DQ  Q ; Pointer to the current data content in memory-mapped|buffered data.
     .Top       DQ  Q ; Pointer to the end of the memory-mapped|buffered data.
     .BufPtr    DQ  Q ; Address of the start of memory-map|allocated buffer.
     .BufSize   DQ  Q ; Size of memory map|buffer.
     .Pos       DQ  Q ; Zero based offset of the current file position: lseek(.Handle,.Pos,SEEK_SET).
     .Size      DQ  Q ; File size in bytes.
     .Handle    DQ  Q ; File descriptor.
     .MapHandle DQ  Q ; Pointer to the start of mapped memory, identical with .BufPtr.
     .Status    DD  D ; File status flags, see FileStatusEnc.
     .NameOffs  DD  D ; Offset of the filename without path inside the .Name. Zero if no path in .Name.
     .ExtOffs   DD  D ; Offset of the file extension inside the .Name.
     .Name      D NAME_MAX * B ; Zero terminated file name.
     ENDSTRUC FILE64

FileStatusEnc
  Definition of flags which describe `FILE64.Status`.

    fi64StFound      EQU 0x00000010 ; File was once succesfully opened.
    fi64StAppend     EQU 0x00100000 ; Created file should move its pointer to the end.
    fi64StStdIO      EQU 0x00200000 ; FILE64.Handle is standard input|output.
    fi64StAllocated  EQU 0x00400000 ; FILE64.BufPtr is pointer to the allocated memory.
    fi64StUnicode    EQU 0x00800000 ; FILE64.Name is in WIDE characters (not used in Linux).
    fi64StMapCreated EQU 0x01000000 ; FILE64.MapHandle is valid for writing.
    fi64StMapOpened  EQU 0x02000000 ; FILE64.MapHandle is valid for reading.
    fi64StMapped     EQU 0x04000000 ; FILE64.Ptr is pointer to the mapped memory.
    fi64StCreated    EQU 0x10000000 ; FILE64.Handle is valid for writing.
    fi64StOpened     EQU 0x20000000 ; FILE64.Handle is valid for reading.

FileNameParse 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 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
  RAX is pointer to the start of name without path.
  RCX is pointer to the start of extension.
  RDX points behind the last FileName character.
  Path starts at %FileNamePtr, size=RAX - OFFSET#FileNamePtr
  Name starts at RAX, size=RCX - RAX
  Extension starts at RCX, size=RDX - RCX
Error
  -
Examples
  %FileNamePtr │ │ │ │ "/var/lib/nam.part1.txt" "\plain" "./.profile" "name" │ │ │ │ │ │ │ │ │ RAX │ │ RAX │ RAX │ RAX │ RCX │ RCX RCX │ RCX RDX RDX RDX RDX

    FileNameParse %MACRO FileNamePtr,Size=-1, Unicode=%^UNICODE
        PUSHQ %Size,%FileNamePtr
        CALL FileNameParse@RT::
    FileNameParse@RT:: PROC1
        PUSH RBX,RSI
         SUB EBX,EBX       ; Prepare returned value of RAX.
         SUB ECX,ECX       ; Prepare returned value of RCX.
         MOV RSI,[RSP+3*8] ; %FileNamePtr.
         MOV RDX,[RSP+4*8] ; %Size.
         TEST RDX
         JS .NextChar:
         ADD RDX,RSI       ; End of input string or -1.
     .NextChar:
         CMP RSI,RDX
         JNB .End:
         LODSB
         Dispatch AL,47,46,0,58,92 ; slash, dot, null, colon, backslash.
         ; Ordinary character.
         LEA RAX,[RSI-1]
         TEST RBX
         JNZ .NextChar:
         MOV RBX,RAX
         JMP .NextChar:
    .46: ; dot .
         LEA RCX,[RSI-1]
         JMP .NextChar:
    .47: ; colon, slash, backslash
    .58:
    .92: MOV RBX,RSI
         JMP .NextChar:
    .0:  DEC RSI ; Byte NULL.
    .End:MOV RDX,RSI
         TEST RCX
         JNZ .E1:
         MOV RCX,RSI
    .E1: TEST RBX
         JNZ .E2:
         MOV RBX,RSI
    .E2: MOV RAX,RBX
        POP RSI,RBX
        RET 2*8
       ENDPROC1 FileNameParse@RT::
     %ENDMACRO FileNameParse

FileAssign theFile, Name$1, Name$2,,,Size=-1, Unicode=%^UNICODE
  Macro FileAssign associates file name with the FILE64 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 FILE64 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.
  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,` of `theFile` are set.
Error
  CF=1 if the concatenated name length exceeds `SIZE# FILE64.Name`, i.e. NAME_MAX=260 bytes.
Depends on
  FileNameParse
Examples
  File1 DS FILE Path$ DB "/usr/doc/",0 Name$ DB "Some",0 Ext$ DB ".txt",0 [.text] FileAssign File1,Path$,Name$,Ext$ FileAssign File2,0 ; Standard input/output, by default redirected to console. FileAssign File3,="/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
       PUSHQ 0                   ; End-of-arguments marker.
       ArgNr %FOR %#..2,STEP=-1
         PUSHQ %*{%ArgNr}        ; Pointers to strings, start with the last one.
       %ENDFOR ArgNr
       PUSHQ %Size, %theFile, RSP
        ADDQ [RSP],(2+%#)*8
        CALL FileAssign@RT::
       POP RSP                   ; Restore stack to equilibrum.
    FileAssign@RT:: PROC1
       PUSH RAX,RBX,RCX,RDX,RBP,RSI,RDI
        MOV RBX,[RSP+9*8]        ; %theFile
        LEA RBP,[RSP+11*8]       ; Pointer to the 1st namepointer.
        LEA RDI,[RBX+FILE64.Name]
        LEA RDX,[RDI+SIZE#FILE64.Name] ; End of reserved room.
    .10:XCHG RBP,RSI
         LODSQ                   ; Load pointer to namestring.
         MOV RBP,RAX
        XCHG RSI,RBP
        TEST RAX                 ; Check the end of pointers.
        JZ .50:
        MOV RCX,[RSP+10*8]       ; Parameter %Size=.
    .20:LODSB
        CMP AL,0
        JE .10:
        CMP RDI,RDX
        JNB .40:
        STOSB
        DEC RCX
        JNZ .20:
        JMP .10:
    .40:SUB EAX,EAX
        STC ; Overflow.
    .50:MOV RCX,RDI
        STOSB
        LEA RDX,[RBX+FILE64.Name]
        PUSHF
          SUB RCX,RDX
          FileNameParse RDX,Size=RCX
          LEA RDX,[RBX+FILE64.Name]
          SUB RAX,RDX
          SUB RCX,RDX
          MOV [RBX+FILE64.NameOffs],EAX
          MOV [RBX+FILE64.ExtOffs],ECX
        POPF
        POP RDI,RSI,RBP,RDX,RCX,RBX,RAX
        RET
    ENDPROC1 FileAssign@RT::

    %ENDMACRO FileAssign

FileExists? theFile
  will test if the given regular 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 FILE64 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
         PUSHQ %theFile
         CALL FileExists?@RT::
    FileExists?@RT:: PROC1
        PUSH RAX,RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+8*8]                           ; theFile.
         LEA RDI,[RBX+FILE64.Name]
         MOV ESI,O_RDONLY+O_DIRECTORY
         XOR EDX,EDX
         LinABI open,RDI,RSI,RDX, Fastmode=Yes       ; Try to open a directory.
         MOV RDI,RAX                                 ; Returned fd or error.
         SAL RAX                                     ; Copy SF to CF.
         JNC .80:                                    ; Return with CF=0,ZF=0 if the directory exists.
         MOV ESI,O_RDONLY
         LEA RDI,[RBX+FILE64.Name]
         LinABI open,RDI,RSI,RDX, Fastmode=Yes       ; Try to open a file.
         MOV RDI,RAX                                 ; Returned fd or error.
         SAL RAX                                     ; Copy SF to CF.
         JC .90:
         SetSt [RBX+FILE64.Status],fi64StFound
         XOR EDX,EDX                                 ; Set CF=0, ZF=1 if the file exists.
    .80: PUSHFQ
          LinABI close,RDI,Fastmode=Yes
         POPFQ
    .90:POP R11,RDI,RSI,RDX,RCX,RBX,RAX
        RET 1*8
      ENDPROC1 FileExists?@RT::
     %ENDMACRO FileExists?

FileMkDir 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 FILE64 object with assigned name.
Output
  CF=0
  RAX=0 if the directory was created or it existed before.
Error
  CF=1
  RAX=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
         PUSHQ %theFile
         CALL FileMkDir@RT::
    FileMkDir@RT:: PROC1
       PUSH RBX,RCX,RBP,RSI,RDI,R11
         MOV RBX,[RSP+7*8] ; theFile.
         LEA RBX,[RBX+FILE64.Name]
         SUB ECX,ECX
         MOV RDI,RBX
         DEC RCX
         XOR EAX,EAX
         REPNE SCASB
         MOV RBP,RDI      ; ASCIIZ FileName is now RBX..RBP.
         MOV RDI,RBX
    .20: MOV RCX,RBP
         MOV AL,'/'
         CMP [RDI],AL
         JNE .30:
         INC RDI
    .30: SUB RCX,RDI
         REPNE SCASB      ; Search for the next slash.
         MOV AL,0
         CLC
         JNE .90:         ; Done when no more slashes left in FileName.
         MOV [RDI-1],AL   ; Temporarily replace slash with NULL.
         MOV ESI,00777q
         XCHG RBX,RDI
          LinABI mkdir,RDI,RSI,Fastmode=Yes
         XCHG RDI,RBX
         MOVB [RDI-1],'/' ; Restore original slash.
         TEST EAX
         JZ .20:
         CMP EAX,-EEXIST  ; EEXIST=17 is the only tolerated error.
         JE .20:
    .80: STC
    .90:POP R11,RDI,RSI,RBP,RCX,RBX
        RET 1*8
      ENDPROC1 FileMkDir@RT::
    %ENDMACRO FileMkDir

FileGetSize FileHandle
  is a service macro used internally in FileOpen, FileCreate, FileMap* to obtain the size of opened file.
  Then it may be obtained faster as FILE64.Size.
Input
  FileHandle is file descriptor of file opened for read or write.
Output
  CF=0
  RAX= file size in bytes.
Error
  CF=1
  RAX= error code.

    FileGetSize %MACRO FileHandle
          PUSHQ %FileHandle
          CALL FileGetSize@RT::
    FileGetSize@RT:: PROC1
        PUSH RCX,RBP,RSI,RDI,R11
         MOV RBP,RSP
         MOV RDI,[RBP+6*8]    ; FileHandle.
         MOV ECX,SIZE# STAT
         ADD ECX,7
         AND ECX,~7
         SUB RSP,RCX
         MOV RSI,RSP          ; STAT
         LinABI fstat,RDI,RSI,Fastmode=Yes
         MOV RCX,[RSI+STAT.st_size]
         MOV RSP,RBP
         CMP RAX,-ERR_MAX
         CMC
         JC  .90:
         MOV RAX,RCX
    .90:POP R11,RDI,RSI,RBP,RCX
        RET 1*8
     ENDPROC1 FileGetSize@RT::
    %ENDMACRO FileGetSize

FileOpen theFile
  opens the assigned file for reading.
Input
  theFile is pointer to a FILE64 object with assigned filename.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX= is errorCode.
Depends on
  FileGetSize

    FileOpen %MACRO theFile
             PUSHQ %theFile
             CALL FileOpen@RT::
    FileOpen@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]          ; theFile.
         LEA RDI,[RBX+FILE64.Name]
         XOR EDX,EDX
         MOV [RBX+FILE64.Size],RDX
         MOV [RBX+FILE64.Pos],RDX
         MOV [RBX+FILE64.Ptr],RDX
         MOV [RBX+FILE64.Top],RDX
         LinABI open,RDI,O_RDONLY,RDX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         SetSt [RBX+FILE64.Status],fi64StOpened+fi64StFound
         MOV [RBX+FILE64.Handle],RAX
         FileGetSize RAX
         JC .90:
         MOV [RBX+FILE64.Size],RAX
         MOV [RBX+FILE64.Top],RAX
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
        RET 1*8
      ENDPROC1 FileOpen@RT::
     %ENDMACRO FileOpen

FileCreate theFile
  creates a new file or rewrites an existing file for writing.
Input
  theFile is pointer to a FILE64 object with assigned filename.
Output
  CF=0
  EAX=0 (size of just rewritten file).
Error
  CF=1
  EAX=errorCode.
Depends on
  FileGetSize

    FileCreate %MACRO theFile
             PUSHQ %theFile
             CALL FileCreate@RT::
    FileCreate@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]             ; ^theFile.
         XOR EAX,EAX
         MOV [RBX+FILE64.Ptr],RAX
         MOV [RBX+FILE64.Top],RAX
         LEA RDI,[RBX+FILE64.Name]
         MOV ESI,O_CREAT|O_WRONLY|O_TRUNC
         JNSt [RBX+FILE64.Status],fi64StAppend,.10:
         MOV ESI,O_CREAT|O_RDWR|O_APPEND ; The macro is used by FileAppend.
    .10: LinABI open,RDI,RSI,777q,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         SetSt [RBX+FILE64.Status],fi64StCreated
         MOV [RBX+FILE64.Handle],RAX
         FileGetSize RAX
         JC .90:
         MOV [RBX+FILE64.Size],RAX
         MOV [RBX+FILE64.Pos],RAX
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
        RET 1*8
      ENDPROC1 FileCreate@RT::
    %ENDMACRO FileCreate

FileAppend 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 FILE64 object with assigned filename.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX=errorCode as returned from GetLastError.
Depends on
  FileCreate

    FileAppend %MACRO theFile
           PUSHQ %theFile
           CALL FileAppend@RT::
     FileAppend@RT:: PROC1
         PUSH RBX
           MOV RBX,[RSP+2*8]         ; ^theFile
           SetSt [RBX+FILE64.Status],fi64StAppend
           FileCreate RBX
         POP RBX
         RET 1*8
       ENDPROC1 FileAppend@RT::
     %ENDMACRO FileAppend

FileFlush theFile
  is a helper 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
  RAX= number of flushed bytes.
Error
  CF=1
  RAX= errorCode (file not created for write).

    FileFlush %MACRO theFile
          PUSHQ %theFile
          CALL FileFlush@RT::
    FileFlush@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]           ; theFile.
         MOV RAX,-EBADFD             ; Error: file is not open for write.
         JNSt [RBX+FILE64.Status],fi64StAllocated,.80:
         JNSt [RBX+FILE64.Status],fi64StCreated,  .80:
         MOV RSI,[RBX+FILE64.BufPtr] ; Start of buffer.
         MOV RDX,[RBX+FILE64.Ptr]    ; Next free position in buffer.
         MOV [RBX+FILE64.Ptr],RSI
         SUB RDX,RSI
         MOV RAX,RDX
         JZ .90:                     ; If nothing to flush.
         MOV RDI,[RBX+FILE64.Handle]
         LinABI write,RDI,RSI,RDX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JNC .90:
    .80: STC
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
        RET 1*8
     ENDPROC1 FileFlush@RT::
    %ENDMACRO FileFlush

FileClose 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 FILE64 object. More than one file may be specified simultaneously.
Output
  -
Error
  -
Depends on
  FileFlush

    FileClose %MACRO theFile
      ArgNr %FOR 1..%#
           PUSHQ %*{%ArgNr}
           CALL FileClose@RT::
         %ENDFOR ArgNr
    FileClose@RT:: PROC1
        PUSH RAX,RBX,RCX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]        ; theFile
         JSt [RBX+FILE64.Status],fi64StMapped,.10:
         FileFlush RBX
         JMPS .20:
    .10: LinABI munmap,[RBX+FILE64.MapHandle],[RBX+FILE64.Size],Fastmode=Yes
    .20: JNSt [RBX+FILE64.Status],fi64StAllocated,.30:
         LinABI munmap,[RBX+FILE64.BufPtr],[RBX+FILE64.BufSize],Fastmode=Yes
    .30: JNSt [RBX+FILE64.Status],fi64StOpened|fi64StCreated, .40:
         LinABI close,[RBX+FILE64.Handle],Fastmode=Yes
    .40: LEA RCX,[RBX+FILE64.NameOffs]
         SUB RCX,RBX
         SHR ECX,2
         XOR EAX,EAX
         MOV RDI,RBX
         REP STOSD           ; Clear the FILE object except for Name and Offs.
        POP R11,RDI,RSI,RCX,RBX,RAX
        RET 1*8
      ENDPROC1 FileClose@RT::
    %ENDMACRO FileClose

FileMove 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 FILE64 objects.
Output
  CF=0
  RAX=0
Error
  CF=1
  RAX= error code.
Depends on
  FileClose, FileMkDir

    FileMove %MACRO SourceFile, DestinationFile
           PUSHQ %DestinationFile, %SourceFile
           CALL FileMove@RT::
    FileMove@RT:: PROC1
         PUSH RCX,RSI,RDI,R11
          MOV RSI,[RSP+5*8] ; SourceFile.
          MOV RDI,[RSP+6*8] ; DestinationFile.
          FileClose RSI,RDI
          FileMkDir RDI
          JC .90:
          LEA RSI,[RSI+FILE64.Name]
          LEA RDI,[RDI+FILE64.Name]
          XCHG RSI,RDI
          LinABI rename,RDI,RSI,Fastmode=Yes
          MOV ECX,EAX
          SAL ECX,1        ; Copy SF to CF.
    .90: POP R11,RDI,RSI,RCX
         RET 2*8
       ENDPROC1 FileMove@RT::
     %ENDMACRO FileMove

FileDelete 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 FILE64object. More than one file may be specified simultaneously.
Output
  CF=0,
  RAX=0 if the last file was succesfully deleted.
Error
  CF=1
  RAX= error code.
Depends on
  FileClose

    FileDelete %MACRO theFile
    ArgNr %FOR 1..%#
           PUSHQ %*{%ArgNr}
           CALL FileDelete@RT::
          %ENDFOR ArgNr
    FileDelete@RT:: PROC1
         PUSH RCX,RDI,R11
          MOV RDI,[RSP+4*8] ; theFile.
          FileClose RDI
          LEA RDI,[RDI+FILE64.Name]
          LinABI unlink,RDI,Fastmode=Yes
          MOV ECX,EAX
          SAL ECX,1         ; Copy SF to CF.
         POP R11,RDI,RCX
         RET 1*8
       ENDPROC1 FileDelete@RT::
     %ENDMACRO FileDelete

FileEach theFile, CallbackProc
  Macro FileEach expects the file object assigned with file name which can contain 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
  theFile is a pointer to FILE64 object which must have assigned the requested file path and file name mask.
  CallbackProc is the address of callback procedure.
Output
  RAX=content of RAX 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:
    RBX=%theFile where the mask in `FILE64.Name` is replaced with the resolved file name found in directory. The file is not open.
    RSI=pointer to the file name without path inside RBX+FILE64.Name.
    RBP=RBP at FileEach macro entry. This allows to address local stack variables of the procedure which invoked FileEach.
    Other registers are undefined at CallbackProc entry.
  CallbackProc output registers:
    RAX is passed through. FileEach returns RAX 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 RBX,RCX,RDX,RBP,RSI,RDI.
Depends on
  FileNameParse
Example
  MyFile DS FILE FileAssign MyFile,="/var/lib/t??_*.txt" FileEach MyFile, ListFile TerminateProgram ListFile PROC StdOutput RSI,Eol=Yes RET ENDP ListFile

    FileEach %MACRO theFile, CallbackProc
         PUSHQ %CallbackProc, %theFile
         CALL FileEach@RT::
    FileEach@RT:: PROC1
    %FileEachMaskSize %SETA (SIZE# FILE64.Name + 7) & ~7 ; Local buffer for the filename mask.
    %FileEachBufSize  %SETA (SIZE# DIRENT64    + 7) & ~7 ; Local buffer for DIRENT64 records.
          PUSH RAX,RBX,RCX,RDX,RSI,RDI,R9,R11
           MOV RBX,[RSP+9*8]   ; RBX=^theFile.
           MOV ECX,%FileEachMaskSize
           SUB EAX,EAX
           MOV [RSP+7*8],RAX   ; Initialize returned RAX with NULL.
           SUB RSP,RCX
           ADD EAX,[RBX+FILE64.NameOffs]
           MOV RDI,RSP
           LEA RSI,[RAX+RBX+FILE64.Name]
           REP MOVSB           ; Copy the ASCIIZ mask without path to LocalVar %FileEachMask$.
           JNZ .10:            ; Test if theFile.NameOffs=0.
           ; The mask was specified without path, e.g. doc*.txt.
           ; Default path ./ will be injected to FILE64.Name, i.e. ./doc*.txt.
           MOV ECX,SIZE#FILE64.Name-2
           LEA RSI,[RCX+RBX+FILE64.Name-1]
           LEA RDI,[RSI+2]
           STD
            REP MOVSB
           CLD
           DEC RDI
           MOVW [RDI],'./'
           MOVB [RDI+SIZE#FILE64.Name-1],0
           FileNameParse RDI
           SUB RAX,RDI
           SUB RCX,RDI
           MOV [RBX+FILE64.NameOffs],EAX
           MOV [RBX+FILE64.ExtOffs],ECX
    .10:   LEA RDI,[RBX+FILE64.Name]    ; RAX=FILE64.NameOffs.
           MOVB [RDI+RAX-1],0           ; Temporary replace / with NULL.
           MOV R9,RDI
           ;; LinABI open,RDI,O_RDONLY+O_DIRECTORY+O_NOATIME,0,Fastmode=Yes ; With O_NOATIME 'open' returned -1.
           LinABI open,RDI,O_RDONLY+O_DIRECTORY, 0, Fastmode=Yes
           MOV EDX,[RBX+FILE64.NameOffs]
           MOVB [R9+RDX-1],'/'          ; Replace temporary NULL back with slash in the mask name.
           MOV EDX,%FileEachBufSize
           SUB RSP,RDX                  ; RDX=Size of temporary buffer.
           MOV RDI,RAX                  ; Directory descriptor (or error code from sys_open).
    .20:   MOV RSI,RSP                  ; Pointer to temporary buffer for DIRENT64 records.
           LinABI getdents64,RDI,RSI,RDX,Fastmode=Yes
           TEST EAX
           JZ .End:                     ; When there are no more dir entries.
           CMP RAX,-ERR_MAX
           JNC .End:                    ; When error occured.
           LEA RCX,[RSI+RAX]            ; End of DIRENT64 records in buffer.
    .30:   CMP RSI,RCX
           JNB .20:                     ; Go to read the next portion of dir entries.
           CALL .DirEnt:                ; Process the DIRENT64 record at RSI. Keep all GPR.
           JC .End:
           MOVZX EAX,[RSI+DIRENT64.d_reclen]
           ADD RSI,RAX
           JMP .30:

    .DirEnt:PROC ; If the resolved name [RSI+DIRENT64.d_name] complies with %FileEachMask$,
      ; update FILE64.Name at [%Param1] with the resolved name and then call [%Param2].
      ; Input: RSI=^DIRENT64
      ;        RBX=^FILE64
      ; Output:CF and RAX as returned from callback. Other registers are unchanged.
             PUSH RBX,RCX,RDX,RBP,RSI,RDI
              CMP [RSI+DIRENT64.d_type],DT_REG
              JNE .NoMatch:                      ; Skip sockets, pipes, devices and other nonregular files.
              LEA RDI,[RSI+DIRENT64.d_name]      ; ^name from the directory.
              MOV RDX,RDI
              LEA RSI,[RSP+7*8+%FileEachBufSize] ; ^file mask without path.
    .D1:      LODSB                     ; Byte from file mask.
              MOV AH,[RDI]              ; Byte from file name.
              INC RDI
              Dispatch AL,0x00,0x2A,0x3F; Test on end-of-mask and wildcard.
              CMP AL,AH                 ; Ordinary character match?
              JE .D1:
              JMP .NoMatch:
    .0x00:    CMP AH,0
              JE .Match:
              JMP .NoMatch:
    .0x3F:    CMP AH,0      ; Question mark '?' in mask complies with one not-nul UTF8 character.
              JE .NoMatch:
              NOT EAX       ; Invert bits in UTF8 AH.
              SUB ECX,ECX
              BSR CX,AX     ; Scan AH, start with MSbit.
              SUB RCX,15
              JZ .D1:
              INC RCX
              SUB RDI,RCX   ; Advance RDI by the size of UTF8 character - 1.
              JMP .D1:
    .0x2A:    ; Asterix '*' complies with zero or more UTF8 characters.
              LODSB         ; The mask character/byte which follows '*'.
              Dispatch AL,0x2A,0x3F,0n00
    .D3:      CMP AH,0
              JE .NoMatch:
              CMP AL,AH
              JE .D1:
              MOV AH,[RDI]
              INC RDI
              JMP .D3:
    .NoMatch: CLC
              JMP .D9:
    .Match:   ; File name at RDX complies with the file mask. Perform callback.
    .0n00:    MOV RSI,RDX
              MOV ECX,SIZE# FILE64.Name
              MOV EAX,[RBX+FILE64.NameOffs]
              SUB ECX,EAX
              JNA .NoMatch:
              LEA RDI,[RBX+FILE64.Name+RAX]
              MOV RDX,RDI
              REP MOVSB
              MOV RSI,RDX           ; Pointer to resolved file name without path.
              MOV RAX,[RSP+17*8+%FileEachBufSize+%FileEachMaskSize] ; ^CallbackProc.
              CALL RAX              ; Perform the callback.
              MOV [RSP+14*8+%FileEachMaskSize+%FileEachBufSize],RAX ; Pass the returned RAX.
    .D9:     POP RDI,RSI,RBP,RDX,RCX,RBX
             RET
            ENDP .DirEnt:
    .End:  LinABI close,RDI, Fastmode=On
           ADD RSP,%FileEachMaskSize+%FileEachBufSize
          POP R11,R9,RDI,RSI,RDX,RCX,RBX,RAX
          RET 2*8
     ENDPROC1 FileEach@RT:
    %ENDMACRO FileEach

FileLoad 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 FILE64 object.
Output
  CF=0
  RAX= file size,
  RSI= pointer to the file contents in allocated memory.
Error
  CF=1
  RAX= errorCode.
  RSI= is undefined.
Depends on
  FileOpen, FileClose

    FileLoad %MACRO theFile
        PUSHQ %theFile
        CALL FileLoad@RT::
    FileLoad@RT:: PROC1
        PUSH RBX,RCX,RDX,RDI,R8,R9,R10,R11
         MOV RBX,[RSP+9*8]      ; ^theFile.
         FileOpen RBX           ; Returns CF=0,RAX=file size.
         JC .80:
         MOV [RBX+FILE64.BufSize],RAX
         TEST RAX               ; Zero-sized files are not supported.
         JZ .80:
         MOV RSI,RAX
         LinABI mmap,0,RSI,PROT_READ+PROT_WRITE,MAP_PRIVATE+MAP_ANONYMOUS,-1,0,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .80:
         MOV [RBX+FILE64.BufPtr],RAX
         MOV [RBX+FILE64.Ptr],RAX
         ADD [RBX+FILE64.Top],RAX
         SetSt [RBX+FILE64.Status],fi64StAllocated
         MOV RSI,RAX
         LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
    .80: PUSHFQ                 ; Save CF.
          PUSH RAX
           LinABI close,[RBX+FILE64.Handle]
           RstSt [RBX+FILE64.Status],fi64StCreated+fi64StOpened
          POP RAX
         POPFQ                  ; Restore CF.
        POP R11,R10,R9,R8,RDI,RDX,RCX,RBX
        RET 1*8
     ENDPROC1 FileLoad@RT::
    %ENDMACRO FileLoad

FileStore theFile, DataPtr, DataSize
  Macro FileStore will open the file, write data and close the file.
Input
  theFile is pointer to an assigned unopened FILE64 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
  RAX= is the size of written data.
Error
  CF=1
  EAX= is error code.
Depends on
  FileCreate, FileClose
Example
  FileStore File1, MyDataPtr, MyDataEnd-MyDataPtr

    FileStore %MACRO theFile,DataPtr,DataSize
          PUSHQ %DataSize,%DataPtr,%theFile
          CALL FileStore@RT::
    FileStore@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]    ; ^theFile.
         FileCreate RBX
         JC .90:
         MOV RSI,[RSP+8*8]    ; DataPtr.
         MOV RDX,[RSP+9*8]    ; DataSize.
         LinABI write,[RBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         MOV [RBX+FILE64.Size],RAX
         ADD [RBX+FILE64.Pos],RAX
         FileClose RBX
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
       RET 3*8
     ENDPROC1 FileStore@RT::
    %ENDMACRO FileStore

FileReset theFile, Position
  Macro FileReset will reset internal file pointers to a new Position in the file.
Input
  theFile is a pointer to a FILE64 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" === ""
           PUSHQ 0
         %ELSE
           PUSHQ %Position
         %ENDIF
         PUSHQ %theFile
         CALL FileReset@RT::
    FileReset@RT:: PROC1
         PUSH RBX,RCX,RDX,RSI,RDI,R11
          MOV RBX,[RSP+7*8]   ; theFile.
          MOV RSI,[RSP+8*8]   ; Position.
          MOV RAX,-EBADF      ; Error code "file is not opened".
          JNSt [RBX+FILE64.Status],fi64StOpened,.90:
          LinABI lseek,[RBX+FILE64.Handle],RSI,SEEK_SET,Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .90:
          MOV [RBX+FILE64.Pos],RAX
          MOV RSI,[RBX+FILE64.BufPtr]
          ADD RSI,RAX
          MOV [RBX+FILE64.Ptr],RSI
          JSt [RBX+FILE64.Status],fi64StMapOpened,.90:
          MOV [RBX+FILE64.Top],RSI
    .90: POP R11,RDI,RSI,RDX,RCX,RBX
         RET 2*8
        ENDPROC1 FileReset@RT::
     %ENDMACRO FileReset

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

    FileRead %MACRO theFile,DataPtr,DataSize
           PUSHQ %DataSize,%DataPtr,%theFile
           CALL FileRead@RT::
    FileRead@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
         MOV RBX,[RSP+7*8]      ; theFile.
         MOV RAX, -EBADFD       ; Error code: file is not open.
         TEST [RBX+FILE64.Status],fi64StOpened
         STC
         JZ .90:
         MOV RSI,[RSP+8*8]      ; DataPtr.
         MOV RDX,[RSP+9*8]      ; DataSize.
         LinABI read,[EBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         ADD [RBX+FILE64.Pos],RAX
         TEST RAX               ; Check ZF=EOF.
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
        RET 3*8
      ENDPROC1 FileRead@RT::
     %ENDMACRO FileRead

FileWriteRT theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  is a runtime macro used internally by FileWrite*. It declares runtime procedure FileWrite@RT with variable number of parameters.
Input
  theFile is pointer to a FILE64 object opened for write by FileCreate or FileAppend.
  DataPtr* is pointer to data being written,
  DataSize* is the number of bytes in data.
Output
  CF=0
  RAX is the number of total written bytes. Other registers are preserved.
Error
  CF=1
  RAX is error code.

    FileWriteRT %MACRO theFile, DataPtr1, DataSize1,,, ; Common runtime procedure declaration for macros FileWrite*
        %IF %# & 1 = 0
          %ERROR ID=5946, 'Macro FileWrite expects odd number of arguments.'
          %EXITMACRO FileWriteRT
        %ENDIF
        PUSHQ 0                     ; Mark the end of arguments.
        ArgNr %FOR %#..2,STEP=-2
          PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
        %ENDFOR ArgNr
        PUSHQ %theFile,RSP
          ADDQ [RSP],(%#+1)*8
          CALL FileWrite@RT::
        POP RSP
    FileWrite@RT::PROC1
        PUSH RBX,RCX,RDX,RBP,RSI,RDI,R11
         MOV RBX,[RSP+9*8]       ; theFile.
         MOV RAX,-EBADFD         ; File was not opened.
         TESTD [RBX+FILE64.Status],fi64StCreated
         STC
         JZ .90:
         PUSHQ 0                 ; Returned RAX will accumulate written size.
          LEA RBP,[RSP+11*8]     ; Pointer to the first DataPtr.
    .20:  XCHG RBP,RSI
          LODSQ                  ; DataPtr.
          MOV RBP,RAX
          TEST RAX               ; Test if it's the end of pointers.
          JZ .80:
          LODSQ                  ; DataSize.
          XCHG RSI,RBP
          MOV RDX,RAX
          INC RAX
          JNZ .30:
          MOV RCX,RDX            ; DataSize=-1, let's find the actual size.
          MOV RDI,RSI
          REPNE SCASB
          SUB RDI,RSI
          LEA RDX,[RDI-1]
    .30:  LinABI write,[RBX+FILE64.Handle],RSI,RDX,Fastmode=Yes
          CMP RAX,-ERR_MAX
          JC .40:                ; Jump when no error.
          STC
          LEA RSP,[RSP+2*8]      ; Keep CF and RAX=error code.
          JMP .90:
    .40:  ADD [RBX+FILE64.Size],RAX
          ADD [RBX+FILE64.Pos],RAX
          ADD [RSP+0*8],RAX      ; Accumulate total written size.
          JMP .20:
    .80: POP RAX
    .90:POP R11,RDI,RSI,RBP,RDX,RCX,RBX
        RET
       ENDP1 FileWrite@RT
    %ENDMACRO FileWriteRT

FileWrite 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 FILE64 object,
  DataPtr* points to the data to be written,
  DataSize* is the size of data in bytes.
Output
  CF=0
  RAX=total written size in bytes.
Error
  CF=1
  RAX= error code.
Depends on
  FileWriteRT

    FileWrite %MACRO theFile,DataPtr,DataSize,,,,
          FileWriteRT %*
      %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 (LineFeed) character `0x0A` is written in the end.
Input
  theFile is pointer to a FILE64 object opened for write,
  DataPtr* points to the data to be written,
  DataSize* is size of data in bytes.
Output
  CF=0
  RAX= is the total written size including LF.
Error
  CF=1
  RAX= error code.
Depends on
  FileWriteRT

    FileWriteLn %MACRO theFile,DataPtr,DataSize,,,
        FileWrite %*, =B 0x0A, 1
     %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 FILE64 object,
  DataPtr$* are pointers to zero terminated strings to be written.
Output
  CF=0
  RAX= total written size in bytes.
Error
  CF=1
  RAX= error code.
Depends on
  FileWriteRT

    FileWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
    %ArgList %SET %theFile
        ArgNr %FOR 2..%#
        %ArgList %SET %ArgList,%*{%ArgNr},-1
              %ENDFOR ArgNr
        FileWriteRT %ArgList
      %ENDMACRO FileWrite$

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 FILE64 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
  FileAppend, FileWrite, FileClose,
Example
  FileEnclose LogFile,Datum,SIZE#Datum

    FileEnclose %MACRO theFile,DataPtr,DataSize,,,,
        FileAppend %theFile
        JC FileEnclose%.Abort:
        FileWrite %*
        JC FileEnclose%.Abort:
        FileClose %theFile
    FileEnclose%.Abort:
     %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 FILE64 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
  FileAppend, FileWriteLn, FileClose,

    FileEncloseLn %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
        FileAppend %theFile
        JC FileEncloseLn%.Abort:
        FileWriteLn %*
        JC FileEncloseLn%.Abort:
        FileClose %theFile
    FileEncloseLn%.Abort:
     %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 FILE64 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
  FileAppend, FileWrite$, FileClose,
Example
  FileEnclose$ LogFile, Time$, =" Job started"

    FileEnclose$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
        FileAppend %theFile
        JC FileEnclose$%.Abort:
        FileWrite$ %*
        JC FileEnclose$%.Abort:
        FileClose %theFile
    FileEnclose$%.Abort:
      %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 RSI.
  The file cannot be assigned with device, pipe or empty name.
Input
  theFile is pointer to an assigned FILE64 object.
Output
  CF=0
  RAX= file size,
  RSI= pointer to the memory-mapped file contents.
Error
  CF=1
  RSI=0
  ZF=0, RAX= errorCode.
  ZF=1,RAX=0 when the file has zero size.
Depends on
  FileOpen

    FileMapOpen %MACRO theFile
          PUSHQ %theFile
          CALL FileMapOpen@RT::
    FileMapOpen@RT:: PROC1
         PUSH RBX,RCX,RDX,RDI,R8,R9,R10,R11
          MOV RBX,[RSP+9*8]            ; theFile.
          XOR ESI,ESI
          FileOpen RBX
          JC .End:
          TEST EAX
          JZ .End:                     ; If the file has size=0.
          LinABI mmap,0,RAX,PROT_READ+PROT_EXEC,MAP_SHARED,[RBX+FILE64.Handle],0,Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .End:
          MOV RSI,RAX
          MOV [RBX+FILE64.Ptr],RAX
          MOV [RBX+FILE64.Top],RAX
          MOV [RBX+FILE64.BufPtr],RAX
          MOV [RBX+FILE64.MapHandle],RAX
          MOV RAX,[RBX+FILE64.Size]
          MOV [RBX+FILE64.BufSize],RAX
          ADD [RBX+FILE64.Top],RAX
          SetSt [RBX+FILE64.Status],fi64StMapped+fi64StMapOpened
          DEC EBX                       ; Set ZF=0.
    .End:POP R11,R10,R9,R8,RDI,RDX,RCX,RBX
        RET 1*8
      ENDPROC1 FileMapOpen@RT::
    %ENDMACRO FileMapOpen

FileMapCreate 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 RDI but not more than FileSize bytes.
  The file cannot be assigned with device, pipe or empty name.
Input
  theFile is pointer to a FILE64 object with assigned name.
  FileSize is the requested size of memory mapped file. It may be omitted or set to 0 when FileMapCreate opens an existing file.
Output
  CF=0
  RAX=FileSize
  RDI= is pointer to the memory mapped file content.
Error
  CF=1
  RDI=undefined,
  RAX= errorCode as returned from GetLastError.
Depends on
  FileAppend

    FileMapCreate %MACRO theFile,FileSize
           %IF %# > 1
             PUSHQ %FileSize
           %ELSE
             PUSHQ 0
           %ENDIF
           PUSHQ %theFile
           CALL FileMapCreate@RT::
    FileMapCreate@RT:: PROC1
          PUSH RBX,RCX,RDX,RSI,R8,R9,R10,R11
           MOV RBX,[RSP+9*8]        ; theFile.
           FileAppend RBX
           JC .90:
           MOV RSI,RAX              ; Current file size.
           MOV RCX,[RSP+10*8]       ; Requested FileSize.
           JRCXZ .10:
           MOV RSI,RCX
    .10:   LinABI ftruncate,[RBX+FILE64.Handle],RSI,Fastmode=Yes
           TEST EAX
           STC
           JNZ .90:
           LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_SHARED,[RBX+FILE64.Handle],RAX,Fastmode=Yes
           CMP RAX,-ERR_MAX
           CMC
           JC .90:
           SetSt [RBX+FILE64.Status],fi64StMapCreated+fi64StMapped+fi64StAllocated+fi64StCreated
           MOV RDI,RAX
           MOV [RBX+FILE64.Size],RSI
           MOV [RBX+FILE64.MapHandle],RAX
           MOV [RBX+FILE64.BufPtr],RAX
           ADD RAX,RSI
           MOV [RBX+FILE64.Ptr],RAX
           MOV [RBX+FILE64.Top],RAX
           XCHG RAX,RSI
    .90: POP R11,R10,R9,R8,RSI,RDX,RCX,RBX
         RET 2*8
       ENDPROC1 FileMapCreate@RT::
     %ENDMACRO FileMapCreate

FileStreamOpen 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 FILE64 object with assigned name.
  BuffSize= specifies the buffer size.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX= error code.
Depends on
  FileOpen

    FileStreamOpen %MACRO theFile,BufSize=16K
           PUSHQ %BufSize,%theFile
           CALL FileStreamOpen@RT::
    FileStreamOpen@RT:: PROC1
         PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
          MOV RBX,[RSP+10*8]  ; theFile.
          FileOpen RBX
          JC .90:
          MOV RSI,[RSP+11*8]  ; BufSize.
          MOV [RBX+FILE64.BufSize],RSI
          XOR EDI,EDI
          LinABI mmap,RDI,RSI,PROT_READ+PROT_WRITE,MAP_PRIVATE+MAP_ANONYMOUS,-1,RDI,Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .90:
          SetSt [RBX+FILE64.Status],fi64StAllocated
          MOV [RBX+FILE64.MapHandle],RAX
          MOV [RBX+FILE64.BufPtr],RAX
          MOV [RBX+FILE64.Ptr],RAX
          MOV [RBX+FILE64.Top],RAX
          MOV RAX,[RBX+FILE64.Size]
    .90: POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
         RET 2*8
      ENDPROC1 FileStreamOpen@RT::
     %ENDMACRO FileStreamOpen

FileStreamRead theFile, DataPtr, DataSize
  reads data from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE64 object.
  DataPtr points to a memory area allocated by the caller,
  DataSize is amount of bytes to read.
Output
  CF=0
  ZF=0
  RAX= how many bytes was read (may be less the DataSize).
End of file
  CF=0
  ZF=1
  RAX= 0 when there are no more bytes in the file (EOF).
Error
  CF=1
  RAX= error code.

    FileStreamRead %MACRO theFile,DataPtr,DataSize
           PUSHQ %DataSize,%DataPtr,%theFile
           CALL FileStreamRead@RT::
    FileStreamRead@RT:: PROC1
         PUSH RBX,RCX,RDX,RSI,RDI,R11
           SUB EDX,EDX
           MOV RBX,[RSP+7*8]      ; theFile.
           MOV RAX,-EBADFD        ; Error: file is not open.
           TESTD [RBX+FILE64.Status],fi64StOpened
           STC
           JZ .90:
           TESTD [RBX+FILE64.Status],fi64StAllocated
           STC
           JZ .90:
           MOV RDI,[RSP+8*8]      ; DataPtr.
    .10:   MOV RSI,[RBX+FILE64.Ptr]
    .20:   MOV RCX,[RBX+FILE64.Top]
           SUB RCX,RSI            ; How many bytes is left in buffer.
           JNA .50:
           CMP RCX,[RSP+9*8]      ; Is it enough for the requested DataSize?
           JA .60:
           SUB [RSP+9*8],RCX
           ADD RDX,RCX
           REP MOVSB
           MOV [RBX+FILE64.Ptr],RSI
           JMP .20:
    .50:   MOV RSI,[RBX+FILE64.BufPtr]
           MOV [RBX+FILE64.Ptr],RSI
           MOV [RBX+FILE64.Top],RSI
           LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
           CMP RAX,-ERR_MAX
           CMC
           JC .90:
           ADD [RBX+FILE64.Top],RAX
           JMP .20:
    .60:   MOV RCX,[RSP+9*8]       ; DataSize.
           ADD RDX,RCX
           REP MOVSB
           MOV [RBX+FILE64.Ptr],RSI
    .70:   MOV RAX,RDX
           ADD [RBX+FILE64.Pos],RDX
           TEST RAX
    .90: POP R11,RDI,RSI,RDX,RCX,RBX
         RET 3*8
     ENDPROC1 FileStreamRead@RT::
    %ENDMACRO FileStreamRead

FileStreamReadLn 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 FILE64 object.
Output
  CF=0
  ZF=0
  RAX= line size (never bigger than theFILE64.BufSize)
  RSI= pointer to the line in buffer.
End of file
  CF=0
  ZF=1
  RAX=0 when there are no more data in file (EOF).
  RSI= undefined
Error
  CF=1
  RAX= error code.
  RSI= undefined.

    FileStreamReadLn %MACRO theFile
          PUSHQ %theFile
          CALL FileStreamReadLn@RT::
    FileStreamReadLn@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R11
          MOV RBX,[RSP+7*8]     ; theFile.
          MOV RAX,-EBADFD       ; Error: file is not open.
          TESTD [RBX+FILE64.Status],fi64StOpened
          STC
          JZ .90:
          TESTD [RBX+FILE64.Status],fi64StAllocated
          STC
          JZ .90:
    .10:  MOV RDI,[RBX+FILE64.Ptr]
          MOV RCX,[RBX+FILE64.Top]
          MOV [RSP+2*8],RDI       ; Returned ESI.
          MOV RDX,RDI
          SUB RCX,RDI
          JNA .30:
          MOV AL,10             ; Search for LineFeed.
          REPNE SCASB
          JE .50:
          CMP RDX,[RBX+FILE64.BufPtr]
          JE .50:
          ; When EOL is out of buffer and start of line is not
          ;  at buffer's beginning, the buffer will be reloaded with the current line.
          MOV RCX,RDX
          SUB RCX,RDI
          LinABI lseek,[RBX+FILE64.Handle],RCX,SEEK_CUR,Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .90:
    .30:  MOV RSI,[RBX+FILE64.BufPtr]
          MOV [RBX+FILE64.Ptr],RSI
          MOV [RBX+FILE64.Top],RSI
          LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .90:
          TEST RAX
          JZ .90:                ; End of file.
          ADD RAX,RSI
          MOV [RBX+FILE64.Top],RAX
          JMP .10:
    .50:  MOV [RBX+FILE64.Ptr],RDI
          MOV RAX,RDI
          SUB RAX,RDX
          ADD [RBX+FILE64.Pos],RAX
    .90:POP R11,RDI,RSI,RDX,RCX,RBX
        RET 1*8
     ENDPROC1 FileStreamReadLn@RT::
    %ENDMACRO FileStreamReadLn

FileStreamReadByte theFile
  reads one byte from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  ZF=0
  AL= the byte read from file. Other bytes in RAX are preserved.
End of file
  CF=0
  ZF=1
  RAX= unchanged, when there are no more bytes in the file (EOF).
Error
  CF=1
  RAX= error code.
Remark
  if CF=0

    FileStreamReadByte %MACRO theFile
         PUSHQ %theFile
         CALL FileStreamReadByte@RT::
    FileStreamReadByte@RT:: PROC1
         PUSH RBX,RCX,RDX,RBP,RSI,RDI,R11
          MOV RBX,[RSP+8*8]       ; theFile.
    .10:  MOV RSI,[RBX+FILE64.Ptr]
          CMP RSI,[RBX+FILE64.Top]
          JB .50:
          MOV RSI,[RBX+FILE64.BufPtr]
          MOV [RBX+FILE64.Ptr],RSI
          MOV [RBX+FILE64.Top],RSI
          MOV RBP,RAX
          LinABI read,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],Fastmode=Yes
          CMP RAX,-ERR_MAX
          CMC
          JC .90:
          ADD [RBX+FILE64.Top],RAX
          TEST RAX
          MOV RAX,RBP
          JZ .90:
          JMP .10:              ; This time it will not fail.
    .50:  LODSB
          MOV [RBX+FILE64.Ptr],RSI
          INCQ [RBX+FILE64.Pos]
          CLC
    .90: POP R11,RDI,RSI,RBP,RDX,RCX,RBX
         RET 1*8
      ENDPROC1 FileStreamReadByte@RT::
     %ENDMACRO FileStreamReadByte

FileStreamCreate 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 FILE64 object with assigned filename.
  BuffSize= specifies the buffer size.
Output
  CF=0
  RAX=0 (size of just rewritten file).
Error
  CF=1
  EAX= errorCode.
Depends on
  FileCreate

    FileStreamCreate %MACRO theFile,BufSize=16K
           PUSHQ %BufSize,%theFile
           CALL FileStreamCreate@RT::
    FileStreamCreate@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
         MOV RBX,[RSP+10*8]     ; theFile.
         RstSt [RBX+FILE64.Status],fi64StAppend
         FileCreate RBX
         JC .90:
         MOV RSI,[RSP+11*8]     ; BufSize.
         XOR EAX,EAX
         LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_PRIVATE+MAP_ANONYMOUS,-1,RAX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         MOV [RBX+FILE64.BufSize],RSI
         MOV [RBX+FILE64.BufPtr],RAX
         MOV [RBX+FILE64.Ptr],RAX
         ADD RAX,RSI
         MOV [RBX+FILE64.Top],RAX
         SetSt [RBX+FILE64.Status],fi64StAllocated
         MOV RAX,[RBX+FILE64.Size]
    .90:POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
        RET 2*8
      ENDPROC1 FileStreamCreate@RT::
    %ENDMACRO FileStreamCreate

FileStreamAppend 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 FILE64 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
           PUSHQ %BufSize,%theFile
           CALL FileStreamAppend@RT::
    FileStreamAppend@RT:: PROC1
        PUSH RBX,RCX,RDX,RSI,RDI,R8,R9,R10,R11
         MOV RBX,[RSP+10*8]     ; theFile.
         SetSt [RBX+FILE64.Status],fi64StAppend
         FileCreate RBX
         JC .90:
         MOV RSI,[RSP+11*8]     ; BufSize.
         XOR EAX,EAX
         LinABI mmap,RAX,RSI,PROT_READ+PROT_WRITE+PROT_EXEC,MAP_PRIVATE+MAP_ANONYMOUS,-1,RAX,Fastmode=Yes
         CMP RAX,-ERR_MAX
         CMC
         JC .90:
         MOV [RBX+FILE64.BufSize],RSI
         MOV [RBX+FILE64.BufPtr],RAX
         MOV [RBX+FILE64.Ptr],RAX
         ADD RAX,RSI
         MOV [RBX+FILE64.Top],RAX
         SetSt [RBX+FILE64.Status],fi64StAllocated
         MOV RAX,[RBX+FILE64.Size]
    .90:POP R11,R10,R9,R8,RDI,RSI,RDX,RCX,RBX
        RET 2*8
       ENDPROC1 FileStreamAppend@RT::
     %ENDMACRO FileStreamAppend

FileStreamWriteByte theFile
  This macro writes one byte from AL to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  AL contains the data byte to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  RAX= error code.
Depends on
  FileFlush

    FileStreamWriteByte %MACRO theFile
          PUSHQ %theFile
          CALL FileStreamWriteByte@RT::
    FileStreamWriteByte@RT:: PROC1
         PUSH RAX,RBX,RDI
          MOV RBX,[RSP+4*8]          ; theFile.
    .10:  MOV RDI,[RBX+FILE64.Ptr]
          CMP RDI,[RBX+FILE64.Top]
          JB .50
          FileFlush RBX              ; Write the buffer if it is full.
          JNC .10:
          MOV [RSP+2*8],RAX          ; Returned RAX on error.
          JMP .90:
    .50:  STOSB
          MOV RAX,[RBX+FILE64.Pos]
          MOV [RBX+FILE64.Ptr],RDI
          INC RAX
          MOV [RBX+FILE64.Pos],RAX
          MOV [RBX+FILE64.Size],RAX
          CLC
    .90: POP RDI,RBX,RAX
         RET 1*8
      ENDPROC1 FileStreamWriteByte@RT::
     %ENDMACRO FileStreamWriteByte

FileStreamWriteWord theFile
  This macro writes one word from AX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  AX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  RAX= error code.
Depends on
  FileFlush

    FileStreamWriteWord %MACRO theFile
          PUSHQ %theFile
          CALL FileStreamWriteWord@RT::
    FileStreamWriteWord@RT:: PROC1
         PUSH RAX,RBX,RCX,RDI
          MOV RBX,[RSP+5*8]           ; theFile.
    .10:  MOV RDI,[RBX+FILE64.Ptr]
          LEA RCX,[RDI+1]
          CMP RCX,[RBX+FILE64.Top]
          JB .50:
          FileFlush RBX               ; Write the buffer if it is full.
          JNC .10:
          MOV [RSP+3*8],RAX           ; Returned RAX on error.
          JMP .90:
    .50:  STOSW
          MOV RAX,[RBX+FILE64.Pos]
          MOV [RBX+FILE64.Ptr],RDI
          ADD EAX,2
          MOV [RBX+FILE64.Pos],RAX
          MOV [RBX+FILE64.Size],RAX
          CLC
    .90: POP RDI,RCX,RBX,RAX
         RET 1*8
      ENDPROC1 FileStreamWriteWord@RT::
     %ENDMACRO FileStreamWriteWord

FileStreamWriteDword theFile
  This macro writes one doubleword from EAX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  EAX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  EAX= errorCode .
Depends on
  FileFlush

    FileStreamWriteDword %MACRO theFile
          PUSHQ %theFile
          CALL FileStreamWriteDword@RT::
    FileStreamWriteDword@RT:: PROC1
         PUSH RAX,RBX,RCX,RDI
          MOV RBX,[RSP+5*8]           ; the File.
    .10:  MOV RDI,[RBX+FILE64.Ptr]
          LEA RCX,[RDI+3]
          CMP RCX,[RBX+FILE64.Top]
          JB .50
          FileFlush RBX               ; Write the buffer if it is full.
          JNC .10:
          MOV [RSP+3*8],RAX           ; Returned RAX on error.
          JMP .90:
    .50:  STOSD
          MOV RAX,[RBX+FILE64.Pos]
          MOV [RBX+FILE64.Ptr],RDI
          ADD EAX,4
          MOV [RBX+FILE64.Pos],RAX
          MOV [RBX+FILE64.Size],RAX
          CLC
    .90: POP RDI,RCX,RBX,RAX
         RET 1*8
       ENDPROC1 FileStreamWriteDword@RT::
     %ENDMACRO FileStreamWriteDword

FileStreamWriteRT theFile, DataPtr1, DataSize1, DataPtr2,DataSize2,,,
  is a runtime defining macro used internally by FileStreamWrite*.
  It declares runtime procedure FileWrite@RT with variable number of parameters.
Input
  theFile is pointer to a FILE64 object opened by FileStreamCreate or FileStreamAppend.
  DataPtr* is pointer to data being written,
  DataSize* is the number of bytes in data.
Output
  CF=0
  RAX is the number of written bytes. Other registers are preserved.
Error
  CF=1
  RAX is error code.
Depends on
  FileFlush

    FileStreamWriteRT %MACRO ; Common runtime procedure for macros FileStreamWrite*
        %IF %# & 1 = 0
          %ERROR ID=5946, 'Macro FileStreamWrite expects odd number of arguments.'
          %EXITMACRO FileStreamWriteRT
        %ENDIF
        PUSHQ 0                     ; Mark the end of arguments.
        ArgNr %FOR %#..2,STEP=-2
        PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
        %ENDFOR ArgNr
        PUSHQ %theFile,RSP
          ADDQ [RSP],(%#+1)*8
          CALL FileStreamWrite@RT::
        POP RSP
    FileStreamWrite@RT::PROC1
        PUSH RBX,RCX,RDX,RBP,RSI,RDI
         MOV RBX,[RSP+8*8]         ; theFile.
         MOV RAX,-EBADFD           ; File was not opened.
         TESTD [RBX+FILE64.Status],fi64StCreated
         STC
         JZ .90:
         TESTD [RBX+FILE64.Status],fi64StAllocated
         STC
         JZ .90:
         PUSHQ 0                    ; Returned RAX will accumulate written size.
          LEA RBP,[RSP+10*8]        ; Pointer to the first DataPtr.
    .20:  XCHG RBP,RSI
          LODSQ                     ; DataPtr.
          MOV RBP,RAX
          TEST RAX                  ; Test if it's the end of pointers.
          JZ .80:
          LODSQ                     ; DataSize.
          XCHG RSI,RBP
          MOV RDX,RAX
          INC RAX
          JNZ .30:
          MOV RCX,RDX               ; DataSize=-1, let's find the actual size.
          MOV RDI,RSI
          REPNE SCASB
          SUB RDI,RSI
          LEA RDX,[RDI-1]
    .30:  MOV RDI,[RBX+FILE64.Ptr]  ; RDX is DataSize.
          MOV RCX,[RBX+FILE64.Top]
          SUB RCX,RDI
          JA .40:
          FileFlush RBX
          JNC .30:
          LEA RSP,[RSP+1*8]         ; Keep CF and RAX=error code.
          JMP .90:
    .40:  SUB RDX,RCX
          JAE .50:
          ADD RCX,RDX
    .50:  ADD [RBX+FILE64.Pos],RCX
          ADD [RBX+FILE64.Size],RCX
          ADD [RSP+0*8],RCX         ; Accumulate total written size.
          REP MOVSB
          MOV [RBX+FILE64.Ptr],RDI
          CMP RDX,RCX
          JG  .30
          JMP .20:
    .80: POP RAX
    .90:POP RDI,RSI,RBP,RDX,RCX,RBX
        RET
       ENDP1 FileStreamWrite@RT::
       %ENDMACRO FileStreamWriteRT

FileStreamWrite 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 FILE64 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
  RAX= total written size in bytes.
Error
  CF=1
  RAX= error code.
Depends on
  FileStreamWriteRT

    FileStreamWrite %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
          FileStreamWriteRT %*
     %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 FILE64 object,
  DataPtr* is pointer to the data to be written,
  DataSize* is the size of the data to be written. It may be bigger than the buffer size specified on opening the file.
Output
  CF=0
  RAX= total written size including LF.
Error
  CF=1
  RAX= error code.
Depends on
  FileStreamWriteRT

    FileStreamWriteLn %MACRO theFile,DataPtr1,DataSize1,DataPtr2,DataSize2,,,
        FileStreamWriteRT %*, =B 0x0A, 1
     %ENDMACRO FileStreamWriteLn

FileStreamWrite$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes one or more zero terminated strings to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple ASCIIZ strings may be written in one macro invocation. Their terminating zeros are not written to the file.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr$* are pointers to the zero terminated strings to be written.
Output
  CF=0
  RAX= total written size.
Error
  CF=1
  RAX= error code.
Depends on
  FileStreamWriteRT

    FileStreamWrite$ %MACRO theFile,DataPtr$1,DataPtr$2,DataPtr$3,,,
    %ArgList %SET %theFile
        ArgNr %FOR 2..%#
        %ArgList %SET %ArgList,%*{%ArgNr},-1
              %ENDFOR ArgNr
        FileStreamWriteRT %ArgList
      %ENDMACRO FileStreamWrite$

      ENDHEAD linf64

▲Back to the top▲