Skip to content

Commit 1a1920c

Browse files
committed
CLI refactor
1 parent 7c19807 commit 1a1920c

File tree

4 files changed

+197
-166
lines changed

4 files changed

+197
-166
lines changed

Diff for: bin/cfb.njs

-166
This file was deleted.

Diff for: packages/cfb-cli/bin/cfb.njs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env node
2+
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
3+
/* eslint-env node */
4+
/* vim: set ts=2 ft=javascript: */
5+
var cli = require('../');
6+
7+
cli();

Diff for: packages/cfb-cli/index.js

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env node
2+
/* index.js (C) 2020-present SheetJS -- http://sheetjs.com */
3+
/* eslint-env node */
4+
/* vim: set ts=2 ft=javascript: */
5+
6+
var n = "cfb-cli";
7+
var X = require('cfb');
8+
var fs = require('fs');
9+
var program = require('commander');
10+
var PRINTJ = require("printj");
11+
function run() {
12+
var sprintf = PRINTJ.sprintf;
13+
program
14+
.version(X.version)
15+
.usage('[options] <file> [subfiles...]')
16+
.option('-l, --list-files', 'list files')
17+
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
18+
.option('-c, --create', 'create file')
19+
.option('-a, --append', 'add files to CFB (overwrite existing data)')
20+
.option('-d, --delete', 'delete files from CFB')
21+
.option('-O, --to-stdout', 'extract raw contents to stdout')
22+
.option('-z, --dump', 'dump internal representation but do not extract')
23+
.option('-q, --quiet', 'process but do not report')
24+
.option('--here', 'skip the CFB root name when extracting')
25+
.option('--osx', 'use OSX-style unzip listing')
26+
.option('--zlib', 'use native zlib')
27+
.option('--local', 'print times in local timezone')
28+
.option('--dev', 'development mode')
29+
.option('--read', 'read but do not print out contents');
30+
program.parse(process.argv);
31+
32+
if (program.zlib) X.utils.use_zlib(require('zlib'));
33+
34+
var exit = process.exit;
35+
var die = function (errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); };
36+
var logit = function (cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); };
37+
38+
if (program.args.length === 0) die(1, "must specify a filename");
39+
40+
if (program.create) {
41+
logit("create", program.args[0]);
42+
var newcfb = X.utils.cfb_new();
43+
X.writeFile(newcfb, program.args[0]);
44+
}
45+
46+
if (!fs.existsSync(program.args[0])) die(1, "must specify a filename");
47+
48+
var opts = ({ type: 'file' }/*:any*/);
49+
if (program.dev) opts.WTF = true;
50+
51+
var cfb = X.read(program.args[0], opts);
52+
if (program.quiet) exit(0);
53+
54+
if (program.dump) {
55+
console.log("Full Paths:");
56+
console.log(cfb.FullPaths.map(function (x/*:string*/) { return " " + x; }).join("\n"));
57+
console.log("File Index:");
58+
console.log(cfb.FileIndex);
59+
exit(0);
60+
}
61+
if (program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
62+
63+
var rlen = cfb.FullPaths[0].length;
64+
65+
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function ($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
66+
var format_date = function (date/*:Date*/, osx/*:?any*/)/*:string*/ {
67+
var datefmt = osx ? "%02u-%02u-%04u %02u:%02u" : "%02u-%02u-%02u %02u:%02u";
68+
var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1;
69+
var DD = program.local ? date.getDate() : date.getUTCDate();
70+
var YY = (program.local ? date.getFullYear() : date.getUTCFullYear()) % (osx ? 10000 : 100);
71+
var hh = program.local ? date.getHours() : date.getUTCHours();
72+
var mm = program.local ? date.getMinutes() : date.getUTCMinutes();
73+
return sprintf(datefmt, MM, DD, YY, hh, mm);
74+
};
75+
76+
if (program.listFiles) {
77+
var basetime = new Date(Date.UTC(1980, 0, 1));
78+
var cnt = 0, rootsize = 0, filesize = 0;
79+
var fmtstr = "%9lu %s %s";
80+
if (program.osx) {
81+
console.log("Archive: " + program.args[0]);
82+
console.log(" Length Date Time Name");
83+
console.log("--------- ---------- ----- ----");
84+
fmtstr = "%9lu %s %s";
85+
} else {
86+
console.log(" Length Date Time Name");
87+
console.log(" -------- ---- ---- ----");
88+
}
89+
cfb.FileIndex.forEach(function (file/*:CFBEntry*/, i/*:number*/) {
90+
switch (file.type) {
91+
case 5:
92+
basetime = file.ct || file.mt || basetime;
93+
rootsize = file.size;
94+
break;
95+
case 2:
96+
var fixname = fix_string(cfb.FullPaths[i]);
97+
if (program.osx && fixname.match(/\\u0001Sh33tJ5/)) return;
98+
if (program.here) fixname = fixname.slice(rlen);
99+
console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname));
100+
filesize += file.size;
101+
++cnt;
102+
}
103+
});
104+
var outfmt = "%9lu %lu file%s";
105+
if (program.osx) {
106+
console.log("--------- -------");
107+
outfmt = "%9lu %lu file%s";
108+
} else {
109+
console.log(" -------- -------");
110+
}
111+
console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
112+
113+
exit(0);
114+
}
115+
116+
function mkdirp(path/*:string*/) {
117+
path.split("/").reduce(function (acc/*:string*/, p/*:string*/) {
118+
acc += p + "/";
119+
if (!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
120+
return acc;
121+
}, "");
122+
}
123+
124+
function write(path/*:string*/, data/*:CFBEntry*/) {
125+
logit("write", fix_string(path));
126+
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0));
127+
}
128+
129+
if (program.create || program.append) {
130+
program.args.slice(1).forEach(function (x/*:string*/) {
131+
logit("append", x);
132+
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
133+
});
134+
X.writeFile(cfb, program.args[0]);
135+
exit(0);
136+
}
137+
138+
if (program.delete) {
139+
program.args.slice(1).forEach(function (x/*:string*/) {
140+
logit("delete", x);
141+
X.utils.cfb_del(cfb, "/" + x);
142+
});
143+
X.writeFile(cfb, program.args[0]);
144+
exit(0);
145+
}
146+
147+
if (program.args.length > 1) {
148+
program.args.slice(1).forEach(function (x/*:string*/) {
149+
var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g, "!"));
150+
if (!data) { console.error(x + ": file not found"); return; }
151+
if (data.type !== 2) { console.error(x + ": not a file"); return; }
152+
var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
153+
if (program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/);
154+
mkdirp(path.slice(0, path.lastIndexOf("/")));
155+
write(path, data);
156+
});
157+
exit(0);
158+
}
159+
160+
if (program.toStdout) exit(0);
161+
for (var i = program.here ? 1 : 0; i !== cfb.FullPaths.length; ++i) {
162+
if (!cfb.FileIndex[i].name) continue;
163+
var fp = cfb.FullPaths[i];
164+
if (program.here) fp = fp.slice(rlen);
165+
if (fp.slice(-1) === "/") mkdirp(fp);
166+
else {
167+
if (fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/")));
168+
write(fp, cfb.FileIndex[i]);
169+
}
170+
}
171+
}
172+
173+
module.exports = run;

Diff for: packages/cfb-cli/package.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "cfb-cli",
3+
"version": "1.0.0",
4+
"description": "Command-line interface for cfb",
5+
"bin": {
6+
"cfb-cli": "./bin/cfb.njs"
7+
},
8+
"main": "index.js",
9+
"author": "Garrett Luu",
10+
"license": "Apache-2.0",
11+
"dependencies": {
12+
"cfb": "^1.1.4",
13+
"commander": "^5.1.0",
14+
"fs": "0.0.1-security",
15+
"printj": "^1.2.2"
16+
}
17+
}

0 commit comments

Comments
 (0)