forked from sheetjs/docs.sheetjs.com
		
	stata
This commit is contained in:
		
							parent
							
								
									5d87422b97
								
							
						
					
					
						commit
						0ee20fd040
					
				| @ -44,7 +44,7 @@ This demo was tested in the following deployments: | ||||
| |:-------------|:--------|:------------|:-----------| | ||||
| | `darwin-x64` | `5.8.1` | `18.5.0`    | 2023-05-08 | | ||||
| | `darwin-arm` | `5.8.1` | `18.5.0`    | 2023-09-25 | | ||||
| | `win10-x64`  | `5.8.1` | `18.5.0`    | 2023-05-08 | | ||||
| | `win10-x64`  | `5.8.1` | `18.5.0`    | 2023-10-09 | | ||||
| | `win11-arm`  | `5.8.1` | `18.5.0`    | 2023-09-25 | | ||||
| | `linux-x64`  | `5.8.1` | `18.5.0`    | 2023-05-08 | | ||||
| | `linux-arm`  | `5.8.1` | `18.5.0`    | 2023-09-25 | | ||||
| @ -55,7 +55,7 @@ This demo was tested in the following deployments: | ||||
| |:-------------|:-------------|:------------|:-----------| | ||||
| | `darwin-x64` | `4.0.0-rc.2` | `14.15.3`   | 2023-05-08 | | ||||
| | `darwin-arm` | `4.0.0-rc.2` | `20.7.0`    | 2023-09-25 | | ||||
| | `win10-x64`  | `4.0.0-rc.2` | `14.15.3`   | 2023-05-08 | | ||||
| | `win10-x64`  | `4.0.0-rc.2` | `14.15.3`   | 2023-10-09 | | ||||
| | `win11-arm`  | `4.0.0-rc.2` | `18.17.1`   | 2023-09-25 | | ||||
| | `linux-x64`  | `4.0.0-rc.2` | `14.15.3`   | 2023-05-08 | | ||||
| | `linux-arm`  | `4.0.0-rc.2` | `20.7.0`    | 2023-09-25 | | ||||
| @ -66,7 +66,7 @@ This demo was tested in the following deployments: | ||||
| |:-------------|:--------|:------------|:-----------| | ||||
| | `darwin-x64` | `2.0.1` | `20.1.0`    | 2023-05-08 | | ||||
| | `darwin-arm` | `2.1.1` | `20.7.0`    | 2023-09-25 | | ||||
| | `win10-x64`  | `2.1.1` | `16.20.2`   | 2023-08-27 | | ||||
| | `win10-x64`  | `2.1.2` | `16.20.2`   | 2023-10-09 | | ||||
| | `linux-x64`  | `2.0.1` | `20.1.0`    | 2023-05-08 | | ||||
| | `linux-arm`  | `2.1.1` | `20.7.0`    | 2023-09-25 | | ||||
| 
 | ||||
| @ -161,7 +161,7 @@ npx boxednode@2.1.1 -s xlsx-cli.js -t xlsx-cli | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| ```bash | ||||
| npx boxednode@2.1.1 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2 | ||||
| npx boxednode@2.1.2 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2 | ||||
| ``` | ||||
| 
 | ||||
| :::info pass | ||||
| @ -169,6 +169,8 @@ npx boxednode@2.1.1 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2 | ||||
| The Windows 10 build requires Visual Studio with "Desktop development with C++" | ||||
| workload, Python 3, and NASM[^1]. | ||||
| 
 | ||||
| The build command should be run in "x64 Native Tools Command Prompt" | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution pass | ||||
| @ -186,11 +188,11 @@ Studio installer. | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| In the most recent Windows test against NodeJS `20.5.1`, the build failed due | ||||
| In the most recent Windows test against NodeJS `20.8.0`, the build failed due | ||||
| to an issue in the OpenSSL dependency: | ||||
| 
 | ||||
| ``` | ||||
| ...\node-v20.5.1\deps\openssl\openssl\crypto\info.c(176,16): error C2153: integer literals must have at least one digit [...\node-v20.5.1\deps\openssl\openssl.vcxproj] | ||||
| ...\node-v20.8.0\deps\openssl\openssl\crypto\cversion.c(75,33): error C2153: integer literals must have at least one digit [...\node-v20.8.0\deps\openssl\openssl.vcxproj] | ||||
| ``` | ||||
| 
 | ||||
| SheetJS libraries are compatible with NodeJS versions dating back to `v0.8`. The | ||||
| @ -202,8 +204,6 @@ was chosen since NodeJS `v18` upgraded the OpenSSL dependency. | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| @ -229,14 +229,14 @@ V8 engine. This demo uses the Rust integration to generate a command line tool. | ||||
| 
 | ||||
| This demo was last tested in the following deployments: | ||||
| 
 | ||||
| | Architecture | V8 Version   | Crate    | Date       | | ||||
| |:-------------|:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `11.4.183.2` | `0.71.2` | 2023-05-22 | | ||||
| | `darwin-arm` | `11.4.183.2` | `0.71.2` | 2023-05-22 | | ||||
| | `win10-x64`  | `11.4.183.2` | `0.71.2` | 2023-05-23 | | ||||
| | `win11-x64`  | `11.7.439.6` | `0.75.1` | 2023-08-31 | | ||||
| | `linux-x64`  | `11.4.183.2` | `0.71.2` | 2023-05-23 | | ||||
| | `linux-arm`  | `11.7.439.6` | `0.75.1` | 2023-08-30 | | ||||
| | Architecture | V8 Version    | Crate    | Date       | | ||||
| |:-------------|:--------------|:---------|:-----------| | ||||
| | `darwin-x64` | `11.4.183.2`  | `0.71.2` | 2023-05-22 | | ||||
| | `darwin-arm` | `11.4.183.2`  | `0.71.2` | 2023-05-22 | | ||||
| | `win10-x64`  | `11.8.172.13` | `0.79.2` | 2023-10-09 | | ||||
| | `win11-x64`  | `11.7.439.6`  | `0.75.1` | 2023-08-31 | | ||||
| | `linux-x64`  | `11.4.183.2`  | `0.71.2` | 2023-05-23 | | ||||
| | `linux-arm`  | `11.7.439.6`  | `0.75.1` | 2023-08-30 | | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| @ -344,7 +344,7 @@ This demo was last tested in the following deployments: | ||||
| |:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `1.33.2` | 2023-05-08 | | ||||
| | `darwin-arm` | `1.34.1` | 2023-06-05 | | ||||
| | `win10-x64`  | `1.33.2` | 2023-05-08 | | ||||
| | `win10-x64`  | `1.37.1` | 2023-10-09 | | ||||
| | `win11-arm`  | `1.37.0` | 2023-09-26 | | ||||
| | `linux-x64`  | `1.33.2` | 2023-05-08 | | ||||
| | `linux-arm`  | `1.36.3` | 2023-08-30 | | ||||
|  | ||||
							
								
								
									
										306
									
								
								docz/docs/03-demos/32-extensions/10-stata.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										306
									
								
								docz/docs/03-demos/32-extensions/10-stata.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,306 @@ | ||||
| --- | ||||
| title: Modern Spreadsheets in Stata | ||||
| sidebar_label: Stata | ||||
| pagination_prev: demos/cloud/index | ||||
| pagination_next: demos/bigdata/index | ||||
| --- | ||||
| 
 | ||||
| import current from '/version.js'; | ||||
| import CodeBlock from '@theme/CodeBlock'; | ||||
| 
 | ||||
| export const b = {style: {color:"blue"}}; | ||||
| 
 | ||||
| [Stata](https://www.stata.com/) is a statistical software package. 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 Stata. We'll create a Stata 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 Stata-friendly format. | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   ofile[(workbook\nXLSB file)] | ||||
|   nfile[(clean file\nXLSX)] | ||||
|   data[[Stata\nVariables]] | ||||
|   ofile --> |Stata Extension\nSheetJS + Duktape| nfile | ||||
|   nfile --> |Stata command\nimport excel|data | ||||
| ``` | ||||
| 
 | ||||
| The demo will read [a Numbers workbook](https://sheetjs.com/pres.numbers) and | ||||
| generate variables for each column. A sample Stata session is shown below: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was last tested by SheetJS users on 2023 October 09. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| Stata has limited support for processing spreadsheets through the `import excel` | ||||
| command[^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 | ||||
| Stata can understand. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| The current recommendation involves a native plugin that reads arbitrary files | ||||
| and generates clean XLSX files that Stata 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 `cleanfile` will take one or two arguments: | ||||
| 
 | ||||
| `plugin call cleanfile, "pres.numbers"` will generate `sheetjs.tmp.xlsx` from | ||||
| the first argument (`"pres.numbers"`) and print instructions to load the file. | ||||
| 
 | ||||
| `plugin call cleanfile, "pres.numbers" verbose` will additionally print CSV | ||||
| contents of each worksheet in the workbook. | ||||
| 
 | ||||
| ```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 | ||||
| 
 | ||||
| Stata C extensions are shared libraries or DLLs that use special Stata methods | ||||
| for parsing arguments and returning values. | ||||
| 
 | ||||
| Arguments are passed to the `stata_call` function in the DLL. | ||||
| 
 | ||||
| `SF_display` and `SF_error` display text and error messages respectively. | ||||
| 
 | ||||
| ### 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 [`cleanfile.c`](pathname:///stata/cleanfile.c) extension defines one plugin | ||||
| function. It can be chained with `import excel`: | ||||
| 
 | ||||
| ```stata | ||||
| program cleanfile, plugin | ||||
| plugin call cleanfile, "pres.numbers" verbose | ||||
| program drop cleanfile | ||||
| import excel "sheetjs.tmp.xlsx", firstrow | ||||
| ``` | ||||
| 
 | ||||
| ### Create Plugin | ||||
| 
 | ||||
| 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-stata`: | ||||
| 
 | ||||
| ```powershell | ||||
| cd c:\ | ||||
| mkdir sheetjs-stata | ||||
| cd sheetjs-stata | ||||
| ``` | ||||
| 
 | ||||
| 2) Enter WSL: | ||||
| 
 | ||||
| ```powershell | ||||
| bash | ||||
| ``` | ||||
| 
 | ||||
| 3) Download [`stplugin.c`](https://www.stata.com/plugins/stplugin.c) and | ||||
| [`stplugin.h`](https://www.stata.com/plugins/stplugin.h) from the Stata website: | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://www.stata.com/plugins/stplugin.c | ||||
| curl -LO https://www.stata.com/plugins/stplugin.h | ||||
| ``` | ||||
| 
 | ||||
| 4) Still 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 the demo source | ||||
| [`cleanfile.c`](https://docs.sheetjs.com/stata/cleanfile.c): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/stata/cleanfile.c | ||||
| ``` | ||||
| 
 | ||||
| 6) Exit WSL: | ||||
| 
 | ||||
| ```bash | ||||
| exit | ||||
| ``` | ||||
| 
 | ||||
| The window will return to the command prompt. | ||||
| 
 | ||||
| 7) Build the DLL: | ||||
| 
 | ||||
| ```powershell | ||||
| cl /LD cleanfile.c stplugin.c duktape.c | ||||
| ``` | ||||
| 
 | ||||
| ### Install Plugin | ||||
| 
 | ||||
| 8) Copy the DLL to `cleanfile.plugin` in the Stata data directory. For example, | ||||
| with a shared data directory `c:\data`: | ||||
| 
 | ||||
| ```powershell | ||||
| mkdir c:\data | ||||
| copy cleanfile.dll c:\data\cleanfile.plugin | ||||
| ``` | ||||
| 
 | ||||
| ### Download SheetJS Scripts | ||||
| 
 | ||||
| 9) Move to the `c:\data` directory | ||||
| 
 | ||||
| ```powershell | ||||
| cd c:\data | ||||
| ``` | ||||
| 
 | ||||
| 10) Enter WSL | ||||
| 
 | ||||
| ```powershell | ||||
| bash | ||||
| ``` | ||||
| 
 | ||||
| 11) Within WSL, download SheetJS scripts and the test file. | ||||
| 
 | ||||
| <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.numbers`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 12) Exit WSL: | ||||
| 
 | ||||
| ```bash | ||||
| exit | ||||
| ``` | ||||
| 
 | ||||
| The window will return to the command prompt. | ||||
| 
 | ||||
| ### Stata Test | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| The screenshot in the introduction shows the result of steps 13 - 19 | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 13) Open Stata | ||||
| 
 | ||||
| 14) Move to the `c:\data` directory in Stata: | ||||
| 
 | ||||
| ```stata | ||||
| cd c:\data | ||||
| ``` | ||||
| 
 | ||||
| 15) Load the `cleanfile` plugin: | ||||
| 
 | ||||
| ```stata | ||||
| program cleanfile, plugin | ||||
| ``` | ||||
| 
 | ||||
| 16) Read the `pres.numbers` test file: | ||||
| 
 | ||||
| ```stata | ||||
| plugin call cleanfile, "pres.numbers" verbose | ||||
| ``` | ||||
| 
 | ||||
| The result will show the data from `pres.numbers`: | ||||
| 
 | ||||
| <pre> | ||||
| <b>. plugin call cleanfile, "pres.numbers" verbose</b>{'\n'} | ||||
| Worksheet 0 Name: Sheet1{'\n'} | ||||
| Name,Index{'\n'} | ||||
| Bill Clinton,42{'\n'} | ||||
| GeorgeW Bush,43{'\n'} | ||||
| Barack Obama,44{'\n'} | ||||
| Donald Trump,45{'\n'} | ||||
| Joseph Biden,46{'\n'} | ||||
| {'\n'} | ||||
| Saved to `sheetjs.tmp.xlsx`{'\n'} | ||||
| <span {...b}>import excel "sheetjs.tmp.xlsx", firstrow</span> will read the first sheet and use headers{'\n'} | ||||
| for more help, see <span {...b}>import excel</span> | ||||
| </pre> | ||||
| 
 | ||||
| 17) Close the plugin: | ||||
| 
 | ||||
| ```stata | ||||
| program drop cleanfile | ||||
| ``` | ||||
| 
 | ||||
| 18) Clear the current session: | ||||
| 
 | ||||
| ```stata | ||||
| clear | ||||
| ``` | ||||
| 
 | ||||
| <p>19) In the result of Step 16, click the link on <code><span {...b}>import | ||||
| excel "sheetjs.tmp.xlsx", firstrow</span></code></p> | ||||
| 
 | ||||
| Alternatively, manually type the command: | ||||
| 
 | ||||
| ```stata | ||||
| import excel "sheetjs.tmp.xlsx", firstrow | ||||
| ``` | ||||
| 
 | ||||
| The output will show the import result: | ||||
| 
 | ||||
| <pre> | ||||
| <b>. import excel "sheetjs.tmp.xlsx", firstrow</b>{'\n'} | ||||
| (2 vars, 5 obs) | ||||
| </pre> | ||||
| 
 | ||||
