Browse Source

Add JS-based argv and file I/O utils

pull/2259/head
Sami Vaarala 5 years ago
parent
commit
46d6ef7bbe
  1. 25
      src-tools/lib/extbindings/args.js
  2. 79
      src-tools/lib/extbindings/fileio.js
  3. 15
      src-tools/lib/util/buffer.js
  4. 183
      src-tools/lib/util/fs.js

25
src-tools/lib/extbindings/args.js

@ -0,0 +1,25 @@
'use strict';
function getArgs() {
if (typeof process === 'object' && process !== null && process.argv) {
// $ nodejs --zero-fill-buffers test.js --bar
// '/usr/bin/node', '/tmp/test.js', '--bar' ]
//
// Command and script are included, Node.js options are stripped, and
// anything following the script is included. For above we'd return
// [ '--bar' ].
return JSON.parse(JSON.stringify(process.argv.slice(2)));
} else if (typeof sysArgv === 'object' && sysArgv !== null) {
// Duktape, use raw argv, scan for '--', and include anything after
// that as arguments.
for (let i = 0; i < sysArgv.length; i++) {
if (sysArgv[i] === '--') {
return JSON.parse(JSON.stringify(sysArgv.slice(i + 1)));
}
}
return [];
} else {
throw new TypeError('no provider for getArgs');
}
}
exports.getArgs = getArgs;

79
src-tools/lib/extbindings/fileio.js

@ -0,0 +1,79 @@
'use strict';
const global = new Function('return this')();
const { assert } = require('../util/assert');
const { bufferToUint8Array } = require('../util/buffer');
function readFile(filename) {
assert(typeof filename === 'string');
if (typeof global.readFile === 'function') {
// Duktape
let data = Object(global.readFile(filename));
assert(data instanceof Uint8Array);
return data;
} else {
// Node.js
const fs = require('fs');
let data = fs.readFileSync(filename);
assert(data instanceof Buffer);
data = bufferToUint8Array(data);
assert(data instanceof Uint8Array);
return data;
}
}
exports.readFile = readFile;
function readFileUtf8(filename) {
assert(typeof filename === 'string');
var u8 = readFile(filename);
assert(u8 instanceof Uint8Array);
if (typeof TextDecoder === 'function') {
// Duktape or recent Node.js
let data = new TextDecoder().decode(u8);
assert(typeof data === 'string');
return data;
} else {
// Older Node.js
assert(typeof Buffer === 'function');
let data = Buffer.from(u8).toString('utf-8');
assert(typeof data === 'string');
return data;
}
}
exports.readFileUtf8 = readFileUtf8;
function writeFile(filename, data) {
assert(typeof filename === 'string');
assert(data instanceof Uint8Array);
if (typeof global.writeFile === 'function') {
// Duktape
global.writeFile(filename, data);
} else {
// Node.js
const fs = require('fs');
fs.writeFileSync(filename, data);
}
}
exports.writeFile = writeFile;
function writeFileUtf8(filename, data) {
assert(typeof filename === 'string');
assert(typeof data === 'string');
if (typeof TextEncoder === 'function') {
// Duktape or recent Node.js
let u8 = new TextEncoder().encode(data);
assert(u8 instanceof Uint8Array);
writeFile(filename, u8);
} else {
// Older Node.js
assert(typeof Buffer === 'function');
let u8 = bufferToUint8Array(Buffer.from(data, 'utf-8'));
assert(u8 instanceof Uint8Array);
writeFile(filename, u8);
}
}
exports.writeFileUtf8 = writeFileUtf8;

15
src-tools/lib/util/buffer.js

@ -0,0 +1,15 @@
'use strict';
const { assert } = require('./assert');
function bufferToArrayBuffer(buf) {
assert(buf instanceof Buffer);
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}
exports.bufferToArrayBuffer = bufferToArrayBuffer;
function bufferToUint8Array(buf) {
assert(buf instanceof Buffer);
return new Uint8Array(bufferToArrayBuffer(buf));
}
exports.bufferToUint8Array = bufferToUint8Array;

183
src-tools/lib/util/fs.js

