version bump 1.2.0: ESM version

Fixes #3 h/t @75lb
This commit is contained in:
SheetJS 2018-09-03 23:35:36 -04:00
parent dc687f5ed0
commit e1e33f9cb6
18 changed files with 1411 additions and 50 deletions

40
.spelling Normal file

@ -0,0 +1,40 @@
# printj (C) 2016-present SheetJS -- http://sheetjs.com
SheetJS
printj
printf
# printf-related terms
16-bit
32-bit
52-bit
64-bit
base-10
fmt
# Third-party
AltiVec
FreeBSD
glibc
libc
nodejs
npm
unicode
# Other terms
CommonJS
NaN
UTF-16
accessor
bitwise
codepages
conformant
errno
falsy
runtime
trigraphs
truthy
typeof
valueOf
variadic
whitespace

@ -9,6 +9,7 @@ ULIB=$(shell echo $(LIB) | tr a-z A-Z)
DEPS=$(sort $(wildcard bits/*.js))
TARGET=$(LIB).js
FLOWTARGET=$(LIB).flow.js
MJSTARGET=$(LIB).mjs
FLOWTGTS=$(TARGET) $(AUXTARGETS)
CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
@ -26,6 +27,7 @@ $(FLOWTGTS): %.js : %.flow.js
$(FLOWTARGET): $(DEPS) lib
cp lib/$(REQS).js $(FLOWTARGET)
cp lib/$(REQS).mjs $(MJSTARGET)
bits/01_version.js: package.json
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
@ -75,7 +77,7 @@ fullint: lint old-lint tslint flow mdlint ## Run all checks
.PHONY: lint
lint: $(TARGET) ## Run eslint checks
@eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json bower.json
@eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
.PHONY: old-lint

136
README.md

@ -11,6 +11,67 @@ A self-contained specification of the printf format string is included below in
[support against various printf implementations](#support-summary)
## Table of Contents
<details>
<summary><b>Table of Contents</b> (click to show)</summary>
<!-- toc -->
* [Installation](#installation)
* [Usage](#usage)
* [Testing](#testing)
* [License](#license)
* [Badges](#badges)
- [printf format string specification](#printf-format-string-specification)
+ [Original C Interface](#original-c-interface)
+ [JS and C strings](#js-and-c-strings)
+ [JS Interface](#js-interface)
* [Specifier heritage and regular expression](#specifier-heritage-and-regular-expression)
* [Conversion Specifier Quick Reference Table](#conversion-specifier-quick-reference-table)
* [Parameter Selection](#parameter-selection)
* [Dynamic Specifiers](#dynamic-specifiers)
- [C Data Model](#c-data-model)
+ [Integer Types](#integer-types)
+ [Character and String Types](#character-and-string-types)
+ [Floating Point Number Types](#floating-point-number-types)
* [Implementation](#implementation)
- [Integer Conversions](#integer-conversions)
* [Restricting Integer Values](#restricting-integer-values)
* [Length Specifiers for Integer Conversions](#length-specifiers-for-integer-conversions)
* [Rendering Unsigned Integers in Base 10 ("u" and "U" conversions)](#rendering-unsigned-integers-in-base-10-u-and-u-conversions)
* [Rendering Unsigned Integers in Base 8 ("o" and "O" conversions)](#rendering-unsigned-integers-in-base-8-o-and-o-conversions)
* [Rendering Unsigned Integers in Base 16 ("x" and "X" conversions)](#rendering-unsigned-integers-in-base-16-x-and-x-conversions)
* [Rendering Signed Integers in Base 10 ("d" "i" and "D" conversions)](#rendering-signed-integers-in-base-10-d-i-and-d-conversions)
- [Floating Point Conversions](#floating-point-conversions)
* [Infinity, NaN, and Negative Zero](#infinity-nan-and-negative-zero)
* [Exponential Form ("e" and "E" conversions)](#exponential-form-e-and-e-conversions)
* [Standard Form ("f" and "F" conversions)](#standard-form-f-and-f-conversions)
* [Value-dependent Form ("g" and "G" conversions)](#value-dependent-form-g-and-g-conversions)
* [Hex-Mantissa Decimal-Binary-Exponent Form ("a" and "A" conversions)](#hex-mantissa-decimal-binary-exponent-form-a-and-a-conversions)
- [Character Conversions](#character-conversions)
* [Rendering Strings ("s" and "S" conversions)](#rendering-strings-s-and-s-conversions)
* [Rendering Characters ("c" and "C" conversions)](#rendering-characters-c-and-c-conversions)
- [Non-Numeric Conversions](#non-numeric-conversions)
* [The literal "%" symbol ("%" conversion)](#the-literal-%25-symbol-%25-conversion)
* [Interpreting and Rendering Pointers ("p" conversion)](#interpreting-and-rendering-pointers-p-conversion)
* [Extracting length of a partial conversion ("n" conversion)](#extracting-length-of-a-partial-conversion-n-conversion)
* [Error messages ("m" conversion)](#error-messages-m-conversion)
- [Extensions](#extensions)
* [Rendering Boolean Values ("y" and "Y" conversions)](#rendering-boolean-values-y-and-y-conversions)
* [Rendering JSON ("J" conversion)](#rendering-json-j-conversion)
* [JS typeof and valueOf ("T" and "V" conversion)](#js-typeof-and-valueof-t-and-v-conversion)
* [Rendering Unsigned Integers in Base 2 ("b" and "B" conversions)](#rendering-unsigned-integers-in-base-2-b-and-b-conversions)
- [Miscellaneous Notes](#miscellaneous-notes)
* [Format Characters](#format-characters)
* [JS and C strings](#js-and-c-strings-1)
* [Browser Deviations](#browser-deviations)
* [Support Summary](#support-summary)
<!-- tocstop -->
</details>
## Installation
With [npm](https://www.npmjs.org/package/printj):
@ -30,9 +91,8 @@ The browser exposes a variable `PRINTJ`
When installed globally, npm installs a script `printj` that renders the format
string with the given arguments. Running the script with `-h` displays help.
The script will manipulate `module.exports` if available (e.g. in a CommonJS
`require` context). This is not always desirable. To prevent the behavior,
define `DO_NOT_EXPORT_PRINTJ`
The script will manipulate `module.exports` if available. This is not always
desirable. To prevent the behavior, define `DO_NOT_EXPORT_PRINTJ`
## Usage
@ -125,8 +185,8 @@ but have different interfaces reflecting different input and output behaviors.
Some functions have wide variants that use wide `wchar_t *` strings rather than
normal C `char *`. The following variants are required by the POSIX spec:
| function | max length | output destination | vintage | wide ver |
|------------|------------|-----------------------|---------|------------|
| function | max length | output destination | vintage | wide form |
|:-----------|:-----------|:----------------------|:--------|:-----------|
| `printf` | unbounded | standard output | K&R | `wprintf` |
| `fprintf` | unbounded | stream (`FILE *`) | K&R | `fwprintf` |
| `sprintf` | unbounded | string (`char *`) | K&R | `swprintf` |
@ -185,7 +245,7 @@ various string functions are included at the end of the document.
## Specifier heritage and regular expression
Note: The regular expressions follow perl `/x` style. Whitespace characters
Note: The regular expressions follow Perl `/x` style. Whitespace characters
outside of character classes are ignored. `#` is a comment character and every
character until the end of the line is ignored. To convert to a standard regex:
@ -298,7 +358,7 @@ This implementation explicitly does not support certain non-standard extensions:
| `i` | integral | cast to C `int`, standard form decimal (alias of `d`) |
| `J` | extended | prints objects using JSON or `util.inspect` |
| `m` | misc | prints info about Error objects (JS equivalent of `errno`) |
| `n` | misc | do not print! stores number of chars written to arg `.len` |
| `n` | misc | do not print! store number of chars written to `.len` field |
| `o` | integral | cast to C `unsigned int`, standard form octal |
| `O` | integral | cast to C `unsigned long`, standard form octal |
| `p` | misc | print `"l"` field of object (fake pointer) |
@ -323,8 +383,8 @@ printf("Count to 3: %d %d %d", 1, 2, 3); // Count to 3: 1 2 3
```
POSIX `printf` permits explicit argument selection, bypassing the standard
behavior of using the arguments in order. To select the `n`-th argument, use
`n$` immediately after the `%` token to select an argument for the conversion:
behavior of consuming arguments in order. To specify the argument at position
`n`, use `n$` immediately after the `%` token:
```C
printf("%d %d %d", 1, 2, 3); // 1 2 3 (implicit order 1, 2, 3 )
@ -463,11 +523,11 @@ Numerous "C data models", specifying the bit/byte sizes of the various types,
have been and continue to be used. For example, OSX and other modern 64-bit
UNIX flavors use the "LP64" C data model. 64-bit Windows currently uses the
"LLP64" model. 32-bit systems generally use the "ILP32" model. The 8-bit byte
sizes for the various types under the various models are defined in ctypes.json
sizes for the data types under the various models are defined in `ctypes.json`
in the `Models` object as per the following table:
| type | ctypes.json | LP64 | ILP32 | LLP64 |
|-------------|-------------|-----:|------:|------:|
| type | JSON key | LP64 | ILP32 | LLP64 |
|:------------|:------------|-----:|------:|------:|
| `char` | `char` | 1 | 1 | 1 |
| `short` | `short` | 2 | 2 | 2 |
| `int` | `int` | 4 | 4 | 4 |
@ -555,16 +615,16 @@ is signed or unsigned according to the conversion specifier. If a length is
specified, it overrides the implied length of the conversion. The following
table describes the behavior of this implementation:
| implied C type | ctypes.json | length | conv default |
|:------------------------------------|:------------|:------:|:-------------|
| `int` or `unsigned int` | `int` | (none) | d i o u x X |
| `char` or `unsigned char` | `char` | hh |
| `short` or `unsigned short` | `short` | h |
| `long` or `unsigned long` | `long` | l | D U O |
| `long long` or `unsigned long long` | `longlong` | L ll q |
| `intmax_t` or `uintmax_t` | `intmax_t` | j |
| `size_t` or `ssize_t` | `size_t` | z Z |
| `ptrdiff_t` or unsigned variant | `ptrdiff_t` | t |
| implied C type | JSON key | length | conversion default |
|:-----------------------------|:------------|:--------:|:-------------------|
| `[unsigned] int` | `int` | (none) | `d i o u x X` |
| `[unsigned] char` | `char` | `hh` |
| `[unsigned] short` | `short` | `h` |
| `[unsigned] long` | `long` | `l` | `D U O` |
| `[unsigned] long long` | `longlong` | `L ll q` |
| `intmax_t` or `uintmax_t` | `intmax_t` | `j` |
| `size_t` or `ssize_t` | `size_t` | `z Z` |
| `ptrdiff_t` or unsigned form | `ptrdiff_t` | `t` |
## Rendering Unsigned Integers in Base 10 ("u" and "U" conversions)
@ -615,7 +675,7 @@ JS recognizes a few special IEEE754 values, as described in the following table:
|------------:|:--------------|:-----------------------------------------------|
| `Infinity` | `1./0.` | Positive limiting value `lim{x->0+} 1/x` |
| `-Infinity` | `-1./0.` | Negative limiting value `lim{x->0+} -1/x` |
| `NaN` | `0./0.` | Placeholder for "not-a-number" e.g. `0./0.` |
| `NaN` | `0./0.` | Placeholder for "not-a-number" such as `0./0.` |
| `-0.` | `-1/Infinity` | Negative limiting value `lim{x->0-} x` |
JS `Number` methods render different strings from the POSIX spec:
@ -625,7 +685,7 @@ JS `Number` methods render different strings from the POSIX spec:
| `Infinity` | `"inf" "INF"` or `"infinity" "INFINITY"` | `"Infinity"` |
| `-Infinity` | `"-inf" "-INF"` or `"-infinity" "-INFINITY"` | `"-Infinity"` |
| `NaN` | `"[-]nan" "[-]NAN"` w/opt parenthesized chars | `"NaN"` |
| `-0.` | uses negative sign (e.g. `"-0"` under `"%f"`) | same as `+0.` |
| `-0.` | uses negative sign (`"-0"` under `"%f"`) | same as `+0.` |
This implementation performs the required adjustments.
@ -656,12 +716,12 @@ The final form (exponential or standard) is determined based on the value. The
threshold is different from the JS `toString` / `toPrecision` thresholds and
depends on the specified precision as well as the base-10 exponent:
| Value | `"%.3g"` | `toPrecision(3)` |
|----------:|:-----------|:-----------------|
| 1.2345e-4 | `0.000123` | `0.000123` |
| 1.2345e-5 | `1.23e-05` | `0.0000123` |
| 1.2345e-6 | `1.23e-06` | `0.00000123` |
| 1.2345e-7 | `1.23e-07` | `1.23e-7` |
| Value | `"%.3g"` | `toPrecision(3)` |
|------------:|:-----------|:-----------------|
| `1.2345e-4` | `0.000123` | `0.000123` |
| `1.2345e-5` | `1.23e-05` | `0.0000123` |
| `1.2345e-6` | `1.23e-06` | `0.00000123` |
| `1.2345e-7` | `1.23e-07` | `1.23e-7` |
According to JS spec, `toPrecision` uses standard form when `precision > E` and
`E >= -6`. For printf standard form is used when `precision > E` and `E >= -4`.
@ -673,20 +733,20 @@ the exponent expression, and radix of the exponent expression. The standard
exponential form uses decimal for all three parts. For base 16, there are quite
a few reasonable combinations. Consider the value `1.234567e-80`:
| Mant | Exp Base | Radix-10 (sigil `";"`) | Radix-16 (sigil `";"`) |
|:----:|:--------:|:-----------------------|:-----------------------|
| 10 | 10 | `1.234567;-80` | `1.234567;-50` |
| 16 | 10 | `1.3c0c9539b8887;-80` | `1.3c0c9539b8887;-50` |
| 16 | 16 | `5.daf8c8f5f4104;-67` | `5.daf8c8f5f4104;-43` |
| 16 | 4 | `1.76be323d7d041;-133` | `1.76be323d7d041;-85` |
| 16 | 2 | `1.76be323d7d041;-266` | `1.76be323d7d041;-10a` |
| Mantissa | Exp Base | Radix 10 (sigil `";"`) | Radix 16 (sigil `";"`) |
|:--------:|:--------:|:-----------------------|:-----------------------|
| 10 | 10 | `1.234567;-80` | `1.234567;-50` |
| 16 | 10 | `1.3c0c9539b8887;-80` | `1.3c0c9539b8887;-50` |
| 16 | 16 | `5.daf8c8f5f4104;-67` | `5.daf8c8f5f4104;-43` |
| 16 | 4 | `1.76be323d7d041;-133` | `1.76be323d7d041;-85` |
| 16 | 2 | `1.76be323d7d041;-266` | `1.76be323d7d041;-10a` |
POSIX `"%a"` uses a hex mantissa (16), decimal exponent radix (10), and binary
exponent base (2). The general normalized form requires that the integral part
of the mantissa to exceed 0 and not to exceed `exponent base - 1` except in the
special case of `0`. The sigil is `p` and exponent sign is always used.
JS `num.toString(radix)` is implementation-dependent for valid non-10 radices
JS `num.toString(radix)` is implementation-dependent for radices other than 10
(`2-9, 11-36`). IE uses hex-mantissa decimal-hex-exponent form when the
absolute value of the base-2 exponent exceeds 60. Otherwise, IE uses an exact
standard hexadecimal form. Chrome, Safari and other browsers always use the

@ -4,6 +4,11 @@
/*exported PRINTJ */
/*:: declare var DO_NOT_EXPORT_PRINTJ:?boolean; */
/*:: declare function define(cb:()=>any):void; */
#ifdef USE_ESM
var PRINTJ/*:PRINTJModule*/ = /*::(*/{}/*:: :any)*/;
#include "01_version.js"
export const version = PRINTJ.version;
#else
var PRINTJ/*:PRINTJModule*/;
(function (factory/*:(a:any)=>void*/)/*:void*/ {
/*jshint ignore:start */
@ -27,3 +32,4 @@ var PRINTJ/*:PRINTJModule*/;
/*jshint ignore:end */
}(function(PRINTJ/*:PRINTJModule*/) {
#include "01_version.js"
#endif

@ -1 +1 @@
PRINTJ.version = '1.1.2';
PRINTJ.version = '1.2.0';

@ -1,10 +1,13 @@
#include "30_ctypes.js"
#include "40_macros.js"
#ifdef USE_ESM
var u_inspect/*:(o:any)=>string*/ = JSON.stringify;
#else
/*:: var util = require('util'); */
/*global process:true, util:true, require:true */
if(typeof process !== 'undefined' && !!process.versions && !!process.versions.node) util=require("util");
var u_inspect/*:(o:any)=>string*/ = (typeof util != 'undefined') ? util.inspect : JSON.stringify;
#endif
function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ {
var o/*:Array<string>*/ = [];

@ -35,7 +35,7 @@
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
O = (arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
PREC_STR(O, prec)
WIDTH(O, width, flags)

1
bits/99_esmfoot.js Normal file

@ -0,0 +1 @@
export { sprintf, vsprintf };

@ -2,8 +2,8 @@ ifndef OUTDIR
OUTDIR=$(PWD)/lib
endif
JSFILES=$(wildcard *.js)
LIBS=$(filter-out $(wildcard [0-9]*_*.js),$(wildcard *.js))
JSFILES=$(wildcard *.js) $(wildcard *.mjs)
LIBS=$(filter-out $(wildcard [0-9]*_*.js),$(JSFILES))
OUTLIBS=$(patsubst %,$(OUTDIR)/%,$(LIBS))

8
bits/loop_code.mjs Normal file

@ -0,0 +1,8 @@
#define USE_ESM
#include "00_header.js"
#define USE_LOOP
#define USE_CODE
#include "10_tokenize.js"
#include "50_doit.js"
#include "80_wrapper.js"
#include "99_esmfoot.js"

582
lib/loop_code.mjs Normal file

@ -0,0 +1,582 @@
/* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint sub:true, eqnull:true */
/*exported PRINTJ */
/*:: declare var DO_NOT_EXPORT_PRINTJ:?boolean; */
/*:: declare function define(cb:()=>any):void; */
var PRINTJ/*:PRINTJModule*/ = /*::(*/{}/*:: :any)*/;
PRINTJ.version = '1.2.0';
export const version = PRINTJ.version;
function tokenize(fmt/*:string*/)/*:ParsedFmt*/ {
var out/*:ParsedFmt*/ = [];
var start/*:number*/ = 0;
var i/*:number*/ = 0;
var infmt/*:boolean*/ = false;
var fmtparam/*:string*/ = "", fmtflags/*:string*/ = "", fmtwidth/*:string*/ = "", fmtprec/*:string*/ = "", fmtlen/*:string*/ = "";
var c/*:number*/ = 0;
var L/*:number*/ = fmt.length;
for(; i < L; ++i) {
c = fmt.charCodeAt(i);
if(!infmt) {
if(c !== 37) continue;
if(start < i) out.push(["L", fmt.substring(start, i)]);
start = i;
infmt = true;
continue;
}
if(c >= 48 && c < 58) {
if(fmtprec.length) fmtprec += String.fromCharCode(c);
else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c);
else fmtwidth += String.fromCharCode(c);
} else switch(c) {
/* positional */
case 36:
if(fmtprec.length) fmtprec += "$";
else if(fmtwidth.charAt(0) == "*") fmtwidth += "$";
else { fmtparam = fmtwidth + "$"; fmtwidth = ""; }
break;
/* flags */
case 39: fmtflags += "'"; break;
case 45: fmtflags += "-"; break;
case 43: fmtflags += "+"; break;
case 32: fmtflags += " "; break;
case 35: fmtflags += "#"; break;
/* width and precision */
case 46: fmtprec = "."; break;
case 42:
if(fmtprec.charAt(0) == ".") fmtprec += "*";
else fmtwidth += "*";
break;
/* length */
case 104:
case 108:
if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c);
fmtlen += String.fromCharCode(c);
break;
case 76:
case 106:
case 122:
case 116:
case 113:
case 90:
case 119:
if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c);
fmtlen = String.fromCharCode(c);
break;
case 73:
if(fmtlen !== "") throw "bad length " + fmtlen + 'I';
fmtlen = 'I';
break;
/* conversion */
case 100:
case 105:
case 111:
case 117:
case 120:
case 88:
case 102:
case 70:
case 101:
case 69:
case 103:
case 71:
case 97:
case 65:
case 99:
case 67:
case 115:
case 83:
case 112:
case 110:
case 68:
case 85:
case 79:
case 109:
case 98:
case 66:
case 121:
case 89:
case 74:
case 86:
case 84:
case 37:
infmt = false;
if(fmtprec.length > 1) fmtprec = fmtprec.substr(1);
out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]);
start = i+1;
fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = "";
break;
default:
throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|");
}
}
if(start < fmt.length) out.push(["L", fmt.substring(start)]);
return out;
}
//#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
var padstr/*:{[s:string]:string}*/ = {
" ": " ",
"0": "000000000000000000000000000000000",
"7": "777777777777777777777777777777777",
"f": "fffffffffffffffffffffffffffffffff"
};
var u_inspect/*:(o:any)=>string*/ = JSON.stringify;
function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ {
var o/*:Array<string>*/ = [];
var argidx/*:number*/ = 0, idx/*:number*/ = 0;
var Vnum/*:number*/ = 0;
var pad/*:string*/ = "";
for(var i/*:number*/ = 0; i < t.length; ++i) {
var m/*:ParsedEntry*/ = t[i], c/*:number*/ = (m[0]/*:string*/).charCodeAt(0);
/* m order: conv full param flags width prec length */
if(c === /*L*/ 76) { o.push(m[1]); continue; }
if(c === /*%*/ 37) { o.push("%"); continue; }
var O/*:string*/ = "";
var isnum/*:number*/ = 0, radix/*:number*/ = 10, bytes/*:number*/ = 4, sign/*:boolean*/ = false;
/* flags */
var flags/*:string*/ = m[3]||"";
var alt/*:boolean*/ = flags.indexOf("#") > -1;
/* position */
if(m[2]) argidx = parseInt(m[2])-1;
/* %m special case */
else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; }
/* grab width */
var width = 0; if(m[ 4] != null && m[ 4].length > 0) { if(m[ 4].charAt(0) !== '*') width = parseInt(m[ 4], 10); else if(m[ 4].length === 1) width = args[idx++]; else width = args[parseInt(m[ 4].substr(1), 10)-1]; }
/* grab precision */
var prec = -1; if(m[ 5] != null && m[ 5].length > 0) { if(m[ 5].charAt(0) !== '*') prec = parseInt(m[ 5], 10); else if(m[ 5].length === 1) prec = args[idx++]; else prec = args[parseInt(m[ 5].substr(1), 10)-1]; }
/* position not specified */
if(!m[2]) argidx = idx++;
/* grab argument */
var arg/*:any*/ = args[argidx];
/* grab length */
var len/*:string*/ = m[6] || "";
switch(c) {
/* str cCsS */
case /*S*/ 83:
case /*s*/ 115:
/* only valid flag is "-" for left justification */
O = String(arg);
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* first char of string or convert */
case /*C*/ 67:
case /*c*/ 99:
switch(typeof arg) {
case "number":
var cc/*:number*/ = arg;
if(c == 67 || len.charCodeAt(0) === /*l*/ 108) { cc &= 0xFFFFFFFF; O = String.fromCharCode( cc); }
else { cc &= 0xFF; O = String.fromCharCode( cc); }
break;
case "string": O = /*::(*/arg/*:: :string)*/.charAt(0); break;
default: O = String(arg).charAt(0);
}
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* int diDuUoOxXbB */
/* signed integer */
case /*D*/ 68: bytes = 8;
/* falls through */
case /*d*/ 100:
case /*i*/ 105: isnum = -1; sign = true; break;
/* unsigned integer */
case /*U*/ 85: bytes = 8;
/* falls through */
case /*u*/ 117: isnum = -1; break;
/* unsigned octal */
case /*O*/ 79: bytes = 8;
/* falls through */
case /*o*/ 111: isnum = -1; radix = (8); break;
/* unsigned hex */
case /*x*/ 120: isnum = -1; radix = (-16); break;
case /*X*/ 88: isnum = -1; radix = (16); break;
/* unsigned binary (extension) */
case /*B*/ 66: bytes = 8;
/* falls through */
case /*b*/ 98: isnum = -1; radix = (2); break;
/* flt fegFEGaA */
/* floating point logic */
case /*F*/ 70:
case /*f*/ 102: isnum = (1); break;
case /*E*/ 69:
case /*e*/ 101: isnum = (2); break;
case /*G*/ 71:
case /*g*/ 103: isnum = (3); break;
/* floating hex */
case /*A*/ 65:
case /*a*/ 97: isnum = (4); break;
/* misc pnmJVTyY */
/* JS has no concept of pointers so interpret the `l` key as an address */
case /*p*/ 112:
Vnum = typeof arg == "number" ? arg : arg ? Number(arg.l) : -1;
if(isNaN(Vnum)) Vnum = -1;
if(alt) O = Vnum.toString(10);
else {
Vnum = Math.abs(Vnum);
O = "0x" + Vnum.toString(16).toLowerCase();
}
break;
/* store length in the `len` key */
case /*n*/ 110:
if(arg) { arg.len=0; for(var oo/*:number*/ = 0; oo < o.length; ++oo) arg.len += o[oo].length; }
continue;
/* process error */
case /*m*/ 109:
if(!(arg instanceof Error)) O = "Success";
else if(arg.message) O = arg.message;
else if(arg.errno) O = "Error number " + arg.errno;
else O = "Error " + String(arg);
break;
/* JS-specific conversions (extension) */
case /*J*/ 74: O = (alt ? u_inspect : JSON.stringify)(arg); break;
case /*V*/ 86: O = arg == null ? "null" : String(arg.valueOf()); break;
case /*T*/ 84:
if(alt) { /* from '[object %s]' extract %s */
O = Object.prototype.toString.call(arg).substr(8);
O = O.substr(0, O.length - 1);
} else O = typeof arg;
break;
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = (arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
}
if(width < 0) { width = -width; flags += "-"; }
if(isnum == -1) {
Vnum = Number(arg);
/* parse byte length field */
switch(len) {
/* char */
case "hh": { bytes = 1; } break;
/* short */
case "h": { bytes = 2; } break;
/* long */
case "l": { if(bytes == 4) bytes = 8; } break;
/* long long */
case "L":
case "q":
case "ll": { if(bytes == 4) bytes = 8; } break;
/* intmax_t */
case "j": { if(bytes == 4) bytes = 8; } break;
/* ptrdiff_t */
case "t": { if(bytes == 4) bytes = 8; } break;
/* size_t */
case "z":
case "Z": { if(bytes == 4) bytes = 8; } break;
/* CRT size_t or ptrdiff_t */
case "I":
{ if(bytes == 4) bytes = 8; }
break;
/* CRT wchar_t */
case "w": break;
}
/* restrict value */
switch(bytes) {
case 1: Vnum = (Vnum & 0xFF); if(sign && (Vnum > 0x7F)) Vnum -= (0xFF + 1); break;
case 2: Vnum = (Vnum & 0xFFFF); if(sign && (Vnum > 0x7FFF)) Vnum -= (0xFFFF + 1); break;
case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break;
default: Vnum = isNaN(Vnum) ? 0 : Math.round(Vnum); break;
}
/* generate string */
if(bytes > 4 && Vnum < 0 && !sign) {
if(radix == 16 || radix == -16) {
O = (Vnum>>>0).toString(16);
Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32));
O = (Vnum>>>0).toString(16) + (8 - O.length >= 0 ? padstr[ "0"].substr(0,8 - O.length) : "") + O;
O = (16 - O.length >= 0 ? padstr[ "f"].substr(0,16 - O.length) : "") + O;
if(radix == 16) O = O.toUpperCase();
} else if(radix == 8) {
O = (Vnum>>>0).toString(8);
O = (10 - O.length >= 0 ? padstr[ "0"].substr(0,10 - O.length) : "") + O;
Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30));
O = (Vnum>>>0).toString(8) + O.substr(O.length - 10);
O = O.substr(O.length - 20);
O = "1" + (21 - O.length >= 0 ? padstr[ "7"].substr(0,21 - O.length) : "") + O;
} else {
Vnum = (-Vnum) % 1e16;
var d1/*:Array<number>*/ = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6];
var di/*:number*/ = d1.length - 1;
while(Vnum > 0) {
if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; }
--di; Vnum = Math.floor(Vnum / 10);
}
O = d1.join("");
}
} else {
if(radix === -16) O = Vnum.toString(16).toLowerCase();
else if(radix === 16) O = Vnum.toString(16).toUpperCase();
else O = Vnum.toString(radix);
}
/* apply precision */
if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */
else {
if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) {
if(O.substr(0,1) != "-") O = (prec - O.length >= 0 ? padstr[ "0"].substr(0,prec - O.length) : "") + O;
else O = O.substr(0,1) + (prec + 1 - O.length >= 0 ? padstr[ "0"].substr(0,prec + 1 - O.length) : "") + O.substr(1);
}
/* add prefix for # form */
if(!sign && alt && Vnum !== 0) switch(radix) {
case -16: O = "0x" + O; break;
case 16: O = "0X" + O; break;
case 8: if(O.charAt(0) != "0") O = "0" + O; break;
case 2: O = "0b" + O; break;
}
}
/* add sign character */
if(sign && O.charAt(0) != "-") {
if(flags.indexOf("+") > -1) O = "+" + O;
else if(flags.indexOf(" ") > -1) O = " " + O;
}
/* width */
if(width > 0) {
if(O.length < width) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) {
if(prec > O.length) O = ((prec - O.length) >= 0 ? padstr[ "0"].substr(0,(prec - O.length)) : "") + O;
pad = ((width - O.length) >= 0 ? padstr[ (prec > 0 ? " " : "0")].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
}
} else if(isnum > 0) {
Vnum = Number(arg);
if(arg === null) Vnum = 0/0;
if(len == "L") bytes = 12;
var isf/*:boolean*/ = isFinite(Vnum);
if(!isf) { /* Infinity or NaN */
if(Vnum < 0) O = "-";
else if(flags.indexOf("+") > -1) O = "+";
else if(flags.indexOf(" ") > -1) O = " ";
O += (isNaN(Vnum)) ? "nan" : "inf";
} else {
var E/*:number*/ = 0;
if(prec == -1 && isnum != 4) prec = 6;
/* g/G conditional behavior */
if(isnum == 3) {
O = Vnum.toExponential(1);
E = +O.substr(O.indexOf("e") + 1);
if(prec === 0) prec = 1;
if(prec > E && E >= -4) { isnum = (11); prec = prec -(E + 1); }
else { isnum = (12); prec = prec - 1; }
}
/* sign: workaround for negative zero */
var sg/*:string*/ = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : "";
if(Vnum < 0) Vnum = -Vnum;
switch(isnum) {
/* f/F standard */
case 1: case 11:
if(Vnum < 1e21) {
O = Vnum.toFixed(prec);
if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; }
else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,"");
else if(O.indexOf(".") == -1) O+= ".";
break;
}
O = Vnum.toExponential(20);
E = +O.substr(O.indexOf("e")+1);
O = O.charAt(0) + O.substr(2,O.indexOf("e")-2);
O = O + (E - O.length + 1 >= 0 ? padstr[ "0"].substr(0,E - O.length + 1) : "");
if(alt || (prec > 0 && isnum !== 11)) O = O + "." + (prec >= 0 ? padstr[ "0"].substr(0,prec) : "");
break;
/* e/E exponential */
case 2: case 12:
O = Vnum.toExponential(prec);
E = O.indexOf("e");
if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2);
if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E);
else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e");
break;
/* a/A hex */
case 4:
if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+(prec >= 0 ? padstr["0"].substr(0,prec) : ""):"")+"p+0"; break;}
O = Vnum.toString(16);
/* First char 0-9 */
var ac/*:number*/ = O.charCodeAt(0);
if(ac == 48) {
ac = 2; E = -4; Vnum *= 16;
while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; }
O = Vnum.toString(16);
ac = O.charCodeAt(0);
}
var ai/*:number*/ = O.indexOf(".");
if(O.indexOf("(") > -1) {
/* IE exponential form */
var am/*:?Array<any>*/ = O.match(/\(e(.*)\)/);
var ae/*:number*/ = am ? (+am[1]) : 0;
E += 4 * ae; Vnum /= Math.pow(16, ae);
} else if(ai > 1) {
E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1);
} else if(ai == -1) {
E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1);
}
/* at this point 1 <= Vnum < 16 */
if(bytes > 8) {
if(ac < 50) { E -= 3; Vnum *= 8; }
else if(ac < 52) { E -= 2; Vnum *= 4; }
else if(ac < 56) { E -= 1; Vnum *= 2; }
/* at this point 8 <= Vnum < 16 */
} else {
if(ac >= 56) { E += 3; Vnum /= 8; }
else if(ac >= 52) { E += 2; Vnum /= 4; }
else if(ac >= 50) { E += 1; Vnum /= 2; }
/* at this point 1 <= Vnum < 2 */
}
O = Vnum.toString(16);
if(O.length > 1) {
if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) {
var _f/*:boolean*/ = O.charCodeAt(0) == 102;
O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16);
if(_f && O.charCodeAt(0) == 49) E += 4;
}
if(prec > 0) {
O = O.substr(0, prec + 2);
if(O.length < prec + 2) {
if(O.charCodeAt(0) < 48) O = O.charAt(0) + ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "") + O.substr(1);
else O += ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "");
}
} else if(prec === 0) O = O.charAt(0) + (alt ? "." : "");
} else if(prec > 0) O = O + "." + (prec >= 0 ? padstr["0"].substr(0,prec) : "");
else if(alt) O = O + ".";
O = "0x" + O + "p" + (E>=0 ? "+" + E : E);
break;
}
if(sg === "") {
if(flags.indexOf("+") > -1) sg = "+";
else if(flags.indexOf(" ") > -1) sg = " ";
}
O = sg + O;
}
/* width */
if(width > O.length) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) {
pad = ((width - O.length) >= 0 ? padstr[ "0"].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
if(c < 96) O = O.toUpperCase();
}
o.push(O);
}
return o.join("");
}
function vsprintf(fmt/*:string*/, args/*:Args*/)/*:string*/ { return doit(tokenize(fmt), args); }
function sprintf(/*:: ...argz*/)/*:string*/ {
var args/*:Array<any>*/ = new Array(arguments.length - 1);
for(var i/*:number*/ = 0; i < args.length; ++i) args[i] = arguments[i+1];
return doit(tokenize(arguments[0]), args);
}
export { sprintf, vsprintf };

