koffi 1.3.12 → 2.1.0-beta.1

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 (104) hide show
  1. package/CMakeLists.txt +8 -10
  2. package/ChangeLog.md +48 -16
  3. package/README.md +6 -0
  4. package/benchmark/atoi_koffi.js +12 -8
  5. package/benchmark/atoi_napi.js +12 -8
  6. package/benchmark/atoi_node_ffi.js +11 -10
  7. package/benchmark/raylib_cc.cc +12 -9
  8. package/benchmark/raylib_koffi.js +15 -13
  9. package/benchmark/raylib_node_ffi.js +15 -13
  10. package/benchmark/raylib_node_raylib.js +14 -11
  11. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/changes.md +160 -1
  27. package/doc/conf.py +14 -1
  28. package/doc/contribute.md +0 -1
  29. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  30. package/doc/dist/doctrees/changes.doctree +0 -0
  31. package/doc/dist/doctrees/environment.pickle +0 -0
  32. package/doc/dist/doctrees/functions.doctree +0 -0
  33. package/doc/dist/doctrees/index.doctree +0 -0
  34. package/doc/dist/doctrees/types.doctree +0 -0
  35. package/doc/dist/html/.buildinfo +1 -1
  36. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  37. package/doc/dist/html/_sources/changes.md.txt +160 -1
  38. package/doc/dist/html/_sources/functions.md.txt +17 -13
  39. package/doc/dist/html/_sources/types.md.txt +87 -35
  40. package/doc/dist/html/benchmarks.html +7 -3
  41. package/doc/dist/html/changes.html +241 -14
  42. package/doc/dist/html/contribute.html +5 -1
  43. package/doc/dist/html/functions.html +30 -23
  44. package/doc/dist/html/genindex.html +5 -1
  45. package/doc/dist/html/index.html +13 -19
  46. package/doc/dist/html/memory.html +7 -3
  47. package/doc/dist/html/objects.inv +0 -0
  48. package/doc/dist/html/platforms.html +6 -2
  49. package/doc/dist/html/search.html +5 -1
  50. package/doc/dist/html/searchindex.js +1 -1
  51. package/doc/dist/html/start.html +5 -1
  52. package/doc/dist/html/types.html +104 -43
  53. package/doc/functions.md +139 -15
  54. package/doc/templates/badges.html +5 -0
  55. package/doc/types.md +108 -40
  56. package/package.json +2 -2
  57. package/qemu/qemu.js +1 -1
  58. package/qemu/registry/machines.json +5 -5
  59. package/qemu/registry/sha256sum.txt +16 -16
  60. package/src/abi_arm32.cc +91 -19
  61. package/src/abi_arm32_fwd.S +121 -57
  62. package/src/abi_arm64.cc +91 -19
  63. package/src/abi_arm64_fwd.S +96 -0
  64. package/src/abi_arm64_fwd.asm +128 -0
  65. package/src/abi_riscv64.cc +89 -19
  66. package/src/abi_riscv64_fwd.S +96 -0
  67. package/src/abi_x64_sysv.cc +94 -22
  68. package/src/abi_x64_sysv_fwd.S +96 -0
  69. package/src/abi_x64_win.cc +89 -19
  70. package/src/abi_x64_win_fwd.asm +128 -0
  71. package/src/abi_x86.cc +94 -19
  72. package/src/abi_x86_fwd.S +96 -0
  73. package/src/abi_x86_fwd.asm +128 -0
  74. package/src/call.cc +128 -78
  75. package/src/call.hh +17 -4
  76. package/src/ffi.cc +514 -145
  77. package/src/ffi.hh +30 -9
  78. package/src/index.js +4 -2
  79. package/src/parser.cc +19 -44
  80. package/src/util.cc +160 -27
  81. package/src/util.hh +7 -2
  82. package/test/async.js +1 -2
  83. package/test/callbacks.js +56 -11
  84. package/test/misc.c +50 -15
  85. package/test/raylib.js +2 -2
  86. package/test/sqlite.js +27 -19
  87. package/test/sync.js +71 -35
  88. package/vendor/libcc/libcc.cc +18 -5
  89. package/vendor/libcc/libcc.hh +70 -23
  90. package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
  91. package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
  95. package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
  96. package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
  97. package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
  98. package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
  99. package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
  100. package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
  101. package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
  103. package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
  104. package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
@@ -3,7 +3,7 @@
3
3
  <head><meta charset="utf-8"/>
4
4
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
5
5
  <meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
6
- <link rel="index" title="Index" href="genindex" /><link rel="search" title="Search" href="search" /><link rel="next" title="Function calls" href="functions" /><link rel="prev" title="Quick start" href="start" />
6
+ <link rel="index" title="Index" href="genindex" /><link rel="search" title="Search" href="search" /><link rel="next" title="Functions" href="functions" /><link rel="prev" title="Quick start" href="start" />
7
7
 
8
8
  <meta name="generator" content="sphinx-5.0.1, furo 2022.06.04.1"/>
9
9
  <title>Data types - Koffi</title>
@@ -165,13 +165,17 @@
165
165
  <li class="toctree-l1"><a class="reference internal" href="platforms">Requirements</a></li>
166
166
  <li class="toctree-l1"><a class="reference internal" href="start">Quick start</a></li>
