2023-03-12 06:25:57 +00:00
|
|
|
---
|
|
|
|
title: C + QuickJS
|
|
|
|
pagination_prev: demos/bigdata/index
|
|
|
|
pagination_next: solutions/input
|
|
|
|
---
|
|
|
|
|
2023-04-27 09:12:19 +00:00
|
|
|
import current from '/version.js';
|
2023-05-07 13:58:36 +00:00
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
2023-04-27 09:12:19 +00:00
|
|
|
|
2023-03-12 06:25:57 +00:00
|
|
|
QuickJS is an embeddable JS engine written in C. It provides a separate set of
|
|
|
|
functions for interacting with the filesystem and the global object. It can run
|
|
|
|
the standalone browser scripts.
|
|
|
|
|
2023-03-14 08:38:47 +00:00
|
|
|
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
|
|
|
|
parsed and evaluated in a QuickJS context.
|
|
|
|
|
2023-03-12 06:25:57 +00:00
|
|
|
## Integration Details
|
|
|
|
|
|
|
|
_Initialize QuickJS_
|
|
|
|
|
|
|
|
QuickJS provides a `global` object through `JS_GetGlobalObject`:
|
|
|
|
|
|
|
|
```c
|
|
|
|
/* initialize */
|
|
|
|
JSRuntime *rt = JS_NewRuntime();
|
|
|
|
JSContext *ctx = JS_NewContext(rt);
|
|
|
|
|
|
|
|
/* obtain reference to global object */
|
|
|
|
JSValue global = JS_GetGlobalObject(ctx);
|
|
|
|
|
|
|
|
/* DO WORK HERE */
|
|
|
|
|
|
|
|
/* free after use */
|
|
|
|
JS_FreeValue(ctx, global);
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
JS_FreeContext(ctx);
|
|
|
|
JS_FreeRuntime(rt);
|
|
|
|
```
|
|
|
|
|
|
|
|
:::warning
|
|
|
|
|
|
|
|
All values must be freed with `JS_FreeValue` before calling `JS_FreeContext`!
|
|
|
|
|
|
|
|
`JS_IsException` should be used for validation.
|
|
|
|
|
|
|
|
Cleanup and validation code is omitted from the discussion. The integration
|
|
|
|
example shows structured validation and controlled memory usage.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
_Load SheetJS Scripts_
|
|
|
|
|
|
|
|
The main library can be loaded by reading the script from the file system and
|
|
|
|
evaluating in the QuickJS context:
|
|
|
|
|
|
|
|
```c
|
|
|
|
static char *read_file(const char *filename, size_t *sz) {
|
|
|
|
FILE *f = fopen(filename, "rb");
|
|
|
|
if(!f) return NULL;
|
|
|
|
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fsee (f, 0, SEEK_SET); }
|
|
|
|
char *buf = (char *)malloc(fsize * sizeof(char));
|
|
|
|
*sz = fread((void *) buf, 1, fsize, f);
|
|
|
|
fclose(f);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ...
|
|
|
|
/* load library */
|
|
|
|
{
|
|
|
|
size_t len; char *buf = read_file("xlsx.full.min.js", &len);
|
|
|
|
JS_Eval(ctx, buf, len, "<input>", 0);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
To confirm the library is loaded, `XLSX.version` can be inspected:
|
|
|
|
|
|
|
|
```c
|
|
|
|
/* obtain reference to the XLSX object */
|
|
|
|
JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX");
|
|
|
|
|
|
|
|
/* print version */
|
|
|
|
JSValue version = JS_GetPropertyStr(ctx, XLSX, "version");
|
|
|
|
size_t vlen; const char *vers = JS_ToCStringLen(ctx, &vlen, version);
|
|
|
|
printf("Version: %s\n", vers);
|
|
|
|
```
|
|
|
|
|
|
|
|
### Reading Files
|
|
|
|
|
|
|
|
`JS_NewArrayBuffer` can generate an `ArrayBuffer` from a C byte array. The
|
|
|
|
function signature expects `uint8_t *` instead of `char *`:
|
|
|
|
|
|
|
|
```c
|
|
|
|
/* read file */
|
|
|
|
size_t dlen; uint8_t * dbuf = (uint8_t *)read_file("pres.numbers", &dlen);
|
|
|
|
|
|
|
|
/* load data into array buffer */
|
|
|
|
JSValue ab = JS_NewArrayBuffer(ctx, dbuf, dlen, NULL, NULL, 0);
|
|
|
|
|
|
|
|
/* obtain reference to the XLSX object */
|
|
|
|
JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX");
|
|
|
|
|
|
|
|
/* call XLSX.read(ab) */
|
|
|
|
JSValue XLSX_read = JS_GetPropertyStr(ctx, XLSX, "read");
|
|
|
|
JSValue args[] = { ab };
|
|
|
|
JSValue wb = JS_Call(ctx, XLSX_read, XLSX, 1, args);
|
|
|
|
```
|
|
|
|
|
|
|
|
## Complete Example
|
|
|
|
|
|
|
|
The "Integration Example" covers a traditional integration in a C application,
|
|
|
|
while the "CLI Test" demonstrates other concepts using the `quickjs` CLI tool.
|
|
|
|
|
|
|
|
### Integration Example
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
2023-06-03 09:10:50 +00:00
|
|
|
This demo was tested in the following deployments:
|
2023-03-12 06:25:57 +00:00
|
|
|
|
2023-06-03 09:10:50 +00:00
|
|
|
| Architecture | Git Commit | Date |
|
|
|
|
|:-------------|:-----------|:-----------|
|
|
|
|
| `darwin-x64` | `2788d71` | 2023-02-12 |
|
2023-06-05 20:12:53 +00:00
|
|
|
| `darwin-arm` | `2788d71` | 2023-06-05 |
|
2023-06-03 09:10:50 +00:00
|
|
|
| `linux-x64` | `2788d71` | 2023-06-02 |
|
2023-03-12 06:25:57 +00:00
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
0) Build `libquickjs.a`:
|
|
|
|
|
|
|
|
```bash
|
2023-04-09 06:58:43 +00:00
|
|
|
git clone https://github.com/bellard/quickjs
|
2023-03-12 06:25:57 +00:00
|
|
|
cd quickjs
|
|
|
|
git checkout 2788d71
|
|
|
|
make
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
1) Copy `libquickjs.a` and `quickjs.h` into the working directory:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cp quickjs/libquickjs.a .
|
|
|
|
cp quickjs/quickjs.h .
|
|
|
|
```
|
|
|
|
|
|
|
|
2) Download [`sheetjs.quick.c`](pathname:///quickjs/sheetjs.quick.c):
|
|
|
|
|
|
|
|
```bash
|
|
|
|
curl -LO https://docs.sheetjs.com/quickjs/sheetjs.quick.c
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Build the sample application:
|
|
|
|
|
|
|
|
```bash
|
2023-06-03 09:10:50 +00:00
|
|
|
gcc -o sheetjs.quick -Wall -lm sheetjs.quick.c libquickjs.a
|
2023-03-12 06:25:57 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
This program tries to parse the file specified by the first argument
|
|
|
|
|
|
|
|
4) Download the standalone script and test file:
|
|
|
|
|
|
|
|
<ul>
|
2023-04-27 09:12:19 +00:00
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
2023-03-12 06:25:57 +00:00
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
2023-05-07 13:58:36 +00:00
|
|
|
<CodeBlock language="bash">{`\
|
2023-04-27 09:12:19 +00:00
|
|
|
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
|
|
|
curl -LO https://sheetjs.com/pres.numbers`}
|
2023-05-07 13:58:36 +00:00
|
|
|
</CodeBlock>
|
2023-03-12 06:25:57 +00:00
|
|
|
|
|
|
|
5) Run the test program:
|
|
|
|
|
|
|
|
```
|
|
|
|
./sheetjs.quick pres.numbers
|
|
|
|
```
|
|
|
|
|
|
|
|
If successful, the program will print the library version number, file size,
|
|
|
|
first worksheet name, and the contents of the first sheet as CSV rows.
|
|
|
|
|
|
|
|
|
|
|
|
### CLI Test
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
|
|
|
This demo was last tested on 2023 March 11 against QuickJS `2021-03-27`.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
0) Ensure `quickjs` command line utility is installed
|
|
|
|
|
|
|
|
1) Download the standalone script and the test file:
|
|
|
|
|
|
|
|
<ul>
|
2023-04-27 09:12:19 +00:00
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
2023-03-12 06:25:57 +00:00
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
2023-05-07 13:58:36 +00:00
|
|
|
<CodeBlock language="bash">{`\
|
2023-04-27 09:12:19 +00:00
|
|
|
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
|
|
|
curl -LO https://sheetjs.com/pres.numbers`}
|
2023-05-07 13:58:36 +00:00
|
|
|
</CodeBlock>
|
2023-03-12 06:25:57 +00:00
|
|
|
|
|
|
|
2) Download [`SheetJSQuick.js`](pathname:///quickjs/SheetJSQuick.js)
|
|
|
|
|
|
|
|
```bash
|
|
|
|
curl -LO https://docs.sheetjs.com/quickjs/SheetJSQuick.js
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Test the program:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
quickjs SheetJSQuick.js
|
|
|
|
```
|
|
|
|
|
|
|
|
If successful, the script will generate `SheetJSQuick.xlsx`.
|
|
|
|
|