forked from KolibriOS/kolibrios
dll.obj: Added error handling with detailed inform user which error occurred through @notyfy
git-svn-id: svn://kolibrios.org@9669 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
254d30c075
commit
803d2a454e
@ -2,26 +2,28 @@
|
||||
---
|
||||
History
|
||||
|
||||
0.1 + First realised, kernel load dll.obj at runtime as starting point berfore app startup
|
||||
dll.obj process app import table, but not depended librarys, after that app gots control in his starting point
|
||||
0.1 + First realised, kernel load dll.obj at runtime as starting point berfore app startup
|
||||
dll.obj process app import table, but not depended librarys, after that app gots control in his starting point
|
||||
|
||||
0.2 + Introduced new KX header as extension for current format (see decription below)
|
||||
+ Add KX header processing
|
||||
+ Improved import table test logic, no reason to kill app for import absence - skip import processing (tnx ProMiNick)
|
||||
+ Added ReadMe.txt (this doc)
|
||||
|
||||
0.2.1 + Branch from dll.inc, now this file is not external. Improved error handling. Now dll.Load return 0 in success only
|
||||
Added corrsponding error codes if one of library or entry not found
|
||||
+ Added error handling with detailed inform user which error occurred through @notyfy.
|
||||
Now application is not crashed if bad format, can't load library or no found entry
|
||||
|
||||
0.2 + Introduced new KX header as extension for current format (see decription below)
|
||||
+ Add KX header processing
|
||||
+ Improved import table test logic, no reason to kill app for import absence - skip import processing (tnx ProMiNick)
|
||||
|
||||
---
|
||||
Purpose
|
||||
|
||||
Automatically libraries loads and linking imports.
|
||||
|
||||
---
|
||||
Limitations
|
||||
TODO
|
||||
|
||||
|
||||
1) No error messages are issued if the library or symbol in the library is not found or somthing went wrong
|
||||
|
||||
|
||||
2) There is no autoloading of dependent libraries (the library format needs to be improved, see intorduction of KX header extension bellow)
|
||||
1) The library format needs to be improved, see intorduction of KX header extension bellow
|
||||
|
||||
---
|
||||
How to use
|
||||
@ -30,7 +32,7 @@ How to use
|
||||
1) In the version field of a header, (after MENUET0x) you must specify the number 2
|
||||
2) After existing header add KX header extension as descriprion bellow
|
||||
3) Specify imported libraries. Currentry format of import table same as in case of using dll.Load
|
||||
4) Add code, without connecting dll.inc and, accordingly, without calling dll.Load. The heap initialization function (f. 68.11) does not need to be called either.
|
||||
4) Add code, without connecting dll.inc and, accordingly, without calling dll.Load. The heap initialization function (f. 68.11) does not need to be called either.
|
||||
|
||||
5) Compile the app and run. If everything is done correctly, then on startup the debug board will display the message "App header version 2"
|
||||
If the DLL.OBJ library is missing, a message will be displayed, incl. via @NOTIFY. If you get a page error make sure you have completed steps 2 and 3
|
||||
@ -55,7 +57,7 @@ Fields between offset 8 and at end of KX header may be added later.
|
||||
|
||||
0 2 SigMagic Module identifier with the value "KX"
|
||||
|
||||
2 1 SigRevision This field should be 0.
|
||||
2 1 SigRevision This field should be 0.
|
||||
In the future, it can take on the revision value
|
||||
(but can't take values higher than 64)
|
||||
|
||||
|
@ -1,25 +1,35 @@
|
||||
;
|
||||
; KolibriOS Dll load support
|
||||
; Support for Dll auto load & linking
|
||||
;
|
||||
; (C) 2020-2021 Coldy
|
||||
; (C) 2020-2022 Coldy
|
||||
; Thank's you for use this code and software based on it!
|
||||
; I will glad if it's will be helpful.
|
||||
;
|
||||
; Distributed under terms of GPL
|
||||
;
|
||||
|
||||
format MS COFF
|
||||
public @EXPORT as 'EXPORTS'
|
||||
|
||||
include '../../../proc32.inc'
|
||||
include '../../../macros.inc'
|
||||
|
||||
section '.flat' code readable align 16
|
||||
|
||||
include 'external.inc'
|
||||
include 'dll.inc'
|
||||
|
||||
; This need for @notyfy pre/postformat
|
||||
STR_BUILD_OFFSET = 1
|
||||
STR_BUILD_EXTRA = 5
|
||||
|
||||
mem_alloc = mem.Alloc
|
||||
|
||||
include 'strhlp.inc'
|
||||
|
||||
app_version equ word[8]
|
||||
i_table_min_size = 1
|
||||
|
||||
sizeof.kx_header = 8
|
||||
|
||||
ERROR_BAD_IMAGE = 0x010
|
||||
|
||||
APP_STARTUP_THUNK:
|
||||
; First make shure that app
|
||||
; have header version 2.0 or more
|
||||
@ -41,10 +51,10 @@ APP_STARTUP_THUNK:
|
||||
mov esi,0x24
|
||||
lodsw
|
||||
cmp ax, 'KX'
|
||||
jne @f ; Not KX
|
||||
jne .image_error ; Not KX
|
||||
lodsw
|
||||
cmp ax, 0
|
||||
jne @f ; Bad magic
|
||||
jne .image_error ; Bad magic
|
||||
lodsw
|
||||
|
||||
bt ax, 6 ; Have import?
|
||||
@ -54,22 +64,22 @@ APP_STARTUP_THUNK:
|
||||
; Test import table (use legacy style)
|
||||
mov eax, [sizeof.kx_header + 0x24] ; i_table_ptr
|
||||
test eax, eax
|
||||
jz .app_start ; i_table_ptr = 0 ?
|
||||
jz .image_error;.import_error;.app_start ; i_table_ptr = 0 ? => Bad image
|
||||
;js .error
|
||||
mov esi, [0x10]
|
||||
cmp esi, eax
|
||||
jbe @f ; i_table_ptr >= img_size ?
|
||||
jbe .image_error;@f ; i_table_ptr >= img_size ?
|
||||
mov ebx, eax
|
||||
add ebx, i_table_min_size
|
||||
cmp esi, ebx
|
||||
jb @f ; i_table_ptr + i_table_min_size > img_size ?
|
||||
jb .image_error;@f ; i_table_ptr + i_table_min_size > img_size ?
|
||||
|
||||
; Link app/dependent libs import tables with libs export table
|
||||
; TODO: need revision of the exists lib format and dll.Load (for libs import binds)
|
||||
|
||||
stdcall dll.Load,eax
|
||||
test eax, eax
|
||||
jnz .import_error
|
||||
jnz .link_error;.import_error
|
||||
.app_start:
|
||||
; Start of app code
|
||||
mov eax, [0x0C]
|
||||
@ -78,9 +88,11 @@ APP_STARTUP_THUNK:
|
||||
@@:
|
||||
mov eax, -1
|
||||
int 0x40
|
||||
.import_error:
|
||||
; Run @NOTIFY and tell user then error occured
|
||||
; BOARD will contaits details
|
||||
.image_error:
|
||||
mov eax, ERROR_BAD_IMAGE
|
||||
.link_error:
|
||||
; Run @NOTIFY and tell user then error occurred
|
||||
call show_error
|
||||
jmp @b
|
||||
.denied:
|
||||
; Kolibri has no ability kill app if this enter from no from main thread
|
||||
@ -90,13 +102,98 @@ APP_STARTUP_THUNK:
|
||||
; } APP_STARTUP_THUNK
|
||||
|
||||
|
||||
; WARNING! This code must be after app initialization thunk!
|
||||
include '../../../dll.inc'
|
||||
; eax = error code (see ERROR_xxx above in this and dll.inc files)
|
||||
|
||||
show_error:
|
||||
|
||||
; Store error code
|
||||
mov edx, eax
|
||||
|
||||
; Get app name
|
||||
sub esp,1024
|
||||
mov eax, 9
|
||||
mov ebx, esp
|
||||
mov ecx, -1
|
||||
int 0x40
|
||||
|
||||
;
|
||||
|
||||
mov esi, esp
|
||||
add esi, 10 ; esi = app name
|
||||
|
||||
|
||||
cmp edx, ERROR_ENTRY_NOT_FOUND
|
||||
je .entry_not_found
|
||||
|
||||
; Init heap not needed
|
||||
; (kernel already initialized heap implicitly when load dll.obj)
|
||||
|
||||
cmp edx, ERROR_LIBRARY_NOT_LOAD
|
||||
je .library_not_loaded
|
||||
|
||||
ccall str_build, szWrongFormat, esi, szBanner
|
||||
jmp @f
|
||||
|
||||
.library_not_loaded:
|
||||
ccall str_build, szLibraryNotLoaded, esi, szBanner, s_libdir.fname
|
||||
jmp @f
|
||||
|
||||
.entry_not_found:
|
||||
mov eax, [szEntryName]
|
||||
ccall str_build, szEntryNotFound, esi, szBanner, eax, s_libdir.fname
|
||||
|
||||
@@:
|
||||
add esp, 1024
|
||||
|
||||
mov byte[eax],'"'
|
||||
mov byte[edi],'"'
|
||||
mov dword[edi+1],"-tdE" ; with title, disable autoclose, error icon
|
||||
|
||||
mov esi, eax
|
||||
|
||||
; Display error
|
||||
mov [pNotify.params], eax
|
||||
mov ebx, pNotify
|
||||
mov eax, 70
|
||||
int 0x40
|
||||
|
||||
stdcall mem.Free, esi
|
||||
|
||||
.exit:
|
||||
ret
|
||||
|
||||
|
||||
align 4
|
||||
;dd 0xdeadbeef
|
||||
dd APP_STARTUP_THUNK
|
||||
@EXPORT:
|
||||
export \
|
||||
dll.Load, 'dll_load', \
|
||||
dll.Link, 'dll_link', \
|
||||
dll.GetProcAddress, 'dll_sym' ;
|
||||
dll.Load, 'dll_load', \
|
||||
dll.Link, 'dll_link', \
|
||||
dll.GetProcAddress, 'dll_sym'
|
||||
|
||||
|
||||
pNotify:
|
||||
dd 7, 0
|
||||
.params dd 0
|
||||
dd 0, 0
|
||||
db "/sys/@notify", 0
|
||||
|
||||
; { Strings
|
||||
if defined LANG_RUS
|
||||
include 'strings.rus'
|
||||
;elseif defined LANG_xxx
|
||||
; TODO: Add another supported languges here
|
||||
; - Copy 'elseif defined LANG_xxx', change xxx here and below to the
|
||||
; corresponded constat of you languge
|
||||
; - Create strings.xxx in the root of this project and do translate,
|
||||
; follow the format message below.
|
||||
; - add include 'strings.xxx'
|
||||
else ; Default languge (English)
|
||||
szBanner db "Error!\n",0
|
||||
szWrongFormat db "$ - $Application has wrong format!",0
|
||||
szLibraryNotLoaded db "$ - $Can't load library $", 0
|
||||
szEntryNotFound db "$ - $Entry $\nin library $\nnot found!",0
|
||||
|
||||
end if
|
||||
; } Strings
|
192
programs/develop/libraries/dll/dll.inc
Normal file
192
programs/develop/libraries/dll/dll.inc
Normal file
@ -0,0 +1,192 @@
|
||||
;
|
||||
; (C) KolibriOS team (original dll.inc)
|
||||
; (C) 2022, Edited by Coldy
|
||||
;
|
||||
; This module based on original dll.inc.
|
||||
;
|
||||
; - Improved error handling. Now dll.Load return 0 is success guarantie
|
||||
; Also added corrsponding error codes if one of library or entry not found
|
||||
;
|
||||
|
||||
|
||||
ERROR_LIBRARY_NOT_LOAD = 0x100
|
||||
ERROR_ENTRY_NOT_FOUND = 0x101
|
||||
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; load one or more DLL file in COFF format and try to import functions by our list
|
||||
; if first function in import list begins with 'lib_', call it as DLL initialization
|
||||
; return eax = 1 as fail, if anyone of .obj file not found in /sys/lib
|
||||
; return 0 if all fine or error code LIBRARY_NOT_LOAD or ENTRY_NOT_FOUND
|
||||
; dirties all registers! eax, ebx, ecx, edx, esi, edi
|
||||
proc dll.Load, import_table:dword
|
||||
mov esi, [import_table]
|
||||
.next_lib:
|
||||
mov edx, [esi]
|
||||
or edx, edx
|
||||
jz .exit
|
||||
push esi
|
||||
mov esi, [esi + 4]
|
||||
mov edi, s_libdir.fname
|
||||
@@:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jnz @b
|
||||
mcall 68, 19, s_libdir
|
||||
or eax, eax
|
||||
jz .fail_load
|
||||
push eax
|
||||
stdcall dll.Link, eax, edx
|
||||
test eax, eax
|
||||
jnz .fail_link
|
||||
;push eax
|
||||
mov eax, [esp]
|
||||
mov eax, [eax]
|
||||
cmp dword[eax], 'lib_'
|
||||
pop eax
|
||||
jnz @f
|
||||
stdcall dll.Init, [eax + 4]
|
||||
@@:
|
||||
pop esi
|
||||
add esi, 8
|
||||
jmp .next_lib
|
||||
.exit:
|
||||
xor eax, eax
|
||||
ret
|
||||
.fail_load:
|
||||
add esp, 4
|
||||
;xor eax, eax
|
||||
;inc eax
|
||||
mov eax, ERROR_LIBRARY_NOT_LOAD
|
||||
ret
|
||||
.fail_link:
|
||||
add esp, 4
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
; scans dll export table for a functions we want to import
|
||||
; break scan on first unresolved import
|
||||
; return value: 0 - success or ENTRY_NOT_FOUND
|
||||
proc dll.Link, exp:dword, imp:dword
|
||||
;push eax
|
||||
mov esi, [imp]
|
||||
; Import table alreary checked in APP_STARTUP_THUNK
|
||||
;test esi, esi
|
||||
;jz .fail1;.done
|
||||
.next:
|
||||
lodsd
|
||||
test eax, eax
|
||||
jz .done
|
||||
mov ebx, eax
|
||||
stdcall dll.GetProcAddress, [exp], eax
|
||||
or eax, eax
|
||||
jz .fail ;.done
|
||||
mov [esi - 4], eax
|
||||
jmp .next
|
||||
; @@:
|
||||
;mov dword[esp], 0
|
||||
;.fail1:
|
||||
; No imports
|
||||
;mov eax, BAD_IMAGE
|
||||
;jmp .done
|
||||
.fail:
|
||||
mov [szEntryName],ebx
|
||||
mov eax, ERROR_ENTRY_NOT_FOUND
|
||||
.done:
|
||||
;pop eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
; calls lib_init with predefined parameters
|
||||
; no return value
|
||||
proc dll.Init, dllentry:dword
|
||||
pushad
|
||||
mov eax, mem.Alloc
|
||||
mov ebx, mem.Free
|
||||
mov ecx, mem.ReAlloc
|
||||
mov edx, dll.Load
|
||||
stdcall [dllentry]
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
; scans export table for a sz_name function
|
||||
; returns in eax function address or 0 if not found
|
||||
proc dll.GetProcAddress, exp:dword, sz_name:dword
|
||||
mov edx, [exp]
|
||||
xor eax, eax
|
||||
.next:
|
||||
or edx, edx
|
||||
jz .end
|
||||
cmp dword[edx], 0
|
||||
jz .end
|
||||
stdcall strcmp, [edx], [sz_name]
|
||||
test eax, eax
|
||||
jz .ok
|
||||
add edx, 8
|
||||
jmp .next
|
||||
.ok:
|
||||
mov eax, [edx + 4]
|
||||
.end:
|
||||
cmp eax, -1
|
||||
jnz @f
|
||||
xor eax, eax
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
; compares strings
|
||||
; returns eax = 0 if equal, -1 otherwise
|
||||
proc strcmp, str1:dword, str2:dword
|
||||
push esi edi
|
||||
mov esi, [str1]
|
||||
mov edi, [str2]
|
||||
xor eax, eax
|
||||
@@:
|
||||
lodsb
|
||||
scasb
|
||||
jne .fail
|
||||
or al, al
|
||||
jnz @b
|
||||
jmp .ok
|
||||
.fail:
|
||||
or eax, -1
|
||||
.ok:
|
||||
pop edi esi
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
s_libdir:
|
||||
db '/sys/lib/'
|
||||
.fname rb 32
|
||||
|
||||
szEntryName dd 0
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.Alloc, size
|
||||
push ebx ecx
|
||||
mov ecx, [size]
|
||||
mcall 68, 12
|
||||
pop ecx ebx
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.ReAlloc, mptr, size
|
||||
push ebx ecx edx
|
||||
mov ecx, [size]
|
||||
mov edx, [mptr]
|
||||
mcall 68, 20
|
||||
pop edx ecx ebx
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.Free, mptr
|
||||
push ebx ecx
|
||||
mov ecx,[mptr]
|
||||
mcall 68, 13
|
||||
pop ecx ebx
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------------------
|
7
programs/develop/libraries/dll/external.inc
Normal file
7
programs/develop/libraries/dll/external.inc
Normal file
@ -0,0 +1,7 @@
|
||||
;
|
||||
; This file is used for external includes
|
||||
; If server and locale relative paths is different
|
||||
; then need a corresponding copy on each side
|
||||
|
||||
include '../../../proc32.inc'
|
||||
include '../../../macros.inc'
|
303
programs/develop/libraries/dll/strhlp.inc
Normal file
303
programs/develop/libraries/dll/strhlp.inc
Normal file
@ -0,0 +1,303 @@
|
||||
;
|
||||
; String helpers
|
||||
;
|
||||
; (C) KolibriOS team (parts from another project)
|
||||
; (C) 2022 Coldy (str_buld function)
|
||||
; Thank's you for use this code and software based on it!
|
||||
; I will glad if it's will be helpful.
|
||||
;
|
||||
; Distributed under terms of GPL
|
||||
;
|
||||
|
||||
;****************************************
|
||||
;* input: esi = pointer to string *
|
||||
;* output: ecx = length of the string *
|
||||
;****************************************
|
||||
strlen:
|
||||
push eax esi
|
||||
xor ecx, ecx
|
||||
@@:
|
||||
lodsb
|
||||
or al, al
|
||||
jz @f
|
||||
inc ecx
|
||||
jmp @b
|
||||
@@:
|
||||
pop esi eax
|
||||
ret
|
||||
|
||||
;*************************************************
|
||||
;* input: esi = pointer to the src string *
|
||||
;* edi = pointer to the dest string *
|
||||
;* ecx = number of bytes to copy *
|
||||
;*************************************************
|
||||
strncpy:
|
||||
push eax ecx esi edi
|
||||
@@:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jz @f
|
||||
dec ecx
|
||||
jz @f
|
||||
jmp @b
|
||||
@@:
|
||||
pop edi esi ecx eax
|
||||
ret
|
||||
|
||||
if 0 ; { Not used
|
||||
|
||||
;*************************************************
|
||||
;* input: esi = pointer to the src string *
|
||||
;* edi = pointer to the dest string *
|
||||
;*************************************************
|
||||
strcpy:
|
||||
push esi edi
|
||||
; ecx = ???
|
||||
; ZF = 0
|
||||
rep movsb
|
||||
pop edi esi
|
||||
ret
|
||||
|
||||
;*************************************************
|
||||
;* input: esi = pointer to the src string *
|
||||
;* edi = pointer to the dest string *
|
||||
;* ecx = number of bytes to copy *
|
||||
;*************************************************
|
||||
strncat:
|
||||
push edi
|
||||
push ecx esi
|
||||
mov esi, edi
|
||||
call strlen
|
||||
add edi, ecx
|
||||
pop esi ecx
|
||||
call strncpy
|
||||
pop edi
|
||||
ret
|
||||
|
||||
;*************************************************
|
||||
;* (c) Coldy 2022 *
|
||||
;* input: edi = pointer to the dest string *
|
||||
;* ecx = number of bytes to zero *
|
||||
;*************************************************
|
||||
;memnz:
|
||||
; push eax ecx edi
|
||||
; xor eax, eax
|
||||
; rep stosb
|
||||
; pop edi ecx eax
|
||||
; ret
|
||||
|
||||
end if ; }
|
||||
|
||||
;
|
||||
; str_build
|
||||
;
|
||||
; Purose: Build output string by template. Allocate necessary output
|
||||
; buffer, copy parts from template and insert strings instead
|
||||
; of $ wildcard.
|
||||
;
|
||||
; SPECIAL CASE:
|
||||
; For use dollar sing ($) in text, just mark this plase(s) in
|
||||
; template and provide pointer(s) on string with this sign in args)
|
||||
;
|
||||
; PRECAUTION:
|
||||
; 1. Not safe, caller must provide args count >= $ wildcard count
|
||||
; 2. If used dynamic memory allocator then caller must free output
|
||||
; buffer
|
||||
; 3. Looks like cdecl, but she is not. For cdecl need compat wrapper
|
||||
; 4. Dirties all registers, incl. ebp
|
||||
;
|
||||
; Input:
|
||||
; esp+4 = pointer to template string
|
||||
; esp+8 = wildcard strings pointers in reverse order
|
||||
;
|
||||
; Options:
|
||||
if ~STR_BUILD_OFFSET
|
||||
STR_BUILD_OFFSET = 0
|
||||
; Optional, specify STR_BUILD_OFFSET value for offset from start
|
||||
; of output buffer (this useful for postinsert initial characters
|
||||
; before output sting). By default - no offset (0)
|
||||
end if
|
||||
if ~STR_BUILD_EXTRA
|
||||
STR_BUILD_EXTRA = 0
|
||||
; Optional, specify STR_BUILD_EXTRA value for extra length of
|
||||
; output bufer (this useful for postadding characters after
|
||||
; output string). By default - no extra length (0)
|
||||
end if
|
||||
|
||||
;
|
||||
; { STR_BUILD_NO_DOLLAR_SIGN - should be removed, see cpecial case above }
|
||||
|
||||
;
|
||||
; Next two options below can reduse total code size by exclude
|
||||
; corresponding parts if they are not used
|
||||
;
|
||||
if ~STR_BUILD_NO_STARTING_TEXT
|
||||
STR_BUILD_NO_STARTING_TEXT = 0
|
||||
; Specify STR_BUILD_NO_STARTING_TEXT if you do not used templates
|
||||
; starting with text, e.g."Some text first $, $"
|
||||
; By default is disabled (0)
|
||||
end if
|
||||
;
|
||||
if ~STR_BUILD_NO_DOUBLE_WILDCARD
|
||||
STR_BUILD_NO_DOUBLE_WILDCARD = 0
|
||||
; Specify STR_BUILD_NO_DOUBLE_WILDCARD if you not used templates
|
||||
; with double wildcards, e.g. "$$ some text" or "Some text $$"
|
||||
; By default is disabled (0)
|
||||
end if
|
||||
;
|
||||
; mem_alloc(size)
|
||||
; external memory allocator, stdcall. Must return pointer (in eax)
|
||||
; to base of memory block by size length. By defauld used internal
|
||||
;
|
||||
; Output:
|
||||
; eax = Pointer to output string (see PRECAUTION #2) or 0 if error
|
||||
; edi = Cursor of output string. No mean inf if eax = 0
|
||||
;
|
||||
; Stack struct
|
||||
; ------
|
||||
; | ArgN |
|
||||
; -------
|
||||
; | ... |
|
||||
; -------
|
||||
; ebp+4 | Arg1 |
|
||||
; ------ -------
|
||||
; ebp | TplS | Template string
|
||||
; ------ -------
|
||||
; | ret | Caller return address (not used), esp when entry
|
||||
; -------
|
||||
; | $off1 | 1st offset in template string
|
||||
; -------
|
||||
; | ... |
|
||||
; -------
|
||||
; | $offN | N-offset in template string
|
||||
; -------
|
||||
; | EOTpl | End of template string, esp after phase 1.1
|
||||
; -------
|
||||
; | Len1 | Length of 1st wildcard string
|
||||
; -------
|
||||
; | ... |
|
||||
; -------
|
||||
; | LenN | Length of N wildcard string, esp after phase 1.2
|
||||
; -------
|
||||
;
|
||||
str_build:
|
||||
mov ebp, esp ; Store caller esp...
|
||||
add ebp, 8 ; ... and shift return address and tamplate string
|
||||
mov esi, [ebp-4]
|
||||
xor edx, edx ; Offsets, length...
|
||||
xor edi, edi ; Found count...
|
||||
|
||||
; Phase 1.1. Scan to find positions $ and store to stack offsets $+1
|
||||
; and end of template string. Break scan if zero byte appear
|
||||
.scan:
|
||||
lodsb
|
||||
inc edx
|
||||
or al, al
|
||||
jz .end_scan
|
||||
cmp al, '$'
|
||||
je .found
|
||||
jmp .scan
|
||||
.found:
|
||||
push edx ; Store offset
|
||||
inc edi
|
||||
jmp .scan
|
||||
.end_scan:
|
||||
or edi, edi
|
||||
jz .error ; Not found
|
||||
push edx ; Store last offset (end of template string)
|
||||
sub edx, edi
|
||||
dec edx ; Total length + zero string
|
||||
|
||||
; Phase 1.2. Store to stack lengths of wildcard strings
|
||||
mov eax, edi
|
||||
@@:
|
||||
mov esi,[ebp+4*(eax-1)]
|
||||
call strlen
|
||||
add edx, ecx
|
||||
push ecx
|
||||
dec eax
|
||||
inc edi ; once edi*2 instead
|
||||
test eax,eax
|
||||
jnz @b
|
||||
|
||||
add edx, STR_BUILD_OFFSET + STR_BUILD_EXTRA
|
||||
|
||||
; Phase 1.3. Allocate buffer for output string
|
||||
if defined mem_alloc
|
||||
stdcall mem_alloc, edx
|
||||
else
|
||||
mov eax, 68
|
||||
mov ebx, 12
|
||||
mov ecx, edx
|
||||
int 0x40
|
||||
end if
|
||||
test eax,eax
|
||||
jz .exit
|
||||
|
||||
mov byte[eax+edx],0 ; Mark end of output string
|
||||
|
||||
; Phase 2. Build output string
|
||||
|
||||
; eax = base of output string
|
||||
xor ebx, ebx ; ebx = index of args data
|
||||
; ecx = free, but used below
|
||||
mov edx, edi ; edx = index of stored data
|
||||
; esi = free, but used below
|
||||
mov edi, eax ; edi = cursor of output string
|
||||
|
||||
add edi, STR_BUILD_OFFSET
|
||||
if ~STR_BUILD_NO_STARTING_TEXT ; {
|
||||
mov ecx, [esp+4*edx] ; Offset
|
||||
cmp ecx,1 ; Wildcard first?
|
||||
je .build
|
||||
|
||||
mov esi, -2 ; One or double wildcard at the end
|
||||
neg ecx
|
||||
add ecx, [esp+4*edx-4] ; Next offset
|
||||
cmp ecx, 1 ; More one wildcard at the end?
|
||||
je @f
|
||||
dec esi
|
||||
|
||||
@@:
|
||||
mov ecx,esi
|
||||
add ecx,[esp+4*edx-4] ; Next offset
|
||||
mov esi,[ebp-4] ; Template string
|
||||
call strncpy
|
||||
add edi, ecx ; Advance cursor
|
||||
end if; } STR_BUILD_NO_STARTING_TEXT
|
||||
.build:
|
||||
mov esi, [ebp+4*ebx] ; Wildcard string
|
||||
mov ecx,[esp+4*ebx] ; Length
|
||||
call strncpy
|
||||
add edi, ecx ; Advance cursor
|
||||
mov ecx, [esp+4*edx] ; Offset
|
||||
|
||||
mov esi,[ebp-4] ; Template string
|
||||
add esi, ecx
|
||||
cmp byte [esi], 0 ; End of string?
|
||||
je .exit
|
||||
if ~STR_BUILD_NO_DOUBLE_WILDCARD ; {
|
||||
cmp byte [esi], '$'
|
||||
je @f
|
||||
end if; } STR_BUILD_NO_DOUBLE_WILDCARD
|
||||
neg ecx
|
||||
add ecx,[esp+4*edx-4] ; Next offset
|
||||
dec ecx
|
||||
call strncpy
|
||||
add edi, ecx ; Advance cursor
|
||||
@@: ; { STR_BUILD_NO_DOUBLE_WILDCARD }
|
||||
inc ebx
|
||||
dec edx
|
||||
cmp ebx, edx
|
||||
jne .build
|
||||
.exit:
|
||||
; Restore stack
|
||||
sub ebp, 8
|
||||
mov esp,ebp
|
||||
ret
|
||||
|
||||
.error:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
5
programs/develop/libraries/dll/strings.rus
Normal file
5
programs/develop/libraries/dll/strings.rus
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
szBanner db "舘芋<E88898>!\n",0
|
||||
szWrongFormat db "$ - $摚能𨯂走鴙諰 銈酮罱 能走恩平剁!",0
|
||||
szLibraryNotLoaded db "$ - $摚╳妞恩陋 <20>␡膇兩<E88687> ”‵車漭芥 $", 0
|
||||
szEntryNotFound db "$ - $<24>恕 $\n<> ”‵車漭炙 $\n郊 <20>岸平!",0
|
Loading…
Reference in New Issue
Block a user