167
167
  <li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Data types</a></li>
168
- <li class="toctree-l1"><a class="reference internal" href="functions">Function calls</a></li>
168
+ <li class="toctree-l1"><a class="reference internal" href="functions">Functions</a></li>
169
169
  <li class="toctree-l1"><a class="reference internal" href="memory">Memory usage</a></li>
170
170
  <li class="toctree-l1"><a class="reference internal" href="benchmarks">Benchmarks</a></li>
171
171
  <li class="toctree-l1"><a class="reference internal" href="contribute">Contributing</a></li>
172
172
  <li class="toctree-l1"><a class="reference internal" href="changes">Changelog</a></li>
173
173
  </ul>
174
174
 
175
+ </div>
176
+ <div style="text-align: center; margin-top: 2em;">
177
+ <a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-2.0.1-brightgreen" alt="NPM"/></a>
178
+ <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
175
179
  </div>
176
180
  </div>
177
181
 
@@ -219,7 +223,7 @@
219
223
  </tr>
220
224
  </thead>
221
225
  <tbody>
222
- <tr class="row-even"><td><p>Null</p></td>
226
+ <tr class="row-even"><td><p>Undefined</p></td>
223
227
  <td><p>void</p></td>
224
228
  <td><p>0</p></td>
225
229
  <td><p></p></td>
@@ -506,6 +510,8 @@
506
510
  </section>
507
511
  <section id="struct-types">
508
512
  <h2>Struct types<a class="headerlink" href="#struct-types" title="Permalink to this heading">#</a></h2>
513
+ <section id="struct-definition">
514
+ <h3>Struct definition<a class="headerlink" href="#struct-definition" title="Permalink to this heading">#</a></h3>
509
515
  <p>Koffi converts JS objects to C structs, and vice-versa.</p>
510
516
  <p>Unlike function declarations, as of now there is only one way to create a struct type, with the <code class="docutils literal notranslate"><span class="pre">koffi.struct()</span></code> function. This function takes two arguments: the first one is the name of the type, and the second one is an object containing the struct member names and types. You can omit the first argument to declare an anonymous struct.</p>
511
517
  <p>The following example illustrates how to declare the same struct in C and in JS with Koffi:</p>
@@ -538,50 +544,38 @@
538
544
  <span class="linenos">3</span><span class="kd">const</span> <span class="nx">Function2</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;Function&#39;</span><span class="p">,</span> <span class="nx">A</span><span class="p">,</span> <span class="p">[</span><span class="nx">A</span><span class="p">]);</span>
539
545
  </pre></div>
540
546
  </div>
541
- </section>
542
- <section id="pointer-types">
543
- <h2>Pointer types<a class="headerlink" href="#pointer-types" title="Permalink to this heading">#</a></h2>
544
- <p>In C, pointer arguments are used for differenty purposes. It is important to distinguish these use cases because Koffi provides different ways to deal with each of them:</p>
547
+ <p>Koffi automatically follows the platform C ABI regarding alignment and padding. However, you can override these rules if needed with:</p>
545
548
  <ul class="simple">
546
- <li><p><strong>Struct pointers</strong>: Use of struct pointers by C libraries fall in two cases: avoid (potentially) expensive copies, and to let the function change struct contents (output or input/output arguments).</p></li>
547
- <li><p><strong>Opaque handles</strong>: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. <code class="docutils literal notranslate"><span class="pre">FILE</span> <span class="pre">*</span></code>). Only the functions provided by the library can do something with this pointer, in Koffi we call this a handle. This is usually done for ABI-stability reason, and to prevent library users from messing directly with library internals.</p></li>
548
- <li><p><strong>Arrays</strong>: in C, you dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.</p></li>
549
- <li><p><strong>Pointers to primitive types</strong>: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.</p></li>
549
+ <li><p>Pack all members without padding with <code class="docutils literal notranslate"><span class="pre">koffi.pack()</span></code> (instead of <code class="docutils literal notranslate"><span class="pre">koffi.struct()</span></code>)</p></li>
550
+ <li><p>Change alignment of a specific member as shown below</p></li>
550
551
  </ul>
