From 62641b5da66704810e1b13a8fe3945fcac42f547 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Tue, 3 Oct 2023 18:58:43 -0400 Subject: [PATCH] maple --- docz/docs/03-demos/09-cloud/11-aws.md | 4 +- .../03-demos/32-extensions/09-mathematica.md | 2 +- docz/docs/03-demos/32-extensions/11-matlab.md | 2 +- docz/docs/03-demos/32-extensions/12-maple.md | 209 ++++++++++++++++++ docz/static/maple/maple.png | Bin 0 -> 12689 bytes docz/static/maple/sheetjs-maple.c | 115 ++++++++++ 6 files changed, 328 insertions(+), 4 deletions(-) create mode 100644 docz/docs/03-demos/32-extensions/12-maple.md create mode 100644 docz/static/maple/maple.png create mode 100644 docz/static/maple/sheetjs-maple.c diff --git a/docz/docs/03-demos/09-cloud/11-aws.md b/docz/docs/03-demos/09-cloud/11-aws.md index 01bb6be1..647b2b8d 100644 --- a/docz/docs/03-demos/09-cloud/11-aws.md +++ b/docz/docs/03-demos/09-cloud/11-aws.md @@ -354,8 +354,8 @@ required in NodeJS scripts. ### Connecting to S3 -The `AWS` module includes a function `S3` that performs the connection. Access -keys for an IAM user[^9] must be used: +The `aws-sdk` module includes a function `S3` that performs the connection. +Access keys for an IAM user[^9] must be used: ```js /* credentials */ diff --git a/docz/docs/03-demos/32-extensions/09-mathematica.md b/docz/docs/03-demos/32-extensions/09-mathematica.md index ce559aab..a01f484b 100644 --- a/docz/docs/03-demos/32-extensions/09-mathematica.md +++ b/docz/docs/03-demos/32-extensions/09-mathematica.md @@ -21,7 +21,7 @@ data from opaque spreadsheets and parse the data from Mathematica. :::note -This demo was last tested in 2023 August 21 in Mathematica 13.2.1. +This demo was last tested by SheetJS users on 2023 August 21 in Mathematica 13. ::: diff --git a/docz/docs/03-demos/32-extensions/11-matlab.md b/docz/docs/03-demos/32-extensions/11-matlab.md index e7307391..8acba17c 100644 --- a/docz/docs/03-demos/32-extensions/11-matlab.md +++ b/docz/docs/03-demos/32-extensions/11-matlab.md @@ -21,7 +21,7 @@ spreadsheets into simple XLSX files for MATLAB. :::note -This demo was last tested in 2023 September 12 in MATLAB R2023a. +This demo was last tested by SheetJS users on 2023 September 12 in MATLAB R2023a. ::: diff --git a/docz/docs/03-demos/32-extensions/12-maple.md b/docz/docs/03-demos/32-extensions/12-maple.md new file mode 100644 index 00000000..f63f2f7e --- /dev/null +++ b/docz/docs/03-demos/32-extensions/12-maple.md @@ -0,0 +1,209 @@ +--- +title: Modern Spreadsheets in Maple +sidebar_label: Maple +pagination_prev: demos/cloud/index +pagination_next: demos/bigdata/index +--- + +import current from '/version.js'; +import CodeBlock from '@theme/CodeBlock'; + +[Maple](https://www.maplesoft.com/products/Maple/) is a numeric computing +platform. It offers a robust C-based extension system. + +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo uses SheetJS to pull data from a spreadsheet for further analysis +within Maple. We'll create a Maple native extension that loads the +[Duktape](/docs/demos/engines/duktape) JavaScript engine and uses the SheetJS +library to read data from spreadsheets and converts to a Maple-friendly format. + +```mermaid +flowchart LR + ofile[(workbook\nXLSB file)] + nfile[(clean file\nXLSX)] + data[[Maple\nTable]] + ofile --> |Maple Extension\nSheetJS + Duktape| nfile + nfile --> |ExcelTools\nImport|data +``` + +:::note + +This demo was last tested by SheetJS users on 2023 October 3 in Maple 2023. + +::: + +:::info pass + +Maple has limited support for processing spreadsheets through the `ExcelTools` +package[^1]. At the time of writing, it lacked support for XLSB, NUMBERS, and +other common spreadsheet formats. + +SheetJS libraries help fill the gap by normalizing spreadsheets to a form that +Maple can understand. + +::: + +## Integration Details + +The current recommendation involves a native plugin that reads arbitrary files +and generates clean XLSX files that Maple can import. + +The extension function ultimately pairs the SheetJS `read`[^2] and `write`[^3] +methods to read data from the old file and write a new file: + +```js +var wb = XLSX.read(original_file_data, {type: "buffer"}); +var new_file_data = XLSX.write(wb, {type: "array", bookType: "xlsx"}); +``` + +The extension function will receive a file name and perform the following steps: + +```mermaid +flowchart LR + ofile{{File\nName}} + subgraph JS Operations + ojbuf[(Buffer\nFile Bytes)] + wb(((SheetJS\nWorkbook))) + njbuf[(Buffer\nXLSX bytes)] + end + obuf[(File\nbytes)] + nbuf[(New file\nbytes)] + nfile[(XLSX\nFile)] + ofile --> |C\nRead File| obuf + obuf --> |Duktape\nBuffer Ops| ojbuf + ojbuf --> |SheetJS\n`read`| wb + wb --> |SheetJS\n`write`| njbuf + njbuf --> |Duktape\nBuffer Ops| nbuf + nbuf --> |C\nWrite File| nfile +``` + +### C Extensions + +Maple C extensions are shared libraries or DLLs that use special Maple methods +for parsing arguments and returning values. + +To simplify the flow, the new function will take one argument (the original file +name) and return one value (the new file name). + +The official documentation has a comprehensive list[^4] of methods. For this +demo, the following methods are used: + +- `MapleNumArgs` and `IsMapleString` are used in argument validation. The demo +function will raise a Maple exception if no file name is specified. + +- `MapleRaiseError` and `MapleRaiseError2` programmatically raise errors. + +- `MapleToString` and `ToMapleString` convert between Maple and C strings. + +### Duktape JS Engine + +This demo uses the [Duktape JavaScript engine](/docs/demos/engines/duktape). The +SheetJS + Duktape demo covers engine integration details in more detail. + +The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone) +can be loaded in Duktape by reading the source from the filesystem. + +## Complete Demo + +:::info pass + +This demo was tested in Windows x64. The path names and build commands will +differ in other platforms and operating systems. + +::: + +The [`sheetjs-maple.c`](pathname:///maple/sheetjs-maple.c) extension exports the +`SheetToXLSX` Maple method. It takes a file name argument, parses the specified +file, exports data to `sheetjsw.xlsx` and returns the string `"sheetjsw.xlsx"`. + +This can be chained with `Import` from `ExcelTools`: + +```maple +with(ExcelTools); +Import(SheetToXLSX("pres.numbers")) +``` + +0) Ensure "Windows Subsystem for Linux" (WSL) and Visual Studio are installed. + +1) Open a new "x64 Native Tools Command Prompt" window and create a project +folder `c:\sheetjs-maple`: + +```powershell +cd c:\ +mkdir sheetjs-maple +cd sheetjs-maple +``` + +2) Copy the headers and `lib` files from the Maple folder to the project folder. +For example, using Maple 2023 on Windows x64: + +```powershell +copy "C:\Program Files\Maple 2023\extern\include\"*.h . +copy "c:\Program Files\Maple 2023\bin.x86_64_WINDOWS"\*.lib . +``` + +3) Run `bash` to enter WSL + +4) Within WSL, install Duktape: + +```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} . +``` + +5) Still within WSL, download SheetJS scripts and the test file. + +{`\ +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.numbers`} + + +6) Still within WSL, download the extension C code + +```bash +curl -LO https://docs.sheetjs.com/maple/sheetjs-maple.c +``` + +7) Exit WSL by running `exit`. The window will return to the command prompt. + +8) Build the extension DLL: + +```powershell +cl -Gz sheetjs-maple.c duktape.c /EHsc -link -dll -out:sheetjs-maple.dll maplec.lib +``` + +9) Close and re-open Maple, then create a new Maple Worksheet or Document + +10) Run the following command in Maple to change the working directory: + +```maple +currentdir("c:\\sheetjs-maple"); +``` + +11) Load the `SheetToXLSX` method from the extension: + +```maple +with(ExternalCalling): +dll:=ExternalLibraryName("sheetjs-maple"): +SheetToXLSX:=DefineExternal("SheetToXLSX",dll): +``` + +12) Read the `pres.numbers` test file: + +```maple +with(ExcelTools); +Import(SheetToXLSX("pres.numbers")) +``` + +The result will show the data from `pres.numbers` + +![Maple Screenshot](pathname:///maple/maple.png) + +[^1]: See ["ExcelTools"](https://www.maplesoft.com/support/help/Maple/view.aspx?path=ExcelTools) in the Maple documentation. +[^2]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^3]: See [`write` in "Writing Files"](/docs/api/write-options) +[^4]: See ["C OpenMaple and ExternalCalling Application Program Interface (API)"](https://www.maplesoft.com/support/help/maple/view.aspx?path=OpenMaple%2FC%2FAPI) in the Maple documentation. \ No newline at end of file diff --git a/docz/static/maple/maple.png b/docz/static/maple/maple.png new file mode 100644 index 0000000000000000000000000000000000000000..3234b655839229357e2f9ed235ea9adcfe73321e GIT binary patch literal 12689 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 +#include +#include +#include "maplec.h" +#include "duktape.h" + +/* --- EXPORT_DECL macro from official example --- */ + +#if !defined(EXPORT_DECL) +#ifdef _MSC_VER +#define EXPORT_DECL __declspec(dllexport) +#else +#define EXPORT_DECL +#endif +#endif + +/* --- the SheetJS + Duktape demo cover these machinations --- */ + +#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_DUK(cmd) { \ + const char *errmsg = duk_safe_to_string(ctx, -1); \ + duk_destroy_heap(ctx); \ + MapleRaiseError2(kv, "error in %1 : %2", ToMapleString(kv, cmd), ToMapleString(kv, errmsg)); \ + return NULL; \ +} + +#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); + +/* SheetToXLSX function */ +EXPORT_DECL ALGEB M_DECL SheetToXLSX( MKernelVector kv, ALGEB *args ) { + duk_int_t res = 0; + + /* get filename */ + if(MapleNumArgs(kv, (ALGEB)args) != 1) { + MapleRaiseError(kv, "must specify a filename"); + return NULL; + } + if(!IsMapleString(kv, args[1])) { + MapleRaiseError(kv, "filename must be a string"); + return NULL; + } + const char *filename = MapleToString(kv, args[1]); + + /* initialize duktape */ + 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 SheetJS library */ + res = eval_file(ctx, "shim.min.js"); + if(res != 0) FAIL_DUK("shim load") + res = eval_file(ctx, "xlsx.full.min.js"); + if(res != 0) FAIL_DUK("library load") + + /* read file */ + res = load_file(ctx, filename, "buf"); + if(res != 0) FAIL_DUK("file load") + printf("Loaded file %s\n", filename); + + /* parse workbook and write to XLSX */ + DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); + DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'xlsx'}));");\ + + /* write file */ + res = save_file(ctx, "sheetjsw.xlsx", "newbuf");\ + if(res != 0) FAIL_DUK("save sheetjsw.xlsx") + + /* return filename */ + return ToMapleString(kv, "sheetjsw.xlsx"); +}