koffi 2.0.1 → 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 (78) hide show
  1. package/CMakeLists.txt +1 -8
  2. package/benchmark/atoi_koffi.js +12 -8
  3. package/benchmark/atoi_napi.js +12 -8
  4. package/benchmark/atoi_node_ffi.js +11 -10
  5. package/benchmark/raylib_cc.cc +12 -9
  6. package/benchmark/raylib_koffi.js +15 -13
  7. package/benchmark/raylib_node_ffi.js +15 -13
  8. package/benchmark/raylib_node_raylib.js +14 -11
  9. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  10. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  11. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  24. package/doc/changes.md +12 -8
  25. package/doc/dist/doctrees/changes.doctree +0 -0
  26. package/doc/dist/doctrees/environment.pickle +0 -0
  27. package/doc/dist/doctrees/functions.doctree +0 -0
  28. package/doc/dist/doctrees/index.doctree +0 -0
  29. package/doc/dist/doctrees/types.doctree +0 -0
  30. package/doc/dist/html/_sources/changes.md.txt +12 -8
  31. package/doc/dist/html/_sources/functions.md.txt +4 -4
  32. package/doc/dist/html/_sources/types.md.txt +69 -34
  33. package/doc/dist/html/benchmarks.html +1 -1
  34. package/doc/dist/html/changes.html +44 -33
  35. package/doc/dist/html/contribute.html +1 -1
  36. package/doc/dist/html/functions.html +7 -7
  37. package/doc/dist/html/genindex.html +1 -1
  38. package/doc/dist/html/index.html +3 -3
  39. package/doc/dist/html/memory.html +1 -1
  40. package/doc/dist/html/objects.inv +0 -0
  41. package/doc/dist/html/platforms.html +2 -2
  42. package/doc/dist/html/search.html +1 -1
  43. package/doc/dist/html/searchindex.js +1 -1
  44. package/doc/dist/html/start.html +1 -1
  45. package/doc/dist/html/types.html +77 -40
  46. package/doc/functions.md +4 -4
  47. package/doc/types.md +68 -33
  48. package/package.json +2 -2
  49. package/qemu/qemu.js +1 -1
  50. package/src/call.cc +42 -26
  51. package/src/call.hh +15 -3
  52. package/src/ffi.cc +70 -13
  53. package/src/ffi.hh +7 -0
  54. package/src/index.js +4 -2
  55. package/src/parser.cc +3 -5
  56. package/src/util.cc +44 -1
  57. package/src/util.hh +4 -0
  58. package/test/async.js +1 -2
  59. package/test/callbacks.js +2 -3
  60. package/test/misc.c +21 -1
  61. package/test/raylib.js +1 -1
  62. package/test/sqlite.js +3 -3
  63. package/test/sync.js +27 -3
  64. package/build/qemu/2.0.1/koffi_darwin_arm64.tar.gz +0 -0
  65. package/build/qemu/2.0.1/koffi_darwin_x64.tar.gz +0 -0
  66. package/build/qemu/2.0.1/koffi_freebsd_arm64.tar.gz +0 -0
  67. package/build/qemu/2.0.1/koffi_freebsd_ia32.tar.gz +0 -0
  68. package/build/qemu/2.0.1/koffi_freebsd_x64.tar.gz +0 -0
  69. package/build/qemu/2.0.1/koffi_linux_arm32hf.tar.gz +0 -0
  70. package/build/qemu/2.0.1/koffi_linux_arm64.tar.gz +0 -0
  71. package/build/qemu/2.0.1/koffi_linux_ia32.tar.gz +0 -0
  72. package/build/qemu/2.0.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  73. package/build/qemu/2.0.1/koffi_linux_x64.tar.gz +0 -0
  74. package/build/qemu/2.0.1/koffi_openbsd_ia32.tar.gz +0 -0
  75. package/build/qemu/2.0.1/koffi_openbsd_x64.tar.gz +0 -0
  76. package/build/qemu/2.0.1/koffi_win32_arm64.tar.gz +0 -0
  77. package/build/qemu/2.0.1/koffi_win32_ia32.tar.gz +0 -0
  78. package/build/qemu/2.0.1/koffi_win32_x64.tar.gz +0 -0
