Ticket #2859: sprintf-update.diff

File sprintf-update.diff, 15.6 KB (added by Shane Grant, 10 years ago)
  • binaries/data/mods/mod/globalscripts/sprintf.js

     
    11/**
    2 sprintf() for JavaScript 0.7-beta1
    3 http://www.diveintojavascript.com/projects/javascript-sprintf
     2sprintf() for JavaScript (10/9/2014)
     3https://github.com/alexei/sprintf.js
    44
    5 Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
     5Copyright (c) 2007-2013, Alexandru Marasteanu <hello [at) alexei (dot] ro>
    66All rights reserved.
    77
    88Redistribution and use in source and binary forms, with or without
    99modification, are permitted provided that the following conditions are met:
    10     * Redistributions of source code must retain the above copyright
    11       notice, this list of conditions and the following disclaimer.
    12     * Redistributions in binary form must reproduce the above copyright
    13       notice, this list of conditions and the following disclaimer in the
    14       documentation and/or other materials provided with the distribution.
    15     * Neither the name of sprintf() for JavaScript nor the
    16       names of its contributors may be used to endorse or promote products
    17       derived from this software without specific prior written permission.
     10* Redistributions of source code must retain the above copyright
     11  notice, this list of conditions and the following disclaimer.
     12* Redistributions in binary form must reproduce the above copyright
     13  notice, this list of conditions and the following disclaimer in the
     14  documentation and/or other materials provided with the distribution.
     15* Neither the name of this software nor the names of its contributors may be
     16  used to endorse or promote products derived from this software without
     17  specific prior written permission.
    1818
    1919THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    2020ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    2121WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    22 DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
    23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     23ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    2424(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    2525LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    2626ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     
    2727(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    2828SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2929
     30**/
    3031
    31 Changelog:
    32 2010.09.06 - 0.7-beta1
    33   - features: vsprintf, support for named placeholders
    34   - enhancements: format cache, reduced global namespace pollution
     32(function(window) {
     33    var re = {
     34        not_string: /[^s]/,
     35        number: /[dief]/,
     36        text: /^[^\x25]+/,
     37        modulo: /^\x25{2}/,
     38        placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fiosuxX])/,
     39        key: /^([a-z_][a-z_\d]*)/i,
     40        key_access: /^\.([a-z_][a-z_\d]*)/i,
     41        index_access: /^\[(\d+)\]/,
     42        sign: /^[\+\-]/
     43    }
    3544
    36 2010.05.22 - 0.6:
    37  - reverted to 0.4 and fixed the bug regarding the sign of the number 0
    38  Note:
    39  Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)
    40  who warned me about a bug in 0.5, I discovered that the last update was
    41  a regress. I appologize for that.
     45    function sprintf() {
     46        var key = arguments[0], cache = sprintf.cache
     47        if (!(cache[key] && cache.hasOwnProperty(key))) {
     48            cache[key] = sprintf.parse(key)
     49        }
     50        return sprintf.format.call(null, cache[key], arguments)
     51    }
    4252
    43 2010.05.09 - 0.5:
    44  - bug fix: 0 is now preceeded with a + sign
    45  - bug fix: the sign was not at the right position on padded results (Kamal Abdali)
    46  - switched from GPL to BSD license
     53    sprintf.format = function(parse_tree, argv) {
     54        var cursor = 1, tree_length = parse_tree.length, node_type = "", arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ""
     55        for (i = 0; i < tree_length; i++) {
     56            node_type = get_type(parse_tree[i])
     57            if (node_type === "string") {
     58                output[output.length] = parse_tree[i]
     59            }
     60            else if (node_type === "array") {
     61                match = parse_tree[i] // convenience purposes only
     62                if (match[2]) { // keyword argument
     63                    arg = argv[cursor]
     64                    for (k = 0; k < match[2].length; k++) {
     65                        if (!arg.hasOwnProperty(match[2][k])) {
     66                            throw new Error(sprintf("[sprintf] property '%s' does not exist", match[2][k]))
     67                        }
     68                        arg = arg[match[2][k]]
     69                    }
     70                }
     71                else if (match[1]) { // positional argument (explicit)
     72                    arg = argv[match[1]]
     73                }
     74                else { // positional argument (implicit)
     75                    arg = argv[cursor++]
     76                }
    4777
    48 2007.10.21 - 0.4:
    49  - unit test and patch (David Baird)
     78                if (get_type(arg) == "function") {
     79                    arg = arg()
     80                }
    5081
    51 2007.09.17 - 0.3:
    52  - bug fix: no longer throws exception on empty paramenters (Hans Pufal)
     82                if (re.not_string.test(match[8]) && (get_type(arg) != "number" && isNaN(arg))) {
     83                    throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
     84                }
    5385
    54 2007.09.11 - 0.2:
    55  - feature: added argument swapping
     86                if (re.number.test(match[8])) {
     87                    is_positive = arg >= 0
     88                }
    5689
    57 2007.04.03 - 0.1:
    58  - initial release
    59 **/
     90                switch (match[8]) {
     91                    case "b":
     92                        arg = arg.toString(2)
     93                    break
     94                    case "c":
     95                        arg = String.fromCharCode(arg)
     96                    break
     97                    case "d":
     98                    case "i":
     99                        arg = parseInt(arg, 10)
     100                    break
     101                    case "e":
     102                        arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential()
     103                    break
     104                    case "f":
     105                        arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
     106                    break
     107                    case "o":
     108                        arg = arg.toString(8)
     109                    break
     110                    case "s":
     111                        arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg)
     112                    break
     113                    case "u":
     114                        arg = arg >>> 0
     115                    break
     116                    case "x":
     117                        arg = arg.toString(16)
     118                    break
     119                    case "X":
     120                        arg = arg.toString(16).toUpperCase()
     121                    break
     122                }
     123                if (re.number.test(match[8]) && (!is_positive || match[3])) {
     124                    sign = is_positive ? "+" : "-"
     125                    arg = arg.toString().replace(re.sign, "")
     126                }
     127                else {
     128                    sign = ""
     129                }
     130                pad_character = match[4] ? match[4] === "0" ? "0" : match[4].charAt(1) : " "
     131                pad_length = match[6] - (sign + arg).length
     132                pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : "") : ""
     133                output[output.length] = match[5] ? sign + arg + pad : (pad_character === "0" ? sign + pad + arg : pad + sign + arg)
     134            }
     135        }
     136        return output.join("")
     137    }
    60138
    61 var sprintf = (function() {
    62     function get_type(variable) {
    63         return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
    64     }
    65     function str_repeat(input, multiplier) {
    66         for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
    67         return output.join('');
    68     }
     139    sprintf.cache = {}
    69140
    70     var str_format = function() {
    71         if (!str_format.cache.hasOwnProperty(arguments[0])) {
    72             str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
    73         }
    74         return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
    75     };
     141    sprintf.parse = function(fmt) {
     142        var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
     143        while (_fmt) {
     144            if ((match = re.text.exec(_fmt)) !== null) {
     145                parse_tree[parse_tree.length] = match[0]
     146            }
     147            else if ((match = re.modulo.exec(_fmt)) !== null) {
     148                parse_tree[parse_tree.length] = "%"
     149            }
     150            else if ((match = re.placeholder.exec(_fmt)) !== null) {
     151                if (match[2]) {
     152                    arg_names |= 1
     153                    var field_list = [], replacement_field = match[2], field_match = []
     154                    if ((field_match = re.key.exec(replacement_field)) !== null) {
     155                        field_list[field_list.length] = field_match[1]
     156                        while ((replacement_field = replacement_field.substring(field_match[0].length)) !== "") {
     157                            if ((field_match = re.key_access.exec(replacement_field)) !== null) {
     158                                field_list[field_list.length] = field_match[1]
     159                            }
     160                            else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
     161                                field_list[field_list.length] = field_match[1]
     162                            }
     163                            else {
     164                                throw new SyntaxError("[sprintf] failed to parse named argument key")
     165                            }
     166                        }
     167                    }
     168                    else {
     169                        throw new SyntaxError("[sprintf] failed to parse named argument key")
     170                    }
     171                    match[2] = field_list
     172                }
     173                else {
     174                    arg_names |= 2
     175                }
     176                if (arg_names === 3) {
     177                    throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
     178                }
     179                parse_tree[parse_tree.length] = match
     180            }
     181            else {
     182                throw new SyntaxError("[sprintf] unexpected placeholder")
     183            }
     184            _fmt = _fmt.substring(match[0].length)
     185        }
     186        return parse_tree
     187    }
    76188
    77     str_format.format = function(parse_tree, argv) {
    78         var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
    79         for (i = 0; i < tree_length; i++) {
    80             node_type = get_type(parse_tree[i]);
    81             if (node_type === 'string') {
    82                 output.push(parse_tree[i]);
    83             }
    84             else if (node_type === 'array') {
    85                 match = parse_tree[i]; // convenience purposes only
    86                 if (match[2]) { // keyword argument
    87                     arg = argv[cursor];
    88                     for (k = 0; k < match[2].length; k++) {
    89                         if (!arg.hasOwnProperty(match[2][k])) {
    90                             throw(new Error('[sprintf] property "' + match[2][k] + '" does not exist.'));
    91                         }
    92                         arg = arg[match[2][k]];
    93                     }
    94                 }
    95                 else if (match[1]) { // positional argument (explicit)
    96                     arg = argv[match[1]];
    97                 }
    98                 else { // positional argument (implicit)
    99                     arg = argv[cursor++];
    100                 }
     189    var vsprintf = function(fmt, argv, _argv) {
     190        _argv = (argv || []).slice(0)
     191        _argv.splice(0, 0, fmt)
     192        return sprintf.apply(null, _argv)
     193    }
    101194
    102                 if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
    103                     throw(new Error('[sprintf] expecting number but found ' + get_type(arg) + '.'));
    104                 }
    105                 switch (match[8]) {
    106                     case 'b': arg = arg.toString(2); break;
    107                     case 'c': arg = String.fromCharCode(arg); break;
    108                     case 'd': arg = parseInt(arg, 10); break;
    109                     case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
    110                     case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
    111                     case 'o': arg = arg.toString(8); break;
    112                     case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
    113                     case 'u': arg = Math.abs(arg); break;
    114                     case 'x': arg = arg.toString(16); break;
    115                     case 'X': arg = arg.toString(16).toUpperCase(); break;
    116                 }
    117                 arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
    118                 pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
    119                 pad_length = match[6] - String(arg).length;
    120                 pad = match[6] ? str_repeat(pad_character, pad_length) : '';
    121                 output.push(match[5] ? arg + pad : pad + arg);
    122             }
    123         }
    124         return output.join('');
    125     };
     195    /**
     196     * helpers
     197     */
     198    function get_type(variable) {
     199        return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
     200    }
    126201
    127     str_format.cache = {};
     202    function str_repeat(input, multiplier) {
     203        return Array(multiplier + 1).join(input)
     204    }
    128205
    129     str_format.parse = function(fmt) {
    130         var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
    131         while (_fmt) {
    132             if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
    133                 parse_tree.push(match[0]);
    134             }
    135             else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
    136                 parse_tree.push('%');
    137             }
    138             else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
    139                 if (match[2]) {
    140                     arg_names |= 1;
    141                     var field_list = [], replacement_field = match[2], field_match = [];
    142                     if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
    143                         field_list.push(field_match[1]);
    144                         while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
    145                             if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
    146                                 field_list.push(field_match[1]);
    147                             }
    148                             else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
    149                                 field_list.push(field_match[1]);
    150                             }
    151                             else {
    152                                 throw(new Error('[sprintf] huh?'));
    153                             }
    154                         }
    155                     }
    156                     else {
    157                         throw(new Error('[sprintf] huh?'));
    158                     }
    159                     match[2] = field_list;
    160                 }
    161                 else {
    162                     arg_names |= 2;
    163                 }
    164                 if (arg_names === 3) {
    165                     throw(new Error('[sprintf] mixing positional and named placeholders is not (yet) supported'));
    166                 }
    167                 parse_tree.push(match);
    168             }
    169             else {
    170                 throw(new Error('[sprintf] No placeholder found in the ‘' + _fmt + '’ format string. Maybe you used an incorrect syntax for your placeholder?'));
    171             }
    172             _fmt = _fmt.substring(match[0].length);
    173         }
    174         return parse_tree;
    175     };
     206    /**
     207     * export to either browser or node.js
     208     */
     209    if (typeof exports !== "undefined") {
     210        exports.sprintf = sprintf
     211        exports.vsprintf = vsprintf
     212    }
     213    else {
     214        window.sprintf = sprintf
     215        window.vsprintf = vsprintf
    176216
    177     return str_format;
    178 })();
    179 
    180 var vsprintf = function(fmt, argv) {
    181     argv.unshift(fmt);
    182     return sprintf.apply(null, argv);
    183 };
     217        if (typeof define === "function" && define.amd) {
     218            define(function() {
     219                return {
     220                    sprintf: sprintf,
     221                    vsprintf: vsprintf
     222                }
     223            })
     224        }
     225    }
     226})(typeof window === "undefined" ? this : window);
     227 No newline at end of file