forked from inexorabletash/polyfill
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sprintf.js
138 lines (117 loc) · 4.21 KB
/
sprintf.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//
// Format arguments into a string
// var s = sprintf( pattern[, arg1[, arg2[, ... ] ] ] )
// Arguments:
// pattern: format string
//
// Format sequences:
// %[flags][width][.precision]specifier
// flags:
// - left-justify (default is right-justify)
// + show '+' sign if positive
// 0 pad with zeros, if numeric and right-justified (default is space)
// width:
// minimum width; if output would be narrower, padded with padding character
// precision:
// for strings, maximum width (truncated to fit)
// for floating point values, number of decimal places (rounded or padded to fit)
// otherwise, ignored
// specifier:
// % - literal '%' character, e.g. sprintf("we're %d%% complete", percent)
// c - character; numeric arg treated as char code; otherwise first char of arg as string
// s - string
// d - decimal integer, via Math.floor()
// o - octal integer, via Math.floor()
// b - binary integer, via Math.floor()
// x - hexadecimal integer (lowercase, e.g. d00d), via Math.floor()
// X - hexadecimal integer (uppercase, e.g. D00D), via Math.floor()
// f - decimal floating point
//
// Exceptions:
// If insufficient arguments specified, e.g. sprintf("%s %s", "abc")
// Unsupported specifier, e.g. sprintf("%r", obj)
(function (global) {
function sprintf(pattern) {
var arg = 1;
var args = arguments;
function nextarg() {
if (arg >= args.length) {
throw Error("Ran out of arguments: " + arg);
}
return args[arg++];
}
var regex = /([^%]|%([\-+0]*)(\d+)?(\.\d+)?([%csdobxXf]))/g;
function repl(str, unit, flags, width, precision, specifier) {
if (unit.charAt(0) != '%') {
return unit;
}
function toNumber(x) {
if (typeof x === 'number') { return x; }
if (typeof x === 'boolean') { return x ? 1 : 0; }
return parseFloat(String(x));
}
// flags
var left = !!(flags.match(/-/));
var zero = !!(flags.match(/0/));
var sign = !!(flags.match(/\+/));
width = (typeof width === 'string' && width.length > 0) ? parseInt(width, 10) : (void 0);
precision = (typeof precision === 'string' && precision.length > 1) ? parseInt(precision.substring(1), 10) : (void 0);
//console.log(unit, "left=", left, "zero=", zero, "width=", width, "precision=", precision, "specifier=", specifier);
// Stringify
var r, neg;
switch (specifier) {
case '%': // escaped %
return '%';
case 'c': // character - handle both printf('%c',65) and printf('%c','A')
r = nextarg();
if (typeof r === 'number') { r = String.fromCharCode(r); }
r = String(r).charAt(0);
break;
case 's': // string
r = String(nextarg());
if (precision !== (void 0)) { r = r.substring(0, precision); }
break;
case 'd': // decimal
case 'o': // octal
case 'b': // binary
case 'x': // hexadecimal
case 'X': // hexadecimal (uppercase)
case 'f': // floating point
r = toNumber(nextarg());
neg = (r < 0);
r = Math.abs(r);
switch (specifier) {
case 'd': r = Math.floor(r).toString(10); break;
case 'o': r = Math.floor(r).toString(8); break;
case 'b': r = Math.floor(r).toString(2); break;
case 'x': r = Math.floor(r).toString(16).toLowerCase(); break;
case 'X': r = Math.floor(r).toString(16).toUpperCase(); break;
case 'f': r = (precision !== (void 0)) ? r.toFixed(precision) : r.toString(10); break;
}
break;
default:
throw Error("Unsupported formatting specifier: " + specifier);
}
// Format
var pad_len = width ? width - r.length : 0;
var sign_char = '';
if (neg || sign) {
--pad_len;
sign_char = neg ? '-' : '+';
}
var pad_char = (zero && !left) ? '0' : ' ';
var pad = (pad_len > 0) ? (new Array(pad_len + 1)).join(pad_char) : "";
if (left) {
return sign_char + r + pad;
}
else if (zero) {
return sign_char + pad + r;
}
else {
return pad + sign_char + r;
}
}
return pattern.replace(regex, repl);
}
global.sprintf = sprintf;
}(self));