551
- <section id="struct-pointers">
552
- <h3>Struct pointers<a class="headerlink" href="#struct-pointers" title="Permalink to this heading">#</a></h3>
553
- <p>The following Win32 example uses <code class="docutils literal notranslate"><span class="pre">GetCursorPos()</span></code> (with an output parameter) to retrieve and show the current cursor position.</p>
554
- <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;koffi&#39;</span><span class="p">);</span>
555
- <span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">&#39;kernel32.dll&#39;</span><span class="p">);</span>
556
- <span class="linenos"> 3</span>
557
- <span class="linenos"> 4</span><span class="c1">// Type declarations</span>
558
- <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">POINT</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">&#39;POINT&#39;</span><span class="p">,</span> <span class="p">{</span>
559
- <span class="linenos"> 6</span> <span class="nx">x</span><span class="o">:</span> <span class="s1">&#39;long&#39;</span><span class="p">,</span>
560
- <span class="linenos"> 7</span> <span class="nx">y</span><span class="o">:</span> <span class="s1">&#39;long&#39;</span>
561
- <span class="linenos"> 8</span><span class="p">});</span>
562
- <span class="linenos"> 9</span>
563
- <span class="linenos">10</span><span class="c1">// Functions declarations</span>
564
- <span class="linenos">11</span><span class="kd">const</span> <span class="nx">GetCursorPos</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;int __stdcall GetCursorPos(_Out_ POINT *pos)&#39;</span><span class="p">);</span>
565
- <span class="linenos">12</span>
566
- <span class="linenos">13</span><span class="c1">// Get and show cursor position</span>
567
- <span class="linenos">14</span><span class="kd">let</span> <span class="nx">pos</span> <span class="o">=</span> <span class="p">{};</span>
568
- <span class="linenos">15</span><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">GetCursorPos</span><span class="p">(</span><span class="nx">pos</span><span class="p">))</span>
569
- <span class="linenos">16</span> <span class="k">throw</span> <span class="ow">new</span> <span class="ne">Error</span><span class="p">(</span><span class="s1">&#39;Failed to get cursor position&#39;</span><span class="p">);</span>
570
- <span class="linenos">17</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">pos</span><span class="p">);</span>
552
+ <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// This struct is 3 bytes long</span>
553
+ <span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">PackedStruct</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pack</span><span class="p">(</span><span class="s1">&#39;PackedStruct&#39;</span><span class="p">,</span> <span class="p">{</span>
554
+ <span class="linenos"> 3</span> <span class="nx">a</span><span class="o">:</span> <span class="s1">&#39;int8_t&#39;</span><span class="p">,</span>
555
+ <span class="linenos"> 4</span> <span class="nx">b</span><span class="o">:</span> <span class="s1">&#39;int16_t&#39;</span>
556
+ <span class="linenos"> 5</span><span class="p">});</span>
557
+ <span class="linenos"> 6</span>
558
+ <span class="linenos"> 7</span><span class="c1">// This one is 18 bytes long, the second member has an alignment requirement of 16 bytes</span>
559
+ <span class="linenos"> 8</span><span class="kd">const</span> <span class="nx">BigStruct</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">&#39;BigStruct&#39;</span><span class="p">,</span> <span class="p">{</span>
560
+ <span class="linenos"> 9</span> <span class="nx">a</span><span class="o">:</span> <span class="s1">&#39;int8_t&#39;</span><span class="p">,</span>
561
+ <span class="linenos">10</span> <span class="nx">b</span><span class="o">:</span> <span class="p">[</span><span class="mf">16</span><span class="p">,</span> <span class="s1">&#39;int16_t&#39;</span><span class="p">]</span>
562
+ <span class="linenos">11</span><span class="p">})</span>
571
563
  </pre></div>
572
564
  </div>
573
565
  </section>
574
- <section id="opaque-handles">
575
- <h3>Opaque handles<a class="headerlink" href="#opaque-handles" title="Permalink to this heading">#</a></h3>
576
- <p>Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque <code class="docutils literal notranslate"><span class="pre">FILE</span> <span class="pre">*</span></code> pointer. You can open and close files with <code class="docutils literal notranslate"><span class="pre">fopen()</span></code> and <code class="docutils literal notranslate"><span class="pre">fclose()</span></code>, and manipule the handle with other functions such as <code class="docutils literal notranslate"><span class="pre">fread()</span></code> or <code class="docutils literal notranslate"><span class="pre">ftell()</span></code>.</p>
577
- <p>In Koffi, you can manage this with opaque handles. Declare the handle type with <code class="docutils literal notranslate"><span class="pre">koffi.handle(name)</span></code>, and use a pointer to this type either as a return type or some kind of <a class="reference internal" href="functions#output-parameters"><span class="std std-doc">output parameter</span></a> (with a double pointer).</p>
566
+ <section id="opaque-types">
567
+ <h3>Opaque types<a class="headerlink" href="#opaque-types" title="Permalink to this heading">#</a></h3>
568
+ <p>Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque <code class="docutils literal notranslate"><span class="pre">FILE</span> <span class="pre">*</span></code> pointer. You can open and close files with <code class="docutils literal notranslate"><span class="pre">fopen()</span></code> and <code class="docutils literal notranslate"><span class="pre">fclose()</span></code>, and manipule the opaque pointer with other functions such as <code class="docutils literal notranslate"><span class="pre">fread()</span></code> or <code class="docutils literal notranslate"><span class="pre">ftell()</span></code>.</p>
569
+ <p>In Koffi, you can manage this with opaque types. Declare the opaque type with <code class="docutils literal notranslate"><span class="pre">koffi.opaque(name)</span></code>, and use a pointer to this type either as a return type or some kind of <a class="reference internal" href="functions#output-parameters"><span class="std std-doc">output parameter</span></a> (with a double pointer).</p>
578
570
  <div class="admonition note">
579
571
  <p class="admonition-title">Note</p>
580
- <p>Opaque handles <strong>have changed in version 2.0</strong>.</p>
572
+ <p>Opaque types <strong>have changed in version 2.0, and again in version 2.1</strong>.</p>
581
573
  <p>In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.</p>
582
574
  <p>Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to <code class="docutils literal notranslate"><span class="pre">ConcatNewOut</span></code> in the JS part), and is described in the section on <a class="reference internal" href="functions#output-parameters"><span class="std std-doc">output parameters</span></a>.</p>