| 20) Open the Data Editor (in Browse or Edit mode) and compare to the screenshot: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| [^1]: Run `help import excel` in Stata or see ["import excel"](https://www.stata.com/manuals/dimportexcel.pdf) in the Stata documentation. | ||||
| [^2]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^3]: See [`write` in "Writing Files"](/docs/api/write-options) | ||||
| @ -194,7 +194,7 @@ Each browser demo was tested in the following environments: | ||||
| | Edge 116    | 2023-09-02 |                                         | | ||||
| | Safari 16.6 | 2023-09-02 | File System Access API is not supported | | ||||
| | Brave 1.57  | 2023-09-02 | File System Access API is not supported | | ||||
| | Firefox 113 | 2023-05-22 | File System Access API is not supported | | ||||
| | Firefox 118 | 2023-10-09 | File System Access API is not supported | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -787,7 +787,7 @@ This demo was last tested in the following deployments: | ||||
| |:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `0.75.1` | 2023-08-26 | | ||||
| | `darwin-arm` | `0.73.0` | 2023-06-05 | | ||||
| | `win10-x64`  | `0.71.2` | 2023-05-23 | | ||||
| | `win10-x64`  | `0.79.2` | 2023-10-09 | | ||||
| | `linux-x64`  | `0.71.2` | 2023-05-23 | | ||||
| | `linux-arm`  | `0.75.1` | 2023-08-30 | | ||||
| 
 | ||||
