diff --git a/programs/develop/libraries/libs-dev/libini/libini.asm b/programs/develop/libraries/libs-dev/libini/libini.asm
new file mode 100644
index 0000000000..f7e544cf69
--- /dev/null
+++ b/programs/develop/libraries/libs-dev/libini/libini.asm
@@ -0,0 +1,710 @@
+;;================================================================================================;;
+;;//// libini.asm //// (c) mike.dld, 2006-2008 ///////////////////////////////////////////////////;;
+;;================================================================================================;;
+;; ;;
+;; This file is part of Common development libraries (Libs-Dev). ;;
+;; ;;
+;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
+;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
+;; of the License, or (at your option) any later version. ;;
+;; ;;
+;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;;
+;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
+;; Lesser General Public License for more details. ;;
+;; ;;
+;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;;
+;; If not, see . ;;
+;; ;;
+;;================================================================================================;;
+;; ;;
+;; 2009-03-08 (mike.dld) ;;
+;; bug-fixes: ;;
+;; - moved buffer bound check in libini._.low.read_value up (reported by Insolor) ;;
+;; new features: ;;
+;; - comments support (char is ini.COMMENT_CHAR, defaults to ';') ;;
+;; inline comments are not supported ;;
+;; 2008-12-29 (mike.dld) ;;
+;; bug-fixes: ;;
+;; - unnecessary 'stosb' in ini.get_str was causing problems ;;
+;; new features: ;;
+;; - new functions: ini.get_color and ini.set_color ;;
+;; 2008-08-06 (mike.dld) ;;
+;; changes: ;;
+;; - split private procs into libini_p.asm, added comments ;;
+;; 2008-02-07 (mike.dld) ;;
+;; changes: ;;
+;; - renamed all *.aux.* to *._.* to match overall libraries design ;;
+;; 2007-09-26 (mike.dld) ;;
+;; bug-fixes: ;;
+;; - value was not correctly trimmed (reported by diamond) ;;
+;; 2007-08-01 (mike.dld) ;;
+;; bug-fixes: ;;
+;; - serious defect in ini.set_str causing displaced write operations ;;
+;; (reported by diamond) ;;
+;; - another serious defect in ini.enum_keys introduced with refactoring ;;
+;; changes: ;;
+;; - callback for enum_keys now takes additional parameter - key value ;;
+;; - handling trailing spaces in section/key/value ;;
+;; 2007-05-19 (mike.dld) ;;
+;; bug-fixes: ;;
+;; - last char still wasn't read correctly ;;
+;; - digits of number were reversed when using ini.set_int ;;
+;; - now using 'ini.aux.unget_char' instead of dangerous 'dec esi' ;;
+;; changes: ;;
+;; - all non-public functions now start with ini.aux.* ;;
+;; - added ini.enum_sections and ini.enum_keys ;;
+;; - removed ini.query_sec (use ini.enum_* instead) ;;
+;; ;;
+;;================================================================================================;;
+
+format MS COFF
+
+public @EXPORT as 'EXPORTS'
+
+include '../../../../proc32.inc'
+include '../../../../macros.inc'
+include '../libio/libio.inc'
+purge section ; mov,add,sub
+
+include 'libini_p.inc'
+
+section '.flat' code readable align 16
+
+include 'libini_p.asm'
+
+;;================================================================================================;;
+proc ini.enum_sections _f_name, _callback ;///////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Enumerate sections, calling callback function for each of them ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _callback = callback function address: func(f_name, sec_name), where ;;
+;> f_name = ini filename (as passed to the function) ;;
+;> sec_name = section name found ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;;================================================================================================;;
+locals
+ f IniFile
+ f_addr dd ?
+ sec_buf dd ?
+endl
+
+ push ebx esi edi
+
+ cld
+
+ invoke mem.alloc, ini.MAX_NAME_LEN
+ or eax, eax
+ jz .exit_error.2
+ mov [sec_buf], eax
+
+ xor eax, eax
+ mov [f.fh], eax
+ mov [f.buf], eax
+ invoke file.open, [_f_name], O_READ
+ cmp eax, 32
+ jb .exit_error
+ mov [f.fh], eax
+ invoke mem.alloc, ini.MEM_SIZE
+ or eax, eax
+ jz .exit_error
+ mov [f.buf], eax
+ lea ebx, [f]
+ mov [f_addr], ebx
+
+ invoke file.seek, [f.fh], 0, SEEK_SET
+ stdcall libini._.preload_block, [f_addr]
+
+ .next_section:
+ stdcall libini._.find_next_section, [f_addr]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.get_char, [f_addr]
+ stdcall libini._.skip_spaces, [f_addr]
+ mov edi, [sec_buf]
+ @@: stdcall libini._.get_char, [f_addr]
+ cmp al, ']'
+ je @f
+ or al, al
+ jz .exit_ok
+ cmp al, 13
+ je .next_section
+ cmp al, 10
+ je .next_section
+ stosb
+ jmp @b
+ @@: xor al, al
+ stosb
+ add edi, -2
+ @@: cmp byte[edi], 32
+ ja @f
+ mov byte[edi], 0
+ dec edi
+ jmp @b
+ @@:
+ pushad
+ mov eax, [f_addr]
+ stdcall [_callback], [_f_name], [sec_buf]
+ or eax, eax
+ popad
+ jnz .next_section
+
+ .exit_ok:
+ invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ invoke mem.free, [sec_buf]
+ xor eax, eax
+ pop edi esi ebx
+ ret
+
+ .exit_error:
+ invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ invoke mem.free, [sec_buf]
+ .exit_error.2:
+ or eax, -1
+ pop edi esi ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.enum_keys _f_name, _sec_name, _callback ;////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Enumerate keys within a section, calling callback function for each of them ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _callback = callback function address: func(f_name, sec_name, key_name, key_value), where ;;
+;> f_name = ini filename (as passed to the function) ;;
+;> sec_name = section name (as passed to the function) ;;
+;> key_name = key name found ;;
+;> key_value = value of key found ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;;================================================================================================;;
+locals
+ f IniFile
+ f_addr dd ?
+ key_buf dd ?
+ val_buf dd ?
+endl
+
+ push ebx esi edi
+
+ cld
+
+ invoke mem.alloc, ini.MAX_NAME_LEN
+ or eax, eax
+ jz .exit_error.3
+ mov [key_buf], eax
+ invoke mem.alloc, ini.MAX_VALUE_LEN
+ or eax, eax
+ jz .exit_error.2
+ mov [val_buf], eax
+
+ xor eax, eax
+ mov [f.fh], eax
+ mov [f.buf], eax
+ invoke file.open, [_f_name], O_READ
+ cmp eax, 32
+ jb .exit_error
+ mov [f.fh], eax
+ invoke mem.alloc, ini.MEM_SIZE
+ or eax, eax
+ jz .exit_error
+ mov [f.buf], eax
+ lea ebx, [f]
+ mov [f_addr], ebx
+ stdcall libini._.find_section, ebx, [_sec_name]
+ or eax, eax
+ jnz .exit_error
+
+ .next_key:
+ stdcall libini._.skip_line, [f_addr]
+ stdcall libini._.skip_nonblanks, [f_addr]
+ or al, al
+ jz .exit_error
+ cmp al, '['
+ je .exit_error
+ mov edi, [key_buf]
+ @@: stdcall libini._.get_char, [f_addr]
+ or al, al
+ jz .exit_error
+ cmp al, '='
+ je @f
+ stosb
+ jmp @b
+ @@:
+ xor al, al
+ stosb
+ add edi, -2
+ @@: cmp byte[edi], 32
+ ja @f
+ mov byte[edi], 0
+ dec edi
+ jmp @b
+ @@: stdcall libini._.low.read_value, [f_addr], [val_buf], ini.MAX_VALUE_LEN
+ pushad
+ stdcall [_callback], [_f_name], [_sec_name], [key_buf], [val_buf]
+ or eax, eax
+ popad
+ jnz .next_key
+
+ @@: invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ xor eax, eax
+ stosb
+ pop edi esi ebx
+ ret
+
+ .exit_error:
+ invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ invoke mem.free, [val_buf]
+ .exit_error.2:
+ invoke mem.free, [key_buf]
+ .exit_error.3:
+ or eax, -1
+ pop edi esi ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.get_str _f_name, _sec_name, _key_name, _buffer, _buf_len, _def_val ;/////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Read string ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _buffer = destination buffer address ;;
+;> _buf_len = buffer size (maximum bytes to read) ;;
+;> _def_val = default value to return if no key, section or file found ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;< [_buffer] = [_def_val] (error) / found key value ;;
+;;================================================================================================;;
+locals
+ f IniFile
+ f_addr dd ?
+endl
+
+ push ebx esi edi
+
+ xor eax, eax
+ mov [f.fh], eax
+ mov [f.buf], eax
+ invoke file.open, [_f_name], O_READ
+ cmp eax, 32
+ jb .exit_error
+ mov [f.fh], eax
+ invoke mem.alloc, ini.MEM_SIZE
+ or eax, eax
+ jz .exit_error
+ mov [f.buf], eax
+ lea ebx, [f]
+ mov [f_addr], ebx
+ stdcall libini._.find_section, ebx, [_sec_name]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.find_key, ebx, [_key_name]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.low.read_value, [f_addr], [_buffer], [_buf_len]
+ @@: invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ xor eax, eax
+ pop edi esi ebx
+ ret
+
+ .exit_error:
+ invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ mov edi, [_buffer]
+ mov esi, [_def_val]
+ xor al, al
+ or esi, esi
+ jz .exit_error.2
+ @@: lodsb
+ .exit_error.2:
+ stosb
+ or al, al
+ jnz @b
+ or eax, -1
+ pop edi esi ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.set_str _f_name, _sec_name, _key_name, _buffer, _buf_len ;///////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Write string ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _buffer = source buffer address ;;
+;> _buf_len = buffer size (bytes to write) ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;;================================================================================================;;
+locals
+ f IniFile
+ f_addr dd ?
+endl
+
+ push ebx esi edi
+
+ xor eax, eax
+ mov [f.fh], eax
+ mov [f.buf], eax
+ invoke file.open, [_f_name], O_READ + O_WRITE + O_CREATE
+ cmp eax, 32
+ jb .exit_error
+ mov [f.fh], eax
+ invoke mem.alloc, ini.MEM_SIZE
+ or eax, eax
+ jz .exit_error
+ mov [f.buf], eax
+ lea ebx, [f]
+ mov [f_addr], ebx
+
+ stdcall libini._.find_section, ebx, [_sec_name]
+ or eax, eax
+ jnz .create_section
+
+ stdcall libini._.find_key, ebx, [_key_name]
+ or eax, eax
+ jnz .create_key
+
+ .modify_key:
+ stdcall libini._.get_value_length, [f_addr]
+ sub eax, [_buf_len]
+ stdcall libini._.shift_content, [f_addr], eax
+
+ .modify_key.ex:
+ invoke file.tell, [f.fh]
+ sub eax, [f.cnt]
+ invoke file.seek, [f.fh], eax, SEEK_SET
+ invoke file.write, [f.fh], [_buffer], [_buf_len]
+
+ pop edi esi ebx
+ xor eax, eax
+ ret
+
+ .create_key:
+ mov edi, [f.buf]
+ add edi, ini.BLOCK_SIZE
+ push edi
+
+ .create_key.ex:
+ mov esi, [_key_name]
+ call libini._.string_copy
+ mov byte[edi], '='
+ inc edi
+ mov esi, [_buffer]
+ mov ecx, [_buf_len]
+ rep movsb
+ mov word[edi], 0x0A0D
+ add edi, 2
+ mov eax, edi
+
+ pop edi
+ sub eax, edi
+ mov [_buffer], edi
+ mov [_buf_len], eax
+ neg eax
+ stdcall libini._.shift_content, [f_addr], eax
+
+ jmp .modify_key.ex
+
+ .create_section:
+ mov edi, [f.buf]
+ add edi, ini.BLOCK_SIZE
+ push edi
+
+ mov esi, [_sec_name]
+ mov byte[edi], '['
+ inc edi
+ call libini._.string_copy
+ mov dword[edi], ']' + (0x0A0D shl 8)
+ add edi, 3
+
+ jmp .create_key.ex
+
+ .exit_error:
+ pop edi esi ebx
+ or eax, -1
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.get_int _f_name, _sec_name, _key_name, _def_val ;////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Read integer ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _def_val = default value to return if no key, section or file found ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = [_def_val] (error) / found key value ;;
+;;================================================================================================;;
+locals
+ f IniFile
+ f_addr dd ?
+endl
+
+ push ebx esi edi
+
+ xor eax, eax
+ mov [f.fh], eax
+ mov [f.buf], eax
+ invoke file.open, [_f_name], O_READ
+ cmp eax, 32
+ jb .exit_error
+ mov [f.fh], eax
+ invoke mem.alloc, ini.MEM_SIZE
+ or eax, eax
+ jz .exit_error
+ mov [f.buf], eax
+ lea ebx, [f]
+ mov [f_addr], ebx
+ stdcall libini._.find_section, ebx, [_sec_name]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.find_key, ebx, [_key_name]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.skip_spaces, [f_addr]
+ xor eax, eax
+ xor ebx, ebx
+ xor edx, edx
+ stdcall libini._.get_char, [f_addr]
+ cmp al, '-'
+ jne .lp1
+ inc bh
+ @@: stdcall libini._.get_char, [f_addr]
+ .lp1: cmp al, '0'
+ jb @f
+ cmp al, '9'
+ ja @f
+ inc bl
+ add eax, -'0'
+ imul edx, 10
+ add edx, eax
+ jmp @b
+ @@:
+ or bl, bl
+ jz .exit_error
+ or bh, bh
+ jz @f
+ neg edx
+ @@: invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ mov eax, edx
+ pop edi esi ebx
+ ret
+
+ .exit_error:
+ invoke file.close, [f.fh]
+ invoke mem.free, [f.buf]
+ mov eax, [_def_val]
+ pop edi esi ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.set_int _f_name, _sec_name, _key_name, _val ;////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Write integer ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _val = value ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;;================================================================================================;;
+locals
+ buf rb 16
+endl
+
+ push ecx edx edi
+
+ lea edi, [buf]
+ add edi, 15
+ mov eax, [_val]
+ or eax, eax
+ jns @f
+ mov byte[edi], '-'
+ neg eax
+ inc edi
+ @@: mov ecx, 10
+ @@: xor edx, edx
+ idiv ecx
+ add dl, '0'
+ mov [edi], dl
+ dec edi
+ or eax, eax
+ jnz @b
+ lea eax, [buf]
+ add eax, 15
+ sub eax, edi
+ inc edi
+
+ stdcall ini.set_str, [_f_name], [_sec_name], [_key_name], edi, eax
+
+ pop edi edx ecx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.get_color _f_name, _sec_name, _key_name, _def_val ;//////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Read color ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _def_val = default value to return if no key, section or file found ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = [_def_val] (error) / found key value ;;
+;;================================================================================================;;
+locals
+ buf rb 14
+endl
+
+ push ebx esi edi
+
+ lea esi, [buf]
+ stdcall ini.get_str, [_f_name], [_sec_name], [_key_name], esi, 14, 0
+ cmp byte[esi],0
+ je .exit_error
+
+ xor ebx, ebx
+ stdcall libini._.str_to_int
+ movzx ebx, al
+ shl ebx, 16
+ lodsb
+ cmp al, ','
+ jne @f
+ stdcall libini._.str_to_int
+ mov bh, al
+ lodsb
+ cmp al, ','
+ jne @f
+ stdcall libini._.str_to_int
+ mov bl, al
+
+ @@: mov eax, ebx
+
+ pop edi esi ebx
+ ret
+
+ .exit_error:
+ mov eax, [_def_val]
+ pop edi esi ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc ini.set_color _f_name, _sec_name, _key_name, _val ;//////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Write color ;;
+;;------------------------------------------------------------------------------------------------;;
+;> _f_name = ini filename ;;
+;> _sec_name = section name ;;
+;> _key_name = key name ;;
+;> _val = value ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (error) / 0 ;;
+;;================================================================================================;;
+locals
+ buf rb 16
+endl
+
+ push ecx edx edi
+
+ lea edi, [buf]
+ mov ecx, 10
+ mov ebx, [_val]
+ mov eax, ebx
+ shr eax, 16
+ and eax, 0x0ff
+ stdcall libini._.int_to_str
+ mov byte[edi], ','
+ inc edi
+ movzx eax, bh
+ stdcall libini._.int_to_str
+ mov byte[edi], ','
+ inc edi
+ movzx eax, bl
+ stdcall libini._.int_to_str
+
+ lea eax, [buf]
+ sub edi, eax
+
+ stdcall ini.set_str, [_f_name], [_sec_name], [_key_name], eax, edi
+
+ pop edi edx ecx
+ ret
+endp
+
+
+;;================================================================================================;;
+;;////////////////////////////////////////////////////////////////////////////////////////////////;;
+;;================================================================================================;;
+;! Imported functions section ;;
+;;================================================================================================;;
+;;////////////////////////////////////////////////////////////////////////////////////////////////;;
+;;================================================================================================;;
+
+
+align 16
+@IMPORT:
+
+library \
+ libio , 'libio.obj'
+
+import libio , \
+ file.size , 'file_size' , \
+ file.open , 'file_open' , \
+ file.read , 'file_read' , \
+ file.write , 'file_write' , \
+ file.seek , 'file_seek' , \
+ file.eof? , 'file_iseof' , \
+ file.seteof , 'file_seteof' , \
+ file.tell , 'file_tell' , \
+ file.close , 'file_close'
+
+
+;;================================================================================================;;
+;;////////////////////////////////////////////////////////////////////////////////////////////////;;
+;;================================================================================================;;
+;! Exported functions section ;;
+;;================================================================================================;;
+;;////////////////////////////////////////////////////////////////////////////////////////////////;;
+;;================================================================================================;;
+
+
+align 16
+@EXPORT:
+
+export \
+ libini._.init , 'lib_init' , \
+ 0x00080008 , 'version' , \
+ ini.enum_sections , 'ini_enum_sections' , \
+ ini.enum_keys , 'ini_enum_keys' , \
+ ini.get_str , 'ini_get_str' , \
+ ini.get_int , 'ini_get_int' , \
+ ini.get_color , 'ini_get_color' , \
+ ini.set_str , 'ini_set_str' , \
+ ini.set_int , 'ini_set_int' , \
+ ini.set_color , 'ini_set_color'
diff --git a/programs/develop/libraries/libs-dev/libini/libini_p.asm b/programs/develop/libraries/libs-dev/libini/libini_p.asm
new file mode 100644
index 0000000000..659160c943
--- /dev/null
+++ b/programs/develop/libraries/libs-dev/libini/libini_p.asm
@@ -0,0 +1,623 @@
+;;================================================================================================;;
+;;//// libini_p.asm //// (c) mike.dld, 2006-2008 /////////////////////////////////////////////////;;
+;;================================================================================================;;
+;; ;;
+;; This file is part of Common development libraries (Libs-Dev). ;;
+;; ;;
+;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
+;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
+;; of the License, or (at your option) any later version. ;;
+;; ;;
+;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;;
+;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
+;; Lesser General Public License for more details. ;;
+;; ;;
+;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;;
+;; If not, see . ;;
+;; ;;
+;;================================================================================================;;
+
+mem.alloc dd ?
+mem.free dd ?
+mem.realloc dd ?
+dll.load dd ?
+
+;;================================================================================================;;
+proc libini._.init ;//////////////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Library entry point (called after library load) ;;
+;;------------------------------------------------------------------------------------------------;;
+;> eax = memory allocation routine ;;
+;> ebx = memory freeing routine ;;
+;> ecx = memory reallocation routine ;;
+;> edx = library loading routine ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = 1 (fail) / 0 (ok) (library initialization result) ;;
+;;================================================================================================;;
+ mov [mem.alloc], eax
+ mov [mem.free], ebx
+ mov [mem.realloc], ecx
+ mov [dll.load], edx
+
+ invoke dll.load, @IMPORT
+ or eax, eax
+ jz .ok
+
+ xor eax, eax
+ inc eax
+ ret
+
+ .ok: xor eax,eax
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.unget_char _f ;/////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push eax ecx
+ mov ecx, [_f]
+ inc [ecx + IniFile.cnt]
+ dec esi
+ mov eax, [ecx + IniFile.bsize]
+ cmp [ecx + IniFile.cnt], eax
+ jle @f
+ stdcall libini._.unload_block, [_f]
+ @@: pop ecx eax
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.get_char _f ;///////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ mov ecx, [_f]
+ dec [ecx + IniFile.cnt]
+ jns @f
+ stdcall libini._.preload_block, [_f]
+ dec [ecx + IniFile.cnt]
+ @@: lodsb
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.skip_nonblanks _f ;/////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ mov ecx, [_f]
+ @@: stdcall libini._.get_char, [_f]
+ cmp al, 32
+ je @b
+ cmp al, 13
+ je @b
+ cmp al, 10
+ je @b
+ cmp al, 9
+ je @b
+ cmp al, ini.COMMENT_CHAR
+ jne @f
+ stdcall libini._.skip_line, [_f]
+ jmp @b
+ @@: stdcall libini._.unget_char, [_f]
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.skip_spaces _f ;////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ mov ecx, [_f]
+ @@: stdcall libini._.get_char, [_f]
+ cmp al, 32
+ je @b
+ cmp al, 9
+ je @b
+ @@: stdcall libini._.unget_char, [_f]
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.skip_line _f ;//////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ mov ecx, [_f]
+ @@: stdcall libini._.get_char, [_f]
+ or al, al
+ jz @f
+ cmp al, 13
+ je @f
+ cmp al, 10
+ jne @b
+ @@: stdcall libini._.unget_char, [_f]
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.unload_block _f ;///////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push eax ebx ecx
+ mov ebx, [_f]
+ mov eax, [ebx + IniFile.pos]
+ add eax, -ini.BLOCK_SIZE
+ invoke file.seek, [ebx + IniFile.fh], eax, SEEK_SET
+ stdcall libini._.preload_block, ebx
+ add esi, eax
+ mov [ebx + IniFile.cnt], 0
+ pop ecx ebx eax
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.preload_block _f ;//////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push eax ebx ecx
+ mov ebx, [_f]
+ @@: mov esi, [ebx + IniFile.buf]
+ push edi
+ mov edi, esi
+ mov ecx, ini.BLOCK_SIZE / 4
+ xor eax, eax
+ rep stosd
+ pop edi
+ invoke file.tell, [ebx + IniFile.fh]
+ mov [ebx + IniFile.pos], eax
+ invoke file.read, [ebx + IniFile.fh], esi, ini.BLOCK_SIZE
+ mov esi,[ebx + IniFile.buf]
+ cmp eax,ini.BLOCK_SIZE
+ jl @f
+ @@: mov [ebx + IniFile.cnt], eax
+ mov [ebx + IniFile.bsize], eax
+ pop ecx ebx eax
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.reload_block _f ;///////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push eax ebx ecx
+ mov ebx, [_f]
+ push [ebx + IniFile.bsize]
+ push esi [ebx + IniFile.cnt]
+ invoke file.seek, [ebx + IniFile.fh], [ebx + IniFile.pos], SEEK_SET
+ stdcall libini._.preload_block, ebx
+ pop [ebx + IniFile.cnt] esi
+ pop eax
+ sub eax,[ebx + IniFile.bsize]
+ sub [ebx + IniFile.cnt], eax
+ pop ecx ebx eax
+ ret
+endp
+
+; f_info - contains current file block number
+; esi - position in block from where to shift
+; ecx - number of bytes to shift by
+
+;;================================================================================================;;
+proc libini._.shift_content _f, _delta ;//////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Shift file content starting from cursor position (~ delete) ;;
+;? Content is copied by 'delta' bytes up/down ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (fail) / 0 (ok) ;;
+;;================================================================================================;;
+locals
+ buf dd ?
+endl
+
+ xor eax, eax
+ cmp [_delta], 0
+ je .skip
+
+ push ebx ecx
+ invoke mem.alloc, ini.BLOCK_SIZE
+ or eax, eax
+ jz .fail
+ mov [buf], eax
+
+ cmp [_delta], 0
+ jl .down
+
+ mov ebx, [_f]
+ mov ecx, [ebx + IniFile.cnt]
+ mov ebx, [ebx + IniFile.fh]
+ invoke file.tell, ebx
+ sub eax, ecx
+ invoke file.seek, ebx, eax, SEEK_SET
+ @@: invoke file.seek, ebx, [_delta], SEEK_CUR
+ invoke file.eof?, ebx
+ or eax, eax
+ jnz .done
+ invoke file.read, ebx, [buf], ini.BLOCK_SIZE
+ mov ecx, eax
+ mov eax, [_delta]
+ neg eax
+ sub eax, ecx
+ invoke file.seek, ebx, eax, SEEK_CUR
+ invoke file.write, ebx, [buf], ecx
+ jmp @b
+ .done:
+ mov eax, [_delta]
+ neg eax
+ invoke file.seek, ebx, eax, SEEK_CUR
+ invoke file.seteof, ebx
+ stdcall libini._.reload_block, [_f]
+ invoke mem.free, [buf]
+ pop ecx ebx
+ .skip:
+ ret
+ .fail:
+ or eax, -1
+ pop ecx ebx
+ ret
+
+ .down:
+ neg [_delta]
+
+ mov ebx, [_f]
+ mov ecx, [ebx + IniFile.cnt]
+ mov ebx, [ebx + IniFile.fh]
+ invoke file.tell, ebx
+ sub eax, ecx
+ lea edx, [eax - 1]
+ push edx
+ @@: invoke file.seek, ebx, edx, SEEK_SET
+ invoke file.eof?, ebx
+ or eax, eax
+ jnz @f
+ add edx, ini.BLOCK_SIZE
+ jmp @b
+ @@: cmp edx, [esp]
+ je .skip.2
+ add edx, -ini.BLOCK_SIZE
+ cmp edx, [esp]
+ jl @f
+ invoke file.seek, ebx, edx, SEEK_SET
+ invoke file.read, ebx, [buf], ini.BLOCK_SIZE
+ mov ecx, eax
+ mov eax, [_delta]
+ sub eax, ecx
+ invoke file.seek, ebx, eax, SEEK_CUR
+ invoke file.write, ebx, [buf], ecx
+ jmp @b
+ @@:
+ .skip.2:
+ add esp, 4
+ stdcall libini._.reload_block, [_f]
+ invoke mem.free, [buf]
+ pop ecx ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.get_value_length _f ;///////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push ebx ecx edx eax
+ mov ebx, [_f]
+ invoke file.tell, [ebx + IniFile.fh]
+ push esi [ebx + IniFile.cnt] [ebx + IniFile.pos]
+ sub eax, [ebx + IniFile.cnt]
+ mov edx, eax
+
+ stdcall libini._.skip_line, [_f]
+ invoke file.tell, [ebx + IniFile.fh]
+ sub eax, [ebx + IniFile.cnt]
+ sub eax, edx
+ mov [esp + 4 * 3], eax
+
+ pop eax
+ invoke file.seek, [ebx + IniFile.fh], eax, SEEK_SET
+ stdcall libini._.preload_block, [_f]
+ pop [ebx + IniFile.cnt] esi
+ pop eax edx ecx ebx
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.string_copy ;///////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ @@: lodsb
+ or al, al
+ jz @f
+ stosb
+ jmp @b
+ @@: ret
+endp
+
+;;================================================================================================;;
+proc libini._.find_next_section _f ;//////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push ebx edi
+
+ @@: stdcall libini._.skip_nonblanks, [_f]
+ cmp al, '['
+ je @f
+ or al, al
+ jz .exit_error
+ stdcall libini._.skip_line, [_f]
+ or al, al
+ jz .exit_error
+ jmp @b
+ @@:
+ pop edi ebx
+ xor eax, eax
+ ret
+
+ .exit_error:
+ pop edi ebx
+ or eax, -1
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.find_section _f, _sec_name ;////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Find section in file ;;
+;? Search is performed from the beginning of file ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (fail) / 0 (ok) ;;
+;< [_f.pos] = new cursor position (right after ']' char if eax = 0, at the end of file otherwise) ;;
+;;================================================================================================;;
+ push ebx edi
+
+ mov ecx, [_f]
+ invoke file.seek, [ecx + IniFile.fh], 0, SEEK_SET
+ stdcall libini._.preload_block, [_f]
+
+ .next_section:
+ stdcall libini._.find_next_section, [_f]
+ or eax, eax
+ jnz .exit_error
+
+ stdcall libini._.get_char, [_f]
+ stdcall libini._.skip_spaces, [_f]
+ mov edi, [_sec_name]
+ @@: stdcall libini._.get_char, [_f]
+ cmp al, ']'
+ je @f
+ or al, al
+ jz .exit_error
+ cmp al, 13
+ je .next_section
+ cmp al, 10
+ je .next_section
+ scasb
+ je @b
+ cmp byte[edi - 1], 0
+ jne .next_section
+ dec edi
+ stdcall libini._.unget_char, [_f]
+ stdcall libini._.skip_spaces, [_f]
+ stdcall libini._.get_char, [_f]
+ cmp al, ']'
+ jne .next_section
+ @@:
+ cmp byte[edi], 0
+ jne .next_section
+ pop edi ebx
+ xor eax, eax
+ ret
+
+ .exit_error:
+ pop edi ebx
+ or eax, -1
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.find_key _f, _key_name ;////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? Find key in section ;;
+;? Search is performed within current section starting from cursor position ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = -1 (fail) / 0 (ok) ;;
+;< [_f.pos] = new cursor position (right after '=' char if eax = 0, at the end of file or right ;;
+;< before '[' char otherwise) ;;
+;;================================================================================================;;
+ push ebx edi
+
+ .next_value:
+ mov edi, [_key_name]
+ stdcall libini._.skip_line, [_f]
+ stdcall libini._.skip_nonblanks, [_f]
+ or al, al
+ jz .exit_error
+ cmp al, '['
+ je .exit_error
+ @@: stdcall libini._.get_char, [_f]
+ or al, al
+ jz .exit_error
+ cmp al, '='
+ je @f
+ scasb
+ je @b
+ cmp byte[edi - 1], 0
+ jne .next_value
+ dec edi
+ stdcall libini._.unget_char, [_f]
+ stdcall libini._.skip_spaces, [_f]
+ stdcall libini._.get_char, [_f]
+ cmp al, '='
+ je @f
+ jmp .next_value
+ @@:
+ cmp byte[edi], 0
+ jne .next_value
+
+ pop edi ebx
+ xor eax, eax
+ ret
+
+ .exit_error:
+ pop edi ebx
+ or eax, -1
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.low.read_value _f_addr, _buffer, _buf_len ;/////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push edi eax
+ mov edi, [_buffer]
+ stdcall libini._.skip_spaces, [_f_addr]
+ @@: dec [_buf_len]
+ jz @f
+ stdcall libini._.get_char, [_f_addr]
+ cmp al, 13
+ je @f
+ cmp al, 10
+ je @f
+ stosb
+ or al, al
+ jnz @b
+ @@: stdcall libini._.unget_char, [_f_addr]
+ mov byte[edi], 0
+ dec edi
+ @@: cmp edi, [_buffer]
+ jb @f
+ cmp byte[edi], 32
+ ja @f
+ mov byte[edi], 0
+ dec edi
+ jmp @b
+ @@: pop eax edi
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.str_to_int ;////////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> esi = string buffer address ;;
+;;------------------------------------------------------------------------------------------------;;
+;< eax = binary number representation (no overflow checks made) ;;
+;;================================================================================================;;
+ push edx
+
+ xor eax, eax
+ xor edx, edx
+
+ @@: lodsb
+ cmp al, '0'
+ jb @f
+ cmp al, '9'
+ ja @f
+ add eax, -'0'
+ imul edx, 10
+ add edx, eax
+ jmp @b
+
+ @@: dec esi
+ mov eax, edx
+ pop edx
+ ret
+endp
+
+;;================================================================================================;;
+proc libini._.int_to_str ;////////////////////////////////////////////////////////////////////////;;
+;;------------------------------------------------------------------------------------------------;;
+;? --- TBD --- ;;
+;;------------------------------------------------------------------------------------------------;;
+;> eax = number to convert ;;
+;> ecx = base ;;
+;> edi = string buffer address ;;
+;;------------------------------------------------------------------------------------------------;;
+;< --- TBD --- ;;
+;;================================================================================================;;
+ push ecx edx
+
+ or eax, eax
+ jns @f
+ mov byte[edi], '-'
+ inc edi
+ @@: call .recurse
+ pop edx ecx
+ ret
+
+ .recurse:
+ cmp eax,ecx
+ jb @f
+ xor edx,edx
+ div ecx
+ push edx
+ call .recurse
+ pop eax
+ @@: cmp al,10
+ sbb al,0x69
+ das
+ stosb
+ retn
+endp
diff --git a/programs/develop/libraries/libs-dev/libini/libini_p.inc b/programs/develop/libraries/libs-dev/libini/libini_p.inc
new file mode 100644
index 0000000000..73311b4c71
--- /dev/null
+++ b/programs/develop/libraries/libs-dev/libini/libini_p.inc
@@ -0,0 +1,34 @@
+;;================================================================================================;;
+;;//// libini_p.inc //// (c) mike.dld, 2007-2008 /////////////////////////////////////////////////;;
+;;================================================================================================;;
+;; ;;
+;; This file is part of Common development libraries (Libs-Dev). ;;
+;; ;;
+;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
+;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
+;; of the License, or (at your option) any later version. ;;
+;; ;;
+;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;;
+;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
+;; Lesser General Public License for more details. ;;
+;; ;;
+;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;;
+;; If not, see . ;;
+;; ;;
+;;================================================================================================;;
+
+
+ini.MAX_NAME_LEN = 1024
+ini.MAX_VALUE_LEN = 4096
+ini.MEM_SIZE = 4096
+ini.BLOCK_SIZE = ini.MEM_SIZE / 2
+
+ini.COMMENT_CHAR = ';'
+
+struct IniFile
+ fh dd ?
+ buf dd ?
+ cnt dd ?
+ pos dd ?
+ bsize dd ?
+ends