575
+ <p>In addition to this, you should use <code class="docutils literal notranslate"><span class="pre">koffi.opaque()</span></code> (introduced in Koffi 2.1) instead of <code class="docutils literal notranslate"><span class="pre">koffi.handle()</span></code> which is deprecated, and will be removed eventually in Koffi 3.0.</p>
576
+ <p>Consult the <a class="reference internal" href="changes"><span class="doc std std-doc">migration guide</span></a> for more information.</p>
583
577
  </div>
584
- <p>The full example below implements an iterative string builder (concatenator) in C, and uses it from Javascript to output a mix of Hello World and FizzBuzz. The builder is hidden behind an opaque handle, and is created and destroyed using a pair of C functions: <code class="docutils literal notranslate"><span class="pre">ConcatNew</span></code> (or <code class="docutils literal notranslate"><span class="pre">ConcatNewOut</span></code>) and <code class="docutils literal notranslate"><span class="pre">ConcatFree</span></code>.</p>
578
+ <p>The full example below implements an iterative string builder (concatenator) in C, and uses it from Javascript to output a mix of Hello World and FizzBuzz. The builder is hidden behind an opaque type, and is created and destroyed using a pair of C functions: <code class="docutils literal notranslate"><span class="pre">ConcatNew</span></code> (or <code class="docutils literal notranslate"><span class="pre">ConcatNewOut</span></code>) and <code class="docutils literal notranslate"><span class="pre">ConcatFree</span></code>.</p>
585
579
  <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Build with: clang -fPIC -o handles.so -shared handles.c -Wall -O2</span>
586
580
  <span class="linenos"> 2</span>
587
581
  <span class="linenos"> 3</span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span>
@@ -703,7 +697,7 @@
703
697
  <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;koffi&#39;</span><span class="p">);</span>
704
698
  <span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">&#39;./handles.so&#39;</span><span class="p">);</span>
705
699
  <span class="linenos"> 3</span>
706
- <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">Concat</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">handle</span><span class="p">(</span><span class="s1">&#39;Concat&#39;</span><span class="p">);</span>
700
+ <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">Concat</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">opaque</span><span class="p">(</span><span class="s1">&#39;Concat&#39;</span><span class="p">);</span>
707
701
  <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">ConcatNewOut</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;bool ConcatNewOut(_Out_ Concat **out)&#39;</span><span class="p">);</span>
708
702
  <span class="linenos"> 6</span><span class="kd">const</span> <span class="nx">ConcatNew</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;Concat *ConcatNew()&#39;</span><span class="p">);</span>
709
703
  <span class="linenos"> 7</span><span class="kd">const</span> <span class="nx">ConcatFree</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;void ConcatFree(Concat *c)&#39;</span><span class="p">);</span>
@@ -753,6 +747,50 @@
753
747
  </pre></div>
754
748
  </div>
755
749
  </section>
750
+ </section>
751
+ <section id="pointer-types">
752
+ <h2>Pointer types<a class="headerlink" href="#pointer-types" title="Permalink to this heading">#</a></h2>
753
+ <p>In C, pointer arguments are used for differenty purposes. It is important to distinguish these use cases because Koffi provides different ways to deal with each of them:</p>
754
+ <ul class="simple">
755
+ <li><p><strong>Struct pointers</strong>: Use of struct pointers by C libraries fall in two cases: avoid (potentially) expensive copies, and to let the function change struct contents (output or input/output arguments).</p></li>
756
+ <li><p><strong>Opaque pointers</strong>: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. <code class="docutils literal notranslate"><span class="pre">FILE</span> <span class="pre">*</span></code>). Only the functions provided by the library can do something with this pointer, in Koffi we call this an opaque type. This is usually done for ABI-stability reason, and to prevent library users from messing directly with library internals.</p></li>
757
+ <li><p><strong>Arrays</strong>: in C, you dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.</p></li>
758
+ <li><p><strong>Pointers to primitive types</strong>: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.</p></li>
759
+ </ul>
760
+ <section id="struct-pointers">
761
+ <h3>Struct pointers<a class="headerlink" href="#struct-pointers" title="Permalink to this heading">#</a></h3>
762
+ <p>The following Win32 example uses <code class="docutils literal notranslate"><span class="pre">GetCursorPos()</span></code> (with an output parameter) to retrieve and show the current cursor position.</p>
763
+ <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;koffi&#39;</span><span class="p">);</span>
764
+ <span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">&#39;kernel32.dll&#39;</span><span class="p">);</span>
765
+ <span class="linenos"> 3</span>
766
+ <span class="linenos"> 4</span><span class="c1">// Type declarations</span>
767
+ <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">POINT</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">&#39;POINT&#39;</span><span class="p">,</span> <span class="p">{</span>
768
+ <span class="linenos"> 6</span> <span class="nx">x</span><span class="o">:</span> <span class="s1">&#39;long&#39;</span><span class="p">,</span>
769
+ <span class="linenos"> 7</span> <span class="nx">y</span><span class="o">:</span> <span class="s1">&#39;long&#39;</span>
770
+ <span class="linenos"> 8</span><span class="p">});</span>
771
+ <span class="linenos"> 9</span>
772
+ <span class="linenos">10</span><span class="c1">// Functions declarations</span>
773
+ <span class="linenos">11</span><span class="kd">const</span> <span class="nx">GetCursorPos</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;int __stdcall GetCursorPos(_Out_ POINT *pos)&#39;</span><span class="p">);</span>
774
+ <span class="linenos">12</span>
775
+ <span class="linenos">13</span><span class="c1">// Get and show cursor position</span>
776
+ <span class="linenos">14</span><span class="kd">let</span> <span class="nx">pos</span> <span class="o">=</span> <span class="p">{};</span>
777
+ <span class="linenos">15</span><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">GetCursorPos</span><span class="p">(</span><span class="nx">pos</span><span class="p">))</span>
778
+ <span class="linenos">16</span> <span class="k">throw</span> <span class="ow">new</span> <span class="ne">Error</span><span class="p">(</span><span class="s1">&#39;Failed to get cursor position&#39;</span><span class="p">);</span>
779
+ <span class="linenos">17</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">pos</span><span class="p">);</span>
780
+ </pre></div>
781
+ </div>
782
+ </section>
783
+ <section id="named-pointer-types">
784
+ <h3>Named pointer types<a class="headerlink" href="#named-pointer-types" title="Permalink to this heading">#</a></h3>
785
+ <p>Some C libraries use handles, which behave as pointers to opaque structs. An example of this is the HANDLE type in the Win32 API. If you want to reproduce this behavior, you can define a <strong>named pointer type</strong> to an opaque type, like so:</p>
786
+ <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">HANDLE</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="s1">&#39;HANDLE&#39;</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">opaque</span><span class="p">());</span>
787
+ <span class="linenos">2</span>
788
+ <span class="linenos">3</span><span class="c1">// And now you get to use it this way:</span>
789
+ <span class="linenos">4</span><span class="kd">const</span> <span class="nx">GetHandleInformation</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;bool __stdcall GetHandleInformation(HANDLE h, _Out_ uint32_t *flags)&#39;</span><span class="p">);</span>
790
+ <span class="linenos">5</span><span class="kd">const</span> <span class="nx">CloseHandle</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">&#39;bool __stdcall CloseHandle(HANDLE h)&#39;</span><span class="p">);</span>
791
+ </pre></div>
792
+ </div>
793
+ </section>
756
794
  <section id="array-pointers">
757
795
  <h3>Array pointers<a class="headerlink" href="#array-pointers" title="Permalink to this heading">#</a></h3>
758
796
  <p>In C, dynamically-sized arrays are usually passed around as pointers. The length is either passed as an additional argument, or inferred from the array content itself, for example with a terminating sentinel value (such as a NULL pointers in the case of an array of strings).</p>
@@ -793,7 +831,7 @@
793
831
  <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;koffi&#39;</span><span class="p">);</span>
794
832
  <span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">&#39;kernel32.dll&#39;</span><span class="p">);</span>
795
833
  <span class="linenos"> 3</span>
796
- <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">HANDLE</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="s1">&#39;HANDLE&#39;</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">handle</span><span class="p">());</span>
834
+ <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">HANDLE</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="s1">&#39;HANDLE&#39;</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">opaque</span><span class="p">());</span>
797
835
  <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">FILETIME</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">&#39;FILETIME&#39;</span><span class="p">,</span> <span class="p">{</span>
798
836
  <span class="linenos"> 6</span> <span class="nx">dwLowDateTime</span><span class="o">:</span> <span class="s1">&#39;uint&#39;</span><span class="p">,</span>
799
837
  <span class="linenos"> 7</span> <span class="nx">dwHighDateTime</span><span class="o">:</span> <span class="s1">&#39;uint&#39;</span>
@@ -921,18 +959,27 @@
921
959
  <p>The reverse case is also true, Koffi can convert a C fixed-size buffer to a JS string. This happens by default for char, char16 and char16_t arrays, but you can also explicitly ask for this with the <code class="docutils literal notranslate"><span class="pre">string</span></code> array hint (e.g. <code class="docutils literal notranslate"><span class="pre">koffi.array('char',</span> <span class="pre">8,</span> <span class="pre">'string')</span></code>).</p>
922
960
  </section>
923
961
  </section>
962
+ <section id="disposable-types">
963
+ <h2>Disposable types<a class="headerlink" href="#disposable-types" title="Permalink to this heading">#</a></h2>
964
+ <p>Disposable types allow you to register a function that will automatically called after each C to JS conversion performed by Koffi. This can be used to avoid leaking heap-allocated strings, for example.</p>
965
+ <p>Read the documentation for <a class="reference internal" href="functions#heap-allocated-values"><span class="std std-doc">disposable types</span></a> on the page about function calls.</p>
966
+ </section>
967
+ <section id="utility-functions">
968
+ <h2>Utility functions<a class="headerlink" href="#utility-functions" title="Permalink to this heading">#</a></h2>
924
969
  <section id="type-introspection">
925
- <h2>Type introspection<a class="headerlink" href="#type-introspection" title="Permalink to this heading">#</a></h2>
970
+ <h3>Type introspection<a class="headerlink" href="#type-introspection" title="Permalink to this heading">#</a></h3>
926
971
  <p>Koffi exposes three functions to explore type information:</p>
927
972
  <ul class="simple">
