console.dll in PE format

git-svn-id: svn://kolibrios.org@6699 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
CleverMouse 2016-11-10 19:26:46 +00:00
parent d5ca21b332
commit a5bb6e3fd4
30 changed files with 4519 additions and 741 deletions

View File

@ -383,7 +383,7 @@ tup.append_table(img_files, {
{"DEVELOP/MTDBG", PROGS .. "/develop/mtdbg/mtdbg"},
{"DEVELOP/SCANCODE", PROGS .. "/develop/scancode/trunk/scancode"},
{"DEVELOP/T_EDIT", PROGS .. "/other/t_edit/t_edit"},
{"DEVELOP/test_gets", PROGS .. "/develop/libraries/console/examples/test_gets"},
{"DEVELOP/test_gets", PROGS .. "/develop/libraries/console_coff/examples/test_gets"},
{"DEVELOP/THREAD", PROGS .. "/develop/examples/thread/trunk/thread"},
{"DEVELOP/INFO/ASM.SYN", PROGS .. "/other/t_edit/info/asm.syn"},
{"DEVELOP/INFO/CPP_KOL_CLA.SYN", PROGS .. "/other/t_edit/info/cpp_kol_cla.syn"},
@ -415,7 +415,7 @@ tup.append_table(img_files, {
{"LIB/ARCHIVER.OBJ", PROGS .. "/fs/kfar/trunk/kfar_arc/kfar_arc.obj"},
{"LIB/BOX_LIB.OBJ", PROGS .. "/develop/libraries/box_lib/trunk/box_lib.obj"},
{"LIB/BUF2D.OBJ", PROGS .. "/develop/libraries/buf2d/trunk/buf2d.obj"},
{"LIB/CONSOLE.OBJ", PROGS .. "/develop/libraries/console/console.obj"},
{"LIB/CONSOLE.OBJ", PROGS .. "/develop/libraries/console_coff/console.obj"},
{"LIB/LIBGFX.OBJ", PROGS .. "/develop/libraries/libs-dev/libgfx/libgfx.obj"},
{"LIB/LIBIMG.OBJ", PROGS .. "/develop/libraries/libs-dev/libimg/libimg.obj"},
{"LIB/LIBINI.OBJ", PROGS .. "/develop/libraries/libs-dev/libini/libini.obj"},
@ -509,9 +509,9 @@ tup.append_table(extra_files, {
-- For russian build, add russian-only programs.
if build_type == "rus" then tup.append_table(img_files, {
{"PERIOD", PROGS .. "/other/period/trunk/period"},
{"DEVELOP/TESTCON2", PROGS .. "/develop/libraries/console/examples/testcon2_rus"},
{"DEVELOP/TESTCON2", PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
}) else tup.append_table(img_files, {
{"DEVELOP/TESTCON2", PROGS .. "/develop/libraries/console/examples/testcon2_eng"},
{"DEVELOP/TESTCON2", PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
}) end
if build_type == "rus" then tup.append_table(extra_files, {

View File

@ -27,6 +27,7 @@ end virtual
virtual at 0
file filename:pehea,0F8h
load NumberOfSections word from 6
load TimeDateStamp dword from 8
load SizeOfOptionalHeader word from 14h
if SizeOfOptionalHeader<>0E0h
error Nonstandard PE header
@ -103,14 +104,25 @@ DeltaDeleted = NumBytesDeleted and not (FileAlignment - 1)
; Use store instead of declaring SizeOfHeaders - DeltaDeleted directly in dd
; to avoid the second compilation pass.
store dword SizeOfHeaders - DeltaDeleted at SizeOfHeadersField
TimeStampInExportTable = 0
; sections
repeat NumberOfSections
file filename:pehea+0F8h+(%-1)*28h,18h
load a dword from $-4
store dword a-DeltaDeleted at $-4
load VirtualSize dword from $-10h
load VirtualAddress dword from $-0Ch
load SizeOfRawData dword from $-8
load PointerToRawData dword from $-4
PointerToRawData = PointerToRawData - DeltaDeleted
store dword PointerToRawData at $-4
if DirRVA_EXPORT <> 0 & DirRVA_EXPORT+4 >= VirtualAddress & DirRVA_EXPORT+8 <= VirtualAddress + VirtualSize & DirRVA_EXPORT+8 <= VirtualAddress + SizeOfRawData
TimeStampInExportTable = DirRVA_EXPORT+4 - VirtualAddress + PointerToRawData
end if
file filename:pehea+0F8h+(%-1)*28h+24h,4
end repeat
; padding to keep FileAlignment
times NumBytesDeleted - DeltaDeleted db 0
; data
file filename:pehea+0F8h+NumberOfSections*28h
if TimeDateStamp <> 0
store dword TimeDateStamp at TimeStampInExportTable
end if

View File

@ -1,2 +1,3 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("console.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "console.obj")
ROOT = "../../../.."
tup.rule("console.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "console.dll")

View File

@ -1,31 +1,13 @@
; ”㭪樨 à ¡®âë á ª®­á®«ìî ¤«ï ¯à®£à ¬¬ Š®«¨¡à¨Ž‘
; diamond, 2006-2008
format PE console 0.8 DLL at 7FEF0000h
format MS COFF
public EXPORTS
section '.flat' code readable align 16
section '.flat' code readable executable
include 'font.inc'
include 'conscrl.inc'
;void __stdcall START(dword state);
START:
; N.B. The current kernel implementation does not require
; evident heap initialization, because if DLL is loaded, heap is already initialized
; (if heap was not initialized, loader does this implicitly).
; So this action does nothing useful, but nothing harmful.
push ebx
push 68
pop eax
push 11
pop ebx
int 0x40
pop ebx
or eax, -1
ret 4
include '../../../export.inc'
; ˆ­¨æ¨ «¨§ æ¨ï ª®­á®«¨
; void __stdcall con_init(dword wnd_width, dword wnd_height,
@ -33,6 +15,11 @@ START:
align 4
con_init:
mov [con_flags], 7
mov [con.cursor_height], (15*font_height+50)/100
mov [con.input_start], con.input_buffer
mov [con.input_end], con.input_buffer
mov [con.entered_char], -1
pop eax
pop [con.wnd_width]
@ -1840,6 +1827,7 @@ con.wake:
; <20>®â®ª ®ª­  ª®­á®«¨. Ž¡à ¡ â뢠¥â ¢¢®¤ ¨ ¢ë¢®¤.
con.thread:
or [con.vscroll_pt], -1
; <20>®â®ª ॠ£¨àã¥â ­  IPC, ª®â®à®¥ ¨á¯®«ì§ã¥âáï ⮫쪮 ¤«ï ⮣®, çâ®¡ë ¥£® ¬®¦­® ¡ë«® "à §¡ã¤¨âì"
push 40
pop eax
@ -1849,6 +1837,7 @@ con.thread:
mov al, 60
mov bl, 1
mov ecx, con.ipc_buf
mov byte [ecx+4], 8
push 0x11
pop edx
int 0x40
@ -2545,108 +2534,56 @@ con.def_scr_height dd 300
con.def_wnd_x dd 200
con.def_wnd_y dd 50
con.init_cmd db 0
con.title_init_console db "Console",0
struc process_info
{
cpu_usage dd ? ; +0
window_stack_position dw ? ; +4
window_stack_value dw ? ; +6
dw ? ; +8
process_name rb 12 ; +10
memory_start dd ? ; +22
used_memory dd ? ; +26
PID dd ? ; +30
box.x dd ? ; +34
box.y dd ? ; +38
box.width dd ? ; +42
box.height dd ? ; +46
slot_state dw ? ; +50
dw ? ; +52
client_box.x dd ? ; +54
client_box.y dd ? ; +58
client_box.width dd ? ; +62
client_box.height dd ? ; +66
wnd_state db ? ; +70
rb (1024-71)
}
process_info_buffer process_info
window_status rd 1
con.vscroll_pt dd -1
align 16
EXPORTS:
dd szStart, START
dd szVersion, 0x00020008
dd szcon_init, con_init
dd szcon_write_asciiz, con_write_asciiz
dd szcon_write_string, con_write_length
dd szcon_printf, con_printf
dd szcon_exit, con_exit
dd szcon_get_flags, con_get_flags
dd szcon_set_flags, con_set_flags
dd szcon_kbhit, con_kbhit
dd szcon_getch, con_getch
dd szcon_getch2, con_getch2
dd szcon_gets, con_gets
dd szcon_gets2, con_gets2
dd szcon_get_font_height, con_get_font_height
dd szcon_get_cursor_height,con_get_cursor_height
dd szcon_set_cursor_height,con_set_cursor_height
dd szcon_cls, con_cls
dd szcon_get_cursor_pos, con_get_cursor_pos
dd szcon_set_cursor_pos, con_set_cursor_pos
dd szcon_set_title, con_set_title
dd 0
con_flags dd 7
con.cursor_height dd (15*font_height+50)/100
con.input_start dd con.input_buffer
con.input_end dd con.input_buffer
con_esc_attr_n dd 0
con_esc_attrs dd 0,0,0,0
con_esc db 0
con_sci db 0
con.entered_char dw -1
con.bGetchRequested db 0
con.bWasE0 db 0
szStart db 'START',0
szcon_init db 'con_init',0
szcon_write_asciiz db 'con_write_asciiz',0
szcon_write_string db 'con_write_string',0
szcon_printf db 'con_printf',0
szcon_exit db 'con_exit',0
szVersion db 'version',0
szcon_get_flags db 'con_get_flags',0
szcon_set_flags db 'con_set_flags',0
szcon_kbhit db 'con_kbhit',0
szcon_getch db 'con_getch',0
szcon_getch2 db 'con_getch2',0
szcon_gets db 'con_gets',0
szcon_gets2 db 'con_gets2',0
szcon_get_font_height db 'con_get_font_height',0
szcon_get_cursor_height db 'con_get_cursor_height',0
szcon_set_cursor_height db 'con_set_cursor_height',0
szcon_cls db 'con_cls',0
szcon_get_cursor_pos db 'con_get_cursor_pos',0
szcon_set_cursor_pos db 'con_set_cursor_pos',0
szcon_set_title db 'con_set_title',0
align 4
data export
export 'console.dll', \
version, 'version', \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_write_length, 'con_write_string', \
con_printf, 'con_printf', \
con_exit, 'con_exit', \
con_get_flags, 'con_get_flags', \
con_set_flags, 'con_set_flags', \
con_kbhit, 'con_kbhit', \
con_getch, 'con_getch', \
con_getch2, 'con_getch2', \
con_gets, 'con_gets', \
con_gets2, 'con_gets2', \
con_get_font_height, 'con_get_font_height', \
con_get_cursor_height, 'con_get_cursor_height', \
con_set_cursor_height, 'con_set_cursor_height', \
con_cls, 'con_cls', \
con_get_cursor_pos, 'con_get_cursor_pos', \
con_set_cursor_pos, 'con_set_cursor_pos', \
con_set_title, 'con_set_title'
end data
version dd 0x00020008
con.thread_err db 'Cannot create console thread!',13,10,0
con.nomem_err db 'Not enough memory!',13,10,0
con.aFinished db ' [Finished]',0
con.aNull db '(null)',0
con.beep db 0x90, 0x3C, 0x00
con.ipc_buf dd 0,8,0,0
db 0
section '.data' data readable writable align 16
section '.data' data readable writable
con_flags dd ?
con.cursor_height dd ?
con.input_start dd ?
con.input_end dd ?
con_esc_attr_n dd ?
con_esc_attrs dd ?,?,?,?
con_esc db ?
con_sci db ?
con.entered_char dw ?
con.bGetchRequested db ?
con.bWasE0 db ?
con.init_cmd db ?
con.finished_title rb 256
@ -2675,12 +2612,15 @@ con.bUpPressed_saved rb 1
con.bDownPressed_saved rb 1
con.bScrollingUp_saved rb 1
con.bScrollingDown_saved rb 1
con.vscroll_pt dd ?
con.input_buffer rw 128
con.input_buffer_end = $
con.kbd_layout rb 128
con.ipc_buf rb 0x11
; 1 = exit, 2 = set title, 3 = redraw, 4 = getch
con.thread_op rb 1
con.bUpPressed rb 1
@ -2690,3 +2630,29 @@ con.bScrollingDown rb 1
con.stack rb 1024
con.stack_top = $
struc process_info
{
cpu_usage dd ? ; +0
window_stack_position dw ? ; +4
window_stack_value dw ? ; +6
dw ? ; +8
process_name rb 12 ; +10
memory_start dd ? ; +22
used_memory dd ? ; +26
PID dd ? ; +30
box.x dd ? ; +34
box.y dd ? ; +38
box.width dd ? ; +42
box.height dd ? ; +46
slot_state dw ? ; +50
dw ? ; +52
client_box.x dd ? ; +54
client_box.y dd ? ; +58
client_box.width dd ? ; +62
client_box.height dd ? ; +66
wnd_state db ? ; +70
rb (1024-71)
}
process_info_buffer process_info
window_status rd 1

View File

@ -1,4 +1,4 @@
console.obj exports the following functions
console.dll exports the following functions
typedef unsigned long dword; /* 32-bit unsigned integer */
typedef unsigned short word; /* 16-bit unsigned integer */

View File

@ -1,4 +1,4 @@
console.obj ýêñïîðòèðóåò ñëåäóþùèå ôóíêöèè:
console.dll ýêñïîðòèðóåò ñëåäóþùèå ôóíêöèè:
typedef unsigned long dword; /* 32-АХРМНЕ АЕГГМЮЙНБНЕ ЖЕКНЕ */
typedef unsigned short word; /* 16-АХРМНЕ АЕГГМЮЙНБНЕ ЖЕКНЕ */

View File

@ -1,2 +1,3 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.foreach_rule("*.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "%B")
ROOT = "../../../../.."
tup.foreach_rule("*.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B")

View File

@ -1,41 +1,9 @@
format PE console 0.8
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 3
use32
db 'MENUET01'
dd 1
dd start
dd i_end
dd mem
dd mem
dd 0
dd 0
include '../../../../import.inc'
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 (getch() demo in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
invoke con_set_title, caption
; C-equivalent of the following code:
; con_printf(start_string);
@ -78,91 +46,20 @@ done:
push 1
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_printf dd szcon_printf
con_exit dd szcon_exit
con_getch dd szcon_getch
dd 0
szStart db 'START',0
szVersion db 'version',0
szcon_init db 'con_init',0
szcon_printf db 'con_printf',0
szcon_exit db 'con_exit',0
szcon_getch db 'con_getch',0
dllname db '/sys/lib/console.obj',0
data import
library console, 'console.dll'
import console, \
con_set_title, 'con_set_title', \
con_printf, 'con_printf', \
con_exit, 'con_exit', \
con_getch, 'con_getch'
end data
caption db 'Console test - getch()',0
start_string db 'Press any key to see its code, or Esc to exit',10,0
string_normal db 'normal character with code %d=0x%02X',10,0
string_extended db 'extended character with code %d=0x%02X',10,0
i_end:
align 4
rb 2048 ; stack
mem:

View File

@ -1,41 +1,9 @@
format PE console 0.8
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 3
use32
db 'MENUET01'
dd 1
dd start
dd i_end
dd mem
dd mem
dd 0
dd 0
include '../../../../import.inc'
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 (gets() demo in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
invoke con_set_title, caption
; C-equivalent of the following code:
; for (;;)
@ -65,92 +33,22 @@ done:
push 1
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_exit dd szcon_exit
con_gets dd szcon_gets
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_exit db 'con_exit',0
szcon_gets db 'con_gets',0
dllname db '/sys/lib/console.obj',0
data import
library console, 'console.dll'
import console, \
con_set_title, 'con_set_title', \
con_write_asciiz, 'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets, 'con_gets'
end data
caption db 'Console test - gets()',0
str1 db 'Enter string (empty for exit): ',0
str2 db 'You entered: ',0
i_end:
s rb 256
align 4
rb 2048 ; stack
mem:

View File

@ -1,35 +1,8 @@
format PE GUI 0.8 ; initialize console ourselves
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 4
use32
db 'MENUET01'
dd 1
dd start
dd i_end
dd mem
dd mem
dd 0
dd 0
include '../../../../import.inc'
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 (gets2() demo in this case).
push caption
push 25
push 80
@ -66,8 +39,8 @@ done:
push 1
call [con_exit]
exit:
or eax, -1
int 0x40
xor eax, eax
ret
proc mycallback stdcall, keycode:dword, pstr:dword, pn:dword, ppos:dword
mov eax, [keycode]
@ -160,80 +133,16 @@ proc mycallback stdcall, keycode:dword, pstr:dword, pn:dword, ppos:dword
ret
endp
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_exit dd szcon_exit
con_gets2 dd szcon_gets2
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_exit db 'con_exit',0
szcon_gets2 db 'con_gets2',0
dllname db '/sys/lib/console.obj',0
data import
library console, 'console.dll'
import console, \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets2, 'con_gets2'
end data
caption db 'Console test - gets2()',0
str1 db 'Enter string (empty for exit): ',0
@ -246,10 +155,4 @@ str5.len = $ - str5
str6 db 'next line in the history'
str6.len = $ - str6
i_end:
s rb 256
align 4
rb 2048 ; stack
mem:

View File

@ -1,58 +1,20 @@
use32
db 'MENUET01'
dd 1
dd start
dd i_end
dd mem
dd mem
dd 0
dd 0
; useful includes
include '../../../../macros.inc'
purge mov,add,sub
include '../../../../proc32.inc'
include '../../../../dll.inc'
format PE console 0.8
include '../../../../import.inc'
start:
; First 3 steps are intended to load/init console DLL
; and are identical for all console programs
; load DLL
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
; yes! Now do some work (say helloworld in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
push aHelloWorld
call [con_write_asciiz]
push 0
call [con_exit]
exit:
or eax, -1
int 0x40
xor eax, eax
ret
caption db 'Console test',0
aHelloWorld db 'Hello, World!',10,0
align 4
@IMPORT:
library console, 'console.obj'
data import
library console, 'console.dll'
import console, \
con_start, 'START', \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets, 'con_gets'
i_end:
align 4
rb 2048 ; stack
mem:
con_exit, 'con_exit'
end data

View File

@ -1,41 +1,9 @@
format PE console 0.8
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
include '../../../../import.inc'
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]
invoke con_set_title, caption
; C-equivalent of the following code:
; for (ebx=0;ebx<0x100;ebx++)
; {
@ -67,85 +35,19 @@ start:
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
data import
library console, 'console.dll'
import console, \
con_set_title, 'con_set_title', \
con_write_asciiz, 'con_write_asciiz', \
con_printf, 'con_printf', \
con_set_flags, 'con_set_flags', \
con_exit, 'con_exit'
end data
caption db 'Console test - colors',0
t1 db 'Color 0x%02X: ',0
@ -153,9 +55,3 @@ 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:

View File

@ -1,41 +1,9 @@
format PE console 0.8
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
include '../../../../import.inc'
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]
invoke con_set_title, caption
; C-equivalent of the following code:
; for (ebx=0;ebx<0x100;ebx++)
; {
@ -67,85 +35,19 @@ start:
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
data import
library console, 'console.dll'
import console, \
con_set_title, 'con_set_title', \
con_write_asciiz, 'con_write_asciiz', \
con_printf, 'con_printf', \
con_set_flags, 'con_set_flags', \
con_exit, 'con_exit'
end data
caption db 'Console test - colors',0
t1 db '–¢¥â 0x%02X: ',0
@ -153,9 +55,3 @@ text db '
text2 db 27,'[7m€ íâ® ¯à¨¬¥à ¨á¯®«ì§®¢ ­¨ï '
db 27,'[1;36;41mEsc'
db 27,'[7m-¯®á«¥¤®¢ â¥«ì­®á⥩.',10,0
i_end:
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,2 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("console.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "console.obj")

View File

@ -0,0 +1,3 @@
fasm console.asm console.obj
kpack console.obj
pause

View File

@ -0,0 +1,45 @@
; ‚ᯮ¬®£ â¥«ì­ë© ä ©« ¤«ï console.inc - ®¯¨á ­¨¥ scrollbar
; ‚¥à⨪ «ì­ ï ¯à®ªàã⪠
virtual at 0
file 'conscrlv.bmp', 36h
; sanity check
load a1 word from 0
load a2 dword from 0xE
if (a1 <> 'BM') | (a2 <> 0x28)
error 'conscrlv.bmp: not BMP file!'
end if
load con.vscroll_width dword from 0x12
load con.vscroll_height dword from 0x16
load a1 dword from 0x1A
if a1 <> 0x180001
error 'conscrlv.bmp: must be 24-bit bitmap!'
end if
end virtual
con.vscroll_btn_height = 21
con.vscroll_bgr_height = 2
con.vscroll_bar_height1 = 2
con.vscroll_bar_height2 = 1
con.vscroll_bar_height3 = 2
if con.vscroll_btn_height*4 + con.vscroll_bgr_height*2 \
+ con.vscroll_bar_height1 + con.vscroll_bar_height2 + con.vscroll_bar_height3 \
<> con.vscroll_height
error 'conscrlv.bmp: invalid dimensions!'
end if
; ‡ £à㦠¥¬ ¤ ­­ë¥ BMP, ­  室㠯८¡à §ãï ¨å ¢ ¤ ­­ë¥ ¤«ï 7-© ä㭪樨
con.vscroll:
repeat con.vscroll_height
file 'conscrlv.bmp':36h + ((con.vscroll_width*3+3) and not 3)*(con.vscroll_height - %),\
con.vscroll_width*3
end repeat
con.vscroll_btn1 = con.vscroll
con.vscroll_btn2 = con.vscroll + con.vscroll_btn_height*con.vscroll_width*3
con.vscroll_btn3 = con.vscroll + 2*con.vscroll_btn_height*con.vscroll_width*3
con.vscroll_btn4 = con.vscroll + 3*con.vscroll_btn_height*con.vscroll_width*3
con.vscroll_bgr1 = con.vscroll + 4*con.vscroll_btn_height*con.vscroll_width*3
con.vscroll_bgr2 = con.vscroll_bgr1 + con.vscroll_bgr_height*con.vscroll_width*3
con.vscroll_bar1 = con.vscroll_bgr2 + con.vscroll_bgr_height*con.vscroll_width*3
con.vscroll_bar2 = con.vscroll_bar1 + con.vscroll_bar_height1*con.vscroll_width*3
con.vscroll_bar3 = con.vscroll_bar2 + con.vscroll_bar_height2*con.vscroll_width*3

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
console.obj exports the following functions
typedef unsigned long dword; /* 32-bit unsigned integer */
typedef unsigned short word; /* 16-bit unsigned integer */
void __stdcall con_init(dword wnd_width, dword wnd_height,
dword scr_width, dword scr_height, const char* title);
Console initialization. Must be called only once.
wnd_width, wnd_height - width and height (in units of characters) of the visible region;
scr_width, scr_height - width and height (in units of characters) of console;
Any of these four parameters can be set to -1 (=0xFFFFFFFF)
to use the library's default values;
title - console window's caption.
void __stdcall con_exit(bool bCloseWindow);
You should call this funstion at the end of the program.
If bCloseWindow is zero, the string "[Finished]" will be added to the caption of the window
and the console window will remain on the screen until the user
closes it.
void __stdcall con_set_title(const char* title);
Set new window caption.
void __stdcall con_write_asciiz(const char* string);
Display ASCIIZ-string to the console at the current position, shifting
the current position.
void __stdcall con_write_string(const char* string, dword length);
Similar to con_write_asciiz, but length of the string must be given as a separate parameter
int __cdecl con_printf(const char* format, ...)
Standard "printf" function from ANSI C.
dword __stdcall con_get_flags(void);
Get output flags.
dword __stdcall con_set_flags(dword new_flags);
Set output flags. This function returns previous values.
Flags (bitmask):
/* text color */
#define CON_COLOR_BLUE 0x01
#define CON_COLOR_GREEN 0x02
#define CON_COLOR_RED 0x04
#define CON_COLOR_BRIGHT 0x08
/* background color */
#define CON_BGR_BLUE 0x10
#define CON_BGR_GREEN 0x20
#define CON_BGR_RED 0x40
#define CON_BGR_BRIGHT 0x80
/* output controls */
#define CON_IGNORE_SPECIALS 0x100
/* if this flag is cleared, function interprets special characters:
10 ('\n') - next line
13 ('\r') - carriage return
8 ('\b') - backspace
9 ('\t') - tab
27 ('\033' = '\x1B') - the beginning of Esc-sequences;
otherwise, these characters will be displayed like ordinary characters. */
/* Supported Esc-sequences:
Esc[<number1>;<number2>;<number3>m - choice of character attributes:
You can specify one, two or three codes in any order;
0 = normal mode (white on black)
1 = bright selection
5 = bright background
7 = inverse mode (black on white)
30 = black characters
31 = red characters
32 = green characters
33 = brown characters
34 = blue characters
35 = purple characters
36 = turqoise characters
37 = white characters
40 = black background
41 = red background
42 = green background
43 = brown background
44 = blue background
45 = purple background
46 = turqoise background
47 = white background
The following sequences appeared in version 5 of library:
Esc[2J - clear screen, move cursor to upper left corner
Esc[<number1>;<number2>H = Esc[<number1>;<number2>f -
move cursor to <number1>,<number2>
Esc[<number>A - move cursor to <number> lines up
Esc[<number>B - move cursor to <number> lines down
Esc[<number>C - move cursor to <number> positions right
Esc[<number>D - move cursor to <number> positions left
*/
/* signal "console closed"; appeared in version 6;
ignored by con_set_flags */
#define CON_WINDOW_CLOSED 0x200
The default value for flags = 7. (grey text on black background)
int __stdcall con_get_font_height(void);
Get the height of the font.
int __stdcall con_get_cursor_height(void);
Get the height of the cursor.
int __stdcall con_set_cursor_height(int new_height);
Set the height of the cursor. This function returns previous value.
An attempt to set the value out of the correct interval (from 0 to
font_height-1) is ignored.
Cursor with zero height isn't displayed.
Default value: - 15% from font height.
int __stdcall con_getch(void);
Get one character from the keyboard.
For normal characters function returns ASCII-code. For extended
characters (eg, Fx, and arrows), first function call returns 0
and second call returns the extended code (similar to the DOS-function
input). Starting from version 7, after closing the console window,
this function returns 0.
word __stdcall con_getch2(void);
Reads a character from the keyboard. Low byte contains the ASCII-code
(0 for extended characters), high byte - advanced code (like in BIOS
input functions). Starting from version 7, after closing the console
window, this function returns 0.
int __stdcall con_kbhit(void);
Returns 1 if a key was pressed, 0 otherwise. To read pressed keys use
con_getch and con_getch2. Starting from version 6, after closing
the console window, this function returns 1.
char* __stdcall con_gets(char* str, int n);
Reads a string from the keyboard. Reading is interrupted when got
"new line" character, or after reading the (n-1) characters (depending on
what comes first). In the first case the newline is also recorded in the
str. The acquired line is complemented by a null character.
Starting from version 6, the function returns a pointer to the entered
line if reading was successful, and NULL if the console window was closed.
typedef int (__stdcall * con_gets2_callback)(int keycode, char** pstr, int* pn, int* ppos);
char* __stdcall con_gets2(con_gets2_callback callback, char* str, int n);
Con_gets completely analogous, except that when the user
press unrecognized key, it calls the specified callback-procedure
(which may, for example, handle up / down for history and tab to enter
autocompletion). You should pass to the procedure: key code and three pointers
- to the string, to the maximum length and to the current position.
function may change the contents of string and may change the string
itself (for example, to reallocate memory for increase the limit),
maximum length, and position of the line - pointers are passed for it.
Return value: 0 = line wasn't changed 1 = line changed, you should
remove old string and display new, 2 = line changed, it is necessary
to display it; 3 = immediately exit the function.
Starting from version 6, the function returns a pointer to the entered
line with the successful reading, and NULL if the console window was closed.
void __stdcall con_cls();
Clear screen and set cursor at upper left corner.
void __stdcall con_get_cursor_pos(int* px, int* py);
Wrote current (x) coordinate of cursor to *px, and (y) to *py.
void __stdcall con_set_cursor_pos(int x, int y);
Set the cursor position to the specified coordinates. If any of the
parameters beyond the relevant range (from 0 to 1 scr_width-
for x, from 0 to 1 for scr_height-y, scr_width scr_height and were asked if
call con_init), then the corresponding coordinate of the cursor does not change.

View File

@ -0,0 +1,165 @@
console.obj экспортирует следующие функции:
typedef unsigned long dword; /* 32-битное беззнаковое целое */
typedef unsigned short word; /* 16-битное беззнаковое целое */
void __stdcall con_init(dword wnd_width, dword wnd_height,
dword scr_width, dword scr_height, const char* title);
Инициализация консоли. Вызывается один раз в начале программы.
wnd_width, wnd_height - высота и ширина (в символах) видимой в окне консоли
области;
scr_width, scr_height - высота и ширина (в символах) всей консоли;
любые из первых 4 параметров могут быть установлены в -1 (=0xFFFFFFFF)
- использовать значения по умолчанию;
title - заголовок окна консоли.
void __stdcall con_exit(bool bCloseWindow);
Вызывается при завершении программы. Если (байтовый) параметр bCloseWindow
нулевой, то окно консоли остаётся на экране до того момента, как пользователь
пожелает закрыть его, при этом к заголовку добавляется строка " [Finished]".
void __stdcall con_set_title(const char* title);
Устанавливает новый заголовок окна консоли.
void __stdcall con_write_asciiz(const char* string);
Выводит ASCIIZ-строку в консоль в текущую позицию, продвигает текущую позицию.
void __stdcall con_write_string(const char* string, dword length);
Аналогично con_write_asciiz, но выводит ровно length символов.
int __cdecl con_printf(const char* format, ...)
Стандартная printf из ANSI C.
dword __stdcall con_get_flags(void);
Получает значение флагов вывода.
dword __stdcall con_set_flags(dword new_flags);
Устанавливает значение флагов вывода. Возвращает старое значение.
Флаги (битовая маска):
/* цвет текста */
#define CON_COLOR_BLUE 1
#define CON_COLOR_GREEN 2
#define CON_COLOR_RED 4
#define CON_COLOR_BRIGHT 8
/* цвет фона */
#define CON_BGR_BLUE 0x10
#define CON_BGR_GREEN 0x20
#define CON_BGR_RED 0x40
#define CON_BGR_BRIGHT 0x80
/* управление выводом */
#define CON_IGNORE_SPECIALS 0x100
/* Если флаг сброшен, функция интерпретирует специальные символы:
10 ('\n') - перевод в начало следующей строки
13 ('\r') - перевод в начало текущей строки
8 ('\b') - забой (на символ назад)
9 ('\t') - табуляция
27 ('\033'='\x1B') - начало Esc-последовательности;
иначе выводит их как обычные символы. */
/* Поддерживаемые Esc-последовательности:
Esc[<number1>;<number2>;<number3>m - выбор атрибутов символов:
можно указывать один, два или три кода в любом порядке;
0 = нормальное изображение (белые символы на чёрном фоне)
1 = выделение яркостью
5 = яркий фон
7 = реверсное изображение (чёрные символы на белом фоне)
30 = чёрные символы
31 = красные символы
32 = зелёные символы
33 = коричневые символы
34 = синие символы
35 = фиолетовые символы
36 = бирюзовые символы
37 = белые символы
40 = чёрный фон
41 = красный фон
42 = зелёный фон
43 = коричневый фон
44 = синий фон
45 = фиолетовый фон
46 = бирюзовый фон
47 = белый фон
Следующие последовательности появились в версии 5 библиотеки:
Esc[2J - очистить экран, переместить курсор в левый верхний угол
Esc[<number1>;<number2>H = Esc[<number1>;<number2>f -
установить курсор в позицию с координатами <number1>,<number2>
Esc[<number>A - переместить курсор на <number> строк вверх
Esc[<number>B - переместить курсор на <number> строк вниз
Esc[<number>C - переместить курсор на <number> позиций вправо
Esc[<number>D - переместить курсор на <number> позиций влево
*/
/* сигнал о закрытии окна консоли; появился в версии 6 библиотеки;
флаг игнорируется функцией con_set_flags */
#define CON_WINDOW_CLOSED 0x200
Значение по умолчанию для флагов = 7.
int __stdcall con_get_font_height(void);
Возвращает значение высоты шрифта.
int __stdcall con_get_cursor_height(void);
Получает значение высоты курсора.
int __stdcall con_set_cursor_height(int new_height);
Устанавливает значение высоты курсора. Возвращает старое значение.
Попытка установить значение вне корректного интервала (от 0 до font_height-1)
игнорируется.
Курсор высоты 0 не отображается на экране.
Значение высоты по умолчанию - 15% от высоты шрифта.
int __stdcall con_getch(void);
Считывает один символ с клавиатуры.
Для обычных символов возвращается ASCII-код. Для расширенных символов
(например, Fx и стрелочек) первый вызов функции возвращает 0,
а повторный вызов возвращает расширенный код (подобно DOS-функциям ввода).
Начиная с версии 7 библиотеки, после закрытия окна консоли возвращается
значение 0.
word __stdcall con_getch2(void);
Считывает один символ с клавиатуры. Младший байт содержит ASCII-код клавиши
(0 для расширенных символов), старший - расширенный код
(подобно BIOS-функциям ввода).
Начиная с версии 7 библиотеки, после закрытия окна консоли возвращается
значение 0.
int __stdcall con_kbhit(void);
Возвращает 1, если какая-то клавиша была нажата, 0 иначе. Для считывания
нажатой клавиши предназначены функции con_getch и con_getch2.
Начиная с версии 6 библиотеки, после закрытия окна консоли всегда возвращает 1.
char* __stdcall con_gets(char* str, int n);
Считывает строку с клавиатуры. Ввод прерывается при поступлении символа
новой строки, а также по прочтении n-1 символа (в зависимости от того, что
произойдёт раньше). В первом случае символ новой строки также записывается в
str. Считанная строка дополняется нулевым символом.
Начиная с версии 6 библиотеки, функция возвращает указатель на введённую
строку при успешном чтении и NULL, если окно консоли было закрыто. До версии
6 возвращаемое значение было неопределено.
typedef int (__stdcall * con_gets2_callback)(int keycode, char** pstr, int* pn, int* ppos);
char* __stdcall con_gets2(con_gets2_callback callback, char* str, int n);
Функция появилась в версии 4 библиотеки.
Полностью аналогична con_gets за исключением того, что когда пользователь
нажимает нераспознанную клавишу, вызывается указанная callback-процедура
(которая может, например, обрабатывать up/down для истории ввода и tab для
автодополнения). Процедуре передаётся код клавиши и три указателя - на строку,
на лимит и на текущую позицию в строке. Процедура может менять содержимое
строки и может менять саму строку (например, перераспределить память для
увеличения лимита), лимит, позицию в строке - для этого и передаются указатели.
Возвращаемое значение: 0=строка не менялась; 1=строка изменилась, необходимо
удалить старую и вывести новую; 2=строка изменилась, необходимо её вывести;
3=немедленно выйти из функции.
Начиная с версии 6 библиотеки, функция возвращает указатель на введённую
строку при успешном чтении и NULL, если окно консоли было закрыто. До версии
6 возвращаемое значение было неопределено.
void __stdcall con_cls();
Функция появилась в версии 5 библиотеки.
Очищает экран и переводит курсор в левый верхний угол.
void __stdcall con_get_cursor_pos(int* px, int* py);
Функция появилась в версии 5 библиотеки.
Записывает в *px текущую координату курсора по оси x, в *py - по оси y.
void __stdcall con_set_cursor_pos(int x, int y);
Функция появилась в версии 5 библиотеки.
Устанавливает курсор в позицию с указанными координатами. Если какой-то из
параметров выходит за пределы соответствующего диапазона (от 0 до scr_width-1
для x, от 0 до scr_height-1 для y, scr_width и scr_height были заданы при
вызове con_init), то соответствующая координата курсора не меняется.

View File

@ -0,0 +1,2 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.foreach_rule("*.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "%B")

View File

@ -0,0 +1,268 @@
; Macroinstructions for defining and calling procedures
macro stdcall proc,[arg] ; directly call STDCALL procedure
{ common
if ~ arg eq
reverse
pushd arg
common
end if
call proc }
macro invoke proc,[arg] ; indirectly call STDCALL procedure
{ common
if ~ arg eq
reverse
pushd arg
common
end if
call [proc] }
macro ccall proc,[arg] ; directly call CDECL procedure
{ common
size@ccall = 0
if ~ arg eq
reverse
pushd arg
size@ccall = size@ccall+4
common
end if
call proc
if size@ccall
add esp,size@ccall
end if }
macro cinvoke proc,[arg] ; indirectly call CDECL procedure
{ common
size@ccall = 0
if ~ arg eq
reverse
pushd arg
size@ccall = size@ccall+4
common
end if
call [proc]
if size@ccall
add esp,size@ccall
end if }
macro proc [args] ; define procedure
{ common
match name params, args>
\{ define@proc name,<params \} }
prologue@proc equ prologuedef
macro prologuedef procname,flag,parmbytes,localbytes,reglist
{ if parmbytes | localbytes
push ebp
mov ebp,esp
if localbytes
sub esp,localbytes
end if
end if
irps reg, reglist \{ push reg \} }
epilogue@proc equ epiloguedef
macro epiloguedef procname,flag,parmbytes,localbytes,reglist
{ irps reg, reglist \{ reverse pop reg \}
if parmbytes | localbytes
leave
end if
if flag and 10000b
retn
else
retn parmbytes
end if }
macro define@proc name,statement
{ local params,flag,regs,parmbytes,localbytes,current
if used name
name:
match =stdcall args, statement \{ params equ args
flag = 11b \}
match =stdcall, statement \{ params equ
flag = 11b \}
match =c args, statement \{ params equ args
flag = 10001b \}
match =c, statement \{ params equ
flag = 10001b \}
match =params, params \{ params equ statement
flag = 0 \}
virtual at ebp+8
match =uses reglist=,args, params \{ regs equ reglist
params equ args \}
match =regs =uses reglist, regs params \{ regs equ reglist
params equ \}
match =regs, regs \{ regs equ \}
match =,args, params \{ defargs@proc args \}
match =args@proc args, args@proc params \{ defargs@proc args \}
parmbytes = $ - (ebp+8)
end virtual
name # % = parmbytes/4
all@vars equ
current = 0
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \}
macro locals
\{ virtual at ebp-localbytes+current
macro label . \\{ deflocal@proc .,:, \\}
struc db [val] \\{ \common deflocal@proc .,db,val \\}
struc dw [val] \\{ \common deflocal@proc .,dw,val \\}
struc dp [val] \\{ \common deflocal@proc .,dp,val \\}
struc dd [val] \\{ \common deflocal@proc .,dd,val \\}
struc dt [val] \\{ \common deflocal@proc .,dt,val \\}
struc dq [val] \\{ \common deflocal@proc .,dq,val \\}
struc rb cnt \\{ deflocal@proc .,rb cnt, \\}
struc rw cnt \\{ deflocal@proc .,rw cnt, \\}
struc rp cnt \\{ deflocal@proc .,rp cnt, \\}
struc rd cnt \\{ deflocal@proc .,rd cnt, \\}
struc rt cnt \\{ deflocal@proc .,rt cnt, \\}
struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \}
macro endl
\{ purge label
restruc db,dw,dp,dd,dt,dq
restruc rb,rw,rp,rd,rt,rq
restruc byte,word,dword,pword,tword,qword
current = $-(ebp-localbytes)
end virtual \}
macro ret operand
\{ match any, operand \\{ retn operand \\}
match , operand \\{ match epilogue:reglist, epilogue@proc:<regs>
\\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \}
macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2
end if \} }
macro defargs@proc [arg]
{ common
if ~ arg eq
forward
local ..arg,current@arg
match argname:type, arg
\{ current@arg equ argname
label ..arg type
argname equ ..arg
if dqword eq type
dd ?,?,?,?
else if tbyte eq type
dd ?,?,?
else if qword eq type | pword eq type
dd ?,?
else
dd ?
end if \}
match =current@arg,current@arg
\{ current@arg equ arg
arg equ ..arg
..arg dd ? \}
common
args@proc equ current@arg
forward
restore current@arg
common
end if }
macro deflocal@proc name,def,[val]
{ common
match vars, all@vars \{ all@vars equ all@vars, \}
all@vars equ all@vars name
forward
local ..var,..tmp
..var def val
match =?, val \{ ..tmp equ \}
match any =dup (=?), val \{ ..tmp equ \}
match tmp : value, ..tmp : val
\{ tmp: end virtual
initlocal@proc ..var,def value
virtual at tmp\}
common
match first rest, ..var, \{ name equ first \} }
macro initlocal@proc name,def
{ virtual at name
def
size@initlocal = $ - name
end virtual
position@initlocal = 0
while size@initlocal > position@initlocal
virtual at name
def
if size@initlocal - position@initlocal < 2
current@initlocal = 1
load byte@initlocal byte from name+position@initlocal
else if size@initlocal - position@initlocal < 4
current@initlocal = 2
load word@initlocal word from name+position@initlocal
else
current@initlocal = 4
load dword@initlocal dword from name+position@initlocal
end if
end virtual
if current@initlocal = 1
mov byte [name+position@initlocal],byte@initlocal
else if current@initlocal = 2
mov word [name+position@initlocal],word@initlocal
else
mov dword [name+position@initlocal],dword@initlocal
end if
position@initlocal = position@initlocal + current@initlocal
end while }
macro endp
{ purge ret,locals,endl
finish@proc
purge finish@proc
restore regs@proc
match all,args@proc \{ restore all \}
restore args@proc
match all,all@vars \{ restore all \} }
macro local [var]
{ common
locals
forward done@local equ
match varname[count]:vartype, var
\{ match =BYTE, vartype \\{ varname rb count
restore done@local \\}
match =WORD, vartype \\{ varname rw count
restore done@local \\}
match =DWORD, vartype \\{ varname rd count
restore done@local \\}
match =PWORD, vartype \\{ varname rp count
restore done@local \\}
match =QWORD, vartype \\{ varname rq count
restore done@local \\}
match =TBYTE, vartype \\{ varname rt count
restore done@local \\}
match =DQWORD, vartype \\{ label varname dqword
rq count+count
restore done@local \\}
match , done@local \\{ virtual
varname vartype
end virtual
rb count*sizeof.\#vartype
restore done@local \\} \}
match :varname:vartype, done@local:var
\{ match =BYTE, vartype \\{ varname db ?
restore done@local \\}
match =WORD, vartype \\{ varname dw ?
restore done@local \\}
match =DWORD, vartype \\{ varname dd ?
restore done@local \\}
match =PWORD, vartype \\{ varname dp ?
restore done@local \\}
match =QWORD, vartype \\{ varname dq ?
restore done@local \\}
match =TBYTE, vartype \\{ varname dt ?
restore done@local \\}
match =DQWORD, vartype \\{ label varname dqword
dq ?,?
restore done@local \\}
match , done@local \\{ varname vartype
restore done@local \\} \}
match ,done@local
\{ var
restore done@local \}
common
endl }

View File

@ -0,0 +1,168 @@
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 3
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 (getch() demo in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
; C-equivalent of the following code:
; con_printf(start_string);
; int c;
; while ((c=con_getch())!=27) // Esc=exit
; {
; if (c)
; con_printf("normal character with code %d=0x%02X\n",c,c);
; else
; {
; c=con_getch();
; con_printf("extended character with code %d=0x%02X\n",c,c);
; }
; }
push start_string
call [con_printf]
pop ecx
mainloop:
call [con_getch]
cmp al, 27
jz done
test eax, eax
jz extended
push eax
push eax
push string_normal
@@:
call [con_printf]
add esp, 12
jmp mainloop
extended:
call [con_getch]
test eax, eax
jz done
push eax
push eax
push string_extended
jmp @b
done:
push 1
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_printf dd szcon_printf
con_exit dd szcon_exit
con_getch dd szcon_getch
dd 0
szStart db 'START',0
szVersion db 'version',0
szcon_init db 'con_init',0
szcon_printf db 'con_printf',0
szcon_exit db 'con_exit',0
szcon_getch db 'con_getch',0
dllname db '/sys/lib/console.obj',0
caption db 'Console test - getch()',0
start_string db 'Press any key to see its code, or Esc to exit',10,0
string_normal db 'normal character with code %d=0x%02X',10,0
string_extended db 'extended character with code %d=0x%02X',10,0
i_end:
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,156 @@
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 3
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 (gets() demo in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
; C-equivalent of the following code:
; for (;;)
; {
; con_write_asciiz("Enter string (empty for exit): ");
; if (!con_gets(s,256)) break;
; if (s[0] == '\n') break;
; con_write_asciiz("You entered: ");
; con_write_asciiz(s);
; }
mainloop:
push str1
call [con_write_asciiz]
push 256
push s
call [con_gets]
test eax, eax
jz done
cmp [s], 10
jz done
push str2
call [con_write_asciiz]
push s
call [con_write_asciiz]
jmp mainloop
done:
push 1
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_exit dd szcon_exit
con_gets dd szcon_gets
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_exit db 'con_exit',0
szcon_gets db 'con_gets',0
dllname db '/sys/lib/console.obj',0
caption db 'Console test - gets()',0
str1 db 'Enter string (empty for exit): ',0
str2 db 'You entered: ',0
i_end:
s rb 256
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,255 @@
include 'proc32.inc'
DLL_ENTRY equ 1
DLL_EXIT equ -1
REQ_DLL_VER equ 4
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 (gets2() demo in this case).
push caption
push 25
push 80
push 25
push 80
call [con_init]
; C-equivalent of the following code:
; for (;;)
; {
; con_write_asciiz("Enter string (empty for exit): ");
; if (!con_gets2(mycallback,s,256)) break;
; if (s[0] == '\n') break;
; con_write_asciiz("You entered: ");
; con_write_asciiz(s);
; }
mainloop:
push str1
call [con_write_asciiz]
push 256
push s
push mycallback
call [con_gets2]
test eax, eax
jz done
cmp [s], 10
jz done
push str2
call [con_write_asciiz]
push s
call [con_write_asciiz]
jmp mainloop
done:
push 1
call [con_exit]
exit:
or eax, -1
int 0x40
proc mycallback stdcall, keycode:dword, pstr:dword, pn:dword, ppos:dword
mov eax, [keycode]
cmp al, 0x0F
jz .tab
cmp al, 0x3B
jz .f1
cmp al, 0x48
jz .up
cmp al, 0x50
jz .down
xor eax, eax
ret
.tab:
; Tab pressed - insert "[autocomplete]" to current position
push esi edi
mov eax, [ppos]
mov eax, [eax]
mov ecx, [pn]
mov ecx, [ecx]
mov esi, [pstr]
mov esi, [esi]
add ecx, esi
add esi, eax
mov edx, esi
@@:
lodsb
test al, al
jnz @b
lea edi, [esi+str3.len]
cmp edi, ecx
jbe @f
mov edi, ecx
lea esi, [edi-str3.len]
@@:
cmp esi, edx
jbe @f
dec esi
dec edi
mov al, [esi]
mov [edi], al
jmp @b
@@:
cmp edi, ecx
jb @f
dec edi
@@:
mov ecx, edi
sub ecx, edx
mov edi, edx
mov esi, str3
rep movsb
mov eax, [pstr]
sub edi, [eax]
mov eax, [ppos]
mov [eax], edi
pop edi esi
xor eax, eax
inc eax
ret
.f1:
; F1 pressed - say message
push str4
call [con_write_asciiz]
push str1
call [con_write_asciiz]
push 2
pop eax
ret
.up:
push esi
mov esi, str5
mov ecx, str5.len
jmp @f
.down:
push esi
mov esi, str6
mov ecx, str6.len
@@:
push edi
mov edi, [pstr]
mov edi, [edi]
mov eax, [ppos]
mov [eax], ecx
rep movsb
xor eax, eax
stosb
pop edi esi
inc eax
ret
endp
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_exit dd szcon_exit
con_gets2 dd szcon_gets2
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_exit db 'con_exit',0
szcon_gets2 db 'con_gets2',0
dllname db '/sys/lib/console.obj',0
caption db 'Console test - gets2()',0
str1 db 'Enter string (empty for exit): ',0
str2 db 'You entered: ',0
str3 db '[autocomplete]'
str3.len = $ - str3
str4 db 13,10,'Help? What help do you need?',13,10,0
str5 db 'previous line in the history'
str5.len = $ - str5
str6 db 'next line in the history'
str6.len = $ - str6
i_end:
s rb 256
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,58 @@
use32
db 'MENUET01'
dd 1
dd start
dd i_end
dd mem
dd mem
dd 0
dd 0
; useful includes
include '../../../../macros.inc'
purge mov,add,sub
include '../../../../proc32.inc'
include '../../../../dll.inc'
start:
; First 3 steps are intended to load/init console DLL
; and are identical for all console programs
; load DLL
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
; yes! Now do some work (say helloworld in this case).
push caption
push -1
push -1
push -1
push -1
call [con_init]
push aHelloWorld
call [con_write_asciiz]
push 0
call [con_exit]
exit:
or eax, -1
int 0x40
caption db 'Console test',0
aHelloWorld db 'Hello, World!',10,0
align 4
@IMPORT:
library console, 'console.obj'
import console, \
con_start, 'START', \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets, 'con_gets'
i_end:
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,161 @@
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:

View File

@ -0,0 +1,161 @@
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 '–¢¥â 0x%02X: ',0
text db '‚®â ¯à¨¬¥à ⥪áâ .',10,0
text2 db 27,'[7m€ íâ® ¯à¨¬¥à ¨á¯®«ì§®¢ ­¨ï '
db 27,'[1;36;41mEsc'
db 27,'[7m-¯®á«¥¤®¢ â¥«ì­®á⥩.',10,0
i_end:
align 4
rb 2048 ; stack
mem:

View File

@ -0,0 +1,48 @@
fontname equ 'font8x16.bmp'
virtual at 0
file fontname, 3Eh
; sanity check
load a1 word from 0
load a2 dword from 0xE
if (a1 <> 'BM') | (a2 <> 0x28)
error 'not BMP file!'
end if
load a1 dword from 0x12
load a2 dword from 0x16
if (a1 and 0xF) | (a2 and 0xF) | (a1 > 16*16)
error 'font: invalid width or height'
end if
font_width = a1 shr 4
font_bmp_scanline = (font_width*2 + 3) and not 3
font_height = a2 shr 4
load a1 dword from 0x1A
if a1 <> 0x10001
error 'font: not monochrome bitmap'
end if
end virtual
font:
repeat font_height
cur_scan = %
repeat 256
virtual at 0
a2 = (font_width+14) shr 3
if cur_scan=1 & %=0x10
a2 = (font_width+7) shr 3
end if
file fontname:3Eh + font_bmp_scanline*(font_height*(16-((%-1) shr 4))-cur_scan) + ((((%-1) and 0xF)*font_width) shr 3), a2
dd 0
load a1 dword from 0
a1 = ((a1 and 0x55555555) shl 1) or ((a1 and 0xAAAAAAAA) shr 1)
a1 = ((a1 and 0x33333333) shl 2) or ((a1 and 0xCCCCCCCC) shr 2)
a1 = ((a1 and 0x0F0F0F0F) shl 4) or ((a1 and 0xF0F0F0F0) shr 4)
end virtual
a1 = (a1 shr (((%-1)*font_width) and 7)) and ((1 shl font_width) - 1)
a1 = a1 xor ((1 shl font_width) - 1)
if font_width > 8
dw a1
else
db a1
end if
end repeat
end repeat

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB