; Platform-specific procedures for Linux.

; Reallocate memory at pointer [start.buf] and size [start.allocated],
; new size is in eax.
realloc:
        push    ebx esi edi
        mov     ecx, eax
        push    ebp
        kercall __NR_mmap2, 0, , PROT_READ+PROT_WRITE, MAP_PRIVATE+MAP_ANONYMOUS, -1, 0
        pop     ebp
        cmp     eax, 0xFFFFF000
        ja      nomemory
        add     [start.free], ecx
        xchg    ecx, [start.allocated]
        sub     [start.free], ecx
        mov     edi, eax
        xchg    eax, [start.buf]
        shr     ecx, 2
        jz      .nothing
        push    ecx
        mov     esi, eax
        rep     movsd
        pop     ecx
        shl     ecx, 2
        call    free_eax_ecx
.nothing:
        pop     edi esi ebx
        ret

; Read the next portion of input data to [start.buf].
read:
        mov     ecx, [start.buf]
        add     ecx, [start.allocated]
        mov     edx, [start.free]
        sub     ecx, edx
        kercall __NR_read, [start.in], ,
        test    eax, eax
        js      readerr
        ret

; Write output data: eax=pointer, edi=size.
write:
        mov     ecx, eax
        kercall __NR_write, [start.out], , edi
        cmp     eax, edi
        jnz     writeerr
        ret

; Parse command line, open input and output files.
get_params:
; 1. Initialize default streams: 0 for stdin, 1 for stdout.
        inc     [start.out]
; 2. Prepare for scanning, skipping argv[0].
        mov     ebx, [start.argc]
        cmp     ebx, 1
        jbe     .noargs
        dec     ebx
        lea     esi, [start.argv+4]     ; skip argv[0]
        xor     edi, edi        ; no args parsed yet
; 3. Parse loop.
.parse:
; 3a. Get the next argument.
        lodsd
; 3b. Check whether it is a known option.
        cmp     word [eax], '-e'
        jnz     @f
        cmp     byte [eax+2], 0
        jnz     @f
; 3c. If it is, modify flags and continue the loop.
        mov     [start.flags], 1        ; '-e' is given
        jmp     .nextarg
@@:
; 3d. Otherwise, it is a name of input or output file.
; edi keeps the count of names encountered before;
; edi = 0 means this is input file, edi = 1 - output file,
; otherwise this is third arg, which is an error
        cmp     edi, 1
        ja      information
; 3e. Some parameters of __NR_open differ for input and output. Setup them.
        mov     ecx, O_WRONLY+O_CREAT+O_TRUNC
        mov     edx, 0644o
        jz      @f
        mov     ecx, O_RDONLY
@@:
; 3f. Open/create the file, save the handle.
        push    ebx
        mov     ebx, eax
        kercall __NR_open
        pop     ebx
        test    eax, eax
        js      .fileerr
        mov     [start.in+edi*4], eax
        inc     edi
.nextarg:
        dec     ebx
        jnz     .parse
.noargs:
; 4. End of command line reached. Return.
        ret
.fileerr:
        test    edi, edi
        jz      in_openerr
        jmp     out_openerr

; Exit, return code is in al.
exit:
        movzx   ebx, al
        push    ebx
        mov     eax, [start.buf]
        test    eax, eax
        jz      @f
        mov     ecx, [start.allocated]
        call    free_eax_ecx
@@:
        kercall __NR_close, [start.in]
        kercall __NR_close, [start.out] 
        pop     ebx
        kercall __NR_exit

; Helper procedure for realloc and exit.
free_eax_ecx:
        mov     ebx, eax
        kercall __NR_munmap
        ret

; Output the message given in esi to stderr.
sayerr:
        movzx   edx, byte [esi-1]
        kercall __NR_write, 2, esi, 
        ret

; Get environment variable esi (ebx-relative pointer) to the buffer,
; expanding it if needed.
get_environment_variable:
        mov     ecx, [start.argc]
        lea     ecx, [start.argv+ecx*4+4]
.findvar:
        mov     edx, [ecx]
        add     ecx, 4
        test    edx, edx
        jz      .notfound
        push    esi
        add     esi, ebx
.comparename:
        lodsb
        cmp     al, [edx]
        jnz     @f
        inc     edx
        jmp     .comparename
@@:
        pop     esi
        test    al, al
        jnz     .findvar
        cmp     byte [edx], '='
        jnz     .findvar
        inc     edx
        xor     eax, eax
@@:
        inc     eax
        cmp     byte [edx+eax-1], 0
        jnz     @b
        stdcall alloc_in_buf, eax
@@:
        mov     al, [edx]
        inc     edx
        mov     [edi+ebx], al
        inc     edi
        test    al, al
        jnz     @b
        ret
.notfound:
        stdcall alloc_in_buf, 1
        mov     byte [edi+ebx], 0
        inc     edi
        ret

; Test whether a file with name [.testname] exists.
; Returns eax<0 if not, nonzero otherwise.
test_file_exists:
        push    ebx
        add     ebx, [start.testname]
        sub     esp, 800h
        kercall __NR_stat, , esp
        add     esp, 800h
        pop     ebx
        ret