928
973
  <li><p><code class="docutils literal notranslate"><span class="pre">koffi.sizeof(type)</span></code> to get the size of a type</p></li>
929
974
  <li><p><code class="docutils literal notranslate"><span class="pre">koffi.alignof(type)</span></code> to get the alignment of a type</p></li>
930
975
  <li><p><code class="docutils literal notranslate"><span class="pre">koffi.introspect(type)</span></code> to get the definition of a type in an object containing: name, primitive, size, alignment, members (structs), reference (array, pointer) and length (array)</p></li>
976
+ <li><p><code class="docutils literal notranslate"><span class="pre">koffi.resolve(type)</span></code> to get the resolved type object from a type string</p></li>
931
977
  </ul>
932
978
  <div class="admonition note">
933
979
  <p class="admonition-title">Note</p>
934
980
  <p>The value returned by <code class="docutils literal notranslate"><span class="pre">introspect()</span></code> has <strong>changed in version 2.0</strong>.</p>
935
981
  <p>In Koffi 1.x, it could only be used with struct types and returned the object passed to koffi.struct() with the member names and types.</p>
982
+ <p>Consult the <a class="reference internal" href="changes"><span class="doc std std-doc">migration guide</span></a> for more information.</p>
936
983
  </div>
937
984
  <p>Just like before, you can refer to primitive types by their name or through <code class="docutils literal notranslate"><span class="pre">koffi.types</span></code>:</p>
938
985
  <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="c1">// These two lines do the same:</span>
@@ -941,6 +988,11 @@
941
988
  </pre></div>
942
989
  </div>
943
990
  </section>
991
+ <section id="type-aliases">
992
+ <h3>Type aliases<a class="headerlink" href="#type-aliases" title="Permalink to this heading">#</a></h3>
993
+ <p>You can alias a type with <code class="docutils literal notranslate"><span class="pre">koffi.alias(name,</span> <span class="pre">type)</span></code>. Aliased types are completely equivalent.</p>
994
+ </section>
995
+ </section>
944
996
  </section>
945
997
 
946
998
  </article>
@@ -953,7 +1005,7 @@
953
1005
  <div class="context">
954
1006
  <span>Next</span>
955
1007
  </div>
956
- <div class="title">Function calls</div>
1008
+ <div class="title">Functions</div>
957
1009
  </div>
958
1010
  <svg><use href="#svg-arrow-right"></use></svg>
959
1011
  </a>
@@ -1002,10 +1054,14 @@
1002
1054
  <ul>
1003
1055
  <li><a class="reference internal" href="#">Data types</a><ul>
1004
1056
  <li><a class="reference internal" href="#primitive-types">Primitive types</a></li>
1005
- <li><a class="reference internal" href="#struct-types">Struct types</a></li>
1057
+ <li><a class="reference internal" href="#struct-types">Struct types</a><ul>
1058
+ <li><a class="reference internal" href="#struct-definition">Struct definition</a></li>
1059
+ <li><a class="reference internal" href="#opaque-types">Opaque types</a></li>
1060
+ </ul>
1061
+ </li>
1006
1062
  <li><a class="reference internal" href="#pointer-types">Pointer types</a><ul>
1007
1063
  <li><a class="reference internal" href="#struct-pointers">Struct pointers</a></li>
1008
- <li><a class="reference internal" href="#opaque-handles">Opaque handles</a></li>
1064
+ <li><a class="reference internal" href="#named-pointer-types">Named pointer types</a></li>
1009
1065
  <li><a class="reference internal" href="#array-pointers">Array pointers</a></li>
1010
1066
  <li><a class="reference internal" href="#pointers-to-primitive-types">Pointers to primitive types</a></li>
1011
1067
  </ul>
@@ -1014,7 +1070,12 @@
1014
1070
  <li><a class="reference internal" href="#handling-of-strings">Handling of strings</a></li>
1015
1071
  </ul>
1016
1072
  </li>
1073
+ <li><a class="reference internal" href="#disposable-types">Disposable types</a></li>
1074
+ <li><a class="reference internal" href="#utility-functions">Utility functions</a><ul>
1017
1075
  <li><a class="reference internal" href="#type-introspection">Type introspection</a></li>
1076
+ <li><a class="reference internal" href="#type-aliases">Type aliases</a></li>
1077
+ </ul>
1078
+ </li>
1018
1079
  </ul>
1019
1080
  </li>
1020
1081
  </ul>
package/doc/functions.md CHANGED
@@ -105,14 +105,16 @@ printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END
105
105
 
106
106
  On x86 platforms, only the Cdecl convention can be used for variadic functions.
107
107
 
108
- ## Output parameters
108
+ ## C to JS conversion gotchas
109
+
110
+ ### Output parameters
109
111
 
110
112
  By default, Koffi will only forward arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
111
113
 
112
114
  For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) two types of parameters:
113
115
 