@ -1,6 +1,6 @@
{
"name": "printj",
"version": "1.1.2",
"version": "1.2.0",
"author": "sheetjs",
"description": "Pure-JS printf",
"keywords": [
@ -49,7 +49,7 @@
]
},
"homepage": "http://sheetjs.com/opensource",
"files": ["printj.js", "bin/printj.njs", "LICENSE", "README.md", "dist/*.js", "dist/*.map", "dist/LICENSE", "types/index.d.ts", "types/*.json"],
"files": ["printj.js", "printj.mjs", "bin/printj.njs", "LICENSE", "README.md", "dist/*.js", "dist/*.map", "dist/LICENSE", "types/index.d.ts", "types/*.json"],
"bugs": {
"url": "https://github.com/SheetJS/printj/issues"
},

@ -4,6 +4,7 @@
/*exported PRINTJ */
/*:: declare var DO_NOT_EXPORT_PRINTJ:?boolean; */
/*:: declare function define(cb:()=>any):void; */
var PRINTJ/*:PRINTJModule*/;
(function (factory/*:(a:any)=>void*/)/*:void*/ {
/*jshint ignore:start */
@ -27,7 +28,7 @@ var PRINTJ/*:PRINTJModule*/;
/*jshint ignore:end */
}(function(PRINTJ/*:PRINTJModule*/) {
PRINTJ.version = '1.1.2';
PRINTJ.version = '1.2.0';
function tokenize(fmt/*:string*/)/*:ParsedFmt*/ {
var out/*:ParsedFmt*/ = [];
@ -311,7 +312,7 @@ function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ {
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
O = (arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }

@ -25,7 +25,7 @@ var PRINTJ;
/*jshint ignore:end */
}(function(PRINTJ) {
PRINTJ.version = '1.1.2';
PRINTJ.version = '1.2.0';
function tokenize(fmt) {
var out = [];
@ -308,7 +308,7 @@ function doit(t, args) {
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
O = (arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }

582
printj.mjs Normal file

@ -0,0 +1,582 @@
/* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint sub:true, eqnull:true */
/*exported PRINTJ */
/*:: declare var DO_NOT_EXPORT_PRINTJ:?boolean; */
/*:: declare function define(cb:()=>any):void; */
var PRINTJ/*:PRINTJModule*/ = /*::(*/{}/*:: :any)*/;
PRINTJ.version = '1.2.0';
export const version = PRINTJ.version;
function tokenize(fmt/*:string*/)/*:ParsedFmt*/ {
var out/*:ParsedFmt*/ = [];
var start/*:number*/ = 0;
var i/*:number*/ = 0;
var infmt/*:boolean*/ = false;
var fmtparam/*:string*/ = "", fmtflags/*:string*/ = "", fmtwidth/*:string*/ = "", fmtprec/*:string*/ = "", fmtlen/*:string*/ = "";
var c/*:number*/ = 0;
var L/*:number*/ = fmt.length;
for(; i < L; ++i) {
c = fmt.charCodeAt(i);
if(!infmt) {
if(c !== 37) continue;
if(start < i) out.push(["L", fmt.substring(start, i)]);
start = i;
infmt = true;
continue;
}
if(c >= 48 && c < 58) {
if(fmtprec.length) fmtprec += String.fromCharCode(c);
else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c);
else fmtwidth += String.fromCharCode(c);
} else switch(c) {
/* positional */
case 36:
if(fmtprec.length) fmtprec += "$";
else if(fmtwidth.charAt(0) == "*") fmtwidth += "$";
else { fmtparam = fmtwidth + "$"; fmtwidth = ""; }
break;
/* flags */
case 39: fmtflags += "'"; break;
case 45: fmtflags += "-"; break;
case 43: fmtflags += "+"; break;
case 32: fmtflags += " "; break;
case 35: fmtflags += "#"; break;
/* width and precision */
case 46: fmtprec = "."; break;
case 42:
if(fmtprec.charAt(0) == ".") fmtprec += "*";
else fmtwidth += "*";
break;
/* length */
case 104:
case 108:
if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c);
fmtlen += String.fromCharCode(c);
break;
case 76:
case 106:
case 122:
case 116:
case 113:
case 90:
case 119:
if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c);
fmtlen = String.fromCharCode(c);
break;
case 73:
if(fmtlen !== "") throw "bad length " + fmtlen + 'I';
fmtlen = 'I';
break;
/* conversion */
case 100:
case 105:
case 111:
case 117:
case 120:
case 88:
case 102:
case 70:
case 101:
case 69:
case 103:
case 71:
case 97:
case 65:
case 99:
case 67:
case 115:
case 83:
case 112:
case 110:
case 68:
case 85:
case 79:
case 109:
case 98:
case 66:
case 121:
case 89:
case 74:
case 86:
case 84:
case 37:
infmt = false;
if(fmtprec.length > 1) fmtprec = fmtprec.substr(1);
out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]);
start = i+1;
fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = "";
break;
default:
throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|");
}
}
if(start < fmt.length) out.push(["L", fmt.substring(start)]);
return out;
}
//#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
var padstr/*:{[s:string]:string}*/ = {
" ": " ",
"0": "000000000000000000000000000000000",
"7": "777777777777777777777777777777777",
"f": "fffffffffffffffffffffffffffffffff"
};
var u_inspect/*:(o:any)=>string*/ = JSON.stringify;
function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ {
var o/*:Array<string>*/ = [];
var argidx/*:number*/ = 0, idx/*:number*/ = 0;
var Vnum/*:number*/ = 0;
var pad/*:string*/ = "";
for(var i/*:number*/ = 0; i < t.length; ++i) {
var m/*:ParsedEntry*/ = t[i], c/*:number*/ = (m[0]/*:string*/).charCodeAt(0);
/* m order: conv full param flags width prec length */
if(c === /*L*/ 76) { o.push(m[1]); continue; }
if(c === /*%*/ 37) { o.push("%"); continue; }
var O/*:string*/ = "";
var isnum/*:number*/ = 0, radix/*:number*/ = 10, bytes/*:number*/ = 4, sign/*:boolean*/ = false;
/* flags */
var flags/*:string*/ = m[3]||"";
var alt/*:boolean*/ = flags.indexOf("#") > -1;
/* position */
if(m[2]) argidx = parseInt(m[2])-1;
/* %m special case */
else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; }
/* grab width */
var width = 0; if(m[ 4] != null && m[ 4].length > 0) { if(m[ 4].charAt(0) !== '*') width = parseInt(m[ 4], 10); else if(m[ 4].length === 1) width = args[idx++]; else width = args[parseInt(m[ 4].substr(1), 10)-1]; }
/* grab precision */
var prec = -1; if(m[ 5] != null && m[ 5].length > 0) { if(m[ 5].charAt(0) !== '*') prec = parseInt(m[ 5], 10); else if(m[ 5].length === 1) prec = args[idx++]; else prec = args[parseInt(m[ 5].substr(1), 10)-1]; }
/* position not specified */
if(!m[2]) argidx = idx++;
/* grab argument */
var arg/*:any*/ = args[argidx];
/* grab length */
var len/*:string*/ = m[6] || "";
switch(c) {
/* str cCsS */
case /*S*/ 83:
case /*s*/ 115:
/* only valid flag is "-" for left justification */
O = String(arg);
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* first char of string or convert */
case /*C*/ 67:
case /*c*/ 99:
switch(typeof arg) {
case "number":
var cc/*:number*/ = arg;
if(c == 67 || len.charCodeAt(0) === /*l*/ 108) { cc &= 0xFFFFFFFF; O = String.fromCharCode( cc); }
else { cc &= 0xFF; O = String.fromCharCode( cc); }
break;
case "string": O = /*::(*/arg/*:: :string)*/.charAt(0); break;
default: O = String(arg).charAt(0);
}
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* int diDuUoOxXbB */
/* signed integer */
case /*D*/ 68: bytes = 8;
/* falls through */
case /*d*/ 100:
case /*i*/ 105: isnum = -1; sign = true; break;
/* unsigned integer */
case /*U*/ 85: bytes = 8;
/* falls through */
case /*u*/ 117: isnum = -1; break;
/* unsigned octal */
case /*O*/ 79: bytes = 8;
/* falls through */
case /*o*/ 111: isnum = -1; radix = (8); break;
/* unsigned hex */
case /*x*/ 120: isnum = -1; radix = (-16); break;
case /*X*/ 88: isnum = -1; radix = (16); break;
/* unsigned binary (extension) */
case /*B*/ 66: bytes = 8;
/* falls through */
case /*b*/ 98: isnum = -1; radix = (2); break;
/* flt fegFEGaA */
/* floating point logic */
case /*F*/ 70:
case /*f*/ 102: isnum = (1); break;
case /*E*/ 69:
case /*e*/ 101: isnum = (2); break;
case /*G*/ 71:
case /*g*/ 103: isnum = (3); break;
/* floating hex */
case /*A*/ 65:
case /*a*/ 97: isnum = (4); break;
/* misc pnmJVTyY */
/* JS has no concept of pointers so interpret the `l` key as an address */
case /*p*/ 112:
Vnum = typeof arg == "number" ? arg : arg ? Number(arg.l) : -1;
if(isNaN(Vnum)) Vnum = -1;
if(alt) O = Vnum.toString(10);
else {
Vnum = Math.abs(Vnum);
O = "0x" + Vnum.toString(16).toLowerCase();
}
break;
/* store length in the `len` key */
case /*n*/ 110:
if(arg) { arg.len=0; for(var oo/*:number*/ = 0; oo < o.length; ++oo) arg.len += o[oo].length; }
continue;
/* process error */
case /*m*/ 109:
if(!(arg instanceof Error)) O = "Success";
else if(arg.message) O = arg.message;
else if(arg.errno) O = "Error number " + arg.errno;
else O = "Error " + String(arg);
break;
/* JS-specific conversions (extension) */
case /*J*/ 74: O = (alt ? u_inspect : JSON.stringify)(arg); break;
case /*V*/ 86: O = arg == null ? "null" : String(arg.valueOf()); break;
case /*T*/ 84:
if(alt) { /* from '[object %s]' extract %s */
O = Object.prototype.toString.call(arg).substr(8);
O = O.substr(0, O.length - 1);
} else O = typeof arg;
break;
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = (arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
}
if(width < 0) { width = -width; flags += "-"; }
if(isnum == -1) {
Vnum = Number(arg);
/* parse byte length field */
switch(len) {
/* char */
case "hh": { bytes = 1; } break;
/* short */
case "h": { bytes = 2; } break;
/* long */
case "l": { if(bytes == 4) bytes = 8; } break;
/* long long */
case "L":
case "q":
case "ll": { if(bytes == 4) bytes = 8; } break;
/* intmax_t */
case "j": { if(bytes == 4) bytes = 8; } break;
/* ptrdiff_t */
case "t": { if(bytes == 4) bytes = 8; } break;
/* size_t */
case "z":
case "Z": { if(bytes == 4) bytes = 8; } break;
/* CRT size_t or ptrdiff_t */
case "I":
{ if(bytes == 4) bytes = 8; }
break;
/* CRT wchar_t */
case "w": break;
}
/* restrict value */
switch(bytes) {
case 1: Vnum = (Vnum & 0xFF); if(sign && (Vnum > 0x7F)) Vnum -= (0xFF + 1); break;
case 2: Vnum = (Vnum & 0xFFFF); if(sign && (Vnum > 0x7FFF)) Vnum -= (0xFFFF + 1); break;
case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break;
default: Vnum = isNaN(Vnum) ? 0 : Math.round(Vnum); break;
}
/* generate string */
if(bytes > 4 && Vnum < 0 && !sign) {
if(radix == 16 || radix == -16) {
O = (Vnum>>>0).toString(16);
Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32));
O = (Vnum>>>0).toString(16) + (8 - O.length >= 0 ? padstr[ "0"].substr(0,8 - O.length) : "") + O;
O = (16 - O.length >= 0 ? padstr[ "f"].substr(0,16 - O.length) : "") + O;
if(radix == 16) O = O.toUpperCase();
} else if(radix == 8) {
O = (Vnum>>>0).toString(8);
O = (10 - O.length >= 0 ? padstr[ "0"].substr(0,10 - O.length) : "") + O;
Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30));
O = (Vnum>>>0).toString(8) + O.substr(O.length - 10);
O = O.substr(O.length - 20);
O = "1" + (21 - O.length >= 0 ? padstr[ "7"].substr(0,21 - O.length) : "") + O;
} else {
Vnum = (-Vnum) % 1e16;
var d1/*:Array<number>*/ = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6];
var di/*:number*/ = d1.length - 1;
while(Vnum > 0) {
if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; }
--di; Vnum = Math.floor(Vnum / 10);
}
O = d1.join("");
}
} else {
if(radix === -16) O = Vnum.toString(16).toLowerCase();
else if(radix === 16) O = Vnum.toString(16).toUpperCase();
else O = Vnum.toString(radix);
}
/* apply precision */
if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */
else {
if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) {
if(O.substr(0,1) != "-") O = (prec - O.length >= 0 ? padstr[ "0"].substr(0,prec - O.length) : "") + O;
else O = O.substr(0,1) + (prec + 1 - O.length >= 0 ? padstr[ "0"].substr(0,prec + 1 - O.length) : "") + O.substr(1);
}
/* add prefix for # form */
if(!sign && alt && Vnum !== 0) switch(radix) {
case -16: O = "0x" + O; break;
case 16: O = "0X" + O; break;
case 8: if(O.charAt(0) != "0") O = "0" + O; break;
case 2: O = "0b" + O; break;
}
}
/* add sign character */
if(sign && O.charAt(0) != "-") {
if(flags.indexOf("+") > -1) O = "+" + O;
else if(flags.indexOf(" ") > -1) O = " " + O;
}
/* width */
if(width > 0) {
if(O.length < width) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) {
if(prec > O.length) O = ((prec - O.length) >= 0 ? padstr[ "0"].substr(0,(prec - O.length)) : "") + O;
pad = ((width - O.length) >= 0 ? padstr[ (prec > 0 ? " " : "0")].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
}
} else if(isnum > 0) {
Vnum = Number(arg);
if(arg === null) Vnum = 0/0;
if(len == "L") bytes = 12;
var isf/*:boolean*/ = isFinite(Vnum);
if(!isf) { /* Infinity or NaN */
if(Vnum < 0) O = "-";
else if(flags.indexOf("+") > -1) O = "+";
else if(flags.indexOf(" ") > -1) O = " ";
O += (isNaN(Vnum)) ? "nan" : "inf";
} else {
var E/*:number*/ = 0;
if(prec == -1 && isnum != 4) prec = 6;
/* g/G conditional behavior */
if(isnum == 3) {
O = Vnum.toExponential(1);
E = +O.substr(O.indexOf("e") + 1);
if(prec === 0) prec = 1;
if(prec > E && E >= -4) { isnum = (11); prec = prec -(E + 1); }
else { isnum = (12); prec = prec - 1; }
}
/* sign: workaround for negative zero */
var sg/*:string*/ = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : "";
if(Vnum < 0) Vnum = -Vnum;
switch(isnum) {
/* f/F standard */
case 1: case 11:
if(Vnum < 1e21) {
O = Vnum.toFixed(prec);
if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; }
else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,"");
else if(O.indexOf(".") == -1) O+= ".";
break;
}
O = Vnum.toExponential(20);
E = +O.substr(O.indexOf("e")+1);
O = O.charAt(0) + O.substr(2,O.indexOf("e")-2);
O = O + (E - O.length + 1 >= 0 ? padstr[ "0"].substr(0,E - O.length + 1) : "");
if(alt || (prec > 0 && isnum !== 11)) O = O + "." + (prec >= 0 ? padstr[ "0"].substr(0,prec) : "");
break;
/* e/E exponential */
case 2: case 12:
O = Vnum.toExponential(prec);
E = O.indexOf("e");
if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2);
if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E);
else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e");
break;
/* a/A hex */
case 4:
if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+(prec >= 0 ? padstr["0"].substr(0,prec) : ""):"")+"p+0"; break;}
O = Vnum.toString(16);
/* First char 0-9 */
var ac/*:number*/ = O.charCodeAt(0);
if(ac == 48) {
ac = 2; E = -4; Vnum *= 16;
while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; }
O = Vnum.toString(16);
ac = O.charCodeAt(0);
}
var ai/*:number*/ = O.indexOf(".");
if(O.indexOf("(") > -1) {
/* IE exponential form */
var am/*:?Array<any>*/ = O.match(/\(e(.*)\)/);
var ae/*:number*/ = am ? (+am[1]) : 0;
E += 4 * ae; Vnum /= Math.pow(16, ae);
} else if(ai > 1) {
E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1);
} else if(ai == -1) {
E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1);
}
/* at this point 1 <= Vnum < 16 */
if(bytes > 8) {
if(ac < 50) { E -= 3; Vnum *= 8; }
else if(ac < 52) { E -= 2; Vnum *= 4; }
else if(ac < 56) { E -= 1; Vnum *= 2; }
/* at this point 8 <= Vnum < 16 */
} else {
if(ac >= 56) { E += 3; Vnum /= 8; }
else if(ac >= 52) { E += 2; Vnum /= 4; }
else if(ac >= 50) { E += 1; Vnum /= 2; }
/* at this point 1 <= Vnum < 2 */
}
O = Vnum.toString(16);
if(O.length > 1) {
if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) {
var _f/*:boolean*/ = O.charCodeAt(0) == 102;
O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16);
if(_f && O.charCodeAt(0) == 49) E += 4;
}
if(prec > 0) {
O = O.substr(0, prec + 2);
if(O.length < prec + 2) {
if(O.charCodeAt(0) < 48) O = O.charAt(0) + ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "") + O.substr(1);
else O += ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "");
}
} else if(prec === 0) O = O.charAt(0) + (alt ? "." : "");
} else if(prec > 0) O = O + "." + (prec >= 0 ? padstr["0"].substr(0,prec) : "");
else if(alt) O = O + ".";
O = "0x" + O + "p" + (E>=0 ? "+" + E : E);
break;
}
if(sg === "") {
if(flags.indexOf("+") > -1) sg = "+";
else if(flags.indexOf(" ") > -1) sg = " ";
}
O = sg + O;
}
/* width */
if(width > O.length) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) {
pad = ((width - O.length) >= 0 ? padstr[ "0"].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
if(c < 96) O = O.toUpperCase();
}
o.push(O);
}
return o.join("");
}
function vsprintf(fmt/*:string*/, args/*:Args*/)/*:string*/ { return doit(tokenize(fmt), args); }
function sprintf(/*:: ...argz*/)/*:string*/ {
var args/*:Array<any>*/ = new Array(arguments.length - 1);
for(var i/*:number*/ = 0; i < args.length; ++i) args[i] = arguments[i+1];
return doit(tokenize(arguments[0]), args);
}
export { sprintf, vsprintf };

