From abf7f61fb00b15535c18177de66af12b2ddb98e0 Mon Sep 17 00:00:00 2001 From: "Evgeny Grechnikov (Diamond)" Date: Tue, 12 Aug 2008 14:46:18 +0000 Subject: [PATCH] console: added gets2() with user callback git-svn-id: svn://kolibrios.org@852 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/libraries/console/build.bat | 4 +- .../develop/libraries/console/console.asm | 133 ++++++++- .../develop/libraries/console/console.txt | 13 + .../libraries/console/examples/test_gets2.asm | 253 ++++++++++++++++++ 4 files changed, 390 insertions(+), 13 deletions(-) create mode 100644 programs/develop/libraries/console/examples/test_gets2.asm diff --git a/programs/develop/libraries/console/build.bat b/programs/develop/libraries/console/build.bat index b29ac6cbc7..c3aab50ae4 100644 --- a/programs/develop/libraries/console/build.bat +++ b/programs/develop/libraries/console/build.bat @@ -1,2 +1,2 @@ -fasm console.asm ..\console.obj -e:\zhenya\program\menuet\kpack\kpack.exe ..\console.obj \ No newline at end of file +fasm console.asm console.obj +kpack.exe console.obj \ No newline at end of file diff --git a/programs/develop/libraries/console/console.asm b/programs/develop/libraries/console/console.asm index 228e880ed0..378c62fbff 100644 --- a/programs/develop/libraries/console/console.asm +++ b/programs/develop/libraries/console/console.asm @@ -1,5 +1,5 @@ ; ”г­ЄжЁЁ а Ў®вл б Є®­б®«мо ¤«п Їа®Ја ¬¬ Љ®«ЁЎаЁЋ‘ -; diamond, 2006, 2007 +; diamond, 2006-2008 format MS COFF @@ -1139,16 +1139,21 @@ con_getch2: ; void __stdcall con_gets(char* str, int n); con_gets: + pop eax + push 0 + push eax +; void __stdcall con_gets2(con_gets2_callback callback, char* str, int n); +con_gets2: pushad - mov esi, [esp+20h+4] ; str - mov ebx, [esp+20h+8] ; n + mov esi, [esp+20h+8] ; str + mov ebx, [esp+20h+12] ; n sub ebx, 1 jle .ret mov byte [esi], 0 xor ecx, ecx ; ¤«Ё­  㦥 ўўҐ¤с­­®© бва®ЄЁ call con.get_data_ptr .loop: - call con_getch + call con_getch2 test al, al jz .extended cmp al, 8 @@ -1157,6 +1162,8 @@ con_gets: jz .esc cmp al, 13 jz .enter + cmp al, 9 + jz .tab inc ecx mov dl, al call con.write_char_ex @@ -1183,6 +1190,7 @@ con_gets: call con.update_screen cmp ecx, ebx jb .loop +.ret_us: mov edx, [con.cur_x] @@: lodsb @@ -1218,7 +1226,7 @@ con_gets: xor ecx, ecx @@: mov byte [esi], 0 - cmp esi, [esp+20h+4] + cmp esi, [esp+20h+8] jbe .update_screen_and_loop mov al, 8 call con.write_special_char @@ -1234,7 +1242,7 @@ con_gets: lodsb call con.write_char_ex .backspace: - cmp esi, [esp+20h+4] + cmp esi, [esp+20h+8] jbe .loop push esi mov edx, [con.cur_x] @@ -1298,8 +1306,11 @@ con_gets: call con.write_special_char call con.update_screen jmp .ret +.tab: + mov al, 0 + mov ah, 0xF .extended: - call con_getch + xchg al, ah cmp al, 0x4B jz .left cmp al, 0x4D @@ -1310,9 +1321,107 @@ con_gets: jz .end cmp al, 0x53 jz .delete +; give control to callback function + cmp dword [esp+20h+4], 0 + jz .loop +; remember length of text before and length of text after +; and advance cursor to the end of line + push ecx + push eax + lea edx, [esi+1] +@@: + lodsb + test al, al + jz @f + call con.write_char_ex + jmp @b +@@: + sub esi, edx + pop eax + push esi + dec edx + sub edx, [esp+28h+8] + push edx + push esp ; ppos + mov ecx, [esp+30h+4] + lea edx, [esp+30h+12] + push edx ; pn + lea edx, [esp+34h+8] + push edx ; pstr + push eax ; keycode + call ecx + call con.get_data_ptr + dec eax + js .callback_nochange + jz .callback_del + dec eax + jz .callback_output +; callback returned 2 - exit + add esp, 12 + jmp .ret +.callback_nochange: +; callback returned 0 - string was not changed, only restore cursor position + pop esi + pop ecx + test ecx, ecx + jz .cncs +@@: + mov al, 8 + call con.write_special_char + loop @b +.cncs: + pop ecx + add esi, [esp+20h+8] + jmp .callback_done +.callback_del: +; callback returned 1 - string was changed, delete old string and output new + mov ecx, [esp+8] + test ecx, ecx + jz .cds +@@: + mov al, 8 + call con.write_special_char + mov al, ' ' + call con.write_char_ex + mov al, 8 + call con.write_special_char + loop @b +.cds: +.callback_output: +; callback returned 2 - string was changed, output new string + pop edx + pop esi + pop ecx + mov esi, [esp+20h+8] + xor ecx, ecx +@@: + lodsb + test al, al + jz @f + call con.write_char_ex + inc ecx + jmp @b +@@: + dec esi + push ecx + sub ecx, edx + jz .cos +@@: + mov al, 8 + call con.write_special_char + dec esi + loop @b +.cos: + pop ecx +.callback_done: + call con.update_screen + mov ebx, [esp+20h+12] + dec ebx + cmp ecx, ebx + jae .ret_us jmp .loop .left: - cmp esi, [esp+20h+4] + cmp esi, [esp+20h+8] jbe .loop dec esi mov al, 8 @@ -1325,7 +1434,7 @@ con_gets: call con.write_char_ex jmp .update_screen_and_loop .home: - cmp esi, [esp+20h+4] + cmp esi, [esp+20h+8] jz .update_screen_and_loop dec esi mov al, 8 @@ -1342,7 +1451,7 @@ con_gets: jmp .update_screen_and_loop .ret: popad - ret 8 + ret 12 con.update_screen: push eax @@ -2018,7 +2127,7 @@ con.vscroll_pt dd -1 align 16 EXPORTS: dd szStart, START - dd szVersion, 0x00020003 + dd szVersion, 0x00020004 dd szcon_init, con_init dd szcon_write_asciiz, con_write_asciiz dd szcon_printf, con_printf @@ -2029,6 +2138,7 @@ EXPORTS: 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 @@ -2061,6 +2171,7 @@ 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 diff --git a/programs/develop/libraries/console/console.txt b/programs/develop/libraries/console/console.txt index 70ac5cf62f..f7d8d38cc1 100644 --- a/programs/develop/libraries/console/console.txt +++ b/programs/develop/libraries/console/console.txt @@ -112,3 +112,16 @@ void __stdcall con_gets(char* str, int n); новой строки, а также по прочтении n-1 символа (в зависимости от того, что произойдёт раньше). В первом случае символ новой строки также записывается в str. Считанная строка дополняется нулевым символом. + +typedef int (__stdcall * con_gets2_callback)(int keycode, char** pstr, int* pn, int* ppos); +void __stdcall con_gets2(con_gets2_callback callback, char* str, int n); +Полностью аналогична con_gets за исключением того, что когда пользователь +нажимает нераспознанную клавишу, вызывается указанная callback-процедура +(которая может, например, обрабатывать up/down для истории ввода и tab для +автодополнения). Процедуре передаётся код клавиши и три указателя - на строку, +на лимит и на текущую позицию в строке. Процедура может менять содержимое +строки и может менять саму строку (например, перераспределить память для +увеличения лимита), лимит, позицию в строке - для этого и передаются указатели. +Возвращаемое значение: 0=строка не менялась; 1=строка изменилась, необходимо +удалить старую и вывести новую; 2=строка изменилась, необходимо её вывести; +3=немедленно выйти из функции. diff --git a/programs/develop/libraries/console/examples/test_gets2.asm b/programs/develop/libraries/console/examples/test_gets2.asm new file mode 100644 index 0000000000..161cf296ad --- /dev/null +++ b/programs/develop/libraries/console/examples/test_gets2.asm @@ -0,0 +1,253 @@ + +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 -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): "); +; con_gets2(mycallback,s,256); +; 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] + 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: