| 31 | } |
| 32 | |
| 33 | function sprintf_format(parse_tree, argv) { |
| 34 | var cursor = 1, tree_length = parse_tree.length, arg, output = '', i, k, ph, pad, pad_character, pad_length, is_positive, sign |
| 35 | for (i = 0; i < tree_length; i++) { |
| 36 | if (typeof parse_tree[i] === 'string') { |
| 37 | output += parse_tree[i] |
| 38 | } |
| 39 | else if (typeof parse_tree[i] === 'object') { |
| 40 | ph = parse_tree[i] // convenience purposes only |
| 41 | if (ph.keys) { // keyword argument |
| 42 | arg = argv[cursor] |
| 43 | for (k = 0; k < ph.keys.length; k++) { |
| 44 | if (arg == undefined) { |
| 45 | throw new Error(sprintf('[sprintf] Cannot access property "%s" of undefined value "%s"', ph.keys[k], ph.keys[k-1])) |
| 46 | } |
| 47 | arg = arg[ph.keys[k]] |
| 48 | } |
| 49 | } |
| 50 | else if (ph.param_no) { // positional argument (explicit) |
| 51 | arg = argv[ph.param_no] |
| 52 | } |
| 53 | else { // positional argument (implicit) |
| 54 | arg = argv[cursor++] |
| 55 | } |
| 56 | |
| 57 | if (re.not_type.test(ph.type) && re.not_primitive.test(ph.type) && arg instanceof Function) { |
| 58 | arg = arg() |
| 59 | } |
| 60 | |
| 61 | if (re.numeric_arg.test(ph.type) && (typeof arg !== 'number' && isNaN(arg))) { |
| 62 | throw new TypeError(sprintf('[sprintf] expecting number but found %T', arg)) |
| 63 | } |
| 64 | |
| 65 | if (re.number.test(ph.type)) { |
| 66 | is_positive = arg >= 0 |
| 67 | } |
| 68 | |
| 69 | switch (ph.type) { |
| 70 | case 'b': |
| 71 | arg = parseInt(arg, 10).toString(2) |
| 72 | break |
| 73 | case 'c': |
| 74 | arg = String.fromCharCode(parseInt(arg, 10)) |
| 75 | break |
| 76 | case 'd': |
| 77 | case 'i': |
| 78 | arg = parseInt(arg, 10) |
| 79 | break |
| 80 | case 'j': |
| 81 | arg = JSON.stringify(arg, null, ph.width ? parseInt(ph.width) : 0) |
| 82 | break |
| 83 | case 'e': |
| 84 | arg = ph.precision ? parseFloat(arg).toExponential(ph.precision) : parseFloat(arg).toExponential() |
| 85 | break |
| 86 | case 'f': |
| 87 | arg = ph.precision ? parseFloat(arg).toFixed(ph.precision) : parseFloat(arg) |
| 88 | break |
| 89 | case 'g': |
| 90 | arg = ph.precision ? String(Number(arg.toPrecision(ph.precision))) : parseFloat(arg) |