@@ -6,7 +6,7 @@ While the C standard allows for variation in the size of most integer types, Kof
6
6
 
7
7
  JS type | C type | Bytes | Signedness | Note
8
8
  ----------------- | ------------------ | ----- | ---------- | ---------------------------
9
- Null | void | 0 | | Only valid as a return type
9
+ Undefined | void | 0 | | Only valid as a return type
10
10
  Number (integer) | int8 | 1 | Signed |
11
11
  Number (integer) | int8_t | 1 | Signed |
12
12
  Number (integer) | uint8 | 1 | Unsigned |
@@ -69,6 +69,8 @@ let struct2 = koffi.struct({ dummy: koffi.types.long });
69
69
 
70
70
  ## Struct types
71
71
 
72
+ ### Struct definition
73
+
72
74
  Koffi converts JS objects to C structs, and vice-versa.
73
75
 
74
76
  Unlike function declarations, as of now there is only one way to create a struct type, with the `koffi.struct()` 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.
@@ -109,56 +111,44 @@ const Function1 = lib.func('A Function(A value)');
109
111
  const Function2 = lib.func('Function', A, [A]);
110
112
  ```
111
113
 
112
- ## Pointer types
114
+ Koffi automatically follows the platform C ABI regarding alignment and padding. However, you can override these rules if needed with:
113
115
 
114
- 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:
115
-
116
- - **Struct pointers**: 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).
117
- - **Opaque handles**: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. `FILE *`). 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.
118
- - **Arrays**: 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.
119
- - **Pointers to primitive types**: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.
120
-
121
- ### Struct pointers
122
-
123
- The following Win32 example uses `GetCursorPos()` (with an output parameter) to retrieve and show the current cursor position.
116
+ - Pack all members without padding with `koffi.pack()` (instead of `koffi.struct()`)
117
+ - Change alignment of a specific member as shown below
124
118
 
125
119
  ```js
