This repository has been archived by the owner on Dec 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 353
/
sprintf.js
144 lines (123 loc) · 4.42 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
139
140
141
142
143
144
//
// 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()
// i - decimal integer, via |0
// u - decimal integer, via >>>0
// 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+)?([%csiudobxXf]))/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 'i': // int32
case 'u': // uint32
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 'i': r = (r|0).toString(10); break;
case 'u': r = (r>>>0).toString(10); break;
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));