@ -0,0 +1,183 @@
'use strict';
const { readFile, readFileUtf8, writeFile, writeFileUtf8 } = require('../extbindings/fileio');
const { isNodejs, isDuktape } = require('./engine_detect');
const { exec } = require('./exec');
// Forward these to hide the extbindings module.
exports.readFile = readFile;
exports.readFileUtf8 = readFileUtf8;
exports.writeFile = writeFile;
exports.writeFileUtf8 = writeFileUtf8;
function pathJoin() {
// > require('path').join('foo/bar/quux.c', '..', 'baz')
// 'foo/bar/baz'
// > require('path').join('foo/bar/', '..', 'baz')
// 'foo/baz'
// > require('path').join('foo/bar', '..', 'baz')
// 'foo/baz'
// > require('path').join('foo/bar', '..', '..', 'baz')
// 'baz'
// > require('path').join('foo/bar', '..', '..', '..', 'baz')
// '../baz'
// > require('path').join('foo/bar', 'baz')
// 'foo/bar/baz'
// > require('path').join('foo/bar', 'baz/')
// 'foo/bar/baz/'
// > require('path').join('foo/bar/')
// 'foo/bar/'
if (isNodejs()) {
const path = require('path');
return path.join.apply(path, arguments);
} else if (isDuktape()) {
let tmp = Array.prototype.map.call(arguments, String).join('/').replace(/\/+/g, '/').split('/');
for (let idx = 0; idx < tmp.length;) {
if (tmp[idx] === '.') {
void tmp.splice(idx, 1);
} else if (tmp[idx] === '..') {
if (idx >= 1) {
void tmp.splice(idx - 1, 2);
idx--;
} else {
// Keep '..' as is if nothing to rewind.
idx++;
}
} else if (tmp[idx] === '' && idx === tmp.length - 1) {
// Keep empty part caused by trailing slash, e.g. 'foo/bar/'.
idx++;
} else {
idx++;
}
}
return tmp.join('/');
} else {
throw new TypeError('no provided for pathJoin');
}
}
exports.pathJoin = pathJoin;
function listDir(dir) {
if (isNodejs()) {
const fs = require('fs');
return fs.readdirSync(dir);
} else if (isDuktape()) {
return exec([ 'ls', dir ]).stdout.split('\n').filter((fn) => fn !== '');
} else {
throw new TypeError('no provider for listDir');
}
}
exports.listDir = listDir;
function getCwd() {
if (isNodejs()) {
return process.cwd();
} else if (isDuktape()) {
return exec([ 'pwd' ]).stdout.split('\n')[0];
} else {
throw new TypeError('no provider for getCwd');
}
}
exports.getCwd = getCwd;
function copyFile(srcFn, dstFn) {
writeFile(dstFn, readFile(srcFn));
}
exports.copyFile = copyFile;
function dirname(pathArg) {
// > require('path').dirname('foo/bar')
// 'foo'
// > require('path').dirname('foo/bar/')
// 'foo'
// > require('path').dirname('foo/bar//')
// 'foo'
// > require('path').dirname('foo/bar/quux')
// 'foo/bar'
// > require('path').dirname('')
// '.'
// > require('path').dirname('foo')
// '.'
if (isNodejs()) {
const path = require('path');
return path.dirname(pathArg);
} else if (isDuktape()) {
let parts = pathArg.replace(/\/+/g, '/').split('/');
if (parts.length >= 1 && parts[parts.length - 1] === '') {
parts.pop(); // strip trailing slash
}
if (parts.length >= 1) {
parts.pop();
}
return parts.join('/') || '.';
} else {
throw new TypeError('no provider for dirname');
}
}
exports.dirname = dirname;
function basename(pathArg) {
// > require('path').basename('foo')
// 'foo'
// > require('path').basename('foo/')
// 'foo'
// > require('path').basename('foo/bar')
// 'bar'
// > require('path').basename('foo/bar.c')
// 'bar.c'
// > require('path').basename('foo/bar.c/')
// 'bar.c'
// > require('path').basename('foo//bar.c//')
// 'bar.c'
// > require('path').basename('')
// ''
// > require('path').basename('.')
// '.'
// > require('path').basename('..')
// '..'
// > require('path').basename('foo/..')
// '..'
if (isNodejs()) {
const path = require('path');
return path.basename(pathArg);
} else if (isDuktape()) {
let parts = pathArg.replace(/\/+/g, '/').split('/');
if (parts.length >= 1 && parts[parts.length - 1] === '') {
parts.pop(); // strip trailing slash
}
if (parts.length >= 1) {
return parts[parts.length - 1];
} else {
return '';
}
} else {
throw new TypeError('no provider for basename');
}
}
exports.basename = basename;
function fileExists(fn) {
if (isNodejs()) {
const fs = require('fs');
return fs.existsSync(fn);
} else if (isDuktape()) {
try {
void readFile(fn);
return true;
} catch (e) {
/* nop */
}
return false;
} else {
throw new TypeError('no provider for fileExists');
}
}
exports.fileExists = fileExists;
function writeFileJsonPretty(fn, doc) {
writeFileUtf8(fn, JSON.stringify(doc, null, 4) + '\n');
}
exports.writeFileJsonPretty = writeFileJsonPretty;
Loading…
Cancel
Save