114
116
  - [Structs](types.md#struct-types) (to/from JS objects)
115
- - [Opaque handles](types.md#opaque-handles)
117
+ - [Opaque types](types.md#opaque-types)
116
118
 
117
119
  In order to change an argument from input-only to output or input/output, use the following functions:
118
120
 
@@ -124,7 +126,7 @@ The same can be done when declaring a function with a C-like prototype string, w
124
126
  - `_Out_` for output parameters
125
127
  - `_Inout_` for dual input/output parameters
126
128
 
127
- ### Struct example
129
+ #### Struct example
128
130
 
129
131
  This example calls the POSIX function `gettimeofday()`, and uses the prototype-like syntax.
130
132
 
@@ -150,29 +152,80 @@ gettimeofday(tv, null);
150
152
  console.log(tv);
151
153
  ```
152
154
 
153
- ### Opaque handle example
155
+ #### Opaque type example
154
156
 
155
157
  This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.
156
158
 
157
159
  ```js
158
160
  const koffi = require('koffi');
159
- const lib = koffi.load('sqlite.so');
161
+ const lib = koffi.load('sqlite3.so');
160
162
 
161
- const sqlite3_db = koffi.handle('sqlite3_db');
163
+ const sqlite3 = koffi.opaque('sqlite3');
162
164
 
163
- // Use koffi.out() on a pointer to copy out (from C to JS) after the call
164
- const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'str']);
165
- const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [sqlite3_db]);
165
+ // Use koffi.out() on a double pointer to copy out (from C to JS) after the call
166
+ const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3, 2)), 'int', 'str']);
167
+ const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqlite3)]);
166
168
 
167
169
  const SQLITE_OPEN_READWRITE = 0x2;
168
170
  const SQLITE_OPEN_CREATE = 0x4;
169
171
 
