Subversion Repositories Kolibri OS

Rev

Rev 3112 | Rev 3832 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;================================================================================================;;
  2. ;;//// libini.asm //// (c) mike.dld, 2006-2008 ///////////////////////////////////////////////////;;
  3. ;;================================================================================================;;
  4. ;;                                                                                                ;;
  5. ;; This file is part of Common development libraries (Libs-Dev).                                  ;;
  6. ;;                                                                                                ;;
  7. ;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
  8. ;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
  9. ;; of the License, or (at your option) any later version.                                         ;;
  10. ;;                                                                                                ;;
  11. ;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without  ;;
  12. ;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  ;;
  13. ;; Lesser General Public License for more details.                                                ;;
  14. ;;                                                                                                ;;
  15. ;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev.  ;;
  16. ;; If not, see <http://www.gnu.org/licenses/>.                                                    ;;
  17. ;;                                                                                                ;;
  18. ;;================================================================================================;;
  19. ;;                                                                                                ;;
  20. ;; 2009-03-08 (mike.dld)                                                                          ;;
  21. ;;   bug-fixes:                                                                                   ;;
  22. ;;     - moved buffer bound check in libini._.low.read_value up (reported by Insolor)             ;;
  23. ;;   new features:                                                                                ;;
  24. ;;     - comments support (char is ini.COMMENT_CHAR, defaults to ';')                             ;;
  25. ;;       inline comments are not supported                                                        ;;
  26. ;; 2008-12-29 (mike.dld)                                                                          ;;
  27. ;;   bug-fixes:                                                                                   ;;
  28. ;;     - unnecessary 'stosb' in ini.get_str was causing problems                                  ;;
  29. ;;   new features:                                                                                ;;
  30. ;;     - new functions: ini.get_color and ini.set_color                                           ;;
  31. ;; 2008-08-06 (mike.dld)                                                                          ;;
  32. ;;   changes:                                                                                     ;;
  33. ;;     - split private procs into libini_p.asm, added comments                                    ;;
  34. ;; 2008-02-07 (mike.dld)                                                                          ;;
  35. ;;   changes:                                                                                     ;;
  36. ;;     - renamed all *.aux.* to *._.* to match overall libraries design                           ;;
  37. ;; 2007-09-26 (mike.dld)                                                                          ;;
  38. ;;   bug-fixes:                                                                                   ;;
  39. ;;     - value was not correctly trimmed (reported by diamond)                                    ;;
  40. ;; 2007-08-01 (mike.dld)                                                                          ;;
  41. ;;   bug-fixes:                                                                                   ;;
  42. ;;     - serious defect in ini.set_str causing displaced write operations                         ;;
  43. ;;       (reported by diamond)                                                                    ;;
  44. ;;     - another serious defect in ini.enum_keys introduced with refactoring                      ;;
  45. ;;   changes:                                                                                     ;;
  46. ;;     - callback for enum_keys now takes additional parameter - key value                        ;;
  47. ;;     - handling trailing spaces in section/key/value                                            ;;
  48. ;; 2007-05-19 (mike.dld)                                                                          ;;
  49. ;;   bug-fixes:                                                                                   ;;
  50. ;;     - last char still wasn't read correctly                                                    ;;
  51. ;;     - digits of number were reversed when using ini.set_int                                    ;;
  52. ;;     - now using 'ini.aux.unget_char' instead of dangerous 'dec esi'                            ;;
  53. ;;   changes:                                                                                     ;;
  54. ;;     - all non-public functions now start with ini.aux.*                                        ;;
  55. ;;     - added ini.enum_sections and ini.enum_keys                                                ;;
  56. ;;     - removed ini.query_sec (use ini.enum_* instead)                                           ;;
  57. ;;                                                                                                ;;
  58. ;;================================================================================================;;
  59.  
  60. format MS COFF
  61.  
  62. public @EXPORT as 'EXPORTS'
  63.  
  64. include '../../../../proc32.inc'
  65. include '../../../../macros.inc'
  66. include '../libio/libio.inc'
  67. purge section,mov,add,sub
  68.  
  69. include 'libini_p.inc'
  70.  
  71. section '.flat' code readable align 16
  72.  
  73. include 'libini_p.asm'
  74.  
  75. ;;================================================================================================;;
  76. proc ini.enum_sections _f_name, _callback ;///////////////////////////////////////////////////////;;
  77. ;;------------------------------------------------------------------------------------------------;;
  78. ;? Enumerate sections, calling callback function for each of them                                 ;;
  79. ;;------------------------------------------------------------------------------------------------;;
  80. ;> _f_name = ini filename <asciiz>                                                                ;;
  81. ;> _callback = callback function address: func(f_name, sec_name), where                           ;;
  82. ;>   f_name = ini filename (as passed to the function) <asciiz>                                   ;;
  83. ;>   sec_name = section name found <asciiz>                                                       ;;
  84. ;;------------------------------------------------------------------------------------------------;;
  85. ;< eax = -1 (error) / 0                                                                           ;;
  86. ;;================================================================================================;;
  87. locals
  88.   f       IniFile
  89.   f_addr  dd ?
  90.   sec_buf dd ?
  91. endl
  92.  
  93.         push    ebx esi edi
  94.  
  95.         cld
  96.  
  97.         invoke  mem.alloc, ini.MAX_NAME_LEN
  98.         or      eax, eax
  99.         jz      .exit_error.2
  100.         mov     [sec_buf], eax
  101.  
  102.         xor     eax, eax
  103.         mov     [f.fh], eax
  104.         mov     [f.buf], eax
  105.         invoke  file.open, [_f_name], O_READ
  106.         cmp     eax, 32
  107.         jb      .exit_file_error
  108.         mov     [f.fh], eax
  109.         invoke  mem.alloc, ini.MEM_SIZE
  110.         or      eax, eax
  111.         jz      .exit_error
  112.         mov     [f.buf], eax
  113.         lea     ebx, [f]
  114.         mov     [f_addr], ebx
  115.  
  116.         invoke  file.seek, [f.fh], 0, SEEK_SET
  117.         stdcall libini._.preload_block, [f_addr]
  118.  
  119.   .next_section:
  120.         stdcall libini._.find_next_section, [f_addr]
  121.         or      eax, eax
  122.         jnz     .exit_error
  123.  
  124.         stdcall libini._.get_char, [f_addr]
  125.         stdcall libini._.skip_spaces, [f_addr]
  126.         mov     edi, [sec_buf]
  127.     @@: stdcall libini._.get_char, [f_addr]
  128.         cmp     al, ']'
  129.         je      @f
  130.         or      al, al
  131.         jz      .exit_ok
  132.         cmp     al, 13
  133.         je      .next_section
  134.         cmp     al, 10
  135.         je      .next_section
  136.         stosb
  137.         jmp     @b
  138.     @@: xor     al, al
  139.         stosb
  140.         add     edi, -2
  141.     @@: cmp     byte[edi], 32
  142.         ja      @f
  143.         mov     byte[edi], 0
  144.         dec     edi
  145.         jmp     @b
  146.     @@:
  147.         pushad
  148.         mov     eax, [f_addr]
  149.         stdcall [_callback], [_f_name], [sec_buf]
  150.         or      eax, eax
  151.         popad
  152.         jnz     .next_section
  153.  
  154.   .exit_ok:
  155.         invoke  file.close, [f.fh]
  156.         invoke  mem.free, [f.buf]
  157.         invoke  mem.free, [sec_buf]
  158.         xor     eax, eax
  159.         pop     edi esi ebx
  160.         ret
  161.  
  162.   .exit_error:
  163.         invoke  file.close, [f.fh]
  164.         invoke  mem.free, [f.buf]
  165.   .exit_file_error:
  166.         invoke  mem.free, [sec_buf]
  167.   .exit_error.2:
  168.         or      eax, -1
  169.         pop     edi esi ebx
  170.         ret
  171. endp
  172.  
  173. ;;================================================================================================;;
  174. proc ini.enum_keys _f_name, _sec_name, _callback ;////////////////////////////////////////////////;;
  175. ;;------------------------------------------------------------------------------------------------;;
  176. ;? Enumerate keys within a section, calling callback function for each of them                    ;;
  177. ;;------------------------------------------------------------------------------------------------;;
  178. ;> _f_name = ini filename <asciiz>                                                                ;;
  179. ;> _sec_name = section name <asciiz>                                                              ;;
  180. ;> _callback = callback function address: func(f_name, sec_name, key_name, key_value), where      ;;
  181. ;>   f_name = ini filename (as passed to the function) <asciiz>                                   ;;
  182. ;>   sec_name = section name (as passed to the function) <asciiz>                                 ;;
  183. ;>   key_name = key name found <asciiz>                                                           ;;
  184. ;>   key_value = value of key found <asciiz>                                                      ;;
  185. ;;------------------------------------------------------------------------------------------------;;
  186. ;< eax = -1 (error) / 0                                                                           ;;
  187. ;;================================================================================================;;
  188. locals
  189.   f       IniFile
  190.   f_addr  dd ?
  191.   key_buf dd ?
  192.   val_buf dd ?
  193. endl
  194.  
  195.         push    ebx esi edi
  196.  
  197.         cld
  198.  
  199.         invoke  mem.alloc, ini.MAX_NAME_LEN
  200.         or      eax, eax
  201.         jz      .exit_error.3
  202.         mov     [key_buf], eax
  203.         invoke  mem.alloc, ini.MAX_VALUE_LEN
  204.         or      eax, eax
  205.         jz      .exit_error.2
  206.         mov     [val_buf], eax
  207.  
  208.         xor     eax, eax
  209.         mov     [f.fh], eax
  210.         mov     [f.buf], eax
  211.         invoke  file.open, [_f_name], O_READ
  212.         cmp     eax, 32
  213.         jb      .exit_file_error
  214.         mov     [f.fh], eax
  215.         invoke  mem.alloc, ini.MEM_SIZE
  216.         or      eax, eax
  217.         jz      .exit_error
  218.         mov     [f.buf], eax
  219.         lea     ebx, [f]
  220.         mov     [f_addr], ebx
  221.         stdcall libini._.find_section, ebx, [_sec_name]
  222.         or      eax, eax
  223.         jnz     .exit_error
  224.  
  225.   .next_key:
  226.         stdcall libini._.skip_line, [f_addr]
  227.         stdcall libini._.skip_nonblanks, [f_addr]
  228.         or      al, al
  229.         jz      .exit_error
  230.         cmp     al, '['
  231.         je      .exit_error
  232.         mov     edi, [key_buf]
  233.     @@: stdcall libini._.get_char, [f_addr]
  234.         or      al, al
  235.         jz      .exit_error
  236.         cmp     al, '='
  237.         je      @f
  238.         stosb
  239.         jmp     @b
  240.     @@:
  241.         xor     al, al
  242.         stosb
  243.         add     edi, -2
  244.     @@: cmp     byte[edi], 32
  245.         ja      @f
  246.         mov     byte[edi], 0
  247.         dec     edi
  248.         jmp     @b
  249.     @@: stdcall libini._.low.read_value, [f_addr], [val_buf], ini.MAX_VALUE_LEN
  250.         pushad
  251.         stdcall [_callback], [_f_name], [_sec_name], [key_buf], [val_buf]
  252.         or      eax, eax
  253.         popad
  254.         jnz     .next_key
  255.  
  256.     @@: invoke  file.close, [f.fh]
  257.         invoke  mem.free, [f.buf]
  258.         xor     eax, eax
  259.         stosb
  260.         pop     edi esi ebx
  261.         ret
  262.  
  263.   .exit_error:
  264.         invoke  file.close, [f.fh]
  265.         invoke  mem.free, [f.buf]
  266.   .exit_file_error:
  267.         invoke  mem.free, [val_buf]
  268.   .exit_error.2:
  269.         invoke  mem.free, [key_buf]
  270.   .exit_error.3:
  271.         or      eax, -1
  272.         pop     edi esi ebx
  273.         ret
  274. endp
  275.  
  276. ;;================================================================================================;;
  277. proc ini.get_str _f_name, _sec_name, _key_name, _buffer, _buf_len, _def_val ;/////////////////////;;
  278. ;;------------------------------------------------------------------------------------------------;;
  279. ;? Read string                                                                                    ;;
  280. ;;------------------------------------------------------------------------------------------------;;
  281. ;> _f_name = ini filename <asciiz>                                                                ;;
  282. ;> _sec_name = section name <asciiz>                                                              ;;
  283. ;> _key_name = key name <asciiz>                                                                  ;;
  284. ;> _buffer = destination buffer address <byte*>                                                   ;;
  285. ;> _buf_len = buffer size (maximum bytes to read) <dword>                                         ;;
  286. ;> _def_val = default value to return if no key, section or file found <asciiz>                   ;;
  287. ;;------------------------------------------------------------------------------------------------;;
  288. ;< eax = -1 (error) / 0                                                                           ;;
  289. ;< [_buffer] = [_def_val] (error) / found key value <asciiz>                                      ;;
  290. ;;================================================================================================;;
  291. locals
  292.   f      IniFile
  293.   f_addr dd ?
  294. endl
  295.  
  296.         push    ebx esi edi
  297.  
  298.         xor     eax, eax
  299.         mov     [f.fh], eax
  300.         mov     [f.buf], eax
  301.         invoke  file.open, [_f_name], O_READ
  302.         cmp     eax, 32
  303.         jb      .exit_file_error
  304.         mov     [f.fh], eax
  305.         invoke  mem.alloc, ini.MEM_SIZE
  306.         or      eax, eax
  307.         jz      .exit_error
  308.         mov     [f.buf], eax
  309.         lea     ebx, [f]
  310.         mov     [f_addr], ebx
  311.         stdcall libini._.find_section, ebx, [_sec_name]
  312.         or      eax, eax
  313.         jnz     .exit_error
  314.  
  315.         stdcall libini._.find_key, ebx, [_key_name]
  316.         or      eax, eax
  317.         jnz     .exit_error
  318.  
  319.         stdcall libini._.low.read_value, [f_addr], [_buffer], [_buf_len]
  320.     @@: invoke  file.close, [f.fh]
  321.         invoke  mem.free, [f.buf]
  322.         xor     eax, eax
  323.         pop     edi esi ebx
  324.         ret
  325.  
  326.   .exit_error:
  327.         invoke  file.close, [f.fh]
  328.         invoke  mem.free, [f.buf]
  329.   .exit_file_error:
  330.         mov     edi, [_buffer]
  331.         mov     esi, [_def_val]
  332.         xor     al, al
  333.         or      esi, esi
  334.         jz      .exit_error.2
  335.     @@: lodsb
  336.   .exit_error.2:
  337.         stosb
  338.         or      al, al
  339.         jnz     @b
  340.         or      eax, -1
  341.         pop     edi esi ebx
  342.         ret
  343. endp
  344.  
  345. ;;================================================================================================;;
  346. proc ini.set_str _f_name, _sec_name, _key_name, _buffer, _buf_len ;///////////////////////////////;;
  347. ;;------------------------------------------------------------------------------------------------;;
  348. ;? Write string                                                                                   ;;
  349. ;;------------------------------------------------------------------------------------------------;;
  350. ;> _f_name = ini filename <asciiz>                                                                ;;
  351. ;> _sec_name = section name <asciiz>                                                              ;;
  352. ;> _key_name = key name <asciiz>                                                                  ;;
  353. ;> _buffer = source buffer address <byte*>                                                        ;;
  354. ;> _buf_len = buffer size (bytes to write) <dword>                                                ;;
  355. ;;------------------------------------------------------------------------------------------------;;
  356. ;< eax = -1 (error) / 0                                                                           ;;
  357. ;;================================================================================================;;
  358. locals
  359.   f      IniFile
  360.   f_addr dd ?
  361. endl
  362.  
  363.         push    ebx esi edi
  364.  
  365.         xor     eax, eax
  366.         mov     [f.fh], eax
  367.         mov     [f.buf], eax
  368.         invoke  file.open, [_f_name], O_READ + O_WRITE + O_CREATE
  369.         cmp     eax, 32
  370.         jb      .exit_file_error
  371.         mov     [f.fh], eax
  372.         invoke  mem.alloc, ini.MEM_SIZE
  373.         or      eax, eax
  374.         jz      .exit_error
  375.         mov     [f.buf], eax
  376.         lea     ebx, [f]
  377.         mov     [f_addr], ebx
  378.  
  379.         stdcall libini._.find_section, ebx, [_sec_name]
  380.         or      eax, eax
  381.         jnz     .create_section
  382.  
  383.         stdcall libini._.find_key, ebx, [_key_name]
  384.         or      eax, eax
  385.         jnz     .create_key
  386.  
  387.   .modify_key:
  388.         stdcall libini._.get_value_length, [f_addr]
  389.         sub     eax, [_buf_len]
  390.         stdcall libini._.shift_content, [f_addr], eax
  391.  
  392.   .modify_key.ex:
  393.         invoke  file.tell, [f.fh]
  394.         sub     eax, [f.cnt]
  395.         invoke  file.seek, [f.fh], eax, SEEK_SET
  396.         invoke  file.write, [f.fh], [_buffer], [_buf_len]
  397.  
  398.         invoke  file.close, [f.fh]
  399.         pop     edi esi ebx
  400.         xor     eax, eax
  401.         ret
  402.  
  403.   .create_key:
  404.         mov     edi, [f.buf]
  405.         add     edi, ini.BLOCK_SIZE
  406.         push    edi
  407.  
  408.   .create_key.ex:
  409.         mov     esi, [_key_name]
  410.         call    libini._.string_copy
  411.         mov     byte[edi], '='
  412.         inc     edi
  413.         mov     esi, [_buffer]
  414.         mov     ecx, [_buf_len]
  415.         rep     movsb
  416.         mov     word[edi], 0x0A0D
  417.         add     edi, 2
  418.         mov     eax, edi
  419.  
  420.         pop     edi
  421.         sub     eax, edi
  422.         mov     [_buffer], edi
  423.         mov     [_buf_len], eax
  424.         neg     eax
  425.         stdcall libini._.shift_content, [f_addr], eax
  426.  
  427.         jmp     .modify_key.ex
  428.  
  429.   .create_section:
  430.         mov     edi, [f.buf]
  431.         add     edi, ini.BLOCK_SIZE
  432.         push    edi
  433.  
  434.         mov     esi, [_sec_name]
  435.         mov     byte[edi], '['
  436.         inc     edi
  437.         call    libini._.string_copy
  438.         mov     dword[edi], ']' + (0x0A0D shl 8)
  439.         add     edi, 3
  440.  
  441.         jmp     .create_key.ex
  442.  
  443.   .exit_error:
  444.         invoke  file.close, [f.fh]
  445.   .exit_file_error:
  446.         pop     edi esi ebx
  447.         or      eax, -1
  448.         ret
  449. endp
  450.  
  451. ;;================================================================================================;;
  452. proc ini.get_int _f_name, _sec_name, _key_name, _def_val ;////////////////////////////////////////;;
  453. ;;------------------------------------------------------------------------------------------------;;
  454. ;? Read integer                                                                                   ;;
  455. ;;------------------------------------------------------------------------------------------------;;
  456. ;> _f_name = ini filename <asciiz>                                                                ;;
  457. ;> _sec_name = section name <asciiz>                                                              ;;
  458. ;> _key_name = key name <asciiz>                                                                  ;;
  459. ;> _def_val = default value to return if no key, section or file found <dword>                    ;;
  460. ;;------------------------------------------------------------------------------------------------;;
  461. ;< eax = [_def_val] (error) / found key value <dword>                                             ;;
  462. ;;================================================================================================;;
  463. locals
  464.   f      IniFile
  465.   f_addr dd ?
  466. endl
  467.  
  468.         push    edx ebx esi edi
  469.  
  470.         xor     eax, eax
  471.         mov     [f.fh], eax
  472.         mov     [f.buf], eax
  473.         invoke  file.open, [_f_name], O_READ
  474.         cmp     eax, 32
  475.         jb      .exit_file_error
  476.         mov     [f.fh], eax
  477.         invoke  mem.alloc, ini.MEM_SIZE
  478.         or      eax, eax
  479.         jz      .exit_error
  480.         mov     [f.buf], eax
  481.         lea     ebx, [f]
  482.         mov     [f_addr], ebx
  483.         stdcall libini._.find_section, ebx, [_sec_name]
  484.         or      eax, eax
  485.         jnz     .exit_error
  486.  
  487.         stdcall libini._.find_key, ebx, [_key_name]
  488.         or      eax, eax
  489.         jnz     .exit_error
  490.  
  491.         stdcall libini._.skip_spaces, [f_addr]
  492.         xor     eax, eax
  493.         xor     ebx, ebx
  494.         xor     edx, edx
  495.         stdcall libini._.get_char, [f_addr]
  496.         cmp     al, '-'
  497.         jne     .lp1
  498.         inc     bh
  499.     @@: stdcall libini._.get_char, [f_addr]
  500.   .lp1: cmp     al, '0'
  501.         jb      @f
  502.         cmp     al, '9'
  503.         ja      @f
  504.         inc     bl
  505.         add     eax, -'0'
  506.         imul    edx, 10
  507.         add     edx, eax
  508.         jmp     @b
  509.     @@:
  510.         or      bl, bl
  511.         jz      .exit_error
  512.         or      bh, bh
  513.         jz      @f
  514.         neg     edx
  515.     @@: invoke  file.close, [f.fh]
  516.         invoke  mem.free, [f.buf]
  517.         mov     eax, edx
  518.         pop     edi esi ebx edx
  519.         ret
  520.  
  521.   .exit_error:
  522.         invoke  file.close, [f.fh]
  523.   .exit_file_error:
  524.         invoke  mem.free, [f.buf]
  525.         mov     eax, [_def_val]
  526.         pop     edi esi ebx edx
  527.         ret
  528. endp
  529.  
  530. ;;================================================================================================;;
  531. proc ini.set_int _f_name, _sec_name, _key_name, _val ;////////////////////////////////////////////;;
  532. ;;------------------------------------------------------------------------------------------------;;
  533. ;? Write integer                                                                                  ;;
  534. ;;------------------------------------------------------------------------------------------------;;
  535. ;> _f_name = ini filename <asciiz>                                                                ;;
  536. ;> _sec_name = section name <asciiz>                                                              ;;
  537. ;> _key_name = key name <asciiz>                                                                  ;;
  538. ;> _val = value <dword>                                                                           ;;
  539. ;;------------------------------------------------------------------------------------------------;;
  540. ;< eax = -1 (error) / 0                                                                           ;;
  541. ;;================================================================================================;;
  542. locals
  543.   buf rb 16
  544. endl
  545.  
  546.         push    ecx edx edi
  547.  
  548.         lea     edi, [buf]
  549.         add     edi, 15
  550.         mov     eax, [_val]
  551.         or      eax, eax
  552.         jns     @f
  553.         mov     byte[edi], '-'
  554.         neg     eax
  555.         inc     edi
  556.     @@: mov     ecx, 10
  557.     @@: xor     edx, edx
  558.         idiv    ecx
  559.         add     dl, '0'
  560.         mov     [edi], dl
  561.         dec     edi
  562.         or      eax, eax
  563.         jnz     @b
  564.         lea     eax, [buf]
  565.         add     eax, 15
  566.         sub     eax, edi
  567.         inc     edi
  568.  
  569.         stdcall ini.set_str, [_f_name], [_sec_name], [_key_name], edi, eax
  570.  
  571.         pop     edi edx ecx
  572.         ret
  573. endp
  574.  
  575. ;;================================================================================================;;
  576. proc ini.get_color _f_name, _sec_name, _key_name, _def_val ;//////////////////////////////////////;;
  577. ;;------------------------------------------------------------------------------------------------;;
  578. ;? Read color                                                                                     ;;
  579. ;;------------------------------------------------------------------------------------------------;;
  580. ;> _f_name = ini filename <asciiz>                                                                ;;
  581. ;> _sec_name = section name <asciiz>                                                              ;;
  582. ;> _key_name = key name <asciiz>                                                                  ;;
  583. ;> _def_val = default value to return if no key, section or file found <dword>                    ;;
  584. ;;------------------------------------------------------------------------------------------------;;
  585. ;< eax = [_def_val] (error) / found key value <dword>                                             ;;
  586. ;;================================================================================================;;
  587. locals
  588.   buf rb 14
  589. endl
  590.  
  591.         push    ebx esi edi
  592.  
  593.         lea     esi, [buf]
  594.         stdcall ini.get_str, [_f_name], [_sec_name], [_key_name], esi, 14, 0
  595.         cmp     byte[esi],0
  596.         je      .exit_error
  597.  
  598.         xor     ebx, ebx
  599.         stdcall libini._.str_to_int
  600.         movzx   ebx, al
  601.         shl     ebx, 16
  602.         lodsb
  603.         cmp     al, ','
  604.         jne     @f
  605.         stdcall libini._.str_to_int
  606.         mov     bh, al
  607.         lodsb
  608.         cmp     al, ','
  609.         jne     @f
  610.         stdcall libini._.str_to_int
  611.         mov     bl, al
  612.  
  613.     @@: mov     eax, ebx
  614.  
  615.         pop     edi esi ebx
  616.         ret
  617.  
  618.   .exit_error:
  619.         mov     eax, [_def_val]
  620.         pop     edi esi ebx
  621.         ret
  622. endp
  623.  
  624. ;;================================================================================================;;
  625. proc ini.set_color _f_name, _sec_name, _key_name, _val ;//////////////////////////////////////////;;
  626. ;;------------------------------------------------------------------------------------------------;;
  627. ;? Write color                                                                                    ;;
  628. ;;------------------------------------------------------------------------------------------------;;
  629. ;> _f_name = ini filename <asciiz>                                                                ;;
  630. ;> _sec_name = section name <asciiz>                                                              ;;
  631. ;> _key_name = key name <asciiz>                                                                  ;;
  632. ;> _val = value <dword>                                                                           ;;
  633. ;;------------------------------------------------------------------------------------------------;;
  634. ;< eax = -1 (error) / 0                                                                           ;;
  635. ;;================================================================================================;;
  636. locals
  637.   buf rb 16
  638. endl
  639.  
  640.         push    ecx edx edi
  641.  
  642.         lea     edi, [buf]
  643.         mov     ecx, 10
  644.         mov     ebx, [_val]
  645.         mov     eax, ebx
  646.         shr     eax, 16
  647.         and     eax, 0x0ff
  648.         stdcall libini._.int_to_str
  649.         mov     byte[edi], ','
  650.         inc     edi
  651.         movzx   eax, bh
  652.         stdcall libini._.int_to_str
  653.         mov     byte[edi], ','
  654.         inc     edi
  655.         movzx   eax, bl
  656.         stdcall libini._.int_to_str
  657.  
  658.         lea     eax, [buf]
  659.         sub     edi, eax
  660.  
  661.         stdcall ini.set_str, [_f_name], [_sec_name], [_key_name], eax, edi
  662.  
  663.         pop     edi edx ecx
  664.         ret
  665. endp
  666.  
  667. ;;================================================================================================;;
  668. proc ini.get_shortcut _f_name, _sec_name, _key_name, _def_val, _modifiers ;///////////////////////;;
  669. ;;------------------------------------------------------------------------------------------------;;
  670. ;? Read shortcut key                                                                              ;;
  671. ;;------------------------------------------------------------------------------------------------;;
  672. ;> _f_name = ini filename <asciiz>                                                                ;;
  673. ;> _sec_name = section name <asciiz>                                                              ;;
  674. ;> _key_name = key name <asciiz>                                                                  ;;
  675. ;> _def_val = default value to return if no key, section or file found <dword>                    ;;
  676. ;> _modifiers = pointer to dword variable which receives modifiers state as in 66.4 <dword*>      ;;
  677. ;;------------------------------------------------------------------------------------------------;;
  678. ;< eax = [_def_val] (error) / shortcut key value as scancode <int>                                ;;
  679. ;< [[_modifiers]] = unchanged (error) / modifiers state for this shortcut <int>                   ;;
  680. ;;================================================================================================;;
  681. locals
  682.   buf rb 64
  683. endl
  684.  
  685.         push    ebx esi edi
  686.  
  687.         lea     esi, [buf]
  688.         stdcall ini.get_str, [_f_name], [_sec_name], [_key_name], esi, 64, 0
  689.         cmp     byte[esi],0
  690.         je      .exit_error
  691.  
  692.         xor     ebx, ebx        ; ebx holds the value of modifiers
  693. .loop:
  694. ; test for end
  695.         xor     eax, eax
  696.         cmp     byte [esi], al
  697.         jz      .exit_ok        ; exit with scancode zero
  698. ; skip all '+'s
  699.         cmp     byte [esi], '+'
  700.         jnz     @f
  701.         inc     esi
  702.         jmp     .loop
  703. @@:
  704. ; test for names
  705.         mov     edi, .names_table
  706.         xor     edx, edx
  707. .names_loop:
  708.         movzx   ecx, byte [edi]
  709.         inc     edi
  710.         push    esi
  711. @@:
  712.         lodsb
  713.         or      al, 20h
  714.         scasb
  715.         loopz   @b
  716.         jz      .name_found
  717.         pop     esi
  718.         lea     edi, [edi+ecx+4]
  719.         inc     edx
  720.         cmp     byte [edi], 0
  721.         jnz     .names_loop
  722. ; special test: functional keys F<number>
  723.         cmp     byte [esi], 'f'
  724.         jz      @f
  725.         cmp     byte [esi], 'F'
  726.         jnz     .no_fx
  727. @@:
  728.         mov     edi, esi
  729.         inc     esi
  730.         call    libini._.str_to_int
  731.         test    eax, eax
  732.         jnz     .fx
  733.         mov     esi, edi
  734. .no_fx:
  735. ; name not found, that must be usual key
  736.         movzx   eax, byte [esi]
  737.         stdcall libini._.ascii_to_scan, eax
  738.         test    eax, eax
  739.         jz      .exit_error
  740. ; all is ok
  741. .exit_ok:
  742.         mov     ecx, [_modifiers]
  743.         test    ecx, ecx
  744.         jz      @f
  745.         mov     [ecx], ebx
  746.  
  747. @@:
  748.  
  749.         pop     edi esi ebx
  750.         ret
  751.  
  752. .exit_error:
  753.         mov     eax, [_def_val]
  754.         pop     edi esi ebx
  755.         ret
  756. ; handler for Fx
  757. ; eax = number
  758. .fx:
  759.         cmp     eax, 10
  760.         ja      @f
  761.         add     eax, 3Bh-1
  762.         jmp     .exit_ok
  763. @@:
  764.         add     eax, 57h-11
  765.         jmp     .exit_ok
  766. ; handlers for names
  767. .name_found:
  768.         pop     eax     ; ignore saved esi
  769.         call    dword [edi]
  770.         cmp     edx, .num_modifiers
  771.         jae     .exit_ok
  772.         jmp     .loop
  773. ; modifiers
  774. ; syntax of value for each modifier:
  775. ; 0 = none, 1 = exactly one of L+R, 2 = both L+R, 3 = L, 4 = R
  776. ; Logic for switching: LShift+RShift=LShift+Shift=Shift+Shift, LShift+LShift=LShift
  777. ; generic modifier: 0->1->2->2, 3->2, 4->2
  778. ; left modifier: 0->3->3, 1->2->2, 4->2
  779. ; right modifier: 0->4->4, 1->2->2, 3->2
  780. ; Shift corresponds to first hex digit, Ctrl - second, Alt - third
  781. macro shortcut_handle_modifiers name,reg,shift
  782. {
  783. local .set2,.set3,.set4
  784. .#name#_handler:        ; generic modifier
  785.         test    reg, 0xF
  786.         jnz     .set2
  787. if shift
  788.         or      reg, 1 shl shift
  789. else
  790.         inc     reg
  791. end if
  792.         retn
  793. .set2:
  794.         and     reg, not (0xF shl shift)
  795.         or      reg, 2 shl shift
  796.         retn
  797. .l#name#_handler:
  798.         mov     al, reg
  799.         and     al, 0xF shl shift
  800.         jz      .set3
  801.         cmp     al, 3 shl shift
  802.         jnz     .set2
  803.         retn
  804. .set3:
  805.         add     reg, 3 shl shift
  806.         retn
  807. .r#name#_handler:
  808.         mov     al, reg
  809.         and     al, 0xF shl shift
  810.         jz      .set4
  811.         cmp     al, 4 shl shift
  812.         jnz     .set2
  813.         retn
  814. .set4:
  815.         add     reg, 4 shl shift
  816.         retn
  817. }
  818. shortcut_handle_modifiers shift,bl,0
  819. shortcut_handle_modifiers ctrl,bl,4
  820. shortcut_handle_modifiers alt,bh,0
  821. ; names of keys
  822. .name_handler:
  823.         movzx   eax, byte [.names_scancodes+edx-.num_modifiers]
  824.         retn
  825. endp
  826.  
  827. ; note: comparison ignores case, so this table keeps lowercase names
  828. ; macro does this
  829. macro shortcut_name_with_handler name,handler
  830. {
  831. local .start, .end
  832.         db      .end - .start
  833. .start:
  834.         db      name
  835. .end:
  836. repeat .end - .start
  837.         load .a byte from .start + % - 1
  838.         store byte .a or 0x20 at .start + % - 1
  839. end repeat
  840.         dd      handler
  841. }
  842. macro shortcut_name [name]
  843. {
  844.         shortcut_name_with_handler name, .name_handler
  845. }
  846. ; all names here must be in english
  847. ; ... or modify lowercasing in macro and in comparison
  848. .names_table:
  849. ; generic modifiers
  850.         shortcut_name_with_handler 'Ctrl', .ctrl_handler
  851.         shortcut_name_with_handler 'Alt', .alt_handler
  852.         shortcut_name_with_handler 'Shift', .shift_handler
  853. ; concrete modifiers
  854.         shortcut_name_with_handler 'LCtrl', .lctrl_handler
  855.         shortcut_name_with_handler 'RCtrl', .rctrl_handler
  856.         shortcut_name_with_handler 'LAlt', .lalt_handler
  857.         shortcut_name_with_handler 'RAlt', .ralt_handler
  858.         shortcut_name_with_handler 'LShift', .lshift_handler
  859.         shortcut_name_with_handler 'RShift', .rshift_handler
  860. .num_modifiers = 9
  861. ; symbolic names of keys
  862.         shortcut_name 'Home', 'End', 'PgUp', 'PgDn', 'Ins', 'Insert', 'Del', 'Delete'
  863.         shortcut_name 'Tab', 'Plus', 'Esc', 'Enter', 'Backspace', 'Space', 'Left', 'Right'
  864.         shortcut_name 'Up', 'Down'
  865. ; end of table
  866.         db      0
  867. ini.get_shortcut.names_scancodes:
  868. ; scancodes for 'Home' ... 'Down'
  869.         db      47h, 4Fh, 49h, 51h, 52h, 52h, 53h, 53h
  870.         db      0Fh, 4Eh, 01h, 1Ch, 0Eh, 39h, 4Bh, 4Dh
  871.         db      48h, 50h
  872.  
  873. ;;================================================================================================;;
  874. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  875. ;;================================================================================================;;
  876. ;! Imported functions section                                                                     ;;
  877. ;;================================================================================================;;
  878. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  879. ;;================================================================================================;;
  880.  
  881.  
  882. align 16
  883. @IMPORT:
  884.  
  885. library \
  886.         libio , 'libio.obj'
  887.  
  888. import  libio                       , \
  889.         file.size   , 'file_size'   , \
  890.         file.open   , 'file_open'   , \
  891.         file.read   , 'file_read'   , \
  892.         file.write  , 'file_write'  , \
  893.         file.seek   , 'file_seek'   , \
  894.         file.eof?   , 'file_iseof'  , \
  895.         file.seteof , 'file_seteof' , \
  896.         file.tell   , 'file_tell'   , \
  897.         file.close  , 'file_close'
  898.  
  899.  
  900. ;;================================================================================================;;
  901. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  902. ;;================================================================================================;;
  903. ;! Exported functions section                                                                     ;;
  904. ;;================================================================================================;;
  905. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  906. ;;================================================================================================;;
  907.  
  908.  
  909. align 16
  910. @EXPORT:
  911.  
  912. export                                            \
  913.         libini._.init     , 'lib_init'          , \
  914.         0x00080009        , 'version'           , \
  915.         ini.enum_sections , 'ini_enum_sections' , \
  916.         ini.enum_keys     , 'ini_enum_keys'     , \
  917.         ini.get_str       , 'ini_get_str'       , \
  918.         ini.get_int       , 'ini_get_int'       , \
  919.         ini.get_color     , 'ini_get_color'     , \
  920.         ini.set_str       , 'ini_set_str'       , \
  921.         ini.set_int       , 'ini_set_int'       , \
  922.         ini.set_color     , 'ini_set_color'     , \
  923.         ini.get_shortcut  , 'ini_get_shortcut'
  924.