Skip to main content

C + QuickJS

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.

The Standalone scripts can be parsed and evaluated in a QuickJS context.

Integration Details

Initialize QuickJS

QuickJS provides a global object through JS_GetGlobalObject:

/* 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);
danger

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:

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:

/* 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 *:

/* 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

This demo was last tested on 2023 March 11 against QuickJS commit 2788d71 on a Intel Mac. gcc -v printed:

Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0

0) Build libquickjs.a:

git clone https://github.com/bellard/quickjs
cd quickjs
git checkout 2788d71
make
cd ..

1) Copy libquickjs.a and quickjs.h into the working directory:

cp quickjs/libquickjs.a .
cp quickjs/quickjs.h .

2) Download sheetjs.quick.c:

curl -LO https://docs.sheetjs.com/quickjs/sheetjs.quick.c

3) Build the sample application:

gcc -o sheetjs.quick -Wall -lm libquickjs.a sheetjs.quick.c

This program tries to parse the file specified by the first argument

4) Download the standalone script and test file:

curl -LO https://cdn.sheetjs.com/xlsx-0.19.3/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.numbers

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:

curl -LO https://cdn.sheetjs.com/xlsx-0.19.3/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.numbers

2) Download SheetJSQuick.js

curl -LO https://docs.sheetjs.com/quickjs/SheetJSQuick.js

3) Test the program:

quickjs SheetJSQuick.js

If successful, the script will generate SheetJSQuick.xlsx.