diff --git a/build.py b/build.py
index a88ce0d..2616310 100644
--- a/build.py
+++ b/build.py
@@ -80,6 +80,7 @@ BINDIST_MANIFEST = [
"examples/ex_debug_names.py",
"examples/ex_graph.py",
"examples/ex_dbg.py",
+ "examples/ex_custview.py",
"examples/ex_imports.py"
]
@@ -171,7 +172,7 @@ class BuilderBase:
self.linker_out_string(outfile))
for objectfile in objects:
- cmdstring = "%s %s" % (cmdstring, objectfile + self.object_extension)
+ cmdstring = "%s %s" % (cmdstring, objectfile + self.object_extension)
for libpath in libpaths:
cmdstring = "%s %s%s" % (cmdstring, self.libpath_delimiter, libpath)
for library in libraries:
@@ -192,7 +193,7 @@ class BuilderBase:
macrostring += '%s%s ' % (argument_delimiter, item)
return macrostring
-
+
class GCCBuilder(BuilderBase):
""" Generic GCC compiler class """
diff --git a/examples/ex_custview.py b/examples/ex_custview.py
new file mode 100644
index 0000000..2e9ea58
--- /dev/null
+++ b/examples/ex_custview.py
@@ -0,0 +1,166 @@
+# -----------------------------------------------------------------------
+# This is an example illustrating how to use customview in Python
+# (c) Hex-Rays
+#
+import idaapi
+import idc
+from idaapi import simplecustview_t
+#
+
+# -----------------------------------------------------------------------
+class mycv_t(simplecustview_t):
+ def Create(self, sn=None):
+ # Form the title
+ title = "Simple custom view test"
+ if sn:
+ title += " %d" % sn
+ # Create the customview
+ if not simplecustview_t.Create(self, title):
+ return False
+ id = self.AddPopupMenu("Hello")
+ for i in xrange(0, 100):
+ self.AddLine("Line %d" % i)
+ return True
+
+ def OnClick(self, shift):
+ """
+ User clicked in the view
+ @param shift: Shift flag
+ @return Boolean. True if you handled the event
+ """
+ print "OnClick, shift=%d" % shift
+ return True
+
+ def OnDblClick(self, shift):
+ """
+ User dbl-clicked in the view
+ @param shift: Shift flag
+ @return Boolean. True if you handled the event
+ """
+ print "OnDblClick, shift=%d" % shift
+ return True
+
+ def OnCursorPosChanged(self):
+ """
+ Cursor position changed.
+ @return Nothing
+ """
+ print "OnCurposChanged"
+
+ def OnClose(self):
+ """
+ The view is closing. Use this event to cleanup.
+ @return Nothing
+ """
+ print "OnClose " + self.title
+
+ def OnKeydown(self, vkey, shift):
+ """
+ User pressed a key
+ @param vkey: Virtual key code
+ @param shift: Shift flag
+ @return Boolean. True if you handled the event
+ """
+ print "OnKeydown, vk=%d shift=%d" % (vkey, shift)
+ # ESCAPE?
+ if vkey == 27:
+ self.Close()
+ elif vkey == 46:
+ n = self.GetLineNo()
+ self.DelLine(n)
+ self.Refresh()
+ print "Deleted line %d" % n
+ # Goto?
+ elif vkey == ord('G'):
+ v = idc.AskLong(self.GetLineNo(), "Where to go?")
+ if v:
+ self.Jump(v, 0, 5)
+ elif vkey == ord('R'):
+ print "refreshing...."
+ self.Refresh()
+ elif vkey == ord('C'):
+ print "refreshing current line..."
+ self.RefreshCurrent()
+ elif vkey == ord('A'):
+ s = idc.AskStr("NewLine%d" % self.Count(), "Append new line")
+ self.AddLine(s)
+ self.Refresh()
+ elif vkey == ord('X'):
+ print "Clearing all lines"
+ self.ClearLines()
+ self.Refresh()
+ elif vkey == ord('I'):
+ n = self.GetLineNo()
+ s = idc.AskStr("InsertedLine%d" % n, "Insert new line")
+ self.InsertLine(n, s)
+ self.Refresh()
+ elif vkey == ord('E'):
+ l = self.GetCurrentLine(notags=1)
+ if not l:
+ return False
+ n = self.GetLineNo()
+ print "curline=<%s>" % l
+ l = l + idaapi.COLSTR("*", idaapi.SCOLOR_VOIDOP)
+ self.EditLine(n, l)
+ self.RefreshCurrent()
+ print "Edited line %d" % n
+ else:
+ return False
+ return True
+
+ def OnPopup(self):
+ """
+ Context menu popup is about to be shown. Create items dynamically if you wish
+ @return Boolean. True if you handled the event
+ """
+ print "OnPopup"
+
+ def OnHint(self, lineno):
+ """
+ Hint requested for the given line number.
+ @param lineno: The line number (zero based)
+ @return:
+ - string: a string containing the hint
+ - None: if no hint available
+ """
+ return "OnHint, line=%d" % lineno
+
+ def OnPopupMenu(self, menu_id):
+ """
+ A context (or popup) menu item was executed.
+ @param menu_id: ID previously registered with add_popup_menu()
+ @return: Boolean
+ """
+ print "OnPopupMenu, menu_id=%d" % menu_id
+ return True
+
+# -----------------------------------------------------------------------
+try:
+ # created already?
+ mycv
+ print "Already created, will close it..."
+ mycv.Close()
+ del mycv
+except:
+ pass
+
+def show_win():
+ x = mycv_t()
+ if not x.Create():
+ print "Failed to create!"
+ return None
+ x.Show()
+ return x
+mycv = show_win()
+if not mycv:
+ del mycv
+
+def make_many(n):
+ for i in xrange(1, n+1):
+ t = mycv_t()
+ if not t.Create(i):
+ break
+ t.Show()
+ return i
+
+#
\ No newline at end of file
diff --git a/swig/kernwin.i b/swig/kernwin.i
index 5e47153..902afd5 100644
--- a/swig/kernwin.i
+++ b/swig/kernwin.i
@@ -74,6 +74,762 @@ def askseg(defval, format):
%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 };
%{
+
+//
+
+//---------------------------------------------------------------------------
+// Base class for all custview place_t providers
+class custview_data_t
+{
+public:
+ virtual void *get_ud() = 0;
+ virtual place_t *get_min() = 0;
+ virtual place_t *get_max() = 0;
+};
+
+//---------------------------------------------------------------------------
+class cvdata_simpleline_t: public custview_data_t
+{
+private:
+ strvec_t lines;
+ simpleline_place_t pl_min, pl_max;
+public:
+ void *get_ud()
+ {
+ return &lines;
+ }
+ place_t *get_min()
+ {
+ return &pl_min;
+ }
+ place_t *get_max()
+ {
+ return &pl_max;
+ }
+ strvec_t &get_lines()
+ {
+ return lines;
+ }
+ void set_minmax(size_t start=size_t(-1), size_t end=size_t(-1))
+ {
+ if ( start == size_t(-1) && end == size_t(-1) )
+ {
+ end = lines.size();
+ pl_min.n = 0;
+ pl_max.n = end == 0 ? 0 : end - 1;
+ }
+ else
+ {
+ pl_min.n = start;
+ pl_max.n = end;
+ }
+ }
+ bool set_line(size_t nline, simpleline_t &sl)
+ {
+ if ( nline >= lines.size() )
+ return false;
+ lines[nline] = sl;
+ return true;
+ }
+ bool del_line(size_t nline)
+ {
+ if ( nline >= lines.size() )
+ return false;
+ lines.erase(lines.begin()+nline);
+ return true;
+ }
+ void add_line(simpleline_t &line)
+ {
+ lines.push_back(line);
+ }
+ void add_line(const char *str)
+ {
+ lines.push_back(simpleline_t(str));
+ }
+ bool insert_line(size_t nline, simpleline_t &line)
+ {
+ if ( nline >= lines.size() )
+ return false;
+ lines.insert(lines.begin()+nline, line);
+ return true;
+ }
+ bool patch_line(size_t nline, size_t offs, int value)
+ {
+ if ( nline >= lines.size() )
+ return false;
+ qstring &L = lines[nline].line;
+ L[offs] = (uchar) value & 0xFF;
+ return true;
+ }
+ const size_t to_lineno(place_t *pl) const
+ {
+ return ((simpleline_place_t *)pl)->n;
+ }
+ bool curline(place_t *pl, size_t *n)
+ {
+ if ( pl == NULL )
+ return false;
+ *n = to_lineno(pl);
+ return true;
+ }
+ simpleline_t *get_line(size_t nline)
+ {
+ return nline >= lines.size() ? NULL : &lines[nline];
+ }
+ simpleline_t *get_line(place_t *pl)
+ {
+ return pl == NULL ? NULL : get_line(((simpleline_place_t *)pl)->n);
+ }
+ const size_t count() const
+ {
+ return lines.size();
+ }
+ void clear_lines()
+ {
+ lines.clear();
+ set_minmax();
+ }
+};
+
+//---------------------------------------------------------------------------
+class customview_t
+{
+protected:
+ qstring _title;
+ TForm *_form;
+ TCustomControl *_cv;
+ custview_data_t *_data;
+ int _features;
+ enum
+ {
+ HAVE_HINT = 0x0001,
+ HAVE_KEYDOWN = 0x0002,
+ HAVE_POPUP = 0x0004,
+ HAVE_DBLCLICK = 0x0008,
+ HAVE_CURPOS = 0x0010,
+ HAVE_CLICK = 0x0020,
+ HAVE_CLOSE = 0x0040
+ };
+private:
+ struct pyw_popupctx_t
+ {
+ size_t menu_id;
+ customview_t *cv;
+ pyw_popupctx_t(): menu_id(0), cv(NULL) { }
+ pyw_popupctx_t(size_t mid, customview_t *v): menu_id(mid), cv(v) { }
+ };
+ typedef std::map pyw_popupmap_t;
+ static pyw_popupmap_t _global_popup_map;
+ static size_t _global_popup_id;
+ qstring _curline;
+ intvec_t _installed_popups;
+
+ static bool idaapi s_popup_cb(void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ return _this->on_popup();
+ }
+
+ static bool idaapi s_popup_menu_cb(void *ud)
+ {
+ size_t mid = (size_t)ud;
+ pyw_popupmap_t::iterator it = _global_popup_map.find(mid);
+ if ( it == _global_popup_map.end() )
+ return false;
+ return it->second.cv->on_popup_menu(it->second.menu_id);
+ }
+
+ static bool idaapi s_cv_keydown(TCustomControl * /*cv*/, int vk_key, int shift, void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ return _this->on_keydown(vk_key, shift);
+ }
+ // The popup menu is being constructed
+ static void idaapi s_cv_popup(TCustomControl * /*cv*/, void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ _this->on_popup();
+ }
+ // The user clicked
+ static bool idaapi s_cv_click(TCustomControl *cv, int shift, void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ return _this->on_click(shift);
+ }
+ // The user double clicked
+ static bool idaapi s_cv_dblclick(TCustomControl * /*cv*/, int shift, void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ return _this->on_dblclick(shift);
+ }
+ // Cursor position has been changed
+ static void idaapi s_cv_curpos(TCustomControl * /*cv*/, void *ud)
+ {
+ customview_t *_this = (customview_t *)ud;
+ _this->on_curpos_changed();
+ }
+
+ //--------------------------------------------------------------------------
+ static int idaapi s_ui_cb(void *ud, int code, va_list va)
+ {
+ customview_t *_this = (customview_t *)ud;
+ switch ( code )
+ {
+ case ui_get_custom_viewer_hint:
+ {
+ TCustomControl *viewer = va_arg(va, TCustomControl *);
+ place_t *place = va_arg(va, place_t *);
+ int *important_lines = va_arg(va, int *);
+ qstring &hint = *va_arg(va, qstring *);
+ return ((_this->_features & HAVE_HINT) == 0 || place == NULL || _this->_cv != viewer) ? 0 : (_this->on_hint(place, important_lines, hint) ? 1 : 0);
+ }
+ case ui_tform_invisible:
+ {
+ TForm *form = va_arg(va, TForm *);
+ if ( _this->_form != form )
+ break;
+ unhook_from_notification_point(HT_UI, s_ui_cb, _this);
+ _this->on_close();
+ _this->on_post_close();
+ }
+ break;
+ }
+ return 0;
+ }
+
+ void on_post_close()
+ {
+ init_vars();
+ clear_popup_menu();
+ }
+
+public:
+ // All the overridable callbacks
+ // OnClick
+ virtual bool on_click(int /*shift*/) { return false; }
+ // OnDblClick
+ virtual bool on_dblclick(int /*shift*/) { return false; }
+ // OnCurorPositionChanged
+ virtual void on_curpos_changed() { }
+ // OnHostFormClose
+ virtual void on_close() { }
+ // OnKeyDown
+ virtual bool on_keydown(int /*vk_key*/, int /*shift*/) { return false; }
+ // OnPopupShow
+ virtual bool on_popup() { return false; }
+ // OnHint
+ virtual bool on_hint(place_t * /*place*/, int * /*important_lines*/, qstring &/*hint*/) { return false; }
+ // OnPopupMenuClick
+ virtual bool on_popup_menu(size_t menu_id) { return false; }
+
+ void init_vars()
+ {
+ _data = NULL;
+ _features = 0;
+ _curline.clear();
+ _cv = NULL;
+ _form = NULL;
+ }
+
+ customview_t()
+ {
+ init_vars();
+ }
+
+ ~customview_t()
+ {
+ }
+
+ void close()
+ {
+ if ( _form != NULL )
+ close_tform(_form, FORM_SAVE);
+ }
+
+ bool set_range(
+ const place_t *minplace = NULL,
+ const place_t *maxplace = NULL)
+ {
+ if ( _cv == NULL )
+ return false;
+ set_custom_viewer_range(
+ _cv,
+ minplace == NULL ? _data->get_min() : minplace,
+ maxplace == NULL ? _data->get_max() : maxplace);
+ return true;
+ }
+
+ place_t *get_place(
+ bool mouse = false,
+ int *x = 0,
+ int *y = 0)
+ {
+ return _cv == NULL ? NULL : get_custom_viewer_place(_cv, mouse, x, y);
+ }
+
+ //--------------------------------------------------------------------------
+ bool refresh()
+ {
+ if ( _cv == NULL )
+ return false;
+ refresh_custom_viewer(_cv);
+ return true;
+ }
+
+ //--------------------------------------------------------------------------
+ bool refresh_current(bool mouse = false)
+ {
+ int x, y;
+ place_t *pl = get_place(mouse, &x, &y);
+ if ( pl == NULL )
+ return false;
+ return jumpto(pl, x, y);
+ }
+
+ //--------------------------------------------------------------------------
+ const char *get_current_line(bool mouse, bool notags)
+ {
+ const char *r = get_custom_viewer_curline(_cv, mouse);
+ if ( r == NULL || !notags )
+ return r;
+ size_t sz = strlen(r);
+ if ( sz == 0 )
+ return r;
+ _curline.resize(sz + 5, '\0');
+ tag_remove(r, &_curline[0], sz + 1);
+ return _curline.c_str();
+ }
+
+ //--------------------------------------------------------------------------
+ bool is_focused()
+ {
+ return get_current_viewer() == _cv;
+ }
+
+ //--------------------------------------------------------------------------
+ bool jumpto(place_t *place, int x, int y)
+ {
+ return ::jumpto(_cv, place, x, y);
+ }
+
+ //--------------------------------------------------------------------------
+ void clear_popup_menu()
+ {
+ if ( _cv != NULL )
+ set_custom_viewer_popup_menu(_cv, NULL);
+
+ for (intvec_t::iterator it=_installed_popups.begin(), it_end=_installed_popups.end();
+ it != it_end;
+ ++it)
+ {
+ _global_popup_map.erase(*it);
+ }
+ _installed_popups.clear();
+ }
+
+ //--------------------------------------------------------------------------
+ size_t add_popup_menu(
+ const char *title,
+ const char *hotkey)
+ {
+ size_t menu_id = _global_popup_id + 1;
+ // Overlap / already exists?
+ if (_cv == NULL || // No custview?
+ menu_id == 0 || // Overlap?
+ _global_popup_map.find(menu_id) != _global_popup_map.end()) // Already exists?
+ {
+ return 0;
+ }
+ add_custom_viewer_popup_item(_cv, title, hotkey, s_popup_menu_cb, (void *)menu_id);
+
+ // Save global association
+ _global_popup_map[menu_id] = pyw_popupctx_t(menu_id, this);
+ _global_popup_id = menu_id;
+
+ // Remember what menu IDs are set with this form
+ _installed_popups.push_back(menu_id);
+ return menu_id;
+ }
+
+ //--------------------------------------------------------------------------
+ bool create(const char *title, int features, custview_data_t *data)
+ {
+ // Already created? (in the instance)
+ if ( _form != NULL )
+ return true;
+
+ // Already created? (in IDA windows list)
+ HWND hwnd(NULL);
+ TForm *form = create_tform(title, &hwnd);
+ if ( hwnd == NULL )
+ return false;
+
+ _title = title;
+ _data = data;
+ _form = form;
+ _features = features;
+
+ // Create the viewer
+ _cv = create_custom_viewer(
+ title,
+ (TWinControl *)_form,
+ _data->get_min(),
+ _data->get_max(),
+ _data->get_min(),
+ 0,
+ _data->get_ud());
+
+ // Set user-data
+ set_custom_viewer_handler(_cv, CVH_USERDATA, (void *)this);
+
+ //
+ // Set other optional callbacks
+ //
+ if ( (features & HAVE_KEYDOWN) != 0 )
+ set_custom_viewer_handler(_cv, CVH_KEYDOWN, (void *)s_cv_keydown);
+
+ if ( (features & HAVE_POPUP) != 0 )
+ set_custom_viewer_handler(_cv, CVH_POPUP, (void *)s_cv_popup);
+
+ if ( (features & HAVE_DBLCLICK) != 0 )
+ set_custom_viewer_handler(_cv, CVH_DBLCLICK, (void *)s_cv_dblclick);
+
+ if ( (features & HAVE_CURPOS) != 0 )
+ set_custom_viewer_handler(_cv, CVH_CURPOS, (void *)s_cv_curpos);
+
+ if ( (features & HAVE_CLICK) != 0 )
+ set_custom_viewer_handler(_cv, CVH_CLICK, (void *)s_cv_click);
+
+ // Hook to UI notifications (for TForm close event)
+ hook_to_notification_point(HT_UI, s_ui_cb, this);
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------------
+ bool show()
+ {
+ if ( _form == NULL )
+ return false;
+ open_tform(_form, FORM_TAB|FORM_MENU|FORM_RESTORE);
+ return true;
+ }
+};
+
+customview_t::pyw_popupmap_t customview_t::_global_popup_map;
+size_t customview_t::_global_popup_id = 0;
+//---------------------------------------------------------------------------
+class py_simplecustview_t: public customview_t
+{
+private:
+ cvdata_simpleline_t data;
+ PyObject *py_self, *py_this, *py_last_link;
+ int features;
+
+ // Convert a tuple (String, [color, [bgcolor]]) to a simpleline_t
+ static bool py_to_simpleline(PyObject *py, simpleline_t &sl)
+ {
+ if ( PyString_Check(py) )
+ {
+ sl.line = PyString_AsString(py);
+ return true;
+ }
+ Py_ssize_t sz;
+ if ( !PyTuple_Check(py) || (sz = PyTuple_Size(py)) <= 0 )
+ return false;
+ PyObject *py_val = PyTuple_GetItem(py, 0);
+ if ( !PyString_Check(py_val) )
+ return false;
+ sl.line = PyString_AsString(py_val);
+
+ if ( (sz > 1) && (py_val = PyTuple_GetItem(py, 1)) && PyLong_Check(py_val) )
+ sl.color = color_t(PyLong_AsUnsignedLong(py_val));
+
+ if ( (sz > 2) && (py_val = PyTuple_GetItem(py, 2)) && PyLong_Check(py_val) )
+ sl.bgcolor = PyLong_AsUnsignedLong(py_val);
+ return true;
+ }
+
+ //
+ // Callbacks
+ //
+ virtual bool on_click(int shift)
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLICK, "i", shift);
+ PyShowErr(S_ON_CLICK);
+ bool ok = py_result != NULL && PyObject_IsTrue(py_result);
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ // OnDblClick
+ virtual bool on_dblclick(int shift)
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_DBL_CLICK, "i", shift);
+ PyShowErr(S_ON_DBL_CLICK);
+ bool ok = py_result != NULL && PyObject_IsTrue(py_result);
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ // OnCurorPositionChanged
+ virtual void on_curpos_changed()
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CURSOR_POS_CHANGED, NULL);
+ PyShowErr(S_ON_CURSOR_POS_CHANGED);
+ Py_XDECREF(py_result);
+ }
+
+ // OnHostFormClose
+ virtual void on_close()
+ {
+ // Call the close method if it is there and the object is still bound
+ if ( (features & HAVE_CLOSE) != 0 && py_self != NULL )
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLOSE, NULL);
+ PyShowErr(S_ON_CLOSE);
+ Py_XDECREF(py_result);
+
+ // Cleanup
+ Py_DECREF(py_self);
+ py_self = NULL;
+ }
+ }
+
+ // OnKeyDown
+ virtual bool on_keydown(int vk_key, int shift)
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_KEYDOWN, "ii", vk_key, shift);
+ PyShowErr(S_ON_KEYDOWN);
+ bool ok = py_result != NULL && PyObject_IsTrue(py_result);
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ // OnPopupShow
+ virtual bool on_popup()
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP, NULL);
+ PyShowErr(S_ON_POPUP);
+ bool ok = py_result != NULL && PyObject_IsTrue(py_result);
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ // OnHint
+ virtual bool on_hint(place_t *place, int *important_lines, qstring &hint)
+ {
+ size_t ln = data.to_lineno(place);
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_HINT, PY_FMT64, pyul_t(ln));
+ PyShowErr(S_ON_HINT);
+ bool ok = py_result != NULL && PyString_Check(py_result);
+ if ( ok )
+ {
+ if ( important_lines != NULL )
+ *important_lines = 0;
+ hint = PyString_AsString(py_result);
+ }
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ // OnPopupMenuClick
+ virtual bool on_popup_menu(size_t menu_id)
+ {
+ PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP_MENU, PY_FMT64, pyul_t(menu_id));
+ PyShowErr(S_ON_POPUP_MENU);
+ bool ok = py_result != NULL && PyObject_IsTrue(py_result);
+ Py_XDECREF(py_result);
+ return ok;
+ }
+
+ void refresh_range()
+ {
+ data.set_minmax();
+ set_range();
+ }
+
+public:
+ py_simplecustview_t()
+ {
+ py_this = py_self = py_last_link = NULL;
+ }
+ ~py_simplecustview_t()
+ {
+ }
+ // Edits an existing line
+ bool edit_line(size_t nline, PyObject *py_sl)
+ {
+ simpleline_t sl;
+ if ( !py_to_simpleline(py_sl, sl) )
+ return false;
+ return data.set_line(nline, sl);
+ }
+
+ // Low level: patches a line string directly
+ bool patch_line(size_t nline, size_t offs, int value)
+ {
+ return data.patch_line(nline, offs, value);
+ }
+
+ // Insert a line
+ bool insert_line(size_t nline, PyObject *py_sl)
+ {
+ simpleline_t sl;
+ if ( !py_to_simpleline(py_sl, sl) )
+ return false;
+ return data.insert_line(nline, sl);
+ }
+
+ // Adds a line tuple
+ bool add_line(PyObject *py_sl)
+ {
+ simpleline_t sl;
+ if ( !py_to_simpleline(py_sl, sl) )
+ return false;
+ data.add_line(sl);
+ refresh_range();
+ return true;
+ }
+
+ bool del_line(size_t nline)
+ {
+ bool ok = data.del_line(nline);
+ if ( ok )
+ refresh_range();
+ return ok;
+ }
+
+ // Gets the position and returns a tuple (lineno, x, y)
+ PyObject *get_pos(bool mouse)
+ {
+ place_t *pl;
+ int x, y;
+ pl = get_place(mouse, &x, &y);
+ if ( pl == NULL )
+ Py_RETURN_NONE;
+ return Py_BuildValue("(" PY_FMT64 "ii)", pyul_t(data.to_lineno(pl)), x, y);
+ }
+
+ // Returns the line tuple
+ PyObject *get_line(size_t nline)
+ {
+ simpleline_t *r = data.get_line(nline);
+ if ( r == NULL )
+ Py_RETURN_NONE;
+ return Py_BuildValue("(sII)", r->line.c_str(), (unsigned int)r->color, (unsigned int)r->bgcolor);
+ }
+
+ // Returns the count of lines
+ const size_t count() const
+ {
+ return data.count();
+ }
+
+ // Clears lines
+ void clear()
+ {
+ data.clear_lines();
+ refresh_range();
+ }
+
+ bool jumpto(size_t ln, int x, int y)
+ {
+ return customview_t::jumpto(&simpleline_place_t(ln), x, y);
+ }
+
+ // Initializes and links the Python object to this class
+ bool init(PyObject *py_link, const char *title)
+ {
+ // Already created?
+ if ( _form != NULL )
+ return true;
+
+ // Probe callbacks
+ features = 0;
+ static struct
+ {
+ const char *cb_name;
+ int feature;
+ } const cbtable[] =
+ {
+ {S_ON_CLICK, HAVE_CLICK},
+ {S_ON_CLOSE, HAVE_CLOSE},
+ {S_ON_HINT, HAVE_HINT},
+ {S_ON_KEYDOWN, HAVE_KEYDOWN},
+ {S_ON_POPUP, HAVE_POPUP},
+ {S_ON_DBL_CLICK, HAVE_DBLCLICK},
+ {S_ON_CURSOR_POS_CHANGED, HAVE_CURPOS}
+ };
+ for ( size_t i=0; i
+
bool idaapi py_menu_item_callback(void *userdata)
{
PyObject *func, *args, *result;
@@ -106,6 +862,174 @@ bool idaapi py_menu_item_callback(void *userdata)
%rename (add_menu_item) wrap_add_menu_item;
%inline %{
+//
+
+//
+// Pywraps Simple Custom View functions
+//
+PyObject *pyscv_init(PyObject *py_link, const char *title)
+{
+ py_simplecustview_t *_this = new py_simplecustview_t();
+ bool ok = _this->init(py_link, title);
+ if ( !ok )
+ {
+ delete _this;
+ Py_RETURN_NONE;
+ }
+ return _this->get_pythis();
+}
+#define DECL_THIS py_simplecustview_t *_this = py_simplecustview_t::get_this(py_this)
+
+bool pyscv_refresh(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ return false;
+ return _this->refresh();
+}
+
+bool pyscv_delete(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ return false;
+ _this->close();
+ delete _this;
+ return true;
+}
+
+bool pyscv_refresh_current(PyObject *py_this, bool mouse)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ return false;
+ return _this->refresh_current(mouse);
+}
+
+PyObject *pyscv_get_current_line(PyObject *py_this, bool mouse, bool notags)
+{
+ DECL_THIS;
+ const char *line;
+ if ( _this == NULL || (line = _this->get_current_line(mouse, notags)) == NULL )
+ Py_RETURN_NONE;
+ return PyString_FromString(line);
+}
+
+bool pyscv_is_focused(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ return false;
+ return _this->is_focused();
+}
+
+void pyscv_clear_popup_menu(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this != NULL )
+ _this->clear_popup_menu();
+}
+
+size_t pyscv_add_popup_menu(PyObject *py_this, const char *title, const char *hotkey)
+{
+ DECL_THIS;
+ return _this == NULL ? 0 : _this->add_popup_menu(title, hotkey);
+}
+
+size_t pyscv_count(PyObject *py_this)
+{
+ DECL_THIS;
+ return _this == NULL ? 0 : _this->count();
+}
+
+bool pyscv_show(PyObject *py_this)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->show();
+}
+
+void pyscv_close(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this != NULL )
+ _this->close();
+}
+
+bool pyscv_jumpto(PyObject *py_this, size_t ln, int x, int y)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ return false;
+ return _this->jumpto(ln, x, y);
+}
+
+// Returns the line tuple
+PyObject *pyscv_get_line(PyObject *py_this, size_t nline)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ Py_RETURN_NONE;
+ return _this->get_line(nline);
+}
+
+// Gets the position and returns a tuple (lineno, x, y)
+PyObject *pyscv_get_pos(PyObject *py_this, bool mouse)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ Py_RETURN_NONE;
+ return _this->get_pos(mouse);
+}
+
+PyObject *pyscv_clear_lines(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this != NULL )
+ _this->clear();
+ Py_RETURN_NONE;
+}
+
+// Adds a line tuple
+bool pyscv_add_line(PyObject *py_this, PyObject *py_sl)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->add_line(py_sl);
+}
+
+bool pyscv_insert_line(PyObject *py_this, size_t nline, PyObject *py_sl)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->insert_line(nline, py_sl);
+}
+
+bool pyscv_patch_line(PyObject *py_this, size_t nline, size_t offs, int value)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->patch_line(nline, offs, value);
+}
+
+bool pyscv_del_line(PyObject *py_this, size_t nline)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->del_line(nline);
+}
+
+PyObject *pyscv_get_selection(PyObject *py_this)
+{
+ DECL_THIS;
+ if ( _this == NULL )
+ Py_RETURN_NONE;
+ return _this->py_get_selection();
+}
+
+// Edits an existing line
+bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl)
+{
+ DECL_THIS;
+ return _this == NULL ? false : _this->edit_line(nline, py_sl);
+}
+#undef DECL_THIS
+//
//
#ifdef CH_ATTRS
@@ -173,7 +1097,7 @@ static pychoose2_to_choose2_map_t choosers;
py_choose2_t *choose2_find_instance(PyObject *self)
{
pychoose2_to_choose2_map_t::iterator it = choosers.find(self);
- if (it == choosers.end())
+ if ( it == choosers.end() )
return NULL;
return it->second;
}
@@ -186,7 +1110,7 @@ void choose2_add_instance(PyObject *self, py_choose2_t *c2)
void choose2_del_instance(PyObject *self)
{
pychoose2_to_choose2_map_t::iterator it = choosers.find(self);
- if (it != choosers.end())
+ if ( it != choosers.end() )
choosers.erase(it);
}
@@ -194,8 +1118,8 @@ void choose2_del_instance(PyObject *self)
class py_choose2_t
{
private:
- enum
- {
+ enum
+ {
CHOOSE2_HAVE_DEL = 0x0001,
CHOOSE2_HAVE_INS = 0x0002,
CHOOSE2_HAVE_UPDATE = 0x0004,
@@ -274,29 +1198,29 @@ private:
//------------------------------------------------------------------------
void on_get_line(int lineno, char * const *line_arr)
{
- if (lineno == 0)
+ if ( lineno == 0 )
{
- for (size_t i=0;i=0;i--)
+ for ( int i=ncols-1; i>=0; i-- )
line_arr[i][0] = '\0';
// Call Python
PyObject *list = PyObject_CallMethod(self, (char *)S_ON_GET_LINE, "i", lineno - 1);
- if (list == NULL)
+ if ( list == NULL )
return;
- for (int i=ncols-1;i>=0;i--)
+ for ( int i=ncols-1; i>=0; i-- )
{
PyObject *item = PyList_GetItem(list, Py_ssize_t(i));
- if (item == NULL)
+ if ( item == NULL )
continue;
const char *str = PyString_AsString(item);
- if (str != NULL)
+ if ( str != NULL )
qstrncpy(line_arr[i], str, MAXSTR);
}
Py_DECREF(list);
@@ -305,7 +1229,7 @@ private:
size_t on_get_size()
{
PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_SIZE, NULL);
- if (pyres == NULL)
+ if ( pyres == NULL )
return 0;
size_t res = PyInt_AsLong(pyres);
Py_DECREF(pyres);
@@ -334,7 +1258,7 @@ private:
int on_delete_line(int lineno)
{
PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_DELETE_LINE, "i", lineno - 1);
- if (pyres == NULL)
+ if ( pyres == NULL )
return lineno;
size_t res = PyInt_AsLong(pyres);
Py_DECREF(pyres);
@@ -344,7 +1268,7 @@ private:
int on_refresh(int lineno)
{
PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_REFRESH, "i", lineno - 1);
- if (pyres == NULL)
+ if ( pyres == NULL )
return lineno;
size_t res = PyInt_AsLong(pyres);
Py_DECREF(pyres);
@@ -372,7 +1296,7 @@ private:
int on_command(int cmd_id, int lineno)
{
PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "ii", lineno - 1, cmd_id);
- if (pyres==NULL)
+ if ( pyres==NULL )
return lineno;
size_t res = PyInt_AsLong(pyres);
Py_XDECREF(pyres);
@@ -389,15 +1313,15 @@ private:
void on_get_line_attr(int lineno, chooser_item_attrs_t *attr)
{
PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_LINE_ATTR, "i", lineno - 1);
- if (pyres == NULL)
+ if ( pyres == NULL )
return;
- if (PyList_Check(pyres))
+ if ( PyList_Check(pyres) )
{
PyObject *item;
- if ((item = PyList_GetItem(pyres, 0)) != NULL)
+ if ( (item = PyList_GetItem(pyres, 0)) != NULL )
attr->color = PyInt_AsLong(item);
- if ((item = PyList_GetItem(pyres, 1)) != NULL)
+ if ( (item = PyList_GetItem(pyres, 1)) != NULL )
attr->flags = PyInt_AsLong(item);
}
Py_XDECREF(pyres);
@@ -424,7 +1348,7 @@ public:
bool activate()
{
TForm *frm = find_tform(title.c_str());
- if (frm == NULL)
+ if ( frm == NULL )
return false;
switchto_tform(frm, true);
return true;
@@ -470,10 +1394,10 @@ public:
int add_command(const char *caption, int flags=0, int menu_index=-1, int icon=-1)
{
- if (menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS)
+ if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS )
return -1;
bool ret = add_chooser_command(title.c_str(), caption, menu_cbs[menu_cb_idx], menu_index, icon, flags);
- if (!ret)
+ if ( !ret )
return -1;
return menu_cb_idx++;
}
@@ -503,7 +1427,7 @@ public:
// get cols caption and widthes
intvec_t widths;
cols.qclear();
- for (int i=0;ichoose2(flags, ncols, &widths[0], title.c_str(), deflt, popup_names, icon, pts[0], pts[1], pts[2], pts[3]);
// Clear temporary popup_names
- if (popup_names != NULL)
+ if ( popup_names != NULL )
{
- for (int i=0;iactivate();
return 1;
@@ -679,7 +1603,7 @@ int choose2_show(PyObject *self)
void choose2_close(PyObject *self)
{
py_choose2_t *c2 = choose2_find_instance(self);
- if (c2 != NULL)
+ if ( c2 != NULL )
c2->close();
}
@@ -687,7 +1611,7 @@ void choose2_close(PyObject *self)
void choose2_refresh(PyObject *self)
{
py_choose2_t *c2 = choose2_find_instance(self);
- if (c2 != NULL)
+ if ( c2 != NULL )
c2->refresh();
}
@@ -695,7 +1619,7 @@ void choose2_refresh(PyObject *self)
void choose2_activate(PyObject *self)
{
py_choose2_t *c2 = choose2_find_instance(self);
- if (c2 != NULL)
+ if ( c2 != NULL )
c2->activate();
}
@@ -703,7 +1627,7 @@ void choose2_activate(PyObject *self)
int choose2_add_command(PyObject *self, const char *caption, int flags=0, int menu_index=-1, int icon=-1)
{
py_choose2_t *c2 = choose2_find_instance(self);
- if (c2 != NULL)
+ if ( c2 != NULL )
return c2->add_command(caption, flags, menu_index, icon);
else
return -2;
@@ -714,7 +1638,7 @@ int choose2_add_command(PyObject *self, const char *caption, int flags=0, int me
PyObject *choose2_find(const char *title)
{
py_choose2_t *c2 = py_choose2_t::find_chooser(title);
- if (c2 == NULL)
+ if ( c2 == NULL )
return NULL;
return c2->get_self();
}
@@ -874,6 +1798,218 @@ class Choose:
"""
return _idaapi.choose_choose(self, self.flags, self.x0, self.y0, self.x1, self.y1, self.width)
+#
+class simplecustview_t(object):
+
+ def __init__(self):
+ self.this = None
+
+ def __del__(self):
+ """Destructor. It also frees the associated C++ object"""
+ try:
+ _idaapi.pyscv_delete(self.this)
+ except:
+ pass
+
+ @staticmethod
+ def make_sl_arg(line, fgcolor=None, bgcolor=None):
+ return line if (fgcolor is None and bgcolor is None) else (line, fgcolor, bgcolor)
+
+ def Create(self, title):
+ """
+ Creates the custom view. This should be the first method called after instantiation
+
+ @param title: The title of the view
+ @return: Boolean whether it succeeds or fails. It may fail if a window with the same title is already open.
+ In this case better close existing windows
+ """
+ self.title = title
+ self.this = _idaapi.pyscv_init(self, title)
+ return True if self.this else False
+
+ def Close(self):
+ """
+ Destroys the view.
+ One has to call Create() afterwards.
+ Show() can be called and it will call Create() internally.
+ @return: Boolean
+ """
+ return _idaapi.pyscv_close(self.this)
+
+ def Show(self):
+ """
+ Shows an already created view. It the view was close, then it will call Create() for you
+ @return: Boolean
+ """
+ return _idaapi.pyscv_show(self.this)
+
+ def Refresh(self):
+ return _idaapi.pyscv_refresh(self.this)
+
+ def RefreshCurrent(self, mouse = 0):
+ """Refreshes the current line only"""
+ return _idaapi.pyscv_refresh_current(self.this, mouse)
+
+ def Count(self):
+ """Returns the number of lines in the view"""
+ return _idaapi.pyscv_count(self.this)
+
+ def GetSelection(self):
+ """
+ Returns the selected area or None
+ @return:
+ - tuple(x1, y1, x2, y2)
+ - None if no selection
+ """
+ return _idaapi.pyscv_get_selection(self.this)
+
+ def ClearLines(self):
+ """Clears all the lines"""
+ _idaapi.pyscv_clear_lines(self.this)
+
+ def AddLine(self, line, fgcolor=None, bgcolor=None):
+ """
+ Adds a colored line to the view
+ @return: Boolean
+ """
+ return _idaapi.pyscv_add_line(self.this, self.make_sl_arg(line, fgcolor, bgcolor))
+
+ def InsertLine(self, lineno, line, fgcolor=None, bgcolor=None):
+ """Inserts a line in the given position"""
+ return _idaapi.pyscv_insert_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor))
+
+ def EditLine(self, lineno, line, fgcolor=None, bgcolor=None):
+ """Edits an existing line"""
+ return _idaapi.pyscv_edit_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor))
+
+ def PatchLine(self, lineno, offs, value):
+ """Patches an existing line character at the given offset. This is a low level function. You must know what you're doing"""
+ return _idaapi.pyscv_patch_line(self.this, lineno, offs, value)
+
+ def DelLine(self, lineno):
+ return _idaapi.pyscv_del_line(self.this, lineno)
+
+ def GetLine(self, lineno):
+ return _idaapi.pyscv_get_line(self.this, lineno)
+
+ def GetCurrentLine(self, mouse = 0, notags = 0):
+ """
+ Returns the current line.
+ @param mouse: Current line at mouse pos
+ @param notags: If True then tag_remove() will be called before returning the line
+ @return: Returns the current line (colored or uncolored)
+ """
+ return _idaapi.pyscv_get_current_line(self.this, mouse, notags)
+
+ def GetPos(self, mouse = 0):
+ """
+ Returns the current cursor or mouse position.
+ @param mouse: return mouse position
+ @return: Returns a tuple (lineno, x, y)
+ """
+ return _idaapi.pyscv_get_pos(self.this, mouse)
+
+ def GetLineNo(self, mouse = 0):
+ """Calls GetPos() and returns the current line number only or None on failure"""
+ r = self.GetPos(mouse)
+ return None if not r else r[0]
+
+ def Jump(self, lineno, x=0, y=0):
+ return _idaapi.pyscv_jumpto(self.this, lineno, x, y)
+
+ def AddPopupMenu(self, title, hotkey=""):
+ """
+ Adds a popup menu item
+ @param title: The name of the menu item
+ @param hotkey: Hotkey of the item or just empty
+ @return: Returns the
+ """
+ return _idaapi.pyscv_add_popup_menu(self.this, title, hotkey)
+
+ def ClearPopupMenu(self):
+ """
+ Clears all previously installed popup menu items.
+ Use this function if you're generating menu items on the fly (in the OnPopup() callback),
+ and before adding new items
+ """
+ _idaapi.pyscv_clear_popup_menu(self.this)
+
+ def IsFocused(self):
+ """Returns True if the current view is the focused view"""
+ return _idaapi.pyscv_is_focused(self.this)
+
+ # Here are all the supported events
+ # Uncomment any event to enable
+# def OnClick(self, shift):
+# """
+# User clicked in the view
+# @param shift: Shift flag
+# @return Boolean. True if you handled the event
+# """
+# print "OnClick, shift=%d" % shift
+# return True
+#
+# def OnDblClick(self, shift):
+# """
+# User dbl-clicked in the view
+# @param shift: Shift flag
+# @return Boolean. True if you handled the event
+# """
+# print "OnDblClick, shift=%d" % shift
+# return True
+#
+# def OnCursorPosChanged(self):
+# """
+# Cursor position changed.
+# @return Nothing
+# """
+# print "OnCurposChanged"
+#
+# def OnClose(self):
+# """
+# The view is closing. Use this event to cleanup.
+# @return Nothing
+# """
+# print "OnClose"
+#
+# def OnKeydown(self, vkey, shift):
+# """
+# User pressed a key
+# @param vkey: Virtual key code
+# @param shift: Shift flag
+# @return Boolean. True if you handled the event
+# """
+# print "OnKeydown, vk=%d shift=%d" % (vkey, shift)
+# return False
+#
+# def OnPopup(self):
+# """
+# Context menu popup is about to be shown. Create items dynamically if you wish
+# @return Boolean. True if you handled the event
+# """
+# print "OnPopup"
+#
+# def OnHint(self, lineno):
+# """
+# Hint requested for the given line number.
+# @param lineno: The line number (zero based)
+# @return:
+# - string: a string containing the hint
+# - None: if no hint available
+# """
+# return "OnHint, line=%d" % lineno
+#
+# def OnPopupMenu(self, menu_id):
+# """
+# A context (or popup) menu item was executed.
+# @param menu_id: ID previously registered with add_popup_menu()
+# @return: Boolean
+# """
+# print "OnPopupMenu, menu_id=" % menu_id
+# return True
+
+#
+
#
class Choose2:
"""Choose2 wrapper class"""
diff --git a/swig/lines.i b/swig/lines.i
index 6643f82..25feafe 100644
--- a/swig/lines.i
+++ b/swig/lines.i
@@ -1,8 +1,7 @@
-// Convert this for ver 4.8 tag_remove()
-%cstring_output_maxstr_none(char *buf, int bufsize);
-
// FIXME: These should be fixed
+%ignore requires_color_esc;
%ignore tag_on;
+%ignore tag_remove;
%ignore tag_off;
%ignore tag_addchr;
%ignore tag_addstr;
@@ -60,4 +59,128 @@
%include "lines.hpp"
-%clear(char *buf, int bufsize);
+%rename (generate_disassembly) py_generate_disassembly;
+%rename (tag_remove) py_tag_remove;
+%rename (tag_addr) py_tag_addr;
+%rename (tag_skipcodes) py_tag_skipcodes;
+%rename (tag_skipcode) py_tag_skipcode;
+%rename (tag_advance) py_tag_advance;
+%rename (generate_disassembly) py_generate_disassembly;
+
+%inline
+{
+//
+//-------------------------------------------------------------------------
+PyObject *py_tag_remove(const char *instr)
+{
+ size_t sz = strlen(instr);
+ char *buf = new char[sz + 5];
+ if ( buf == NULL )
+ Py_RETURN_NONE;
+ ssize_t r = tag_remove(instr, buf, sz);
+ PyObject *res;
+ if ( r < 0 )
+ {
+ Py_INCREF(Py_None);
+ res = Py_None;
+ }
+ else
+ {
+ res = PyString_FromString(buf);
+ }
+ delete [] buf;
+ return res;
+}
+
+//-------------------------------------------------------------------------
+PyObject *py_tag_addr(ea_t ea)
+{
+ char buf[100];
+ tag_addr(buf, buf + sizeof(buf), ea);
+ return PyString_FromString(buf);
+}
+
+//-------------------------------------------------------------------------
+int py_tag_skipcode(const char *line)
+{
+ return tag_skipcode(line)-line;
+}
+
+//-------------------------------------------------------------------------
+int py_tag_skipcodes(const char *line)
+{
+ return tag_skipcodes(line)-line;
+}
+
+//-------------------------------------------------------------------------
+int py_tag_advance(const char *line, int cnt)
+{
+ return tag_advance(line, cnt)-line;
+}
+
+//-------------------------------------------------------------------------
+PyObject *py_generate_disassembly(ea_t ea, int max_lines, bool as_stack, bool notags)
+{
+ if ( max_lines <= 0 )
+ Py_RETURN_NONE;
+
+ qstring qbuf;
+ char **lines = new char *[max_lines];
+ int lnnum;
+ int nlines = generate_disassembly(ea, lines, max_lines, &lnnum, as_stack);
+
+ PyObject *py_tuple = PyTuple_New(nlines);
+ for ( int i=0; i
+
+}
+
+%pythoncode %{
+#
+
+# ---------------- Color escape sequence defitions -------------------------
+COLOR_ADDR_SIZE = 16 if _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL else 8
+SCOLOR_FG_MAX = '\x28' # Max color number
+SCOLOR_OPND1 = chr(cvar.COLOR_ADDR+1) # Instruction operand 1
+SCOLOR_OPND2 = chr(cvar.COLOR_ADDR+2) # Instruction operand 2
+SCOLOR_OPND3 = chr(cvar.COLOR_ADDR+3) # Instruction operand 3
+SCOLOR_OPND4 = chr(cvar.COLOR_ADDR+4) # Instruction operand 4
+SCOLOR_OPND5 = chr(cvar.COLOR_ADDR+5) # Instruction operand 5
+SCOLOR_OPND6 = chr(cvar.COLOR_ADDR+6) # Instruction operand 6
+SCOLOR_UTF8 = chr(cvar.COLOR_ADDR+10) # Following text is UTF-8 encoded
+
+# ---------------- Line prefix colors --------------------------------------
+PALETTE_SIZE = (cvar.COLOR_FG_MAX+_idaapi.COLOR_BG_MAX)
+
+def requires_color_esc(c):
+ """
+ Checks if the given character requires escaping
+ @param c: character (string of one char)
+ @return: Boolean
+ """
+ t = ord(c[0])
+ return c >= COLOR_ON and c <= COLOR_INV
+
+def COLSTR(str,tag):
+ return SCOLOR_ON + tag + str + SCOLOR_OFF + tag
+
+#
+
+%}
\ No newline at end of file