126
- const koffi = require('koffi');
127
- const lib = koffi.load('kernel32.dll');
128
-
129
- // Type declarations
130
- const POINT = koffi.struct('POINT', {
131
- x: 'long',
132
- y: 'long'
120
+ // This struct is 3 bytes long
121
+ const PackedStruct = koffi.pack('PackedStruct', {
122
+ a: 'int8_t',
123
+ b: 'int16_t'
133
124
  });
134
125
 
135
- // Functions declarations
136
- const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)');
137
-
138
- // Get and show cursor position
139
- let pos = {};
140
- if (!GetCursorPos(pos))
141
- throw new Error('Failed to get cursor position');
142
- console.log(pos);
126
+ // This one is 18 bytes long, the second member has an alignment requirement of 16 bytes
127
+ const BigStruct = koffi.struct('BigStruct', {
128
+ a: 'int8_t',
129
+ b: [16, 'int16_t']
130
+ })
143
131
  ```
144
132
 
145
- ### Opaque handles
133
+ ### Opaque types
146
134
 
147
- 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 `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the handle with other functions such as `fread()` or `ftell()`.
135
+ 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 `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the opaque pointer with other functions such as `fread()` or `ftell()`.
148
136
 
149
- In Koffi, you can manage this with opaque handles. Declare the handle type with `koffi.handle(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](functions.md#output-parameters) (with a double pointer).
137
+ In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](functions.md#output-parameters) (with a double pointer).
150
138
 
151
139
  ```{note}
152
- Opaque handles **have changed in version 2.0**.
140
+ Opaque types **have changed in version 2.0, and again in version 2.1**.
153
141
 
154
142
  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.
155
143
 
156
144
  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 `ConcatNewOut` in the JS part), and is described in the section on [output parameters](functions.md#output-parameters).
157
145
 
146
+ In addition to this, you should use `koffi.opaque()` (introduced in Koffi 2.1) instead of `koffi.handle()` which is deprecated, and will be removed eventually in Koffi 3.0.
147
+
158
148
  Consult the [migration guide](changes.md) for more information.
159
149
  ```
160
150
 
161
- 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: `ConcatNew` (or `ConcatNewOut`) and `ConcatFree`.
151
+ 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: `ConcatNew` (or `ConcatNewOut`) and `ConcatFree`.
162
152
 
163
153
  ```c
164
154
  // Build with: clang -fPIC -o handles.so -shared handles.c -Wall -O2
@@ -283,7 +273,7 @@ const char *ConcatBuild(Concat *c)
283
273
  const koffi = require('koffi');
284
274
  const lib = koffi.load('./handles.so');
285
275
 
286
- const Concat = koffi.handle('Concat');
276
+ const Concat = koffi.opaque('Concat');
287
277
  const ConcatNewOut = lib.func('bool ConcatNewOut(_Out_ Concat **out)');
288
278
  const ConcatNew = lib.func('Concat *ConcatNew()');
289
279
  const ConcatFree = lib.func('void ConcatFree(Concat *c)');
@@ -332,6 +322,51 @@ try {
332
322
  }
333
323
  ```
334
324
 
325
+ ## Pointer types
326
+
327
+ 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:
328
+
329
+ - **Struct pointers**: 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).
330
+ - **Opaque pointers**: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. `FILE *`). 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.
331
+ - **Arrays**: 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.
332
+ - **Pointers to primitive types**: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.
333
+
334
+ ### Struct pointers
335
+
336
+ The following Win32 example uses `GetCursorPos()` (with an output parameter) to retrieve and show the current cursor position.
337
+
338
+ ```js
339
+ const koffi = require('koffi');
340
+ const lib = koffi.load('kernel32.dll');
341
+
342
+ // Type declarations
343
+ const POINT = koffi.struct('POINT', {
344
+ x: 'long',
345
+ y: 'long'
346
+ });
347
+
348
+ // Functions declarations
349
+ const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)');
350
+
351
+ // Get and show cursor position
352
+ let pos = {};
353
+ if (!GetCursorPos(pos))
354
+ throw new Error('Failed to get cursor position');
355
+ console.log(pos);
356
+ ```
357
+
358
+ ### Named pointer types
359
+
360
+ 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 **named pointer type** to an opaque type, like so:
361
+
362
+ ```js
363
+ const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
364
+
365
+ // And now you get to use it this way:
366
+ const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDLE h, _Out_ uint32_t *flags)');
367
+ const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)');
368
+ ```
369
+
335
370
  ### Array pointers
336
371
 
337
372
  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).
@@ -380,7 +415,7 @@ Here is an example based on the Win32 API, listing files in the current director
380
415
  const koffi = require('koffi');
381
416
  const lib = koffi.load('kernel32.dll');
382
417
 
