
This is an FAQ-style repository of SWiG incantations that are regularly needed.

# Rule of thumb

If you are doing something non-trivial in IDAPython, or if you added something to the C++ SDK which will then be reflected in IDAPython, an *immensely* useful rule-of-thumb is to perform a diff of the autogenerated SWiG wrappers.

Typically:
`cp -R obj/<...>/wrappers/ /tmp/wrappers-before`
<recompile...>
`git diff /tmp/wrappers-before/ obj/<...>/wrappers/`

It is always useful to make sure that SWiG did the right thing -- *especially* when modifying typemaps, but not only.

# How to add new module?

We use the "zzz" placeholder for a module name in this "how-to".

1. create file swig/zzz.i
```
%{
#include <zzz.hpp>
%}
%include "zzz.hpp"
```

2. add zzz to the `MODULES_NAMES` var in makefile

3. add a line to python/idc.py if you want to autoload this module
```
import ida_zzz
```

4. [build](../../BUILDING.md)

5. update the content of `api_contents.*`
   (from `obj/<...>/api_contents.*`)

7. rebuild

# Remove an argument from a prototype (because it doesn't make sense in the context of IDAPython)

    %typemap(in,numinputs=0) int length
    {
        $1 = -1; // always -1 in IDAPython
    }

# Add a parameter to a C++ notification

Assume a notification named `struc_renamed`, to which you just
added a `bool success` parameter (to carry along information about the
operation's success so far):

    struc_renamed,          ///< A structure type has been renamed.
                            ///< \param sptr (::struc_t *)
                            ///< \param success (bool)  // <--------- new

That new parameter will be picked up by the hooks-producing code
automatically (great!), which means existing hooks are now broken
(bad.)

We need to add support for calling into "old-style" hooks. That's done
through the `patch_codegen.py` mechanism, and in particular the
`director_method_call_arity_cap` rule. Something like this should do:

    "SwigDirector_IDB_Hooks::struc_renamed" : [
        ("director_method_call_arity_cap", (
            False, # add GIL lock
            "struc_renamed",
            "(method ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)",
            "(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)")
        )),
    ],

# Handle a virtual method's "output" parameter in a director

Assume you have a virtual method taking an 'output' argument:

    void merge_node_helper_t::get_column_headers(qstrvec_t *out, ...)

The neat thing to do here is to let Python implementations do the
following:

    def get_column_headers(self, ...):
        # ...
        return ["Name", "Address"]

To achieve that, you want to use the `directorargout` typemap:

    %typemap(directorargout) qstrvec_t * (qstrvec_t tmp)
    { // %typemap(directorargout) qstrvec_t *
      if ( PyW_PySeqToStrVec(&tmp, $result) >= 0 )
      {
        $1->swap(tmp);
      }
      else
      {
        Swig::DirectorTypeMismatchException::raise(
                SWIG_ErrorType(SWIG_TypeError),
                "in output value of type 'qstrvec_t' in method '$symname'");
      }
    }

# Handle `qstring *errbuf` output parameters

Many C++ functions have an `errbuf` parameter for error messages:

```cpp
pkt_pull_md_result_t *pull_md(eavec_t *funcs, qstring *errbuf, uint32 flags=0);
```

## Default behavior

In `header.i.in`, errbuf is mapped as an output parameter:
```swig
%apply qstring *result { qstring *errbuf };
```
This means by default, `errbuf` is **returned to the user** as part of the result tuple.

## Module-specific overrides

Modules can override this default to convert errors to exceptions:

**1. Raise exception if errbuf is non-empty:**
```swig
%make_argout_errbuf_raise_exception_when_non_empty(errbuf);
```
Used in: `lumina.i` - The Python signature becomes `func(input, flags=0)` with no errbuf parameter. Errors raise `RuntimeError`.

**2. Raise exception if result is null:**
```swig
%make_argout_errbuf_raise_when_null_result(errbuf);
```
Used in: `typeinf.i` - Raises exception using errbuf message when the function returns null.

**3. Return errbuf as string on negative result (custom typemap):**
```swig
%typemap(argout) (qstring *errbuf)
{
  if ( result < 0 )
  {
    Py_XDECREF($result);
    if ( $1 != nullptr )
      $result = PyUnicode_from_qstring(*$1);
    else
      $result = PyUnicode_FromString("Unknown error");
  }
}
```
Used in: `idp.i` for processor notification handlers (`ev_cvt64_supval`, `ev_cvt64_hashval`, `ev_privrange_changed`).

## Modules without explicit errbuf handling

These modules use the default behavior (errbuf returned as output):
- `idd.i` - debugger functions (`init_debugger`, `attach_process`, etc.)
- `loader.i` - loader functions (`load_binary_file`, etc.)
- `bytes.i` - byte manipulation functions
- `expr.i` - expression evaluation (via pywraps)

# "intercept" access to a structure/class field, in order to perform extra work

. tell swig to consider the member as unreachable:

    %ignore idainfo::lflags;

. extend the type to "manually" provide the field:

    %extend idainfo
    {
      // ...
      uint32 _get_lflags() const { return $self->lflags; }
      void _set_lflags(uint32 _f)
      {
        // do the job here
      }

      %pythoncode {
        lflags = property(_get_lflags, _set_lflags)

