; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Files manipulation library. Linux part.
;
;  Target OS: Linux
;
;  Dependencies: Uses system calls for file processing and memory.asm for memory
;                allocations.
;
;  Notes:
;_________________________________________________________________________________________

DIR_SLASH equ '/'

fsFromBegin     = 0
fsFromEnd       = 2
fsFromCurrent   = 1


faReadOnly   = O_RDONLY
faWriteOnly  = O_WRONLY
faReadWrite  = O_RDWR

faOpenAlways   = O_CREAT             ; if the file does not exists it will be created.
faCreateAlways = O_CREAT or O_TRUNC  ; Creates new file always. If the file exists, truncates it.
faCreateOnly   = O_CREAT or O_EXCL   ; Creates new file only if not exists, else error.


if used STDIN | used STDOUT | used STDERR
  initialize InitStdHandles
  begin
    if used STDIN
          mov     dword [__std_handle_in], 0
    end if

    if used STDOUT
          mov     dword [__std_handle_out], 1
    end if

    if used STDERR
          mov     dword [__std_handle_err], 2
    end if
          return
  endp
end if



body FileOpenAccess
begin
        push    edx ecx ebx

        if defined ptrStrTable
          stdcall StrPtr, [.filename]
          mov     ebx, eax
        else
          mov   ebx, [.filename]
        end if

        mov     eax, sys_open
        mov     ecx, [.access]
        mov     edx, S_IRUSR+S_IWUSR+S_IRGRP+S_IWGRP+S_IROTH
        int     $80
        cmp     eax, -1
        jle     .error
        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax

if defined options.DebugMode & options.DebugMode
        stdcall __FileErrorDisplay, eax, [.filename]
end if

        stc
        pop     ebx ecx edx
        return
endp




;--------------------------------------
; if CF = 0, the file was closed.
; if CF = 1, eax is error code.
;--------------------------------------
body FileClose
begin
        push    ebx
        mov     eax, sys_close
        mov     ebx, [.handle]
        int     $80
        cmp     eax, -1
        jle     .error
        clc
        pop     ebx
        return
.error:
        neg     eax
        stc
        pop     ebx
        return
endp


; returns 32bit file size in eax
body FileSize
.stat STAT
begin
        push    edx ecx ebx

        mov     eax, sys_newfstat
        mov     ebx, [.handle]
        lea     ecx, [.stat]
        int     $80

        cmp     eax, -1
        jle     .error

        mov     eax, [.stat.st_size]
        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax
        stc
        pop     ebx ecx edx
        return
endp



body FileRead
begin
        push    edx ecx ebx
        mov     eax, sys_read
        mov     ebx, [.handle]
        mov     ecx, [.buffer]
        mov     edx, [.count]
        int     $80
        cmp     eax, -1
        jle     .error
        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax
        stc
        pop     ebx ecx edx
        return
endp


body FileWrite
begin
        push    edx ecx ebx
        mov     eax, sys_write
        mov     ebx, [.handle]
        mov     ecx, [.buffer]
        mov     edx, [.count]
        int     $80
        cmp     eax, -1
        jle     .error
        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax
        stc
        pop     ebx ecx edx
        return
endp


;----------------------------------------------------
; if CF = 0, eax is the new possition in the file
; if CF = 1, eax is error code.
;----------------------------------------------------
body FileSeek
begin
        push    edx ecx ebx
        mov     eax,sys_lseek
        mov     ebx,[.handle]
        mov     ecx,[.dist]
        mov     edx,[.direction]
        int     $80
        cmp     eax,-1
        jle     .error
        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax
        stc
        pop     ebx ecx edx
        return
endp



body FileTruncate
begin
        push    edx ecx ebx

        mov     eax, sys_lseek
        mov     ebx, [.handle]
        xor     ecx, ecx
        mov     edx, fsFromCurrent
        int     $80
        cmp     eax, -1
        jle     .error

        mov     ecx, eax
        mov     eax, sys_ftruncate
        mov     ebx, [.handle]
        int     $80
        cmp     eax,-1
        jle     .error

        clc
        pop     ebx ecx edx
        return

.error:
        neg     eax
        stc
        pop     ebx ecx edx
        return
endp



;--------------------------------------
; if CF = 0, the file was deleted.
; if CF = 1, eax is error code.
;--------------------------------------
body FileDelete
begin
        push    ebx

        if defined ptrStrTable
          stdcall StrPtr, [.filename]
          mov     ebx, eax
        else
          mov   ebx, [.filename]
        end if

        mov     eax,sys_unlink
        int     $80
        cmp     eax,-1
        jle     .error
        clc
        pop     ebx
        return

.error:
        neg     eax
        stc
        pop     ebx
        return
endp




body GetCurrentDir
.buffer rb 1024
begin
        push    ebx ecx

        mov     eax, sys_getcwd
        lea     ebx, [.buffer]
        mov     ecx, 1024
        int     $80
        cmp     eax, -1
        jle     .error

        stdcall StrDupMem, ebx
        clc
        pop     ecx ebx
        return

