diff --git a/Build.app.htm b/Build.app.htm new file mode 100644 index 0000000..0461f39 --- /dev/null +++ b/Build.app.htm @@ -0,0 +1,5685 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// diff --git a/README.markdown b/README.markdown index e5127a5..675a764 100644 --- a/README.markdown +++ b/README.markdown @@ -1 +1,14 @@ xxd in the browser. (Default behavior only.) + + +Building +======== + +Using `Build.app.htm` (for example, after double clicking it and then pointing +it at the project source tree), build trplkt by running the following command: + + build ./main.src + +(If you prefer to do the build from the terminal, you can also do so using +NodeJS; you'd type `node ./Build.app.htm $BUILDCOMMAND`, where `$BUILDCOMMAND` +is the command given above.) diff --git a/main.src b/main.src new file mode 100644 index 0000000..92844d0 --- /dev/null +++ b/main.src @@ -0,0 +1,23 @@ +import { XXD } from "./src/XXD.src" + +import { SystemB } from "./src/SystemB.src" +import { SystemC } from "./src/SystemC.src" + +void function main() { + if (!system) var system = SystemA.init(SystemB); + if (!system) var system = SystemA.init(SystemC); + + if (!system) { + throw new Error("Unknown environment"); + } + + system.setUpForExec({ + run: function(system, path) { + return system.read(path).then((contents) => { + let xxd = (new XXD(contents)); + xxd.exec(); + system.print(xxd.output); + }); + } + }); +} () diff --git a/src/SystemA.src b/src/SystemA.src new file mode 100644 index 0000000..fbc1b58 --- /dev/null +++ b/src/SystemA.src @@ -0,0 +1,22 @@ +export +class SystemA { + run() { + throw new Error("unimplemented!"); + } + + read(path) { + throw new Error("unimplemented!"); + } + + print(bytes) { + throw new Error("unimplemented!"); + } + + static init($kind) { + try { + return new $kind; + } catch (ex) { + return null; + } + } +} diff --git a/src/SystemB.src b/src/SystemB.src new file mode 100644 index 0000000..7bc766d --- /dev/null +++ b/src/SystemB.src @@ -0,0 +1,79 @@ +import { SystemA } from "./SystemA.src" + +export +class SystemB extends SystemA { + constructor() { + super(); + + if (typeof(window) == "undefined") { + throw new Error("Not a browser environment"); + } + + this._page = window.document.body; + + this._app = null; + this._file = null; + this._fileInput = null; + } + + setUpForExec(app) { + this._app = app; + + this._page.onload = (() => { + this._page.innerHTML = ""; + + this._page.style.fontFamily = "monospace"; + this._page.style.whiteSpace = "pre-wrap"; + + let doc = this._page.ownerDocument; + let $$ = doc.createElement.bind(doc); + + let button = $$("input"); + button.type = "button"; + button.value = "Load\u2026"; + button.style.float = "right"; + button.onclick = () => void(this._fileInput.click()); + this._page.appendChild(button); + + let fileInput = $$("input"); + fileInput.type = "file"; + fileInput.style.display = "none"; + fileInput.onchange = this._onFileSelected.bind(this); + this._fileInput = this._page.appendChild(fileInput); + + this._page.appendChild($$("div")).id = "container"; + }) + } + + _onFileSelected(event) { + this._file = event.target.files[0]; + let path = this._file.webkitRelativePath; + this._app.run(this, path); + } + + read(path) { + return new Promise((resolve, reject) => { + if (path == this._file.webkitRelativePath) { + if (typeof(FileReader) != "undefined") { + let reader = new FileReader(); + + reader.addEventListener("loadend", (event) => { + resolve(new Uint8Array(event.target.result)); + }); + + return void(reader.readAsArrayBuffer(this._file)); + } + return reject(Error("FileReader API not implemented")); + } + return reject(Error("Cannot read file with path: " + path)); + }); + } + + print(output) { + var message = ""; + for (let i = 0, n = output.length; i < n; i++) { + message += String.fromCharCode(output[i]); + } + this._page.textContent = message; + } +} diff --git a/src/SystemC.src b/src/SystemC.src new file mode 100644 index 0000000..4161f4d --- /dev/null +++ b/src/SystemC.src @@ -0,0 +1,75 @@ +import { SystemA } from "./SystemA.src" + +export +class SystemC extends SystemA { + constructor() { + super(); + + if (typeof(process) == "undefined") { + throw new Error("Not a NodeJS environment"); + } + + let [ engine, script, ...args ] = process.argv; + this.args = args; + + this._nodeFS = process.mainModule.require("fs"); + this._nodePath = process.mainModule.require("path"); + + const { FileNodeFSAdapter } = SystemC; + + this._files = new FileNodeFSAdapter(this._nodeFS, this._nodePath); + } + + setUpForExec(app) { + if (this.args.length == 1) { + return void(app.run(this, this.args[0])); + } + throw new Error("Expected file path"); + } + + read(path) { + return this._files.read(path, true); + } + + print(output) { + var message = ""; + for (let i = 0, n = output.length; i < n; i++) { + message += String.fromCharCode(output[i]); + } + + if (typeof(console) != "undefined") { + console.log(message); + } else { // should not happen, but the typeof check is unavoidable + throw new Error("Cannot print message " + JSON.stringify(message)); + } + } +} + +SystemC.FileNodeFSAdapter = class FileNodeFSAdapter { + constructor(fs, path, workDir = ".") { + this._nodeFS = fs; + this._nodePath = path; + this._workDir = workDir; + } + + read(path, raw) { + if (!path.startsWith("/")) { + path = this._nodePath.join(this._workDir, path); + } + if (!raw) { + var options = { encoding: "utf8" }; + } + + return new Promise((resolve, reject) => { + void this._nodeFS.readFile(path, options, (err, contents) => { + if (err) { + reject(err); + } else if (!raw) { + resolve(contents); + } else { + resolve(Uint8Array.from(contents)); + } + }); + }); + } +}