| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: C + QuickJS | 
					
						
							|  |  |  | pagination_prev: demos/bigdata/index | 
					
						
							|  |  |  | pagination_next: solutions/input | 
					
						
							|  |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | import current from '/version.js'; | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | import CodeBlock from '@theme/CodeBlock'; | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | QuickJS is an embeddable JS engine written in C.  It provides a separate set of | 
					
						
							|  |  |  | functions for interacting with the filesystem and the global object.  It can run | 
					
						
							|  |  |  | the standalone browser scripts. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-14 08:38:47 +00:00
										 |  |  | The [Standalone scripts](/docs/getting-started/installation/standalone) can be | 
					
						
							|  |  |  | parsed and evaluated in a QuickJS context. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | ## Integration Details
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Initialize QuickJS_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QuickJS provides a `global` object through `JS_GetGlobalObject`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```c | 
					
						
							|  |  |  | /* initialize */ | 
					
						
							|  |  |  | JSRuntime *rt = JS_NewRuntime(); | 
					
						
							|  |  |  | JSContext *ctx = JS_NewContext(rt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* obtain reference to global object */ | 
					
						
							|  |  |  | JSValue global = JS_GetGlobalObject(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* DO WORK HERE */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* free after use */ | 
					
						
							|  |  |  | JS_FreeValue(ctx, global); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* cleanup */ | 
					
						
							|  |  |  | JS_FreeContext(ctx); | 
					
						
							|  |  |  | JS_FreeRuntime(rt); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::warning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | All values must be freed with `JS_FreeValue` before calling `JS_FreeContext`! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `JS_IsException` should be used for validation. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Cleanup and validation code is omitted from the discussion.  The integration | 
					
						
							|  |  |  | example shows structured validation and controlled memory usage. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Load SheetJS Scripts_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The main library can be loaded by reading the script from the file system and | 
					
						
							|  |  |  | evaluating in the QuickJS context: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```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); fsee  (f, 0, SEEK_SET); } | 
					
						
							|  |  |  |   char *buf = (char *)malloc(fsize * sizeof(char)); | 
					
						
							|  |  |  |   *sz = fread((void *) buf, 1, fsize, f); | 
					
						
							|  |  |  |   fclose(f); | 
					
						
							|  |  |  |   return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ... | 
					
						
							|  |  |  |   /* load library */ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     size_t len; char *buf = read_file("xlsx.full.min.js", &len); | 
					
						
							|  |  |  |     JS_Eval(ctx, buf, len, "<input>", 0); | 
					
						
							|  |  |  |     free(buf); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To confirm the library is loaded, `XLSX.version` can be inspected: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```c | 
					
						
							|  |  |  | /* obtain reference to the XLSX object */ | 
					
						
							|  |  |  | JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* print version */ | 
					
						
							|  |  |  | JSValue version = JS_GetPropertyStr(ctx, XLSX, "version"); | 
					
						
							|  |  |  | size_t vlen; const char *vers = JS_ToCStringLen(ctx, &vlen, version); | 
					
						
							|  |  |  | printf("Version: %s\n", vers); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Reading Files
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `JS_NewArrayBuffer` can generate an `ArrayBuffer` from a C byte array. The | 
					
						
							|  |  |  | function signature expects `uint8_t *` instead of `char *`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```c | 
					
						
							|  |  |  | /* read file */ | 
					
						
							|  |  |  | size_t dlen; uint8_t * dbuf = (uint8_t *)read_file("pres.numbers", &dlen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* load data into array buffer */ | 
					
						
							|  |  |  | JSValue ab = JS_NewArrayBuffer(ctx, dbuf, dlen, NULL, NULL, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* obtain reference to the XLSX object */ | 
					
						
							|  |  |  | JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* call XLSX.read(ab) */ | 
					
						
							|  |  |  | JSValue XLSX_read = JS_GetPropertyStr(ctx, XLSX, "read"); | 
					
						
							|  |  |  | JSValue args[] = { ab }; | 
					
						
							|  |  |  | JSValue wb = JS_Call(ctx, XLSX_read, XLSX, 1, args); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Complete Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The "Integration Example" covers a traditional integration in a C application, | 
					
						
							|  |  |  | while the "CLI Test" demonstrates other concepts using the `quickjs` CLI tool. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Integration Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This demo was last tested on 2023 March 11 against QuickJS commit `2788d71` on | 
					
						
							|  |  |  | a Intel Mac. `gcc -v` printed: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | Apple clang version 14.0.0 (clang-1400.0.29.202) | 
					
						
							|  |  |  | Target: x86_64-apple-darwin21.6.0 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 0) Build `libquickjs.a`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2023-04-09 06:58:43 +00:00
										 |  |  | git clone https://github.com/bellard/quickjs | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | cd quickjs | 
					
						
							|  |  |  | git checkout 2788d71 | 
					
						
							|  |  |  | make | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Copy `libquickjs.a` and `quickjs.h` into the working directory: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cp quickjs/libquickjs.a . | 
					
						
							|  |  |  | cp quickjs/quickjs.h . | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Download [`sheetjs.quick.c`](pathname:///quickjs/sheetjs.quick.c): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/quickjs/sheetjs.quick.c | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) Build the sample application: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | gcc -o sheetjs.quick -Wall -lm libquickjs.a sheetjs.quick.c | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This program tries to parse the file specified by the first argument | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4) Download the standalone script and test file: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <ul> | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | <li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li> | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | <li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li> | 
					
						
							|  |  |  | </ul> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | <CodeBlock language="bash">{`\ | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js | 
					
						
							|  |  |  | curl -LO https://sheetjs.com/pres.numbers`} | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | </CodeBlock> | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 5) Run the test program: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | ./sheetjs.quick pres.numbers | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If successful, the program will print the library version number, file size, | 
					
						
							|  |  |  | first worksheet name, and the contents of the first sheet as CSV rows. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### CLI Test
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This demo was last tested on 2023 March 11 against QuickJS `2021-03-27`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 0) Ensure `quickjs` command line utility is installed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Download the standalone script and the test file: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <ul> | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | <li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li> | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | <li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li> | 
					
						
							|  |  |  | </ul> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | <CodeBlock language="bash">{`\ | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js | 
					
						
							|  |  |  | curl -LO https://sheetjs.com/pres.numbers`} | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | </CodeBlock> | 
					
						
							| 
									
										
										
										
											2023-03-12 06:25:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 2) Download [`SheetJSQuick.js`](pathname:///quickjs/SheetJSQuick.js) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/quickjs/SheetJSQuick.js | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) Test the program: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | quickjs SheetJSQuick.js | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If successful, the script will generate `SheetJSQuick.xlsx`. | 
					
						
							|  |  |  | 
 |