1#!/usr/bin/env node
2/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
3/* eslint-env node */
4/* vim: set ts=2 ft=javascript: */
5/*jshint node:true */
6
7var X/*:CRC32Module*/;
8try { X = require('../'); } catch(e) { X = require('crc-32'); }
9
10function help()/*:number*/ {
11[
12"usage: crc32 [options] [filename]",
13"",
14"Options:",
15"    -h, --help           output usage information",
16"    -V, --version        output the version number",
17"    -S, --seed=<n>       use integer seed as starting value (rolling CRC)",
18"    -H, --hex-seed=<h>   use hex seed as starting value (rolling CRC)",
19"    -d, --signed         print result with format `%d` (default)",
20"    -u, --unsigned       print result with format `%u`",
21"    -x, --hex            print result with format `%0.8x`",
22"    -X, --HEX            print result with format `%0.8X`",
23"    -F, --format=<s>     use specified printf format",
24"",
25"Set filename = '-' or pipe data into crc32 to read from stdin",
26"Default output mode is signed (-d)",
27""
28].forEach(function(l) { console.log(l); });
29	return 0;
30}
31
32function version()/*:number*/ { console.log(X.version); return 0; }
33
34var fs = require('fs');
35require('exit-on-epipe');
36
37function die(msg/*:string*/, ec/*:?number*/)/*:void*/ { console.error(msg); process.exit(ec || 0); }
38
39var args/*:Array<string>*/ = process.argv.slice(2);
40var filename/*:string*/ = "";
41var fmt/*:string*/ = "";
42var seed = 0, r = 10;
43
44for(var i = 0; i < args.length; ++i) {
45	var arg = args[i];
46	if(arg.charCodeAt(0) != 45) { if(filename === "") filename = arg; continue; }
47	var m = arg.indexOf("=") == -1 ? arg : arg.substr(0, arg.indexOf("="));
48	switch(m) {
49		case "-": filename = "-"; break;
50
51		case "--help":     case "-h": process.exit(help()); break;
52		case "--version":  case "-V": process.exit(version()); break;
53
54		case "--signed":   case "-d": fmt = "%d"; break;
55		case "--unsigned": case "-u": fmt = "%u"; break;
56		case "--hex":      case "-x": fmt = "%0.8x"; break;
57		case "--HEX":      case "-X": fmt = "%0.8X"; break;
58		case "--format":   case "-F":
59			fmt = ((m!=arg) ? arg.substr(m.length+1) : args[++i])||""; break;
60
61		case "--hex-seed": case "-H": r = 16;
62		/* falls through */
63		case "--seed":     case "-S":
64			seed=parseInt((m!=arg) ? arg.substr(m.length+1) : args[++i], r)||0; break;
65
66		default: die("crc32: unrecognized option `" + arg + "'", 22);
67	}
68}
69
70if(!process.stdin.isTTY) filename = filename || "-";
71if(filename.length===0) die("crc32: must specify a filename ('-' for stdin)",1);
72
73var crc32 = seed;
74// $FlowIgnore -- Writable is callable but type sig disagrees
75var writable = require('stream').Writable();
76writable._write = function(chunk, e, cb) { crc32 = X.buf(chunk, crc32); cb(); };
77writable._writev = function(chunks, cb) {
78	chunks.forEach(function(c) { crc32 = X.buf(c.chunk, crc32);});
79	cb();
80};
81writable.on('finish', function() {
82	console.log(fmt === "" ? crc32 : require("printj").sprintf(fmt, crc32));
83});
84
85if(filename === "-") process.stdin.pipe(writable);
86else if(fs.existsSync(filename)) fs.createReadStream(filename).pipe(writable);
87else die("crc32: " + filename + ": No such file or directory", 2);
88