70
tests/mjs.html Normal file

@ -0,0 +1,70 @@
<!DOCTYPE html>
<!-- printj.js (C) 2016-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>PRINTJ Live Demo</title>
<style>
table, td {
border: 1px dotted black;
text-align: left;
}
</style>
</head>
<body>
<b>PRINTJ ESM Live Demo</b><br />
<a href="https://git.io/printj">Source Code Repo</a><br />
<a href="https://git.io/printj_issues">Issues? Something look weird? Click here and report an issue</a><br />
<br />
<pre>
usage: import { sprintf as printf } from './printj.mjs';
This implementation supports the full POSIX set of conversions. Consult the enclosed README for full details.
</pre>
<div><a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html">POSIX documentation</a></div><br />
<table id="data">
<tr><th>example</th><th>result</th></tr>
</table>
<script type="module">
/* eslint-env browser */
/*global PRINTJ */
import { sprintf as printf } from './printj.mjs';
var table = document.getElementById("data");
var ex = [
'printf("|Hello %s|", "SheetJS")',
'printf("|%1$d %1$o %1$u %1$x %1$X|", 1234)',
'printf("|%1$d %1$o %1$u %1$x %1$X|", -1234)',
'printf("|%1$d %1$o %1$u %1$x %1$X %1$lld|", 2813308004)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", 1.2)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Math.PI)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Math.LOG2E)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", -Math.LOG10E)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Infinity)',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", -0)',
'printf("|%012s|", "SheetJS")',
'printf("|%-12s|", "SheetJS")',
'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", 1.4142E69)',
'printf("%%")'
];
window.onload = function() {
printf("Hello %s", "world");
ex.forEach(function(m) {
var row = table.insertRow(table.rows.length);
var c1 = row.insertCell(0); c1.innerHTML = "<pre>" + m + "</pre>";
var c2 = row.insertCell(1); c2.innerHTML = "<pre>" + eval(m) + "</pre>";
});
};
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

5
tests/node.mjs Executable file

@ -0,0 +1,5 @@
#!/usr/bin/env node --experimental-modules
import { version, sprintf } from '../printj.mjs'
console.log(sprintf("PRINTJ version %s, 123 = 0x%02hhx", version, 123));

1
tests/printj.mjs Symbolic link

@ -0,0 +1 @@
../printj.mjs