forked from sheetjs/docs.sheetjs.com
c+swift
This commit is contained in:
parent
02c42e79a5
commit
0bf5ac0fa8
@ -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"
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Command-Line Tools
|
||||
pagination_next: demos/engines/index
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
|
232
docz/docs/03-demos/31-engines/01_duktape.md
Normal file
232
docz/docs/03-demos/31-engines/01_duktape.md
Normal file
@ -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:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
```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<br/>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`<br/>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
|
||||
```
|
163
docz/docs/03-demos/31-engines/02_jsc.md
Normal file
163
docz/docs/03-demos/31-engines/02_jsc.md
Normal file
@ -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:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
```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.
|
5
docz/docs/03-demos/31-engines/_category_.json
Normal file
5
docz/docs/03-demos/31-engines/_category_.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"label": "Other Languages",
|
||||
"position": 31,
|
||||
"collapsed": false
|
||||
}
|
@ -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);
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::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:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
2) Save the following script to `sheetjs.duk.c`:
|
||||
|
||||
```c title="sheetjs.duk.c"
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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.
|
||||
|
||||
</details>
|
||||
|
||||
## 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`
|
||||
</details>
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
</details>
|
||||
|
||||
## 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.
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::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:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
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.
|
||||
|
||||
</details>
|
||||
|
||||
## 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 $?
|
||||
|
||||
</details>
|
||||
|
||||
## 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`.
|
||||
</details>
|
||||
|
||||
|
||||
## 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.
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Clipboard Data
|
||||
pagination_prev: demos/engines/index
|
||||
---
|
||||
|
||||
Spreadsheet software like Excel typically support copying and pasting cells and
|
||||
|
@ -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/' },
|
||||
|
104
docz/static/duk/sheetjs.duk.c
Normal file
104
docz/static/duk/sheetjs.duk.c
Normal file
@ -0,0 +1,104 @@
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user