383
- const HANDLE = koffi.pointer('HANDLE', koffi.handle());
418
+ const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
384
419
  const FILETIME = koffi.struct('FILETIME', {
385
420
  dwLowDateTime: 'uint',
386
421
  dwHighDateTime: 'uint'
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -211,6 +211,13 @@
211
211
  <h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this heading">#</a></h1>
212
212
  <section id="history">
213
213
  <h2>History<a class="headerlink" href="#history" title="Permalink to this heading">#</a></h2>
214
+ <section id="koffi-2-0-1">
215
+ <h3>Koffi 2.0.1<a class="headerlink" href="#koffi-2-0-1" title="Permalink to this heading">#</a></h3>
216
+ <p><strong>Main changes:</strong></p>
217
+ <ul class="simple">
218
+ <li><p>Return <code class="docutils literal notranslate"><span class="pre">undefined</span></code> (instead of null) for <code class="docutils literal notranslate"><span class="pre">void</span></code> functions</p></li>
219
+ </ul>
220
+ </section>
214
221
  <section id="koffi-2-0-0">
215
222
  <h3>Koffi 2.0.0<a class="headerlink" href="#koffi-2-0-0" title="Permalink to this heading">#</a></h3>
216
223
  <p><strong>Major new features:</strong></p>
@@ -421,7 +428,7 @@
421
428
  <p>You may need to change your code if you use:</p>
422
429
  <ul class="simple">
423
430
  <li><p>Callback functions</p></li>
424
- <li><p>Opaque handles</p></li>
431
+ <li><p>Opaque types</p></li>
425
432
  <li><p><code class="docutils literal notranslate"><span class="pre">koffi.introspect()</span></code></p></li>
426
433
  </ul>
427
434
  <section id="callback-types">
@@ -471,10 +478,11 @@
471
478
  </div>
472
479
  <p>Koffi 1.x only supported <a class="reference internal" href="functions#javascript-callbacks"><span class="std std-doc">transient callbacks</span></a>, you must use Koffi 2.x for registered callbacks.</p>
473
480
  </section>
474
- <section id="opaque-handles">
475
- <h4>Opaque handles<a class="headerlink" href="#opaque-handles" title="Permalink to this heading">#</a></h4>
476
- <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. Now, you must use them through a pointer, and use an array for output parameters.</p>
477
- <p>For functions that return handles or pass them by parameter:</p>
481
+ <section id="opaque-types">
482
+ <h4>Opaque types<a class="headerlink" href="#opaque-types" title="Permalink to this heading">#</a></h4>
483
+ <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. Now, in Koffi 2.0, you must use them through a pointer, and use an array for output parameters.</p>
484
+ <p>In addition to that, <code class="docutils literal notranslate"><span class="pre">koffi.handle()</span></code> has been deprecated in Koffi 2.1 and replaced with <code class="docutils literal notranslate"><span class="pre">koffi.opaque()</span></code>. They work the same but new code should use <code class="docutils literal notranslate"><span class="pre">koffi.opaque()</span></code>, the former one will eventually be removed in Koffi 3.0.</p>
485
+ <p>For functions that return opaque pointers or pass them by parameter:</p>
478
486
  <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Koffi 1.x</span>
479
487
  <span class="linenos"> 2</span>
480
488
  <span class="linenos"> 3</span><span class="kd">const</span> <span class="nx">FILE</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;FILE&#39;</span><span class="p">);</span>
@@ -487,16 +495,17 @@
487
495
  <span class="linenos">10</span><span class="nx">fclose</span><span class="p">(</span><span class="nx">fp</span><span class="p">);</span>
488
496
  </pre></div>
489
497
  </div>
490
- <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Koffi 2.x</span>
498
+ <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Koffi 2.1</span>
491
499
  <span class="linenos"> 2</span>
492
- <span class="linenos"> 3</span><span class="kd">const</span> <span class="nx">FILE</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;FILE&#39;</span><span class="p">);</span>
493
- <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">fopen</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;fopen&#39;</span><span class="p">,</span> <span class="s1">&#39;FILE *&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;str&#39;</span><span class="p">,</span> <span class="s1">&#39;str&#39;</span><span class="p">]);</span>
494
- <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">fopen</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;fclose&#39;</span><span class="p">,</span> <span class="s1">&#39;int&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;FILE *&#39;</span><span class="p">]);</span>
495
- <span class="linenos"> 6</span>
496
- <span class="linenos"> 7</span><span class="kd">let</span> <span class="nx">fp</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="s1">&#39;EMPTY&#39;</span><span class="p">,</span> <span class="s1">&#39;wb&#39;</span><span class="p">);</span>
497
- <span class="linenos"> 8</span><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">fp</span><span class="p">)</span>
498
- <span class="linenos"> 9</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 open file&#39;</span><span class="p">);</span>
499
- <span class="linenos">10</span><span class="nx">fclose</span><span class="p">(</span><span class="nx">fp</span><span class="p">);</span>
500
+ <span class="linenos"> 3</span><span class="c1">// If you use Koffi 2.0: const FILE = koffi.handle(&#39;FILE&#39;);</span>
501
+ <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">FILE</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;FILE&#39;</span><span class="p">);</span>
502
+ <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">fopen</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;fopen&#39;</span><span class="p">,</span> <span class="s1">&#39;FILE *&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;str&#39;</span><span class="p">,</span> <span class="s1">&#39;str&#39;</span><span class="p">]);</span>
503
+ <span class="linenos"> 6</span><span class="kd">const</span> <span class="nx">fopen</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;fclose&#39;</span><span class="p">,</span> <span class="s1">&#39;int&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;FILE *&#39;</span><span class="p">]);</span>
504
+ <span class="linenos"> 7</span>
505
+ <span class="linenos"> 8</span><span class="kd">let</span> <span class="nx">fp</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="s1">&#39;EMPTY&#39;</span><span class="p">,</span> <span class="s1">&#39;wb&#39;</span><span class="p">);</span>
506
+ <span class="linenos"> 9</span><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">fp</span><span class="p">)</span>
507
+ <span class="linenos">10</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 open file&#39;</span><span class="p">);</span>
508
+ <span class="linenos">11</span><span class="nx">fclose</span><span class="p">(</span><span class="nx">fp</span><span class="p">);</span>
500
509
  </pre></div>
501
510
  </div>
502
511
  <p>For functions that set opaque handles through output parameters (such as <code class="docutils literal notranslate"><span class="pre">sqlite3_open_v2</span></code>), you must now use a single element array as shown below:</p>
@@ -518,24 +527,25 @@
518
527
  <span class="linenos">16</span><span class="nx">sqlite3_close_v2</span><span class="p">(</span><span class="nx">db</span><span class="p">);</span>
519
528
  </pre></div>
520
529
  </div>
521
- <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Koffi 2.x</span>
530
+ <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// Koffi 2.1</span>
522
531
  <span class="linenos"> 2</span>
523
- <span class="linenos"> 3</span><span class="kd">const</span> <span class="nx">sqlite3</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;sqlite3&#39;</span><span class="p">);</span>
524
- <span class="linenos"> 4</span>
525
- <span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">sqlite3_open_v2</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 sqlite3_open_v2(const char *, _Out_ sqlite3 **db, int, const char *)&#39;</span><span class="p">);</span>
526
- <span class="linenos"> 6</span><span class="kd">const</span> <span class="nx">sqlite3_close_v2</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 sqlite3_close_v2(sqlite3 *db)&#39;</span><span class="p">);</span>
527
- <span class="linenos"> 7</span>
528
- <span class="linenos"> 8</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">=</span> <span class="mh">0x2</span><span class="p">;</span>
529
- <span class="linenos"> 9</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_CREATE</span> <span class="o">=</span> <span class="mh">0x4</span><span class="p">;</span>
530
- <span class="linenos">10</span>
531
- <span class="linenos">11</span><span class="kd">let</span> <span class="nx">db</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
532
- <span class="linenos">12</span>
533
- <span class="linenos">13</span><span class="kd">let</span> <span class="nx">ptr</span> <span class="o">=</span> <span class="p">[</span><span class="kc">null</span><span class="p">];</span>
534
- <span class="linenos">14</span><span class="k">if</span> <span class="p">(</span><span class="nx">sqlite3_open_v2</span><span class="p">(</span><span class="s1">&#39;:memory:&#39;</span><span class="p">,</span> <span class="nx">ptr</span><span class="p">,</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">|</span> <span class="nx">SQLITE_OPEN_CREATE</span><span class="p">,</span> <span class="kc">null</span><span class="p">)</span> <span class="o">!=</span> <span class="mf">0</span><span class="p">)</span>
535
- <span class="linenos">15</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 open database&#39;</span><span class="p">);</span>
536
- <span class="linenos">16</span><span class="nx">db</span> <span class="o">=</span> <span class="nx">ptr</span><span class="p">[</span><span class="mf">0</span><span class="p">];</span>
537
- <span class="linenos">17</span>
538
- <span class="linenos">18</span><span class="nx">sqlite3_close_v2</span><span class="p">(</span><span class="nx">db</span><span class="p">);</span>
532
+ <span class="linenos"> 3</span><span class="c1">// If you use Koffi 2.0: const sqlite3 = koffi.handle(&#39;sqlite3&#39;);</span>
533
+ <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">sqlite3</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;sqlite3&#39;</span><span class="p">);</span>
534
+ <span class="linenos"> 5</span>
535
+ <span class="linenos"> 6</span><span class="kd">const</span> <span class="nx">sqlite3_open_v2</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 sqlite3_open_v2(const char *, _Out_ sqlite3 **db, int, const char *)&#39;</span><span class="p">);</span>
536
+ <span class="linenos"> 7</span><span class="kd">const</span> <span class="nx">sqlite3_close_v2</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 sqlite3_close_v2(sqlite3 *db)&#39;</span><span class="p">);</span>
537
+ <span class="linenos"> 8</span>
538
+ <span class="linenos"> 9</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">=</span> <span class="mh">0x2</span><span class="p">;</span>
539
+ <span class="linenos">10</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_CREATE</span> <span class="o">=</span> <span class="mh">0x4</span><span class="p">;</span>
540
+ <span class="linenos">11</span>
541
+ <span class="linenos">12</span><span class="kd">let</span> <span class="nx">db</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
542
+ <span class="linenos">13</span>
543
+ <span class="linenos">14</span><span class="kd">let</span> <span class="nx">ptr</span> <span class="o">=</span> <span class="p">[</span><span class="kc">null</span><span class="p">];</span>
544
+ <span class="linenos">15</span><span class="k">if</span> <span class="p">(</span><span class="nx">sqlite3_open_v2</span><span class="p">(</span><span class="s1">&#39;:memory:&#39;</span><span class="p">,</span> <span class="nx">ptr</span><span class="p">,</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">|</span> <span class="nx">SQLITE_OPEN_CREATE</span><span class="p">,</span> <span class="kc">null</span><span class="p">)</span> <span class="o">!=</span> <span class="mf">0</span><span class="p">)</span>
545
+ <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 open database&#39;</span><span class="p">);</span>
546
+ <span class="linenos">17</span><span class="nx">db</span> <span class="o">=</span> <span class="nx">ptr</span><span class="p">[</span><span class="mf">0</span><span class="p">];</span>
547
+ <span class="linenos">18</span>
548
+ <span class="linenos">19</span><span class="nx">sqlite3_close_v2</span><span class="p">(</span><span class="nx">db</span><span class="p">);</span>
539
549
  </pre></div>
540
550
  </div>
541
551
  </section>
@@ -608,6 +618,7 @@
608
618
  <ul>
609
619
  <li><a class="reference internal" href="#">Changelog</a><ul>
610
620
  <li><a class="reference internal" href="#history">History</a><ul>
621
+ <li><a class="reference internal" href="#koffi-2-0-1">Koffi 2.0.1</a></li>
611
622
  <li><a class="reference internal" href="#koffi-2-0-0">Koffi 2.0.0</a></li>
612
623
  <li><a class="reference internal" href="#koffi-1-3-12">Koffi 1.3.12</a></li>
613
624
  <li><a class="reference internal" href="#koffi-1-3-11">Koffi 1.3.11</a></li>
@@ -630,7 +641,7 @@
630
641
  <li><a class="reference internal" href="#migration-guide">Migration guide</a><ul>
631
642
  <li><a class="reference internal" href="#koffi-1-x-to-2-x">Koffi 1.x to 2.x</a><ul>
632
643
  <li><a class="reference internal" href="#callback-types">Callback types</a></li>
633
- <li><a class="reference internal" href="#opaque-handles">Opaque handles</a></li>
644
+ <li><a class="reference internal" href="#opaque-types">Opaque types</a></li>
634
645
  <li><a class="reference internal" href="#koffi-introspect">koffi.introspect()</a></li>
635
646
  </ul>
636
647
  </li>
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -333,7 +333,7 @@
333
333
  <p>For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) two types of parameters:</p>
334
334
  <ul class="simple">
335
335
  <li><p><a class="reference internal" href="types#struct-types"><span class="std std-doc">Structs</span></a> (to/from JS objects)</p></li>
336
- <li><p><a class="reference internal" href="types#opaque-handles"><span class="std std-doc">Opaque handles</span></a></p></li>
336
+ <li><p><a class="reference internal" href="types#opaque-types"><span class="std std-doc">Opaque types</span></a></p></li>
337
337
  </ul>
338
338
  <p>In order to change an argument from input-only to output or input/output, use the following functions:</p>
339
339
  <ul class="simple">
@@ -370,13 +370,13 @@
370
370
  </pre></div>
371
371
  </div>
372
372
  </section>
373
- <section id="opaque-handle-example">
374
- <h4>Opaque handle example<a class="headerlink" href="#opaque-handle-example" title="Permalink to this heading">#</a></h4>
373
+ <section id="opaque-type-example">
374
+ <h4>Opaque type example<a class="headerlink" href="#opaque-type-example" title="Permalink to this heading">#</a></h4>
375
375
  <p>This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.</p>
376
376
  <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>
377
377
  <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;sqlite3.so&#39;</span><span class="p">);</span>
378
378
  <span class="linenos"> 3</span>
379
- <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">sqlite3</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;sqlite3&#39;</span><span class="p">);</span>
379
+ <span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">sqlite3</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;sqlite3&#39;</span><span class="p">);</span>
380
380
  <span class="linenos"> 5</span>
381
381
  <span class="linenos"> 6</span><span class="c1">// Use koffi.out() on a double pointer to copy out (from C to JS) after the call</span>
382
382
  <span class="linenos"> 7</span><span class="kd">const</span> <span class="nx">sqlite3_open_v2</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;sqlite3_open_v2&#39;</span><span class="p">,</span> <span class="s1">&#39;int&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;str&#39;</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">out</span><span class="p">(</span><span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="nx">sqlite3</span><span class="p">,</span> <span class="mf">2</span><span class="p">)),</span> <span class="s1">&#39;int&#39;</span><span class="p">,</span> <span class="s1">&#39;str&#39;</span><span class="p">]);</span>
@@ -398,7 +398,7 @@
398
398
  <section id="heap-allocated-values">
399
399
  <h3>Heap-allocated values<a class="headerlink" href="#heap-allocated-values" title="Permalink to this heading">#</a></h3>
400
400
  <p>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.</p>
401
- <p>For opaque handles, such as FILE, this does not matter because you will explicitly call <code class="docutils literal notranslate"><span class="pre">fclose()</span></code> 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.</p>
401
+ <p>For opaque types, such as FILE, this does not matter because you will explicitly call <code class="docutils literal notranslate"><span class="pre">fclose()</span></code> 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.</p>
402
402
  <p>To avoid this, you can instruct Koffi to call a function on the original pointer once the conversion is done, by creating a <strong>disposable type</strong> with <code class="docutils literal notranslate"><span class="pre">koffi.dispose(name,</span> <span class="pre">type,</span> <span class="pre">func)</span></code>. This creates a type derived from another type, the only difference being that <em>func</em> gets called with the original pointer once the value has been converted and is not needed anymore.</p>
403
403
  <p>The <em>name</em> can be omitted to create an anonymous disposable type. If <em>func</em> is omitted or is null, Koffi will use <code class="docutils literal notranslate"><span class="pre">koffi.free(ptr)</span></code> (which calls the standard C library <em>free</em> function under the hood).</p>
404
404
  <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">AnonHeapStr</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">disposable</span><span class="p">(</span><span class="s1">&#39;str&#39;</span><span class="p">);</span> <span class="c1">// Anonymous type (cannot be used in function prototypes)</span>
@@ -623,7 +623,7 @@
623
623
  <li><a class="reference internal" href="#c-to-js-conversion-gotchas">C to JS conversion gotchas</a><ul>
624
624
  <li><a class="reference internal" href="#output-parameters">Output parameters</a><ul>
625
625
  <li><a class="reference internal" href="#struct-example">Struct example</a></li>
626
- <li><a class="reference internal" href="#opaque-handle-example">Opaque handle example</a></li>
626
+ <li><a class="reference internal" href="#opaque-type-example">Opaque type example</a></li>
627
627
  </ul>
628
628
  </li>
629
629
  <li><a class="reference internal" href="#heap-allocated-values">Heap-allocated values</a></li>
@@ -172,8 +172,8 @@
172
172
 
173
173
  </div>
174
174
  <div style="text-align: center; margin-top: 2em;">
175
+ <a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-2.0.1-brightgreen" alt="NPM"/></a>
175
176
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
176
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
177
177
  </div>
178
178
  </div>
179
179
 
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -208,7 +208,7 @@
208
208
  </div>
209
209
  <article role="main">
210
210
  <section id="koffi-version">
211
- <h1>Koffi 2.0.0<a class="headerlink" href="#koffi-version" title="Permalink to this heading">#</a></h1>
211
+ <h1>Koffi 2.0.1<a class="headerlink" href="#koffi-version" title="Permalink to this heading">#</a></h1>
212
212
  <section id="overview">
213
213
  <h2>Overview<a class="headerlink" href="#overview" title="Permalink to this heading">#</a></h2>
214
214
  <p>Koffi is a <strong>fast and easy-to-use C FFI module for Node.js</strong>, featuring:</p>
@@ -335,7 +335,7 @@
335
335
  <div class="toc-tree-container">
336
336
  <div class="toc-tree">
337
337
  <ul>
338
- <li><a class="reference internal" href="#">Koffi 2.0.0</a><ul>
338
+ <li><a class="reference internal" href="#">Koffi 2.0.1</a><ul>
339
339
  <li><a class="reference internal" href="#overview">Overview</a></li>
340
340
  <li><a class="reference internal" href="#table-of-contents">Table of contents</a></li>
341
341
  <li><a class="reference internal" href="#license">License</a></li>
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
Binary file
@@ -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="Quick start" href="start" /><link rel="prev" title="Koffi 2.0.0" href="index" />
6
+ <link rel="index" title="Index" href="genindex" /><link rel="search" title="Search" href="search" /><link rel="next" title="Quick start" href="start" /><link rel="prev" title="Koffi 2.0.1" href="index" />
7
7
 
8
8
  <meta name="generator" content="sphinx-5.0.1, furo 2022.06.04.1"/>
9
9
  <title>Requirements - Koffi</title>
@@ -174,8 +174,8 @@
174
174
 
175
175
  </div>
176
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>
177
178
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
178
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
179
179
  </div>
180
180
  </div>
181
181
 
@@ -171,8 +171,8 @@
171
171
 
172
172
  </div>
173
173
  <div style="text-align: center; margin-top: 2em;">
174
+ <a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-2.0.1-brightgreen" alt="NPM"/></a>
174
175
  <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
175
- <a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/NPM-2.0.0-brightgreen" alt="NPM"/></a>
176
176
  </div>
177
177
  </div>
178
178