.error:
        neg     eax
        stc
        pop     ecx ebx
        return
endp




body SetCurrentDir
begin
        push    ebx eax

        stdcall StrPtr, [.hDirectory]
        mov     ebx, eax
        mov     eax, sys_chdir
        int     $80

        clc
        test    eax, eax
        jns     .finish

        neg     eax
        stc

.finish:
        pop     eax ebx
        return
endp



body GetErrorString
.buffer rb 1024
begin
        push    ecx edx

        lea     eax, [.buffer]
        cinvoke strerror_r, [.code], eax, 1024
        test    eax, eax
        jnz     @f
        lea     eax, [.buffer]
@@:
        stdcall StrDupMem, eax

        pop     edx ecx
        clc
        return
endp




body FreeErrorString
begin
        stdcall StrDel, [.ptrString]
        return
endp




ftDirectory  =  DT_DIR
ftUnknown    =  DT_UNKNOWN
ftFile       =  DT_REG


; reads all items of the directory and fills them in the TArray of type TDirItem.
; arguments:
;   dir - string with the path to the directory.
;
; returns:
;   if not error: CF=0; eax = pointer to TArray of TDirItem;
;   if error:     CF=1; eax = error code;

body DirectoryRead
.size   dd ?
begin
        push    ebx ecx edx esi edi

        stdcall GetMem, 1024
        mov     esi, eax

        stdcall CreateArray, sizeof.TDirItem
        mov     edi, eax

; open the file
        if defined ptrStrTable
          stdcall StrPtr, [.dir]
          mov     ebx, eax
        else
          mov   ebx, [.dir]
        end if

        mov     eax, sys_open
        mov     ecx, O_RDONLY or O_DIRECTORY
        mov     edx, S_IWUSR+S_IWGRP+S_IWOTH
        int     $80
        test    eax, eax
        js      .error

        mov     ebx, eax

.read_loop:

        mov     eax, sys_getdents
        mov     ecx, esi
        mov     edx, 1024
        int     $80

; process read information

        test    eax, eax
        jz      .end_of_directory
        js      .error

        mov     [.size], eax

        xor     ecx, ecx

.buffer_parse:
        lea     eax, [esi+ecx+linux_dirent.d_name]
        stdcall StrDup, eax
        push    eax

        stdcall AddArrayItems, edi, 1
        mov     edi, edx

        pop     [eax+TDirItem.hFilename]

        movzx   edx, word [esi+ecx+linux_dirent.d_reclen]
        add     ecx, edx

        movzx   edx, byte [esi+ecx-1]       ; file type.
        mov     [eax+TDirItem.Type], edx

        cmp     ecx, [.size]
        jb      .buffer_parse

        jmp     .read_loop

.end_of_directory:

        mov     eax, sys_close
        int     $80

        stdcall FreeMem, esi
        mov     eax, edi
        pop     edi esi edx ecx ebx
        clc
        return

.error:
        stdcall FreeMem, esi
        neg     eax
        pop     edi esi edx ecx ebx
        stc
        return
endp





body GetFileInfo
.fstat STAT
begin
        push    edi ebx ecx eax

        lea     edi, [.fstat]
        mov     ecx, sizeof.STAT / 4
        xor     eax, eax
        rep stosd

        mov     eax, sys_newfstat
        mov     ebx, [.hFile]
        lea     ecx, [.fstat]
        int     $80

        test    eax, eax
        jnz     .error

        lea     ecx, [.fstat]
        mov     ebx, [.ptrFileInfo]

        mov     eax, [ecx+STAT.st_atime]
        cdq
        mov     dword [ebx+TFileInfo.timeAccessed], eax
        mov     dword [ebx+TFileInfo.timeAccessed+4], edx

        mov     eax, [ecx+STAT.st_mtime]
        cdq
        mov     dword [ebx+TFileInfo.timeModified], eax
        mov     dword [ebx+TFileInfo.timeModified+4], edx
; linux does not support creation time, so we set it as the modified time.
        mov     dword [ebx+TFileInfo.timeCreated], eax
        mov     dword [ebx+TFileInfo.timeCreated+4], edx

        pop     eax ecx ebx edi
        clc
        return

.error:
        neg     eax
        mov     [esp], eax

        pop     eax ecx ebx edi
        stc
        return

endp


flushInput = 0
flushOutput = 1
flushInputOutput = 2

TCFLSH  = $540B         ; Linux constant.


proc TerminalFlush, .hFile, .flush_what
begin
        pushad
        mov     eax, sys_ioctl
        mov     ebx, [.hFile]
        mov     ecx, TCFLSH
        mov     edx, [.flush_what]
        int     $80

        mov     [esp+4*regEAX], eax
        bt      eax, 31         ; if negative - error
        popad
        return
endp