jerry
This commit is contained in:
parent
963168e7b4
commit
6e3b91f9e5
@ -38,11 +38,10 @@ Under the hood, `ArrayBuffer` objects represent raw binary data. "Typed arrays"
|
||||
such as `Float64Array` and `Float32Array` are objects designed for efficient
|
||||
interpretation and mutation of `ArrayBuffer` data.
|
||||
|
||||
|
||||
:::note pass
|
||||
|
||||
`ArrayBuffer` are roughly analogous to heap-allocated memory. Typed arrays
|
||||
behave like typed pointers.
|
||||
`ArrayBuffer` objects are roughly analogous to heap-allocated memory. Typed
|
||||
arrays behave like typed pointers.
|
||||
|
||||
**JavaScript**
|
||||
|
||||
@ -262,7 +261,7 @@ arrays of arrays.
|
||||
A single typed array can be converted to a pure JS array with `Array.from`:
|
||||
|
||||
```js
|
||||
const arr = Array.from(column);
|
||||
const arr = Array.from(row);
|
||||
```
|
||||
|
||||
An array of arrays can be created from the array:
|
||||
|
@ -386,7 +386,7 @@ https.get('https://sheetjs.com/pres.numbers', function(res) {
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was last tested on 2024 January 15 against NodeJS `20.11.0`
|
||||
|
||||
@ -433,7 +433,7 @@ async function parse_from_url(url) {
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was last tested on 2024 January 15 against NodeJS `20.11.0`
|
||||
|
||||
@ -512,7 +512,7 @@ request(url, {encoding: null}, function(err, res, data) {
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was last tested on 2024 January 15 against request `2.88.2`
|
||||
|
||||
@ -554,7 +554,7 @@ async function workbook_dl_axios(url) {
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was last tested on 2024 January 15 against Axios `1.6.5`
|
||||
|
||||
|
@ -301,7 +301,7 @@ This demo was tested in the following environments:
|
||||
| macOS 14.1.2 | `darwin-arm` | `v2.6.0` | 2023-12-01 |
|
||||
| Windows 10 | `win10-x64` | `v2.6.0` | 2023-12-09 |
|
||||
| Windows 11 | `win11-arm` | `v2.6.0` | 2023-12-01 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.6.0` | 2023-10-11 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.7.1` | 2024-01-22 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.6.0` | 2023-12-01 |
|
||||
|
||||
:::
|
||||
|
@ -261,7 +261,7 @@ This demo was tested in the following environments:
|
||||
| macOS 14.0 | `darwin-arm` | `v1.5.2` | 2023-10-18 |
|
||||
| Windows 10 | `win10-x64` | `v1.5.0` | 2023-10-01 |
|
||||
| Windows 11 | `win11-arm` | `v1.5.7` | 2023-12-01 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.5.2` | 2023-10-11 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.5.9` | 2024-01-23 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.5.7` | 2023-12-01 |
|
||||
|
||||
:::
|
||||
|
@ -421,7 +421,7 @@ This demo was last tested in the following deployments:
|
||||
| `win10-x64` | `1.37.1` | 2023-10-09 |
|
||||
| `win11-x64` | `1.37.2` | 2023-10-14 |
|
||||
| `win11-arm` | `1.38.4` | 2023-12-01 |
|
||||
| `linux-x64` | `1.37.1` | 2023-10-11 |
|
||||
| `linux-x64` | `1.39.4` | 2024-01-22 |
|
||||
| `linux-arm` | `1.38.4` | 2023-12-01 |
|
||||
|
||||
:::
|
||||
|
@ -41,7 +41,7 @@ setting the environment variable on supported platforms.
|
||||
:::note pass
|
||||
|
||||
Most of the integration functions are not documented. This explanation is based
|
||||
on version `3.0.0-beta-2056`.
|
||||
on version `3.0.0`.
|
||||
|
||||
:::
|
||||
|
||||
@ -108,7 +108,7 @@ byte[] buf = File.ReadAllBytes(filename);
|
||||
Jint natively supports `Uint8Array` construction from the byte array:
|
||||
|
||||
```csharp
|
||||
Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(buf);
|
||||
Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(buf);
|
||||
```
|
||||
|
||||
`Jint.Engine#SetValue` will assign the `Uint8Array` to a scope variable in JS:
|
||||
@ -163,11 +163,11 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Jint Version | Date |
|
||||
|:-------------|:------------------|:-----------|
|
||||
| `darwin-x64` | `3.0.0-beta-2055` | 2023-11-14 |
|
||||
| `darwin-x64` | `3.0.0` | 2024-01-22 |
|
||||
| `darwin-arm` | `3.0.0-beta-2056` | 2023-12-01 |
|
||||
| `win10-x64` | `3.0.0-beta-2053` | 2023-10-28 |
|
||||
| `win11-arm` | `3.0.0-beta-2056` | 2023-12-01 |
|
||||
| `linux-x64` | `3.0.0-beta-2052` | 2023-10-11 |
|
||||
| `linux-x64` | `3.0.0` | 2024-01-22 |
|
||||
| `linux-arm` | `3.0.0-beta-2056` | 2023-12-01 |
|
||||
|
||||
:::
|
||||
@ -211,10 +211,18 @@ Click "OK" in each window (3 windows) and restart your computer.
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
For macOS x64 and ARM64, install with Homebrew: `brew install dotnet@6`
|
||||
For macOS x64 and ARM64, install the `dotnet-sdk` Cask with Homebrew:
|
||||
|
||||
```bash
|
||||
brew install --cask dotnet-sdk
|
||||
```
|
||||
|
||||
For Steam Deck Holo and other Arch Linux x64 distributions, the `dotnet-sdk` and
|
||||
`dotnet-runtime` packages should be installed using `pacman`.
|
||||
`dotnet-runtime` packages should be installed using `pacman`:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu dotnet-sdk dotnet-runtime
|
||||
```
|
||||
|
||||
<https://dotnet.microsoft.com/en-us/download/dotnet/6.0> is the official source
|
||||
for Windows and ARM64 Linux versions.
|
||||
@ -230,7 +238,7 @@ for Windows and ARM64 Linux versions.
|
||||
```bash
|
||||
mkdir SheetJSJint
|
||||
cd SheetJSJint
|
||||
dotnet new console --framework net6.0
|
||||
dotnet new console
|
||||
dotnet run
|
||||
```
|
||||
|
||||
@ -238,7 +246,7 @@ dotnet run
|
||||
|
||||
```bash
|
||||
dotnet nuget add source https://www.myget.org/F/jint/api/v3/index.json
|
||||
dotnet add package Jint --version 3.0.0-beta-2056
|
||||
dotnet add package Jint --version 3.0.0
|
||||
```
|
||||
|
||||
To verify Jint is installed, replace `Program.cs` with the following:
|
||||
@ -309,7 +317,7 @@ Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
|
||||
|
||||
/* Read and Parse File */
|
||||
byte[] filedata = File.ReadAllBytes(args[0]);
|
||||
Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(filedata);
|
||||
Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(filedata);
|
||||
engine.SetValue("buf", u8);
|
||||
engine.Evaluate("var wb = XLSX.read(buf);");
|
||||
|
||||
|
@ -27,7 +27,7 @@ command-line tool for reading data from files.
|
||||
:::note pass
|
||||
|
||||
Many QuickJS functions are not documented. The explanation was verified against
|
||||
the latest release (commit `daa35bc`).
|
||||
the latest release (commit `9e561d5`).
|
||||
|
||||
:::
|
||||
|
||||
@ -266,10 +266,10 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `2788d71` | 2023-10-18 |
|
||||
| `win10-x64` | `daa35bc` | 2023-12-09 |
|
||||
| `win11-arm` | `03cc5ec` | 2023-12-01 |
|
||||
| `linux-x64` | `03cc5ec` | 2023-12-07 |
|
||||
| `linux-x64` | `9e561d5` | 2024-01-22 |
|
||||
| `linux-arm` | `03cc5ec` | 2023-12-01 |
|
||||
|
||||
When the demo was tested, commit `daa35bc` corresponded to the latest release.
|
||||
When the demo was tested, commit `9e561d5` corresponded to the latest release.
|
||||
|
||||
:::
|
||||
|
||||
@ -285,7 +285,7 @@ tests were run entirely within Windows Subsystem for Linux.
|
||||
```bash
|
||||
git clone https://github.com/bellard/quickjs
|
||||
cd quickjs
|
||||
git checkout daa35bc
|
||||
git checkout 9e561d5
|
||||
make
|
||||
cd ..
|
||||
```
|
||||
@ -342,10 +342,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| Git Commit | Date |
|
||||
|:-----------|:-----------|
|
||||
| `daa35bc` | 2023-12-09 |
|
||||
| `2788d71` | 2023-12-09 |
|
||||
| `9e561d5` | 2024-01-22 |
|
||||
|
||||
When the demo was tested, commit `daa35bc` corresponded to the latest release.
|
||||
When the demo was tested, commit `9e561d5` corresponded to the latest release.
|
||||
|
||||
:::
|
||||
|
||||
@ -354,7 +353,7 @@ When the demo was tested, commit `daa35bc` corresponded to the latest release.
|
||||
```bash
|
||||
git clone https://github.com/bellard/quickjs
|
||||
cd quickjs
|
||||
git checkout daa35bc
|
||||
git checkout 9e561d5
|
||||
make
|
||||
cd ..
|
||||
cp quickjs/qjs .
|
||||
|
@ -16,8 +16,8 @@ ChakraCore is an embeddable JS engine written in C++.
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses Hermes and SheetJS to pull data from a spreadsheet and print CSV
|
||||
rows. We'll explore how to load SheetJS in a ChakraCore context and process
|
||||
This demo uses ChakraCore and SheetJS to pull data from a spreadsheet and print
|
||||
CSV rows. We'll explore how to load SheetJS in a ChakraCore context and process
|
||||
spreadsheets from a C++ program.
|
||||
|
||||
The ["Integration Example"](#integration-example) section includes a complete
|
||||
|
473
docz/docs/03-demos/42-engines/23-jerryscript.md
Normal file
473
docz/docs/03-demos/42-engines/23-jerryscript.md
Normal file
@ -0,0 +1,473 @@
|
||||
---
|
||||
title: C + JerryScript
|
||||
pagination_prev: demos/bigdata/index
|
||||
pagination_next: solutions/input
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[JerryScript](https://jerryscript.net/) is a lightweight JavaScript engine. It
|
||||
is designed for microcontrollers and similar environments.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses JerryScript and SheetJS to pull data from a spreadsheet and print
|
||||
CSV rows. We'll explore how to load SheetJS in a JerryScript realm and process
|
||||
spreadsheets from C programs.
|
||||
|
||||
The ["Integration Example"](#integration-example) section includes a complete
|
||||
command-line tool for reading data from files.
|
||||
|
||||
:::caution pass
|
||||
|
||||
This demo requires a much larger heap size than is normally used in JerryScript
|
||||
deployments! In local testing, the following sizes were needed:
|
||||
|
||||
- 8192 (8M) for <https://sheetjs.com/pres.xlsx>
|
||||
- 65536 (64M) for <https://sheetjs.com/pres.numbers>
|
||||
|
||||
:::
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Architecture | Commit | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `514fa67` | 2024-01-22 |
|
||||
| `darwin-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
| `win11-x64` | `ef4cb2b` | 2023-12-08 |
|
||||
| `win11-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
| `linux-x64` | `ef4cb2b` | 2023-12-08 |
|
||||
| `linux-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
|
||||
The Windows tests were run in WSL.
|
||||
|
||||
Debian and WSL require the `cmake`, `python3` and `python-is-python3` packages.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
:::info pass
|
||||
|
||||
The official JerryScript documentation and examples are out of date. This
|
||||
explanation was verified against the latest release (commit `514fa67`).
|
||||
|
||||
:::
|
||||
|
||||
### Initialize JerryScript
|
||||
|
||||
The global engine instance can be initialized with `jerry_init` and cleaned up
|
||||
with `jerry_cleanup`:
|
||||
|
||||
```c
|
||||
#include "jerryscript.h"
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
/* Initialize engine */
|
||||
/* highlight-next-line */
|
||||
jerry_init(JERRY_INIT_EMPTY);
|
||||
|
||||
// ... use engine methods ...
|
||||
|
||||
/* cleanup before exiting */
|
||||
/* highlight-next-line */
|
||||
jerry_cleanup();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
API methods use `jerry_value_t` values to represent JS values and miscellany.
|
||||
Values representing errors can be distinguished using `jerry_value_is_error`.
|
||||
`jerry_value_t` values can be freed with `jerry_value_free`.
|
||||
|
||||
### Evaluate Code
|
||||
|
||||
Evaluating code involves two steps:
|
||||
|
||||
- `jerry_parse` will parse the script
|
||||
- `jerry_run` will run the parsed script object
|
||||
|
||||
:::note pass
|
||||
|
||||
The return value of `jerry_parse` is a `jerry_value_t` value that can be safely
|
||||
freed after `jerry_run`.
|
||||
|
||||
:::
|
||||
|
||||
The following `eval_str` function parses and executes scripts. If parsing fails,
|
||||
the function will return the parsing error. If parsing succeeds, the function
|
||||
will return the result of executing the code.
|
||||
|
||||
```c
|
||||
jerry_value_t eval_str(const char *code, size_t sz) {
|
||||
/* try to parse code */
|
||||
jerry_value_t parsed = jerry_parse(code, sz, NULL);
|
||||
/* return the parse error if parsing failed */
|
||||
if(jerry_value_is_error(parsed)) return parsed;
|
||||
|
||||
/* run the code */
|
||||
jerry_value_t out = jerry_run(parsed);
|
||||
/* free the parsed representation */
|
||||
jerry_value_free(parsed);
|
||||
|
||||
/* return the result */
|
||||
return out;
|
||||
}
|
||||
```
|
||||
|
||||
### Load SheetJS Scripts
|
||||
|
||||
[SheetJS Standalone scripts](/docs/getting-started/installation/standalone) can
|
||||
be parsed and run in JerryScript.
|
||||
|
||||
Scripts can be read from the filesystem using standard C functions:
|
||||
|
||||
```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); fseek(f, 0, SEEK_SET); }
|
||||
char *buf = (char *)malloc(fsize * sizeof(char));
|
||||
*sz = fread((void *) buf, 1, fsize, f) - 1;
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
```
|
||||
|
||||
The shim script must be evaluated before the main library. In both cases, after
|
||||
reading the script file, the previous `eval_str` function can run the code:
|
||||
|
||||
```c
|
||||
/* evaluate shim.min.js */
|
||||
{
|
||||
size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("shim.min.js", &sz);
|
||||
jerry_value_t result = eval_str(script, sz);
|
||||
if(jerry_value_is_error(result)) { // failed to parse / execute
|
||||
fprintf(stderr, "Failed to evaluate shim.min.js"); return 1;
|
||||
}
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
/* evaluate xlsx.full.min.js */
|
||||
{
|
||||
size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("xlsx.full.min.js", &sz);
|
||||
jerry_value_t result = eval_str(script, sz);
|
||||
if(jerry_value_is_error(result)) { // failed to parse / execute
|
||||
fprintf(stderr, "Failed to evaluate xlsx.full.min.js"); return 1;
|
||||
}
|
||||
jerry_value_free(result);
|
||||
}
|
||||
```
|
||||
|
||||
### Reading Files
|
||||
|
||||
Binary file data can be passed from C to JerryScript with `ArrayBuffer` objects.
|
||||
|
||||
#### Creating ArrayBuffers
|
||||
|
||||
`jerry_arraybuffer` will generate an `ArrayBuffer` object of specified length.
|
||||
After creating the array, `jerry_arraybuffer_write` will copy data.
|
||||
|
||||
The following `load_file` function reads a file from the filesystem and loads
|
||||
the data into an `ArrayBuffer`:
|
||||
|
||||
```c
|
||||
static jerry_value_t load_file(const char *filename) {
|
||||
/* read file */
|
||||
size_t len; char *buf = read_file(filename, &len);
|
||||
if(!buf) return 0;
|
||||
|
||||
/* create ArrayBuffer */
|
||||
jerry_value_t out = jerry_arraybuffer(len);
|
||||
/* copy file data into ArrayBuffer */
|
||||
jerry_arraybuffer_write(out, 0, (const uint8_t*)buf, len);
|
||||
return out;
|
||||
}
|
||||
```
|
||||
|
||||
The process may fail. The result should be tested with `jerry_value_is_error`:
|
||||
|
||||
```c
|
||||
jerry_value_t ab = load_file("pres.xlsx");
|
||||
if(!ab || jerry_value_is_error(ab)) { // failed to create ArrayBuffer
|
||||
fprintf(stderr, "Failed to read pres.xlsx"); return 1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Creating Global Variable
|
||||
|
||||
The `ArrayBuffer` object must be bound to a variable before it can be used.
|
||||
|
||||
:::note pass
|
||||
|
||||
The goal is to bind the `ArrayBuffer` to the `buf` property in global scope.
|
||||
|
||||
:::
|
||||
|
||||
1) Get the global `this` variable (using `jerry_current_realm`):
|
||||
|
||||
```c
|
||||
/* get the global variable */
|
||||
jerry_value_t this = jerry_current_realm();
|
||||
if(jerry_value_is_error(this)) { // failed to get global object
|
||||
fprintf(stderr, "Failed to get global object"); return 1;
|
||||
}
|
||||
```
|
||||
|
||||
2) Create a JerryScript string (`"buf"`) for the property:
|
||||
|
||||
```c
|
||||
/* create a string "buf" for the property access */
|
||||
jerry_value_t prop = jerry_string_sz("buf");
|
||||
if(jerry_value_is_error(this)) { // failed to create "buf"
|
||||
fprintf(stderr, "Failed to create string"); return 1;
|
||||
}
|
||||
```
|
||||
|
||||
3) Assign the property using `jerry_object_set`:
|
||||
|
||||
```c
|
||||
/* set global["buf"] to the ArrayBuffer */
|
||||
jerry_value_t set = jerry_object_set(this, prop, ab);
|
||||
if(jerry_value_is_error(set)) { // failed to set property
|
||||
fprintf(stderr, "Failed to assign ArrayBuffer"); return 1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Parsing Data
|
||||
|
||||
:::note pass
|
||||
|
||||
The goal is to run the equivalent of the following JavaScript code:
|
||||
|
||||
```js
|
||||
/* `buf` is the `ArrayBuffer` from the previous step */
|
||||
var wb = XLSX.read(buf);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
The `ArrayBuffer` from the previous step is available in the `buf` variable.
|
||||
That `ArrayBuffer` can be passed to the SheetJS `read` method[^1], which will
|
||||
parse the raw data and return a SheetJS workbook object[^2].
|
||||
|
||||
`var wb = XLSX.read(buf)` can be stored in a byte array and evaluated directly:
|
||||
|
||||
```c
|
||||
/* run `var wb = XLSX.read(buf)` */
|
||||
{
|
||||
const jerry_char_t code[] = "var wb = XLSX.read(buf);";
|
||||
jerry_value_t result = eval_str(code, sizeof(code) - 1);
|
||||
if(jerry_value_is_error(result)) {
|
||||
fprintf(stderr, "Failed to parse file"); return 1;
|
||||
}
|
||||
jerry_value_free(result);
|
||||
}
|
||||
```
|
||||
|
||||
#### Generating CSV
|
||||
|
||||
:::note pass
|
||||
|
||||
The goal is to run the equivalent of the following JavaScript code:
|
||||
|
||||
```js
|
||||
/* `wb` is the workbook from the previous step */
|
||||
XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
A SheetJS workbook object can contain multiple sheet objects[^3]. The `Sheets`
|
||||
property is an object whose keys are sheet names and whose values are sheet
|
||||
objects. The `SheetNames` property is an array of worksheet names.
|
||||
|
||||
The first sheet name can be found at `wb.SheetNames[0]`. The first sheet object
|
||||
can be found at `wb.Sheets[wb.SheetNames[0]]`.
|
||||
|
||||
The SheetJS `sheet_to_csv` utility function[^4] accepts a sheet object and
|
||||
generates a JS string.
|
||||
|
||||
Combining everything, `XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])`
|
||||
generates a CSV string based on the first worksheet in the workbook `wb`:
|
||||
|
||||
```c
|
||||
const jerry_char_t code[] = "XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])";
|
||||
jerry_value_t csv = eval_str(code, sizeof(code) - 1);
|
||||
if(jerry_value_is_error(result)) { // CSV generation failed
|
||||
fprintf(stderr, "Failed to generate csv"); return 1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Pulling Strings
|
||||
|
||||
JerryScript exposes encoding-aware methods to pull JS strings into C. The
|
||||
`JERRY_ENCODING_UTF8` encoding forces UTF8 interpretations.
|
||||
|
||||
The `jerry_string_size` function returns the number of bytes required to store
|
||||
the string. After allocating memory, `jerry_string_to_buffer` will copy data.
|
||||
The following `pull_str` function uses `malloc`:
|
||||
|
||||
```js
|
||||
char *pull_str(jerry_value_t str, size_t *sz) {
|
||||
/* determine string size in bytes */
|
||||
jerry_size_t str_sz = jerry_string_size(str, JERRY_ENCODING_UTF8);
|
||||
|
||||
/* allocate memory */
|
||||
jerry_char_t *buf = (jerry_char_t *)malloc(str_sz + 1);
|
||||
|
||||
/* copy from JS string to C byte array */
|
||||
jerry_string_to_buffer(str, JERRY_ENCODING_UTF8, buf, str_sz + 1);
|
||||
|
||||
/* pass back size and return the pointer */
|
||||
*sz = str_sz;
|
||||
return (char *)buf;
|
||||
}
|
||||
```
|
||||
|
||||
This function can be used to pull the `csv` value from the previous section:
|
||||
|
||||
```c
|
||||
size_t sz; char *buf = pull_str(result, &sz);
|
||||
printf("%s\n", buf);
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
The "Integration Example" covers a traditional integration in a C application,
|
||||
while the "CLI Test" demonstrates other concepts using the `jerry` CLI tool.
|
||||
|
||||
### Integration Example
|
||||
|
||||
1) Create a project folder:
|
||||
|
||||
```bash
|
||||
mkdir SheetJSJerry
|
||||
cd SheetJSJerry
|
||||
```
|
||||
|
||||
2) Clone the repository and build the library with required options:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git
|
||||
cd jerryscript
|
||||
python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON
|
||||
cd ..
|
||||
```
|
||||
|
||||
3) Download the SheetJS Standalone script, shim script and test file. Move all
|
||||
three files to the `SheetJSJerry` directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
||||
curl -LO https://sheetjs.com/pres.xlsx`}
|
||||
</CodeBlock>
|
||||
|
||||
4) Download [`sheetjs.jerry.c`](pathname:///jerryscript/sheetjs.jerry.c) into
|
||||
the same folder:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/jerryscript/sheetjs.jerry.c
|
||||
```
|
||||
|
||||
5) Build the sample application:
|
||||
|
||||
```bash
|
||||
gcc -o sheetjs.jerry -Ijerryscript/jerry-ext/include -Ijerryscript/jerry-math/include -Ijerryscript/jerry-core/include -ljerry-ext -ljerry-port -ljerry-core -Ljerryscript/build/lib sheetjs.jerry.c -Wno-pointer-sign
|
||||
```
|
||||
|
||||
6) Run the test program:
|
||||
|
||||
```bash
|
||||
./sheetjs.jerry pres.xlsx
|
||||
```
|
||||
|
||||
If successful, the program will print contents of the first sheet as CSV rows.
|
||||
|
||||
### CLI Test
|
||||
|
||||
:::note pass
|
||||
|
||||
Due to limitations of the standalone binary, this demo will encode a test file
|
||||
as a Base64 string and directly add it to an amalgamated script.
|
||||
|
||||
:::
|
||||
|
||||
0) Build the library and command line tool with required options:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git
|
||||
cd jerryscript
|
||||
python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON
|
||||
```
|
||||
|
||||
1) Download the SheetJS Standalone script, shim script and test file. Move all
|
||||
three files to the `jerryscript` cloned repo directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
||||
curl -LO https://sheetjs.com/pres.xlsx`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Bundle the test file and create `payload.js`:
|
||||
|
||||
```bash
|
||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')"
|
||||
```
|
||||
|
||||
3) Create support scripts:
|
||||
|
||||
- `global.js` creates a `global` variable and defines a fake `console`:
|
||||
|
||||
```js title="global.js"
|
||||
var global = (function(){ return this; }).call(null);
|
||||
var console = { log: function(x) { print(x); } };
|
||||
```
|
||||
|
||||
- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
||||
|
||||
```js title="jerry.js"
|
||||
var wb = XLSX.read(payload, {type:'base64'});
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
4) Create the amalgamation `xlsx.jerry.js`:
|
||||
|
||||
```bash
|
||||
cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js
|
||||
```
|
||||
|
||||
The final script defines `global` before loading the standalone library. Once
|
||||
ready, it will read the bundled test data and print the contents as CSV.
|
||||
|
||||
5) Run the script using the `jerry` standalone binary:
|
||||
|
||||
```bash
|
||||
build/bin/jerry xlsx.jerry.js; echo $?
|
||||
```
|
||||
|
||||
If successful, the contents of the test file will be displayed in CSV rows. The
|
||||
status code `0` will be printed after the rows.
|
||||
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book)
|
||||
[^3]: See ["Sheet Objects"](/docs/csf/sheet)
|
||||
[^4]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
@ -26,7 +26,7 @@ This demo showcases a number of JS engines and language bindings.
|
||||
|
||||
Common browser and NodeJS APIs are often missing from light-weight JS engines.
|
||||
|
||||
**Global**
|
||||
#### Global
|
||||
|
||||
Some engines do not provide `globalThis` or `global` or `window`. A `global`
|
||||
variable can be exposed in one line that should be run in the JS engine:
|
||||
@ -35,16 +35,17 @@ variable can be exposed in one line that should be run in the JS engine:
|
||||
var global = (function(){ return this; }).call(null);
|
||||
```
|
||||
|
||||
**Console**
|
||||
#### Console
|
||||
|
||||
Some engines do not provide a `console` object. `console.log` can be shimmed
|
||||
using the engine functionality. For example, `hermes`[^1] provides `print()`:
|
||||
Some engines do not provide a `console` object but offer other ways to print to
|
||||
standard output. For example, Hermes[^1] provides `print()`. A `console` object
|
||||
should be created using the engine print function:
|
||||
|
||||
```js
|
||||
var console = { log: function(x) { print(x); } };
|
||||
```
|
||||
|
||||
**Binary Data**
|
||||
#### Binary Data
|
||||
|
||||
Some engines do not provide easy ways to exchange binary data. For example, it
|
||||
is common to pass null-terminated arrays, which would truncate XLSX, XLS, and
|
||||
@ -53,7 +54,7 @@ other exports. APIs that accept pointers without length should be avoided.
|
||||
Base64 strings are safe for passing between JS and native code, but they should
|
||||
only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`.
|
||||
|
||||
**Byte Conventions**
|
||||
#### Byte Conventions
|
||||
|
||||
Java has no native concept of unsigned bytes. Values in a `byte[]` are limited
|
||||
to the range `-128 .. 127`. They need to be fixed within the JS engine.
|
||||
@ -116,123 +117,12 @@ Swift and Objective-C.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/jsc).
|
||||
|
||||
|
||||
### JerryScript
|
||||
|
||||
JerryScript is a lightweight JavaScript engine designed for use in low-memory
|
||||
environments like microcontrollers. As part of the build suite, the project
|
||||
generates a C library and a standalone CLI tool.
|
||||
environments including microcontrollers.
|
||||
|
||||
The simplest way to interact with the engine is to pass Base64 strings.
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Architecture | Commit | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `ef4cb2b` | 2023-12-08 |
|
||||
| `darwin-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
| `win11-x64` | `ef4cb2b` | 2023-12-08 |
|
||||
| `win11-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
| `linux-x64` | `ef4cb2b` | 2023-12-08 |
|
||||
| `linux-arm` | `ef4cb2b` | 2023-12-08 |
|
||||
|
||||
The Windows tests were run in WSL.
|
||||
|
||||
Debian and WSL require the `cmake`, `python3` and `python-is-python3` packages.
|
||||
|
||||
:::
|
||||
|
||||
:::note pass
|
||||
|
||||
While applications should link against the official libraries, the standalone tool
|
||||
is useful for verifying functionality.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
This demo requires a much larger heap size than is normally used in JerryScript
|
||||
deployments! In local testing, the following sizes were needed:
|
||||
|
||||
- 8192 (8M) for <https://sheetjs.com/pres.xlsx>
|
||||
- 65536 (64M) for <https://sheetjs.com/pres.numbers>
|
||||
|
||||
This works on a Raspberry Pi.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
Due to limitations of the standalone binary, this demo will encode a test file
|
||||
as a Base64 string and directly add it to an amalgamated script.
|
||||
|
||||
0) Build the library and command line tool with required options:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git
|
||||
cd jerryscript
|
||||
python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON
|
||||
```
|
||||
|
||||
1) Download the SheetJS Standalone script, shim script and test file. Move all
|
||||
three files to the `jerryscript` cloned repo directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
||||
curl -LO https://sheetjs.com/pres.xlsx`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Bundle the test file and create `payload.js`:
|
||||
|
||||
```bash
|
||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')"
|
||||
```
|
||||
|
||||
3) Create support scripts:
|
||||
|
||||
- `global.js` creates a `global` variable and defines a fake `console`:
|
||||
|
||||
```js title="global.js"
|
||||
var global = (function(){ return this; }).call(null);
|
||||
var console = { log: function(x) { print(x); } };
|
||||
```
|
||||
|
||||
- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
||||
|
||||
```js title="jerry.js"
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
var wb = XLSX.read(payload, {type:'base64'});
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
4) Create the amalgamation `xlsx.jerry.js`:
|
||||
|
||||
```bash
|
||||
cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js
|
||||
```
|
||||
|
||||
The final script defines `global` before loading the standalone library. Once
|
||||
ready, it will read the bundled test data and print the contents as CSV.
|
||||
|
||||
5) Run the script using the `jerry` standalone binary:
|
||||
|
||||
```bash
|
||||
build/bin/jerry xlsx.jerry.js; echo $?
|
||||
```
|
||||
|
||||
If successful, the contents of the test file will be displayed in CSV rows. The
|
||||
status code `0` will be printed after the rows.
|
||||
|
||||
</details>
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/jerryscript).
|
||||
|
||||
### Jint
|
||||
|
||||
@ -240,14 +130,12 @@ Jint is an embeddable JS engine for .NET written in C#.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/jint).
|
||||
|
||||
|
||||
### Nashorn
|
||||
|
||||
Nashorn shipped with some versions of Java. It is now a standalone library.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/nashorn).
|
||||
|
||||
|
||||
### QuickJS
|
||||
|
||||
QuickJS is an embeddable JS engine written in C. It provides a separate set of
|
||||
@ -256,14 +144,12 @@ the standalone browser scripts.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/quickjs).
|
||||
|
||||
|
||||
### Rhino
|
||||
|
||||
Rhino is an ES3+ engine in Java.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/rhino).
|
||||
|
||||
|
||||
### V8
|
||||
|
||||
V8 is an embeddable JS engine written in C++. It powers Chromium and Chrome,
|
||||
|
143
docz/static/jerryscript/sheetjs.jerry.c
Normal file
143
docz/static/jerryscript/sheetjs.jerry.c
Normal file
@ -0,0 +1,143 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jerryscript.h"
|
||||
|
||||
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); fseek(f, 0, SEEK_SET); }
|
||||
char *buf = (char *)malloc(fsize * sizeof(char));
|
||||
*sz = fread((void *) buf, 1, fsize, f) - 1;
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
jerry_value_t eval_str(const char *code, size_t sz) {
|
||||
jerry_value_t parsed = jerry_parse(code, sz, NULL);
|
||||
if(jerry_value_is_error(parsed)) return parsed;
|
||||
|
||||
jerry_value_t out = jerry_run(parsed);
|
||||
jerry_value_free(parsed);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static jerry_value_t load_file(const char *filename) {
|
||||
size_t len; char *buf = read_file(filename, &len);
|
||||
if(!buf) return 0;
|
||||
|
||||
jerry_value_t out = jerry_arraybuffer(len);
|
||||
jerry_arraybuffer_write(out, 0, (const uint8_t*)buf, len);
|
||||
return out;
|
||||
}
|
||||
|
||||
char *pull_str(jerry_value_t str, size_t *sz) {
|
||||
jerry_size_t str_sz = jerry_string_size(str, JERRY_ENCODING_UTF8);
|
||||
jerry_char_t *buf = (jerry_char_t *)malloc(str_sz + 1);
|
||||
jerry_string_to_buffer(str, JERRY_ENCODING_UTF8, buf, str_sz + 1);
|
||||
*sz = str_sz;
|
||||
return (char *)buf;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int res = 0;
|
||||
|
||||
/* Initialize engine */
|
||||
jerry_init(JERRY_INIT_EMPTY);
|
||||
|
||||
/* evaluate shim.min.js */
|
||||
{
|
||||
size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("shim.min.js", &sz);
|
||||
jerry_value_t result = eval_str(script, sz);
|
||||
if(jerry_value_is_error(result)) {
|
||||
fprintf(stderr, "Failed to evaluate shim.min.js");
|
||||
res = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
/* evaluate xlsx.full.min.js */
|
||||
{
|
||||
size_t sz; const jerry_char_t *script = read_file("xlsx.full.min.js", &sz);
|
||||
jerry_value_t result = eval_str(script, sz);
|
||||
if(jerry_value_is_error(result)) {
|
||||
fprintf(stderr, "Failed to evaluate xlsx.full.min.js");
|
||||
res = 2;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
/* load spreadsheet */
|
||||
jerry_value_t ab = load_file(argv[1]);
|
||||
if(!ab || jerry_value_is_error(ab)) {
|
||||
fprintf(stderr, "Failed to read %s", argv[1]);
|
||||
res = 3;
|
||||
goto exeunt;
|
||||
}
|
||||
|
||||
/* assign to `buf` in the global scope */
|
||||
{
|
||||
/* get `this` */
|
||||
jerry_value_t this = jerry_current_realm();
|
||||
if(jerry_value_is_error(this)) {
|
||||
fprintf(stderr, "Failed to get global object");
|
||||
res = 4;
|
||||
goto exeunt;
|
||||
}
|
||||
|
||||
/* create "buf" str */
|
||||
jerry_value_t prop = jerry_string_sz("buf");
|
||||
if(jerry_value_is_error(this)) {
|
||||
fprintf(stderr, "Failed to create string");
|
||||
res = 5;
|
||||
goto exeunt;
|
||||
}
|
||||
|
||||
/* equivalent of `this["buf"] = buf` */
|
||||
jerry_value_t set = jerry_object_set(this, prop, ab);
|
||||
if(jerry_value_is_error(set)) {
|
||||
fprintf(stderr, "Failed to assign ArrayBuffer");
|
||||
res = 6;
|
||||
goto exeunt;
|
||||
}
|
||||
}
|
||||
|
||||
/* run `var wb = XLSX.read(buf)` */
|
||||
{
|
||||
const jerry_char_t code[] = "var wb = XLSX.read(buf);";
|
||||
jerry_value_t result = eval_str(code, sizeof(code) - 1);
|
||||
if(jerry_value_is_error(result)) {
|
||||
fprintf(stderr, "Failed to parse file");
|
||||
res = 7;
|
||||
goto exeunt;
|
||||
}
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
/* run `XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])` and print result */
|
||||
{
|
||||
const jerry_char_t code[] = "XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])";
|
||||
jerry_value_t result = eval_str(code, sizeof(code) - 1);
|
||||
if(jerry_value_is_error(result)) {
|
||||
fprintf(stderr, "Failed to generate csv");
|
||||
res = 8;
|
||||
} else {
|
||||
size_t sz; char *buf = pull_str(result, &sz);
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
exeunt:
|
||||
jerry_value_free(ab);
|
||||
|
||||
cleanup:
|
||||
/* Cleanup engine */
|
||||
jerry_cleanup();
|
||||
return res;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 47 KiB |
Binary file not shown.
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 39 KiB |
Loading…
Reference in New Issue
Block a user