include 'proc32.inc'

DLL_ENTRY equ 1
DLL_EXIT  equ -1
REQ_DLL_VER equ 2

use32
        db      'MENUET01'
        dd      1
        dd      start
        dd      i_end
        dd      mem
        dd      mem
        dd      0
        dd      0

start:
        stdcall load_dll_and_import, dllname, imports
        test    eax, eax
        jz      exit

; check version
        cmp     word [dll_ver], REQ_DLL_VER
        jb      exit
        cmp     word [dll_ver+2], REQ_DLL_VER
        ja      exit
        push    DLL_ENTRY
        call    [dll_start]

; yes! Now do some work (show color strings in this case).

        push    caption
        push    -1
        push    -1
        push    -1
        push    -1
        call    [con_init]
; C-equivalent of the following code:
; for (ebx=0;ebx<0x100;ebx++)
; {
;   con_printf(t1,ebx);
;   eax = con_set_flags(ebx);
;   con_write_asciiz(text);
;   con_set_flags(eax);
; }
; N.B. For efficiency result of first con_set_flags is not saved
;      in register, but is pushed beforehand to the stack
;      for second con_set_flags.
;      Note that such code cannot be generated by stdcall macros.
        xor	ebx, ebx
@@:
        push    ebx
        push    t1
        call    [con_printf]
        add     esp, 8
        push	ebx
        call	[con_set_flags]
        push	eax
        push    text
        call    [con_write_asciiz]
        call	[con_set_flags]
        inc	bl
        jnz	@b
        push    text2
        call    [con_write_asciiz]
        push    0
        call    [con_exit]
exit:
        or      eax, -1
        int     0x40

proc load_dll_and_import stdcall, _dllname:dword, _imports:dword
        pushad
; load DLL
        push    68
        pop     eax
        push    19
        pop     ebx
        mov     ecx, [_dllname]
        int     0x40
        test    eax, eax
        jz      import_fail

; initialize import
        mov     edi, eax
        mov     esi, [_imports]
import_loop:
        lodsd
        test    eax, eax
        jz      import_done
        mov     edx, edi
import_find:
        mov     ebx, [edx]
        test    ebx, ebx
        jz      import_not_found
        push    eax
@@:
        mov     cl, [eax]
        cmp     cl, [ebx]
        jnz     import_find_next
        test    cl, cl
        jz      import_found
        inc     eax
        inc     ebx
        jmp     @b
import_find_next:
        pop     eax
        add     edx, 8
        jmp     import_find
import_found:
        pop     eax
        mov     eax, [edx+4]
        mov     [esi-4], eax
        jmp     import_loop
import_not_found:
import_fail:
        popad
        xor     eax, eax
        ret
import_done:
        popad
        xor     eax, eax
        inc     eax
        ret
endp

align 4

imports:
dll_start          dd szStart
dll_ver            dd szVersion
con_init           dd szcon_init
con_write_asciiz   dd szcon_write_asciiz
con_printf         dd szcon_printf
con_set_flags      dd szcon_set_flags
con_exit           dd szcon_exit
                   dd 0

szStart            db 'START',0
szVersion          db 'version',0
szcon_init         db 'con_init',0
szcon_write_asciiz db 'con_write_asciiz',0
szcon_printf       db 'con_printf',0
szcon_set_flags    db 'con_set_flags',0
szcon_exit         db 'con_exit',0

dllname  db '/sys/lib/console.obj',0

caption            db 'Console test - colors',0
t1                 db 'Color 0x%02X: ',0
text               db 'This is sample text.',10,0
text2		db	27,'[7mAnd this is an example of '
		db	27,'[1;36;41mEsc'
		db	27,'[7m-sequences.',10,0

i_end:

align 4
rb 2048 ; stack
mem: