From 0bf5ac0fa8393364dcd348e61685a7de2501366e Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 12 Feb 2023 23:07:25 -0500 Subject: [PATCH] c+swift --- .../docs/03-demos/03-desktop/05-neutralino.md | 4 +- .../03-demos/03-desktop/06-reactnative.md | 2 +- docz/docs/03-demos/27-cli.md | 1 + docz/docs/03-demos/31-engines/01_duktape.md | 232 ++++++++++++++ docz/docs/03-demos/31-engines/02_jsc.md | 163 ++++++++++ docz/docs/03-demos/31-engines/_category_.json | 5 + .../{31-engines.md => 31-engines/index.md} | 293 ++---------------- docz/docs/03-demos/32-clipboard.md | 1 + docz/docusaurus.config.js | 1 + docz/static/duk/sheetjs.duk.c | 104 +++++++ 10 files changed, 531 insertions(+), 275 deletions(-) create mode 100644 docz/docs/03-demos/31-engines/01_duktape.md create mode 100644 docz/docs/03-demos/31-engines/02_jsc.md create mode 100644 docz/docs/03-demos/31-engines/_category_.json rename docz/docs/03-demos/{31-engines.md => 31-engines/index.md} (69%) create mode 100644 docz/static/duk/sheetjs.duk.c diff --git a/docz/docs/03-demos/03-desktop/05-neutralino.md b/docz/docs/03-demos/03-desktop/05-neutralino.md index 5f64237..06270b1 100644 --- a/docz/docs/03-demos/03-desktop/05-neutralino.md +++ b/docz/docs/03-demos/03-desktop/05-neutralino.md @@ -135,13 +135,13 @@ cd sheetjs-neu curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js ``` -3) Add the highlighted lines to `neutralino.conf.json` in `nativeAllowList`: +3) Add the highlighted line to `neutralino.conf.json` in `nativeAllowList`: ```json title="neutralino.config.json" "nativeAllowList": [ "app.*", -// highlight-start "os.*", +// highlight-start "filesystem.*", // highlight-end "debug.log" diff --git a/docz/docs/03-demos/03-desktop/06-reactnative.md b/docz/docs/03-demos/03-desktop/06-reactnative.md index 47313c0..c017562 100644 --- a/docz/docs/03-demos/03-desktop/06-reactnative.md +++ b/docz/docs/03-demos/03-desktop/06-reactnative.md @@ -1,5 +1,5 @@ --- -title: React Native for Desktop +title: React Native pagination_prev: demos/mobile/index pagination_next: demos/cloud/index sidebar_position: 6 diff --git a/docz/docs/03-demos/27-cli.md b/docz/docs/03-demos/27-cli.md index aea7874..48daeed 100644 --- a/docz/docs/03-demos/27-cli.md +++ b/docz/docs/03-demos/27-cli.md @@ -1,5 +1,6 @@ --- title: Command-Line Tools +pagination_next: demos/engines/index --- import current from '/version.js'; diff --git a/docz/docs/03-demos/31-engines/01_duktape.md b/docz/docs/03-demos/31-engines/01_duktape.md new file mode 100644 index 0000000..7d13dca --- /dev/null +++ b/docz/docs/03-demos/31-engines/01_duktape.md @@ -0,0 +1,232 @@ +--- +title: C + Duktape +pagination_prev: demos/cli +pagination_next: demos/clipboard +--- + +Duktape is an embeddable JS engine written in C. It has been ported to a number +of exotic architectures and operating systems. + +The [Standalone scripts](/docs/getting-started/installation/standalone) can be +parsed and evaluated in a Duktape context. + +## Integration Details + +_Initialize Duktape_ + +Duktape does not provide a `global` variable. It can be created in one line: + +```c +/* initialize */ +duk_context *ctx = duk_create_heap_default(); + +/* duktape does not expose a standard "global" by default */ +// highlight-next-line +duk_eval_string_noresult(ctx, "var global = (function(){ return this; }).call(null);"); +``` + +_Load SheetJS Scripts_ + +The shim and main libraries can be loaded by reading the scripts from the file +system and evaluating in the Duktape context: + +```c +/* simple wrapper to read the entire script file */ +static duk_int_t eval_file(duk_context *ctx, const char *filename) { + size_t len; + /* read script from filesystem */ + FILE *f = fopen(filename, "rb"); + if(!f) { duk_push_undefined(ctx); perror("fopen"); return 1; } + long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); } + char *buf = (char *)malloc(fsize * sizeof(char)); + len = fread((void *) buf, 1, fsize, f); + fclose(f); + if(!buf) { duk_push_undefined(ctx); perror("fread"); return 1; } + + // highlight-start + /* load script into the context */ + duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); + /* eval script */ + duk_int_t retval = duk_peval(ctx); + /* cleanup */ + duk_pop(ctx); + // highlight-end + return retval; +} + +// ... + duk_int_t res = 0; + + if((res = eval_file(ctx, "shim.min.js")) != 0) { /* error handler */ } + if((res = eval_file(ctx, "xlsx.full.min.js")) != 0) { /* error handler */ } +``` + +To confirm the library is loaded, `XLSX.version` can be inspected: + +```c + /* get version string */ + duk_eval_string(ctx, "XLSX.version"); + printf("SheetJS library version %s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); +``` + +### Reading Files + +Duktape supports `Buffer` natively but should be sliced before processing. +Assuming `buf` is a C byte array, with length `len`, this snippet parses data: + +```c +/* load C char array and save to a Buffer */ +duk_push_external_buffer(ctx); +duk_config_buffer(ctx, -1, buf, len); +duk_put_global_string(ctx, "buf"); + +/* parse with SheetJS */ +duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); +``` + +`workbook` will be a variable in the JS environment that can be inspected using +the various SheetJS API functions. + +### Writing Files + +`duk_get_buffer_data` can pull `Buffer` object data into the C code: + +```c +/* write with SheetJS using type: "array" */ +duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})"); + +/* pull result back to C */ +duk_size_t sz; +char *buf = (char *)duk_get_buffer_data(ctx, -1, sz); + +/* discard result in duktape */ +duk_pop(ctx); +``` + +The resulting `buf` can be written to file with `fwrite`. + +## Complete Example + +:::note + +This demo was tested with Duktape `2.7.0` (`darwin-x64`) on 2023 February 12. + +::: + +This program parses a file and prints CSV data from the first worksheet. It also +generates an XLSB file and writes to the filesystem. + +The [flow diagram is displayed after the example steps](#flow-diagram) + +0) Download and extract Duktape: + +```bash +mkdir sheetjs-duk +cd sheetjs-duk +curl -LO https://duktape.org/duktape-2.7.0.tar.xz +tar -xJf duktape-2.7.0.tar.xz +mv duktape-2.7.0/src/*.{c,h} . +``` + +1) Download the standalone script, shim and test file: + + + +```bash +curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js +curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js +curl -LO https://sheetjs.com/pres.numbers +``` + +2) Download [`sheetjs.duk.c`](pathname:///duk/sheetjs.duk.c): + +```bash +curl -LO https://docs.sheetjs.com/duk/sheetjs.duk.c +``` + +3) Compile standalone `sheetjs.duk` binary + +```bash +gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm +``` + +4) Run the demo: + +```bash +./sheetjs.duk pres.numbers +``` + +If the program succeeded, the CSV contents will be printed to console and the +file `sheetjsw.xlsb` will be created. That file can be opened with Excel. + +#### Flow Diagram + +```mermaid +sequenceDiagram + participant F as Filesystem + participant C as C Code + participant D as Duktape + activate C + opt + Note over F,D: ~ Prepare Duktape ~ + C->>+D: Initialize + deactivate C + D->>-C: Done + activate C + C->>F: Need SheetJS + F->>C: SheetJS Code + C->>+D: Load SheetJS Code + deactivate C + D->>-C: Loaded + activate C + C->>+D: Execute Code + deactivate C + Note over D: Eval SheetJS Code + D->>-C: Done + activate C + Note over D: XLSX
ready to rock + end + opt + Note over F,D: ~ Parse File ~ + C->>F: Read Spreadsheet + F->>C: Spreadsheet File + C->>+D: Load Data + deactivate C + D->>-C: Loaded + activate C + C->>+D: eval `var workbook = XLSX.read(...)` + deactivate C + Note over D: Parse File + D->>-C: Done + activate C + Note over D: `workbook`
can be used later + end + opt + Note over F,D: ~ Print CSV to screen ~ + C->>+D: eval `XLSX.utils.sheet_to_csv(...)` + deactivate C + Note over D: Generate CSV + D->>-C: CSV Data + activate C + Note over C: Print to standard output + end + opt + Note over F,D: ~ Write XLSB File ~ + C->>+D: eval `XLSX.write(...)` + deactivate C + Note over D: Generate File + D->>-C: done + activate C + C->>+D: get file bytes + deactivate C + D->>-C: binary data + activate C + C->>F: Write File + end + deactivate C +``` \ No newline at end of file diff --git a/docz/docs/03-demos/31-engines/02_jsc.md b/docz/docs/03-demos/31-engines/02_jsc.md new file mode 100644 index 0000000..097d6fa --- /dev/null +++ b/docz/docs/03-demos/31-engines/02_jsc.md @@ -0,0 +1,163 @@ +--- +title: Swift + JavaScriptCore +pagination_prev: demos/cli +pagination_next: demos/clipboard +--- + +iOS and MacOS ship with the JavaScriptCore framework for running JS code from +Swift and Objective-C. Hybrid function invocation is tricky, but explicit data +passing is straightforward. The demo shows a standalone Swift sample for MacOS. + +The [Standalone scripts](/docs/getting-started/installation/standalone) can be +parsed and evaluated in a JSC context. + +:::warning Platform Limitations + +JavaScriptCore is primarily deployed in MacOS and iOS applications. There is +some experimental support through the Bun runtime, but production applications +intending to support Windows / Linux / Android should try to embed V8. + +::: + +## Integration Details + +Binary strings can be passed back and forth using `String.Encoding.isoLatin1`. + +_Initialize JavaScriptCore_ + +JSC does not provide a `global` variable. It can be created in one line: + +```swift +var context: JSContext! +do { + context = JSContext(); + context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; }; + // highlight-next-line + context.evaluateScript("var global = (function(){ return this; }).call(null);"); +} catch { print(error.localizedDescription); } +``` + +_Load SheetJS Scripts_ + +The main library can be loaded by reading the scripts from the file system and +evaluating in the JSC context: + +```swift +let src = try String(contentsOfFile: "xlsx.full.min.js"); +context.evaluateScript(src); +``` + +To confirm the library is loaded, `XLSX.version` can be inspected: + +```swift +let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); +if let ver = XLSX.objectForKeyedSubscript("version") { print(ver.toString()); } +``` + +### Reading Files + +`String(contentsOf:encoding:)` reads from a path and returns an encoded string: + +```swift +/* read sheetjs.xls as Base64 string */ +let file_path = shared_dir.appendingPathComponent("sheetjs.xls"); +let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1); +``` + +This string can be loaded into the JS engine and processed: + +```swift +/* load data in JSC */ +context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); + +/* `payload` (the "forKeyedSubscript" parameter) is a binary string */ +context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); +``` + +### Writing Files + +When writing to binary string in JavaScriptCore, the result should be stored in +a variable and converted to string in Swift: + +```swift +/* write to binary string */ +context.evaluateScript("var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})"); + +/* `out` from the script is a binary string that can be stringified in Swift */ +let outvalue: JSValue! = context.objectForKeyedSubscript("out"); +var out: String! = outvalue.toString(); +``` + +`String#write(to:atomically:encoding)` writes the string to the specified path: + +```swift +/* write to sheetjsw.xlsx */ +let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx"); +try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1); +``` + +## Complete Example + +:::note + +This demo was tested on 2023 February 12. `swift --version` printed: + +``` +swift-driver version: 1.62.15 Apple Swift version 5.7.2 +Target: x86_64-apple-macosx12.0 +``` + +::: + +The demo includes a sample `SheetJSCore` Wrapper class to simplify operations. + +:::caution This demo only runs on MacOS + +This example requires MacOS + Swift and will not work on Windows or Linux! + +::: + +0) Ensure Xcode is installed. Create a folder for the project: + +```bash +mkdir sheetjswift +cd sheetjswift +``` + +1) Download the standalone script and the test file: + + + +```bash +curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js +curl -LO https://sheetjs.com/pres.numbers +``` + +2) Download the Swift scripts for the demo + +- [`SheetJSCore.swift`](pathname:///swift/SheetJSCore.swift) Wrapper library +- [`main.swift`](pathname:///swift/main.swift) Command-line script + +```bash +curl -LO https://docs.sheetjs.com/swift/SheetJSCore.swift +curl -LO https://docs.sheetjs.com/swift/main.swift +``` + + +3) Build the `SheetJSwift` binary: + +```bash +swiftc SheetJSCore.swift main.swift -o SheetJSwift +``` + +4) Test the program: + +```bash +./SheetJSwift pres.numbers +``` + +If successful, a CSV will be printed to console. The script also tries to write +to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers. diff --git a/docz/docs/03-demos/31-engines/_category_.json b/docz/docs/03-demos/31-engines/_category_.json new file mode 100644 index 0000000..f21164c --- /dev/null +++ b/docz/docs/03-demos/31-engines/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Other Languages", + "position": 31, + "collapsed": false +} \ No newline at end of file diff --git a/docz/docs/03-demos/31-engines.md b/docz/docs/03-demos/31-engines/index.md similarity index 69% rename from docz/docs/03-demos/31-engines.md rename to docz/docs/03-demos/31-engines/index.md index 7a0e650..34a8b8e 100644 --- a/docz/docs/03-demos/31-engines.md +++ b/docz/docs/03-demos/31-engines/index.md @@ -1,11 +1,16 @@ --- title: JavaScript Engines +pagination_prev: demos/cli +pagination_next: demos/clipboard --- import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +Browser vendors and other organizations have built "JavaScript engines". They +are independent software libraries that are capable of running JS scripts. + The most popular JavaScript engine is V8. Designed for embedding in software, it powers Chrome, NodeJS, UXP, Deno and many other platforms. @@ -14,6 +19,7 @@ for low-power or low-memory environments. Others aim for interoperability with specific programming languages or environments. Typically they support ES3 and are capable of running SheetJS code. +This demo showcases a number of JS engines and language bindings. ## General Caveats @@ -47,186 +53,19 @@ 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`. -## Duktape +## Engines + +This list is sorted in alphabetical order. + +### Duktape Duktape is an embeddable JS engine written in C. It has been ported to a number of exotic architectures and operating systems. -**Reading data** +This demo has been moved [to a dedicated page](/docs/demos/engines/duktape). -Duktape supports `Buffer` natively but should be sliced before processing: -```c -/* parse a C char array as a workbook object */ -duk_push_external_buffer(ctx); -duk_config_buffer(ctx, -1, buf, len); -duk_put_global_string(ctx, "buf"); -duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); -``` - -**Writing data** - -`duk_get_buffer_data` can pull `Buffer` object data into the C code: - -```c -/* write a workbook object to a C char array */ -duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})"); -duk_size_t sz; -char *buf = (char *)duk_get_buffer_data(ctx, -1, sz); -duk_pop(ctx); -``` - -
Complete Example (click to show) - -:::note - -This demo was tested on Intel Mac (`darwin-x64`). - -::: - -0) Download and extract the latest release (2.7.0 at the time of writing) - -```bash -curl -LO https://duktape.org/duktape-2.7.0.tar.xz -tar -xJf duktape-2.7.0.tar.xz -mv duktape-2.7.0/src/*.{c,h} . -``` - -1) Download the standalone script, shim and test file: - - - -2) Save the following script to `sheetjs.duk.c`: - -```c title="sheetjs.duk.c" -/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ -#include -#include -#include -#include "duktape.h" - -#define FAIL_LOAD { \ - duk_push_undefined(ctx); \ - perror("Error in load_file"); \ - return 1; \ -} - -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); - fclose(f); - return buf; -} - -static duk_int_t eval_file(duk_context *ctx, const char *filename) { - size_t len; char *buf = read_file(filename, &len); - if(!buf) FAIL_LOAD - - duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); - duk_int_t retval = duk_peval(ctx); - duk_pop(ctx); - return retval; -} - -static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) { - size_t len; char *buf = read_file(filename, &len); - if(!buf) FAIL_LOAD - - duk_push_external_buffer(ctx); - duk_config_buffer(ctx, -1, buf, len); - duk_put_global_string(ctx, var); - return 0; -} - -static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) { - duk_get_global_string(ctx, var); - duk_size_t sz; - char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz); - - if(!buf) return 1; - FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f); - return 0; -} - -#define FAIL(cmd) { \ - printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \ - duk_destroy_heap(ctx); \ - return res; \ -} - -#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); -int main(int argc, char *argv[]) { - duk_int_t res = 0; - - /* initialize */ - duk_context *ctx = duk_create_heap_default(); - /* duktape does not expose a standard "global" by default */ - DOIT("var global = (function(){ return this; }).call(null);"); - - /* load library */ - res = eval_file(ctx, "shim.min.js"); - if(res != 0) FAIL("shim load") - res = eval_file(ctx, "xlsx.full.min.js"); - if(res != 0) FAIL("library load") - - /* get version string */ - duk_eval_string(ctx, "XLSX.version"); - printf("SheetJS library version %s\n", duk_get_string(ctx, -1)); - duk_pop(ctx); - - /* read file */ - res = load_file(ctx, argv[1], "buf"); - if(res != 0) FAIL("file load") - printf("Loaded file %s\n", argv[1]); - - /* parse workbook */ - DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); - DOIT("ws = wb.Sheets[wb.SheetNames[0]]"); - - /* print CSV */ - duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)"); - printf("%s\n", duk_get_string(ctx, -1)); - duk_pop(ctx); - - /* write file */ -#define WRITE_TYPE(BOOKTYPE) \ - DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\ - res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\ - if(res != 0) FAIL("save sheetjsw." BOOKTYPE) - - WRITE_TYPE("xlsb") - - /* cleanup */ - duk_destroy_heap(ctx); - return res; -} -``` - -3) Compile standalone `sheetjs.duk` binary - -```bash -gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm -``` - -4) Run the demo: - -```bash -./sheetjs.duk pres.numbers -``` - -If the program succeeded, the CSV contents will be printed to console and the -file `sheetjsw.xlsb` will be created. That file can be opened with Excel. - -
- -## Goja +### Goja Goja is a pure Go implementation of ECMAScript 5. It supports the standalone scripts out of the box. @@ -368,7 +207,7 @@ This will print the contents as a CSV to screen AND write to `sheetjsg.csv` -## Hermes +### Hermes Hermes is an embeddable JS engine for React Native. The library and binary distributions include a command-line tool `hermes` for running JS scripts. @@ -439,107 +278,16 @@ hermes xlsx.hermes.js -## JavaScriptCore -:::warning Platform Limitations - -JavaScriptCore is primarily deployed in MacOS and iOS applications. There is -some experimental support through the Bun runtime, but production applications -intending to support Windows / Linux / Android should try to embed V8. - -::: +### JavaScriptCore iOS and MacOS ship with the JavaScriptCore framework for running JS code from -Swift and Objective-C. Hybrid function invocation is tricky, but explicit data -passing is straightforward. The demo shows a standalone Swift sample for MacOS. +Swift and Objective-C. -Binary strings can be passed back and forth using `String.Encoding.isoLatin1`. +This demo has been moved [to a dedicated page](/docs/demos/engines/jsc). -**Reading data** -`String(contentsOf:encoding:)` reads from a path and returns an encoded string: - -```swift -/* read sheetjs.xls as Base64 string */ -let file_path = shared_dir.appendingPathComponent("sheetjs.xls"); -let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1); -``` - -This string can be loaded into the JS engine and processed: - -```swift -/* load data in JSC */ -context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); - -/* `payload` (the "forKeyedSubscript" parameter) is a binary string */ -context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); -``` - -**Writing data** - -When writing to binary string in JavaScriptCore, the result should be stored in -a variable and converted to string in Swift: - -```swift -/* write to binary string */ -context.evaluateScript("var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})"); - -/* `out` from the script is a binary string that can be stringified in Swift */ -let outvalue: JSValue! = context.objectForKeyedSubscript("out"); -var out: String! = outvalue.toString(); -``` - -`String#write(to:atomically:encoding)` writes the string to the specified path: - -```swift -/* write to sheetjsw.xlsx */ -let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx"); -try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1); -``` - -The demo includes a sample `SheetJSCore` Wrapper class to simplify operations. - -
Complete Example (click to show) - -:::caution This demo only runs on MacOS - -This example requires MacOS + Swift and will not work on Windows or Linux! - -::: - -0) Ensure Xcode is installed - -1) Download the standalone script, the shim and the test file: - - - -2) Download the Swift scripts for the demo - -- [`SheetJSCore.swift`](pathname:///swift/SheetJSCore.swift) Wrapper library -- [`main.swift`](pathname:///swift/main.swift) Command-line script - -3) Build the `SheetJSwift` binary: - -```bash -swiftc SheetJSCore.swift main.swift -o SheetJSwift -``` - -4) Test the program: - -```bash -./SheetJSwift pres.numbers -``` - -If successful, a CSV will be printed to console. The script also tries to write -to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers. - -
- -## JerryScript +### JerryScript JerryScript is a lightweight JavaScript engine designed for use in low-memory environments like microcontrollers. As part of the build suite, the project @@ -627,7 +375,8 @@ build/bin/jerry xlsx.jerry.js; echo $? -## QuickJS + +### 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 @@ -686,7 +435,7 @@ If successful, the script will generate `SheetJSQuick.xlsx`. -## Rhino +### Rhino Rhino is an ES3+ engine in Java. The `SheetJSRhino` class and `com.sheetjs` package show a complete JAR deployment, including the full XLSX source. diff --git a/docz/docs/03-demos/32-clipboard.md b/docz/docs/03-demos/32-clipboard.md index 1210dbd..ae855da 100644 --- a/docz/docs/03-demos/32-clipboard.md +++ b/docz/docs/03-demos/32-clipboard.md @@ -1,5 +1,6 @@ --- title: Clipboard Data +pagination_prev: demos/engines/index --- Spreadsheet software like Excel typically support copying and pasting cells and diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index 9968cc2..c8749aa 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -173,6 +173,7 @@ const config = { { from: '/docs/getting-started/demos/excel', to: '/docs/demos/' }, { from: '/docs/demos/content', to: '/docs/demos/static/' }, { from: '/docs/demos/git', to: '/docs/demos/hosting/github/' }, + { from: '/docs/demo/grid', to: '/docs/demos/grid/' }, /* frontend */ { from: '/docs/demos/angular', to: '/docs/demos/frontend/angular/' }, { from: '/docs/demos/react', to: '/docs/demos/frontend/react/' }, diff --git a/docz/static/duk/sheetjs.duk.c b/docz/static/duk/sheetjs.duk.c new file mode 100644 index 0000000..14f89da --- /dev/null +++ b/docz/static/duk/sheetjs.duk.c @@ -0,0 +1,104 @@ +/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ +#include +#include +#include +#include "duktape.h" + +#define FAIL_LOAD { \ + duk_push_undefined(ctx); \ + perror("Error in load_file"); \ + return 1; \ +} + +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); + fclose(f); + return buf; +} + +static duk_int_t eval_file(duk_context *ctx, const char *filename) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); + duk_int_t retval = duk_peval(ctx); + duk_pop(ctx); + return retval; +} + +static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, buf, len); + duk_put_global_string(ctx, var); + return 0; +} + +static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) { + duk_get_global_string(ctx, var); + duk_size_t sz; + char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz); + + if(!buf) return 1; + FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f); + return 0; +} + +#define FAIL(cmd) { \ + printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \ + duk_destroy_heap(ctx); \ + return res; \ +} + +#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); +int main(int argc, char *argv[]) { + duk_int_t res = 0; + + /* initialize */ + duk_context *ctx = duk_create_heap_default(); + /* duktape does not expose a standard "global" by default */ + DOIT("var global = (function(){ return this; }).call(null);"); + + /* load library */ + res = eval_file(ctx, "shim.min.js"); + if(res != 0) FAIL("shim load") + res = eval_file(ctx, "xlsx.full.min.js"); + if(res != 0) FAIL("library load") + + /* get version string */ + duk_eval_string(ctx, "XLSX.version"); + printf("SheetJS library version %s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* read file */ + res = load_file(ctx, argv[1], "buf"); + if(res != 0) FAIL("file load") + printf("Loaded file %s\n", argv[1]); + + /* parse workbook */ + DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); + DOIT("ws = wb.Sheets[wb.SheetNames[0]]"); + + /* print CSV */ + duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)"); + printf("%s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* write file */ +#define WRITE_TYPE(BOOKTYPE) \ + DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\ + res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\ + if(res != 0) FAIL("save sheetjsw." BOOKTYPE) + + WRITE_TYPE("xlsb") + + /* cleanup */ + duk_destroy_heap(ctx); + return res; +}