metasm 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -323,11 +323,21 @@ Execute Printer Play Sleep Zoom Cancel
323
323
  end
324
324
 
325
325
  # update @hl_word from a line & offset, return nil if unchanged
326
- def update_hl_word(line, offset)
326
+ def update_hl_word(line, offset, mode=:asm)
327
327
  return if not line
328
328
  word = line[0...offset].to_s[/\w*$/] << line[offset..-1].to_s[/^\w*/]
329
329
  word = nil if word == ''
330
- @hl_word = word if @hl_word != word
330
+ if @hl_word != word
331
+ if word
332
+ if mode == :asm and defined?(@dasm) and @dasm
333
+ re = @dasm.gui_hilight_word_regexp(word)
334
+ else
335
+ re = Regexp.escape word
336
+ end
337
+ @hl_word_re = /^(.*?)(\b(?:#{re})\b)/
338
+ end
339
+ @hl_word = word
340
+ end
331
341
  end
332
342
 
333
343
  # invalidate the whole widget area
@@ -685,7 +685,7 @@ TrackMouseEvent(
685
685
  #define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY)
686
686
  #define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE)
687
687
 
688
- #define WAIT_TIMEOUT 258L
688
+ #define WAIT_TIMEOUT 258L
689
689
 
690
690
  #define CF_TEXT 1
691
691
  #define CF_BITMAP 2
@@ -960,6 +960,33 @@ GetTextExtentPoint32A(
960
960
  __in_ecount(c) LPCSTR lpString,
961
961
  __in int c,
962
962
  __out LPPOINT lpsz);
963
+
964
+ typedef struct tagRECT {
965
+ LONG left;
966
+ LONG top;
967
+ LONG right;
968
+ LONG bottom;
969
+ } RECT, *LPRECT;
970
+
971
+ #define TPM_LEFTBUTTON 0x0000L
972
+ #define TPM_RIGHTBUTTON 0x0002L
973
+ #define TPM_LEFTALIGN 0x0000L
974
+ #define TPM_CENTERALIGN 0x0004L
975
+ #define TPM_RIGHTALIGN 0x0008L
976
+ #define TPM_TOPALIGN 0x0000L
977
+ #define TPM_VCENTERALIGN 0x0010L
978
+ #define TPM_BOTTOMALIGN 0x0020L
979
+ #define TPM_HORIZONTAL 0x0000L
980
+ #define TPM_VERTICAL 0x0040L
981
+ #define TPM_NONOTIFY 0x0080L
982
+ #define TPM_RETURNCMD 0x0100L
983
+ #define TPM_RECURSE 0x0001L
984
+ #define TPM_HORPOSANIMATION 0x0400L
985
+ #define TPM_HORNEGANIMATION 0x0800L
986
+ #define TPM_VERPOSANIMATION 0x1000L
987
+ #define TPM_VERNEGANIMATION 0x2000L
988
+ #define TPM_NOANIMATION 0x4000L
989
+ #define TPM_LAYOUTRTL 0x8000L
963
990
  WINUSERAPI
964
991
  BOOL
965
992
  WINAPI
@@ -980,6 +1007,17 @@ WINAPI
980
1007
  DestroyMenu(
981
1008
  __in HMENU hMenu);
982
1009
  WINUSERAPI
1010
+ BOOL
1011
+ WINAPI
1012
+ TrackPopupMenu(
1013
+ __in HMENU hMenu,
1014
+ __in UINT uFlags,
1015
+ __in int x,
1016
+ __in int y,
1017
+ __in int nReserved,
1018
+ __in HWND hWnd,
1019
+ __in_opt CONST RECT *prcRect);
1020
+ WINUSERAPI
983
1021
  DWORD
984
1022
  WINAPI
985
1023
  CheckMenuItem(
@@ -999,13 +1037,6 @@ AppendMenuA(
999
1037
  #define OPAQUE 2
1000
1038
  int WINAPI SetBkMode(__in HDC hdc, __in int mode);
1001
1039
 
1002
- typedef struct tagRECT {
1003
- LONG left;
1004
- LONG top;
1005
- LONG right;
1006
- LONG bottom;
1007
- } RECT, *LPRECT;
1008
-
1009
1040
  WINUSERAPI
1010
1041
  int
1011
1042
  WINAPI
@@ -1086,6 +1117,18 @@ UpdateWindow(
1086
1117
  WINUSERAPI
1087
1118
  BOOL
1088
1119
  WINAPI
1120
+ ClientToScreen(
1121
+ __in HWND hWnd,
1122
+ __inout LPPOINT pt);
1123
+ WINUSERAPI
1124
+ BOOL
1125
+ WINAPI
1126
+ ScreenToClient(
1127
+ __in HWND hWnd,
1128
+ __inout LPPOINT pt);
1129
+ WINUSERAPI
1130
+ BOOL
1131
+ WINAPI
1089
1132
  GetClientRect(
1090
1133
  __in HWND hWnd,
1091
1134
  __out LPRECT lpRect);
@@ -1390,11 +1433,11 @@ class WinWidget
1390
1433
  return if not @parent
1391
1434
  @parent.set_focus(self) if @parent.respond_to? :set_focus
1392
1435
  end
1393
-
1436
+
1394
1437
  def focus?
1395
1438
  return true if not @parent
1396
1439
  (@parent.respond_to?(:focus?) ? @parent.focus? : true) and
1397
- (@parent.respond_to?(:has_focus?) ? @parent.has_focus?(self) : true)
1440
+ (@parent.respond_to?(:has_focus?) ? @parent.has_focus?(self) : true)
1398
1441
  end
1399
1442
 
1400
1443
  def redraw
@@ -1484,6 +1527,7 @@ class ContainerChoiceWidget < WinWidget
1484
1527
 
1485
1528
  def set_focus(c)
1486
1529
  @curview = c
1530
+ grab_focus
1487
1531
  redraw
1488
1532
  end
1489
1533
  end
@@ -1519,7 +1563,7 @@ class ContainerVBoxWidget < WinWidget
1519
1563
  cy = 0
1520
1564
  pv = []
1521
1565
  @views.each_with_index { |v, i|
1522
- if y >= cy and y < cy + v.height
1566
+ if y >= cy+1 and y < cy + v.height - 1
1523
1567
  if @focus_idx != i
1524
1568
  @focus_idx = i
1525
1569
  redraw
@@ -1528,8 +1572,7 @@ class ContainerVBoxWidget < WinWidget
1528
1572
  return
1529
1573
  end
1530
1574
  cy += v.height
1531
- if y >= cy and y < cy+@spacing
1532
- vsz = v
1575
+ if y >= cy-1 and y < cy+@spacing+1
1533
1576
  @resizing = v
1534
1577
  @wantheight[@resizing] ||= v.height
1535
1578
  @tmpwantheight = []
@@ -1665,12 +1708,13 @@ class ContainerVBoxWidget < WinWidget
1665
1708
 
1666
1709
  def set_focus(c)
1667
1710
  @focus_idx = @views.index(c)
1711
+ grab_focus
1668
1712
  redraw
1669
1713
  end
1670
1714
  end
1671
1715
 
1672
1716
  module TextWidget
1673
- attr_accessor :caret_x, :caret_y, :hl_word, :font_width, :font_height
1717
+ attr_accessor :caret_x, :caret_y, :hl_word, :hl_word_re, :font_width, :font_height
1674
1718
 
1675
1719
  def initialize_text
1676
1720
  @caret_x = @caret_y = 0 # text cursor position
@@ -1679,11 +1723,21 @@ module TextWidget
1679
1723
  @hl_word = nil
1680
1724
  end
1681
1725
 
1682
- def update_hl_word(line, offset)
1726
+ def update_hl_word(line, offset, mode=:asm)
1683
1727
  return if not line
1684
1728
  word = line[0...offset].to_s[/\w*$/] << line[offset..-1].to_s[/^\w*/]
1685
1729
  word = nil if word == ''
1686
- @hl_word = word if @hl_word != word
1730
+ if @hl_word != word
1731
+ if word
1732
+ if mode == :asm and defined?(@dasm) and @dasm
1733
+ re = @dasm.gui_hilight_word_regexp(word)
1734
+ else
1735
+ re = Regexp.escape(word)
1736
+ end
1737
+ @hl_word_re = /^(.*?)(\b(?:#{re})\b)/
1738
+ end
1739
+ @hl_word = word
1740
+ end
1687
1741
  end
1688
1742
 
1689
1743
  def set_caret_from_click(x, y)
@@ -1737,7 +1791,15 @@ end
1737
1791
  class DrawableWidget < WinWidget
1738
1792
  include TextWidget
1739
1793
 
1740
- attr_accessor :buttons
1794
+ BasicColor = { :white => 'fff', :palegrey => 'ddd', :black => '000', :grey => '444',
1795
+ :red => 'f44', :darkred => '800', :palered => 'faa',
1796
+ :green => '4f4', :darkgreen => '080', :palegreen => 'afa',
1797
+ :blue => '44f', :darkblue => '008', :paleblue => 'aaf',
1798
+ :yellow => 'ff4', :darkyellow => '440', :paleyellow => 'ffa',
1799
+ :orange => 'fc8',
1800
+ }
1801
+ attr_accessor :buttons, :parent_widget
1802
+ attr_accessor :default_color_association
1741
1803
 
1742
1804
  def initialize(*a, &b)
1743
1805
  @color = {}
@@ -1754,12 +1816,7 @@ class DrawableWidget < WinWidget
1754
1816
  end
1755
1817
 
1756
1818
  def initialize_visible_
1757
- { :white => 'fff', :palegrey => 'ddd', :black => '000', :grey => '444',
1758
- :red => 'f00', :darkred => '800', :palered => 'fcc',
1759
- :green => '0f0', :darkgreen => '080', :palegreen => 'cfc',
1760
- :blue => '00f', :darkblue => '008', :paleblue => 'ccf',
1761
- :yellow => 'ff0', :darkyellow => '440', :paleyellow => 'ffc',
1762
- }.each { |tag, val|
1819
+ BasicColor.each { |tag, val|
1763
1820
  @color[tag] = color(val)
1764
1821
  }
1765
1822
  @color[:winbg] = Win32Gui.getsyscolor(Win32Gui::COLOR_BTNFACE)
@@ -1768,11 +1825,24 @@ class DrawableWidget < WinWidget
1768
1825
  initialize_visible if respond_to? :initialize_visible
1769
1826
  end
1770
1827
 
1771
- def set_color_association(h)
1772
- h.each { |k, v| @color[k] = color(v) }
1828
+ def set_color_association(hash)
1829
+ hord = Hash.new { |h, k| h[k] = (hash[k] ? h[hash[k]] + 1 : 0) }
1830
+ hash.sort_by { |k, v| hord[k] }.each { |k, v| @color[k] = color(v) }
1773
1831
  gui_update
1774
1832
  end
1775
1833
 
1834
+ def new_menu
1835
+ toplevel.new_menu
1836
+ end
1837
+
1838
+ def addsubmenu(*a, &b)
1839
+ toplevel.addsubmenu(*a, &b)
1840
+ end
1841
+
1842
+ def popupmenu(m, x, y)
1843
+ toplevel.popupmenu(m, (x+@x).to_i, (y+@y).to_i)
1844
+ end
1845
+
1776
1846
  def paint_(realhdc)
1777
1847
  @hdc = Win32Gui.createcompatibledc(realhdc)
1778
1848
  bmp = Win32Gui.createcompatiblebitmap(realhdc, @width, @height)
@@ -1813,7 +1883,7 @@ class DrawableWidget < WinWidget
1813
1883
  end
1814
1884
 
1815
1885
  def color(col)
1816
- @color[col] ||= col.sub(/^(\w)(\w)(\w)$/, '\\3\\3\\2\\2\\1\\1').to_i(16)
1886
+ @color[col] ||= col.sub(/^(\w\w)(\w\w)(\w\w)$/, '\\3\\2\\1').sub(/^(\w)(\w)(\w)$/, '\\3\\3\\2\\2\\1\\1').to_i(16)
1817
1887
  end
1818
1888
 
1819
1889
  def draw_color(col)
@@ -1853,6 +1923,23 @@ class DrawableWidget < WinWidget
1853
1923
  draw_string(x, y, text)
1854
1924
  end
1855
1925
 
1926
+ # same as draw_string_color + hilight @hl_word_re
1927
+ def draw_string_hl(col, x, y, str)
1928
+ if @hl_word
1929
+ while str =~ @hl_word_re
1930
+ s1, s2 = $1, $2
1931
+ draw_string_color(col, x, y, s1)
1932
+ x += s1.length*@font_width
1933
+ hl_w = s2.length*@font_width
1934
+ draw_rectangle_color(:hl_word_bg, x, y, hl_w, @font_height)
1935
+ draw_string_color(:hl_word, x, y, s2)
1936
+ x += hl_w
1937
+ str = str[s1.length+s2.length..-1]
1938
+ end
1939
+ end
1940
+ draw_string_color(col, x, y, str)
1941
+ end
1942
+
1856
1943
  def keyboard_state(query=nil)
1857
1944
  case query
1858
1945
  when :control, :ctrl
@@ -1952,10 +2039,10 @@ class Window
1952
2039
  :style => Win32Gui::CS_DBLCLKS,
1953
2040
  :hcursor => Win32Gui.loadcursora(0, Win32Gui::IDC_ARROW),
1954
2041
  :lpszclassname => cname,
1955
- :lpfnwndproc => Win32Gui.callback_alloc_c('__stdcall int wndproc(int, int, int, int)') { |hwnd, msg, wp, lp| windowproc(hwnd, msg, wp, lp) }
2042
+ :lpfnwndproc => Win32Gui.callback_alloc_c('__stdcall int wndproc(int, int, int, int)') { |hwnd, msg, wp, lp| windowproc(hwnd, msg, wp, lp) }
1956
2043
 
1957
2044
  Win32Gui.registerclassexa(cls)
1958
-
2045
+
1959
2046
  @hwnd = Win32Gui.createwindowexa(win32styleex, cname, 'win32gui window', win32style, Win32Gui::CW_USEDEFAULT, Win32Gui::SW_HIDE, Win32Gui::CW_USEDEFAULT, 0, 0, 0, 0, 0)
1960
2047
 
1961
2048
  initialize_window(*a, &b)
@@ -1997,7 +2084,8 @@ class Window
1997
2084
  h.update v => {
1998
2085
  :prior => :pgup, :next => :pgdown,
1999
2086
  :escape => :esc, :return => :enter,
2000
- :back => :backspace,
2087
+ :back => :backspace, :apps => :popupmenu,
2088
+ :add => ?+, :subtract => ?-, :multiply => ?*, :divide => ?/,
2001
2089
  }.fetch(key, key)
2002
2090
  }
2003
2091
 
@@ -2053,7 +2141,9 @@ class Window
2053
2141
  when Win32Gui::WM_KEYDOWN, Win32Gui::WM_SYSKEYDOWN
2054
2142
  # SYSKEYDOWN for f10 (default = activate the menu bar)
2055
2143
  if key = Keyboard_trad[wparam]
2056
- if keyboard_state(:control)
2144
+ if [?+, ?-, ?/, ?*].include?(key)
2145
+ # keypad keys generate wm_keydown + wm_char, ignore this one
2146
+ elsif keyboard_state(:control)
2057
2147
  @widget.keypress_ctrl_(key) if @widget
2058
2148
  else
2059
2149
  @widget.keypress_(key) if @widget
@@ -2064,15 +2154,15 @@ class Window
2064
2154
  if keyboard_state(:control) and not keyboard_state(:alt) # altgr+[ returns CTRL on..
2065
2155
  if ?a.kind_of?(String)
2066
2156
  wparam += (keyboard_state(:shift) ? ?A.ord : ?a.ord) - 1 if wparam < 0x1a
2067
- k = wparam.chr
2157
+ key = wparam.chr
2068
2158
  else
2069
2159
  wparam += (keyboard_state(:shift) ? ?A : ?a) - 1 if wparam < 0x1a
2070
- k = wparam
2160
+ key = wparam
2071
2161
  end
2072
- @widget.keypress_ctrl_(k) if @widget
2162
+ @widget.keypress_ctrl_(key) if @widget
2073
2163
  else
2074
- k = (?a.kind_of?(String) ? wparam.chr : wparam)
2075
- @widget.keypress_(k) if @widget
2164
+ key = (?a.kind_of?(String) ? wparam.chr : wparam)
2165
+ @widget.keypress_(key) if @widget
2076
2166
  end
2077
2167
  when Win32Gui::WM_DESTROY
2078
2168
  destroy_window
@@ -2214,12 +2304,39 @@ class Window
2214
2304
 
2215
2305
  # make the window's MenuBar reflect the content of @menu
2216
2306
  def update_menu
2307
+ unuse_menu(@menu)
2217
2308
  Win32Gui.destroymenu(@menuhwnd) if @menuhwnd != 0
2218
2309
  @menuhwnd = Win32Gui.createmenu()
2219
2310
  @menu.each { |e| create_menu_item(@menuhwnd, e) }
2220
2311
  Win32Gui.setmenu(@hwnd, @menuhwnd)
2221
2312
  end
2222
2313
 
2314
+ def popupmenu(m, x, y)
2315
+ hm = Win32Gui.createpopupmenu()
2316
+ m.each { |e| create_menu_item(hm, e) }
2317
+ pt = Win32Gui.alloc_c_struct('POINT', :x => x, :y => y)
2318
+ Win32Gui.clienttoscreen(@hwnd, pt)
2319
+ id = Win32Gui.trackpopupmenu(hm, Win32Gui::TPM_NONOTIFY | Win32Gui::TPM_RETURNCMD, pt.x, pt.y, 0, @hwnd, 0)
2320
+ if p = @control_action[id]
2321
+ # TrackPopup returns before WM_COMMAND is delivered, so if we
2322
+ # want to cleanup @control_action we must call it now & clenup
2323
+ p.call
2324
+ end
2325
+ unuse_menu(m)
2326
+ Win32Gui.destroymenu(hm)
2327
+ end
2328
+
2329
+ def unuse_menu(m)
2330
+ m.flatten.grep(Proc).reverse_each { |c|
2331
+ if @control_action[@controlid-1] == c
2332
+ @controlid -= 1 # recycle IDs
2333
+ @control_action.delete @controlid
2334
+ elsif i = @control_action.index(c)
2335
+ @control_action.delete i
2336
+ end
2337
+ }
2338
+ end
2339
+
2223
2340
  def create_menu_item(menu, entry)
2224
2341
  args = entry.dup
2225
2342
 
@@ -2270,6 +2387,7 @@ class Window
2270
2387
  checked = action.call(!checked)
2271
2388
  Win32Gui.checkmenuitem(menu, id, (checked ? Win32Gui::MF_CHECKED : Win32Gui::MF_UNCHECKED))
2272
2389
  }
2390
+ entry << @control_action[id] # allow deletion in unuse_menu
2273
2391
  end
2274
2392
  @controlid += 1
2275
2393
  end
@@ -2329,7 +2447,7 @@ class OpenFile
2329
2447
  buf = [0].pack('C')*512
2330
2448
  ofn = Win32Gui.alloc_c_struct 'OPENFILENAMEA',
2331
2449
  :lstructsize => :size,
2332
- #:hwndowner => win.hwnd, # 0 for nonmodal
2450
+ #:hwndowner => win.hwnd, # 0 for nonmodal
2333
2451
  :lpstrfilter => "All Files\0*.*\0\0",
2334
2452
  :lpstrfile => buf,
2335
2453
  :lpstrtitle => title,
@@ -2369,6 +2487,10 @@ class IBoxWidget < DrawableWidget
2369
2487
  @oldsel_x = @caret_x_select = 0
2370
2488
  @caret_x = @curline.length
2371
2489
  @caret_x_start = 0
2490
+ @@history ||= {}
2491
+ histkey = opts[:history] || label[0, 10]
2492
+ @history = (@@history[histkey] ||= [])
2493
+ @history_off = @history.length
2372
2494
 
2373
2495
  add_button('Ok', :btnc1, :btnc2) { keypress(:enter) }
2374
2496
  add_button('Cancel', :btnc1, :btnc2) { keypress(:esc) }
@@ -2505,7 +2627,19 @@ class IBoxWidget < DrawableWidget
2505
2627
  end
2506
2628
  @caret_x = @curline.length
2507
2629
  update_caret
2630
+ when :up, :down
2631
+ if @history_off < @history.length or @curline.strip != @history.last
2632
+ @history[@history_off] = @curline.strip
2633
+ end
2634
+ @history_off += (key == :up ? -1 : 1)
2635
+ @history_off %= @history.length
2636
+ @curline = @history[@history_off].to_s
2637
+ @caret_x = @curline.length if @caret_x > @curline.length
2638
+ redraw
2508
2639
  when :enter
2640
+ @history << @curline.strip
2641
+ @history.pop if @history.last == ''
2642
+ @history.pop if @history.last == @history[-2]
2509
2643
  destroy
2510
2644
  Gui.main_iter
2511
2645
  protect { @action.call(@curline.strip) }
@@ -2588,7 +2722,7 @@ class IBoxWidget < DrawableWidget
2588
2722
  elsif mouserelease_buttons(x, y)
2589
2723
  end
2590
2724
  end
2591
-
2725
+
2592
2726
  def update_caret
2593
2727
  return if @oldcaret_x == @caret_x and @oldsel_x == @caret_x_select
2594
2728
  redraw
@@ -2664,7 +2798,7 @@ class LBoxWidget < DrawableWidget
2664
2798
  def initial_size
2665
2799
  @colw = @colwmax.map { |w| (w+1) * @font_width }
2666
2800
  allw = @colw.inject(0) { |a, i| a+i }
2667
- [[allw, 80*@font_width].min, [@list.length+1, 30].min * @font_height+2]
2801
+ [[allw+@font_width, 80*@font_width].min, [@list.length+2, 30].min * @font_height+2]
2668
2802
  end
2669
2803
 
2670
2804
  def resized(w, h)
@@ -2699,7 +2833,11 @@ class LBoxWidget < DrawableWidget
2699
2833
  def paint
2700
2834
  @btnx = []
2701
2835
  @btny = 0
2702
- @btnheight = @font_height * 4/3
2836
+ if @btnheight != @font_height * 4/3
2837
+ # fix vscrollbar height on w7
2838
+ @btnheight = @font_height * 4/3
2839
+ resized(width, height)
2840
+ end
2703
2841
  x = 0
2704
2842
  @colw.each { |w|
2705
2843
  @btnx << x
@@ -2817,7 +2955,6 @@ class LBoxWidget < DrawableWidget
2817
2955
  vscroll((@linehead-off)*@font_height)
2818
2956
  redraw
2819
2957
  when :down
2820
- n = @lineshown-1
2821
2958
  off = [@lineshown, [@lineshown/2, 5].max].min
2822
2959
  vscroll((@linehead+off)*@font_height)
2823
2960
  redraw
@@ -2907,7 +3044,7 @@ class LBoxWidget < DrawableWidget
2907
3044
  redraw
2908
3045
  end
2909
3046
  end
2910
-
3047
+
2911
3048
  def destroy
2912
3049
  @parent.destroy
2913
3050
  end
@@ -2943,7 +3080,7 @@ end
2943
3080
  Win32Gui.getscrollinfo(@hwnd, Win32Gui::SB_VERT, sif)
2944
3081
  case wparam & 0xffff
2945
3082
  when Win32Gui::SB_THUMBPOSITION; val = sif.ntrackpos
2946
- when Win32Gui::SB_THUMBTRACK; val = sif.ntrackpos; nopos = true
3083
+ when Win32Gui::SB_THUMBTRACK; val = sif.ntrackpos #; nopos = true
2947
3084
  when Win32Gui::SB_LINEDOWN; val = sif.npos + 1
2948
3085
  when Win32Gui::SB_LINEUP; val = sif.npos - 1
2949
3086
  when Win32Gui::SB_PAGEDOWN; val = sif.npos + sif.npage