|  | ||||
| @ -264,7 +264,7 @@ This demo was tested in the following deployments: | ||||
| |:-------------|:-----------|:-----------| | ||||
| | `darwin-x64` | `2788d71`  | 2023-07-24 | | ||||
| | `darwin-arm` | `2788d71`  | 2023-06-05 | | ||||
| | `win10-x64`  | `2788d71`  | 2023-07-24 | | ||||
| | `win10-x64`  | `2788d71`  | 2023-10-09 | | ||||
| | `win11-arm`  | `2788d71`  | 2023-09-25 | | ||||
| | `linux-x64`  | `2788d71`  | 2023-06-02 | | ||||
| | `linux-arm`  | `2788d71`  | 2023-08-29 | | ||||
|  | ||||
| @ -82,6 +82,10 @@ in the [issue tracker](https://git.sheetjs.com/sheetjs/docs.sheetjs.com/issues) | ||||
| - [`Chrome and Chromium Extensions`](/docs/demos/extensions/chromium) | ||||
| - [`Google Sheets + Apps Script`](/docs/demos/extensions/gsheet) | ||||
| - [`AppleScript and OSA`](/docs/demos/extensions/osa) | ||||
| - [`Mathematica`](/docs/demos/extensions/mathematica) | ||||
| - [`MATLAB`](/docs/demos/extensions/matlab) | ||||
| - [`Stata`](/docs/demos/extensions/stata) | ||||
| - [`Maple`](/docs/demos/extensions/maple) | ||||
| 
 | ||||
| ### Cloud Platforms | ||||
| 
 | ||||
|  | ||||
| @ -443,6 +443,16 @@ function add_to_sheet(sheet, cell) { | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| #### Some decimal values are rounded | ||||
| 
 | ||||
| Excel appears to round values in certain cases. It is suspected that the XLSX | ||||
| parser handles 15 decimal digits of precision. This results in inaccuracies such | ||||
| as `7581185.559999999` rounding to `7581185.56` and `7581185.5599999903` | ||||
| rounding to `7581185.55999999`. | ||||
| 
 | ||||
| See [Issue 3003](https://git.sheetjs.com/sheetjs/sheetjs/issues/3003) in the | ||||
| main SheetJS CE repo for details. | ||||
| 
 | ||||
| #### Corrupt files | ||||
| 
 | ||||
| Third-party build tools and frameworks may post-process SheetJS scripts. The | ||||
|  | ||||
| @ -4,7 +4,7 @@ version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| [dependencies] | ||||
| v8 = "0.75.1" | ||||
| v8 = "0.79.2" | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "sheet2csv" | ||||
|  | ||||
							
								
								
									
										131
									
								
								docz/static/stata/cleanfile.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										131
									
								
								docz/static/stata/cleanfile.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | ||||
| #include "stplugin.h" | ||||
| #include "duktape.h" | ||||
| 
 | ||||
| #define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); | ||||
| 
 | ||||
| #define FAIL_DUK(cmd) { \ | ||||
|   const char *errmsg = duk_safe_to_string(ctx, -1); \ | ||||
|   duk_destroy_heap(ctx); \ | ||||
|   snprintf(failbuf, 255, "error in %s: %s", cmd, errmsg); \ | ||||
|   SF_error(failbuf); \ | ||||
|   return NULL; \ | ||||
| } | ||||
| 
 | ||||
| #define FAIL_LOAD { \ | ||||
|   duk_push_undefined(ctx); \ | ||||
|   SF_error("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; | ||||
| } | ||||
| 
 | ||||
| STDLL stata_call(int argc, char *argv[]) | ||||
| { | ||||
|   duk_int_t res = 0; | ||||
|   char failbuf[255]; | ||||
| 
 | ||||
|   /* 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") | ||||
| 
 | ||||
|   /* print SheetJS version number */ | ||||
|   //duk_eval_string(ctx, "XLSX.version");
 | ||||
|   //char verbuf[255];
 | ||||
|   //snprintf(verbuf, 255, "SheetJS library version: %s\n", duk_get_string(ctx, -1));
 | ||||
|   //SF_display(verbuf);
 | ||||
| 
 | ||||
|   /* read file */ | ||||
|   res = load_file(ctx, argv[0], "buf"); | ||||
|   if(res != 0) FAIL_DUK("file load") | ||||
| 
 | ||||
|   /* parse workbook */ | ||||
|   DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); | ||||
| 
 | ||||
|   /* print CSV */ | ||||
|   duk_eval_string(ctx, "wb.SheetNames.length"); | ||||
|   duk_uint_t wscnt = duk_get_uint(ctx, -1); | ||||
|   duk_pop(ctx); | ||||
| 
 | ||||
|   /* if argument 2 is "verbose", print CSV contents */ | ||||
|   if(argc>1 && !strncmp(argv[1], "verbose", 7)) for(uint32_t wsidx = 0; wsidx < wscnt; ++wsidx) { | ||||
|     /* select n-th worksheet */ | ||||
|     char wsbuf[80]; | ||||
|     snprintf(wsbuf, 80, "ws = wb.Sheets[wsname = wb.SheetNames[%d]]", wsidx); \ | ||||
|     DOIT(wsbuf); | ||||
| 
 | ||||
|     duk_eval_string(ctx, "wsname"); | ||||
|     char namebuf[60]; | ||||
|     snprintf(namebuf, 60, "Worksheet %d Name: %s\n", wsidx, duk_get_string(ctx, -1)); | ||||
|     duk_pop(ctx); | ||||
|     SF_display(namebuf); | ||||
| 
 | ||||
|     /* convert to CSV */ | ||||
|     duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)"); | ||||
|     const char *csv = duk_get_string(ctx, -1); | ||||
| 
 | ||||
|     /* print each row in a separate line */ | ||||
|     char *tok = strtok(csv, "\n"); | ||||
|     while(tok != NULL) { | ||||
|       SF_display(tok); | ||||
|       SF_display("\n"); | ||||
|       tok = strtok(NULL, "\n"); | ||||
|     } | ||||
|     duk_pop(ctx); | ||||
|   } | ||||
| 
 | ||||
|   /* write to sheetjs.tmp.xlsx */ | ||||
|   DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'xlsx'}));");\ | ||||
|   res = save_file(ctx, "sheetjs.tmp.xlsx", "newbuf");\ | ||||
|   if(res != 0) FAIL_DUK("save sheetjsw.xlsx") | ||||
| 
 | ||||
|   SF_display("\n"); | ||||
|   SF_display("Saved to `sheetjs.tmp.xlsx`\n"); | ||||
|   SF_display("{stata import excel \"sheetjs.tmp.xlsx\", firstrow} will read the first sheet and use headers\n"); | ||||
|   SF_display("for more help, see {help import excel}\n"); | ||||
|   return(0) ; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/stata/commands.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/stata/commands.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/stata/data-editor.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/stata/data-editor.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.1 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user