170
- let db = {};
171
- if (sqlite3_open_v2(':memory:', db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
172
+ let out = [null];
173
+ if (sqlite3_open_v2(':memory:', out, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
172
174
  throw new Error('Failed to open database');
175
+ let db = out[0];
176
+
173
177
  sqlite3_close_v2(db);
174
178
  ```
175
179
 
180
+ ### Heap-allocated values
181
+
182
+ Some C functions return heap-allocated values directly or through output parameters. While Koffi automatically converts values from C to JS (to a string or an object), it does not know when something needs to be freed, or how.
183
+
184
+ For opaque types, such as FILE, this does not matter because you will explicitly call `fclose()` on them. But some values (such as strings) get implicitly converted by Koffi, and you lose access to the original pointer. This creates a leak if the string is heap-allocated.
185
+
186
+ To avoid this, you can instruct Koffi to call a function on the original pointer once the conversion is done, by creating a **disposable type** with `koffi.dispose(name, type, func)`. This creates a type derived from another type, the only difference being that *func* gets called with the original pointer once the value has been converted and is not needed anymore.
187
+
188
+ The *name* can be omitted to create an anonymous disposable type. If *func* is omitted or is null, Koffi will use `koffi.free(ptr)` (which calls the standard C library *free* function under the hood).
189
+
190
+ ```js
191
+ const AnonHeapStr = koffi.disposable('str'); // Anonymous type (cannot be used in function prototypes)
192
+ const NamedHeapStr = koffi.disposable('HeapStr', 'str'); // Same thing, but named so usable in function prototypes
193
+ const ExplicitFree = koffi.disposable('HeapStr16', 'str16', koffi.free); // You can specify any other JS function
194
+ ```
195
+
196
+ The following example illustrates the use of a disposable type derived from *str*.
197
+
198
+ ```js
199
+ const koffi = require('koffi');
200
+ const lib = koffi.load('libc.so.6');
201
+
202
+ // You can also use: const strdup = lib.func('const char *! strdup(const char *str)')
203
+ const HeapStr = koffi.disposable('str');
204
+ const strdup = lib.cdecl('strdup', HeapStr, ['str']);
205
+
206
+ let copy = strdup('Hello!');
207
+ console.log(copy); // Prints Hello!
208
+ ```
209
+
210
+ When you declare functions with the [prototype-like syntax](#c-like-prototypes), you can either use named disposable types or use the '!' shortcut qualifier with compatibles types, as shown in the example below. This qualifier creates an anonymous disposable type that calls `koffi.free(ptr)`.
211
+
212
+ ```js
213
+ const koffi = require('koffi');
214
+ const lib = koffi.load('libc.so.6');
215
+
216
+ // You can also use: const strdup = lib.func('const char *! strdup(const char *str)')
217
+ const strdup = lib.func('str! strdup(const char *str)');
218
+
219
+ let copy = strdup('World!');
220
+ console.log(copy); // Prints World!
221
+ ```
222
+
223
+ Disposable types can only be created from pointer or string types.
224
+
225
+ ```{warning}
226
+ Be careful on Windows: if your shared library uses a different CRT (such as msvcrt), the memory could have been allocated by a different malloc/free implementation or heap, resulting in undefined behavior if you use `koffi.free()`.
227
+ ```
228
+
176
229
  ## Javascript callbacks
177
230
 
178
231
  In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
@@ -187,9 +240,30 @@ const ExampleCallback = koffi.callback('ExampleCallback', 'void', ['int']);
187
240
  const AddDoubleFloat = koffi.callback('double AddDoubleFloat(double d, float f)');
188
241
  ```
189
242
 
190
- Once your callback type is declared, you can use it in struct definitions, or as function parameter and/or return type.
243
+ Once your callback type is declared, you can use a pointer to it in struct definitions, or as function parameters and/or return types.
191
244
 
192
- Here is a small example with the C part and the JS part.
245
+ ```{note}
246
+ Callbacks **have changed in version 2.0**.
247
+
248
+ In Koffi 1.x, callbacks were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
249
+
250
+ Now, you must use them through a pointer: `void CallIt(CallbackType func)` in Koffi 1.x becomes `void CallIt(CallbackType *func)` in version 2.0 and newer.
251
+
252
+ Consult the [migration guide](changes.md) for more information.
253
+ ```
254
+
255
+ Koffi only uses predefined static trampolines, and does not need to generate code at runtime, which makes it compatible with platforms with hardened W^X migitations (such as PaX mprotect). However, this imposes some restrictions on the maximum number of callbacks, and their duration.
256
+
257
+ Thus, Koffi distinguishes two callback modes:
258
+
259
+ - [Transient callbacks](#transient-callbacks) can only be called while the C function they are passed to is running, and are invalidated when it returns. If the C function calls the callback later, the behavior is undefined, though Koffi tries to detect such cases. If it does, an exception will be thrown, but this is no guaranteed. However, they are simple to use, and don't require any special handling.
260
+ - [Registered callbacks](#registered-callbacks) can be called at any time, but they must be manually registered and unregistered. A limited number of registered callbacks can exist at the same time.
261
+
262
+ You need to specify the correct [calling convention](#calling-conventions) on x86 platforms, or the behavior is undefined (Node will probably crash). Only *cdecl* and *stdcall* callbacks are supported.
263
+
264
+ ### Transient callbacks
265
+
266
+ Use transient callbacks when the native C function only needs to call them while it runs (e.g. qsort, progress callback, `sqlite3_exec`). Here is a small example with the C part and the JS part.
193
267
 
194
268
  ```c
195
269
  #include <string.h>
@@ -204,10 +278,11 @@ int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age))
204
278
 
205
279
  ```js
206
280
  const koffi = require('koffi');
281
+ const lib = koffi.load('./callbacks.so'); // Fake path
207
282
 
208
283
  const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
209
284
 
210
- const TransferToJS = lib.func('int TransferToJS(const char *str, int age, TransferCallback cb)');
285
+ const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]);
211
286
 
212
287
  let ret = TransferToJS('Niels', 27, (str, age) => {
213
288
  console.log(str);
@@ -222,7 +297,56 @@ console.log(ret);
222
297
  // 42
223
298
  ```
224
299
 
225
- You need to specify the correct [calling convention](#calling-conventions) on x86 platforms, or the behavior is undefined (Node will probably crash). Only *cdecl* and *stdcall* callbacks are supported.
300
+ ### Registered callbacks
301
+
302
+ Use registered callbacks when the function needs to be called at a later time (e.g. log handler, event handler, `fopencookie/funopen`). Call `koffi.register(func, type)` to register a callback function, with two arguments: the JS function, and the callback type.
303
+
304
+ When you are done, call `koffi.unregister()` (with the value returned by `koffi.register()`) to release the slot. A maximum of 16 registered callbacks can exist at the same time. Failure to do so will leak the slot, and subsequent registrations may fail (with an exception) once all slots are used.
305
+
306
+ The example below shows how to register and unregister delayed callbacks.
307
+
308
+ ```c
309
+ static const char *(*g_cb1)(const char *name);
310
+ static void (*g_cb2)(const char *str);
311
+
312
+ void RegisterFunctions(const char *(*cb1)(const char *name), void (*cb2)(const char *str))
313
+ {
314
+ g_cb1 = cb1;
315
+ g_cb2 = cb2;
316
+ }
317
+
318
+ void SayIt(const char *name)
319
+ {
320
+ const char *str = g_cb1(name);
321
+ g_cb2(str);
322
+ }
323
+ ```
324
+
325
+ ```js
326
+ const koffi = require('koffi');
327
+ const lib = koffi.load('./callbacks.so'); // Fake path
328
+
329
+ const GetCallback = koffi.callback('const char *GetCallback(const char *name)');
330
+ const PrintCallback = koffi.callback('void PrintCallback(const char *str)');
331
+
332
+ const RegisterFunctions = lib.func('void RegisterFunctions(GetCallback *cb1, PrintCallback *cb2)');
333
+ const SayIt = lib.func('void SayIt(const char *name)');
334
+
335
+ let cb1 = koffi.register(name => 'Hello ' + name + '!', koffi.pointer(GetCallback));
336
+ let cb2 = koffi.register(console.log, 'PrintCallback *');
337
+
338
+ RegisterFunctions(cb1, cb2);
339
+ SayIt('Kyoto'); // Prints Hello Kyoto!
340
+
341
+ koffi.unregister(cb1);
342
+ koffi.unregister(cb2);
343
+ ```
344
+
345
+ ### Handling of exceptions
346
+
347
+ If an exception happens inside the JS callback, the C API will receive 0 or NULL (depending on the return value type).
348
+
349
+ Handle the exception yourself (with try/catch) if you need to handle exceptions differently.
226
350
 
227
351
  ## Thread safety
228
352
 
@@ -0,0 +1,5 @@
1
+ <div style="text-align: center; margin-top: 2em;">
2
+ <a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-{{version}}-brightgreen" alt="NPM"/></a>
3
+ <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
4
+ </div>
5
+