tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sprintf.js (11917B)


      1 /**
      2 * Copyright (c) 2007-2016, Alexandru Marasteanu <hello [at) alexei (dot] ro>
      3 * All rights reserved.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions are met:
      7 * * Redistributions of source code must retain the above copyright
      8 *   notice, this list of conditions and the following disclaimer.
      9 * * Redistributions in binary form must reproduce the above copyright
     10 *   notice, this list of conditions and the following disclaimer in the
     11 *   documentation and/or other materials provided with the distribution.
     12 * * Neither the name of this software nor the names of its contributors may be
     13 *   used to endorse or promote products derived from this software without
     14 *   specific prior written permission.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 *
     27 */
     28 
     29 /* eslint-disable */
     30 /* globals window, exports, define */
     31 
     32 (function(window) {
     33    'use strict'
     34 
     35    var re = {
     36        not_string: /[^s]/,
     37        not_bool: /[^t]/,
     38        not_type: /[^T]/,
     39        not_primitive: /[^v]/,
     40        number: /[diefg]/,
     41        numeric_arg: /bcdiefguxX/,
     42        json: /[j]/,
     43        not_json: /[^j]/,
     44        text: /^[^\x25]+/,
     45        modulo: /^\x25{2}/,
     46        placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijosStTuvxX])/,
     47        key: /^([a-z_][a-z_\d]*)/i,
     48        key_access: /^\.([a-z_][a-z_\d]*)/i,
     49        index_access: /^\[(\d+)\]/,
     50        sign: /^[\+\-]/
     51    }
     52 
     53    function sprintf() {
     54        var key = arguments[0], cache = sprintf.cache
     55        if (!(cache[key] && cache.hasOwnProperty(key))) {
     56            cache[key] = sprintf.parse(key)
     57        }
     58        return sprintf.format.call(null, cache[key], arguments)
     59    }
     60 
     61    sprintf.format = function(parse_tree, argv) {
     62        var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ''
     63        for (i = 0; i < tree_length; i++) {
     64            node_type = typeof parse_tree[i]
     65            // The items of parse tree are either strings or results of a match() call.
     66            if (node_type === 'string') {
     67                // this is not a placeholder, this is just a string.
     68                output[output.length] = parse_tree[i]
     69            }
     70            else {
     71                // this is a placeholder, need to identify its type, options and replace
     72                // it with the appropriate argument.
     73                match = parse_tree[i] // convenience purposes only
     74                if (match[2]) { // keyword argument
     75                    arg = argv[cursor]
     76                    for (k = 0; k < match[2].length; k++) {
     77                        if (!arg.hasOwnProperty(match[2][k])) {
     78                            throw new Error(sprintf('[sprintf] property "%s" does not exist', match[2][k]))
     79                        }
     80                        arg = arg[match[2][k]]
     81                    }
     82                }
     83                else if (match[1]) { // positional argument (explicit)
     84                    arg = argv[match[1]]
     85                }
     86                else { // positional argument (implicit)
     87                    arg = argv[cursor++]
     88                }
     89 
     90                // The most commonly used placeholder in DevTools is the string (%S or %s).
     91                // We check it first to avoid unnecessary verifications.
     92                let hasPadding = match[6];
     93                let patternType = match[8];
     94                if (!hasPadding && (patternType === "S" || patternType === "s")) {
     95                    if (typeof arg === "function") {
     96                        arg = arg();
     97                    }
     98                    if (typeof arg !== "string") {
     99                        arg = String(arg);
    100                    }
    101                    output[output.length] = match[7] ? arg.substring(0, match[7]) : arg;
    102                    continue;
    103                }
    104 
    105                if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && typeof arg == 'function') {
    106                    arg = arg()
    107                }
    108 
    109                if (re.numeric_arg.test(match[8]) && (typeof arg != 'number' && isNaN(arg))) {
    110                    throw new TypeError(sprintf("[sprintf] expecting number but found %s", typeof arg))
    111                }
    112 
    113                if (re.number.test(match[8])) {
    114                    is_positive = arg >= 0
    115                }
    116 
    117                switch (match[8]) {
    118                    case 'b':
    119                        arg = parseInt(arg, 10).toString(2)
    120                    break
    121                    case 'c':
    122                        arg = String.fromCharCode(parseInt(arg, 10))
    123                    break
    124                    case 'd':
    125                    case 'i':
    126                        arg = parseInt(arg, 10)
    127                    break
    128                    case 'j':
    129                        arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0)
    130                    break
    131                    case 'e':
    132                        arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential()
    133                    break
    134                    case 'f':
    135                        arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
    136                    break
    137                    case 'g':
    138                        arg = match[7] ? parseFloat(arg).toPrecision(match[7]) : parseFloat(arg)
    139                    break
    140                    case 'o':
    141                        arg = arg.toString(8)
    142                    break
    143                    case 's':
    144                    case 'S':
    145                        arg = String(arg)
    146                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
    147                    break
    148                    case 't':
    149                        arg = String(!!arg)
    150                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
    151                    break
    152                    case 'T':
    153                        arg = Object.prototype.toString.call(arg).slice(8, -1).toLowerCase()
    154                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
    155                    break
    156                    case 'u':
    157                        arg = parseInt(arg, 10) >>> 0
    158                    break
    159                    case 'v':
    160                        arg = arg.valueOf()
    161                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
    162                    break
    163                    case 'x':
    164                        arg = parseInt(arg, 10).toString(16)
    165                    break
    166                    case 'X':
    167                        arg = parseInt(arg, 10).toString(16).toUpperCase()
    168                    break
    169                }
    170                if (re.json.test(match[8])) {
    171                    output[output.length] = arg
    172                }
    173                else {
    174                    if (re.number.test(match[8]) && (!is_positive || match[3])) {
    175                        sign = is_positive ? '+' : '-'
    176                        arg = arg.toString().replace(re.sign, '')
    177                    }
    178                    else {
    179                        sign = ''
    180                    }
    181                    pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' '
    182                    pad_length = match[6] - (sign + arg).length
    183                    pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : '') : ''
    184                    output[output.length] = match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg)
    185                }
    186            }
    187        }
    188        return output.join('')
    189    }
    190 
    191    sprintf.cache = {}
    192 
    193    sprintf.parse = function(fmt) {
    194        var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
    195        while (_fmt) {
    196            if ((match = re.text.exec(_fmt)) !== null) {
    197                parse_tree[parse_tree.length] = match[0]
    198            }
    199            else if ((match = re.modulo.exec(_fmt)) !== null) {
    200                parse_tree[parse_tree.length] = '%'
    201            }
    202            else if ((match = re.placeholder.exec(_fmt)) !== null) {
    203                if (match[2]) {
    204                    arg_names |= 1
    205                    var field_list = [], replacement_field = match[2], field_match = []
    206                    if ((field_match = re.key.exec(replacement_field)) !== null) {
    207                        field_list[field_list.length] = field_match[1]
    208                        while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
    209                            if ((field_match = re.key_access.exec(replacement_field)) !== null) {
    210                                field_list[field_list.length] = field_match[1]
    211                            }
    212                            else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
    213                                field_list[field_list.length] = field_match[1]
    214                            }
    215                            else {
    216                                throw new SyntaxError("[sprintf] failed to parse named argument key")
    217                            }
    218                        }
    219                    }
    220                    else {
    221                        throw new SyntaxError("[sprintf] failed to parse named argument key")
    222                    }
    223                    match[2] = field_list
    224                }
    225                else {
    226                    arg_names |= 2
    227                }
    228                if (arg_names === 3) {
    229                    throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
    230                }
    231                parse_tree[parse_tree.length] = match
    232            }
    233            else {
    234                throw new SyntaxError("[sprintf] unexpected placeholder")
    235            }
    236            _fmt = _fmt.substring(match[0].length)
    237        }
    238        return parse_tree
    239    }
    240 
    241    var vsprintf = function(fmt, argv, _argv) {
    242        _argv = (argv || []).slice(0)
    243        _argv.splice(0, 0, fmt)
    244        return sprintf.apply(null, _argv)
    245    }
    246 
    247    /**
    248     * helpers
    249     */
    250 
    251    var preformattedPadding = {
    252        '0': ['', '0', '00', '000', '0000', '00000', '000000', '0000000'],
    253        ' ': ['', ' ', '  ', '   ', '    ', '     ', '      ', '       '],
    254        '_': ['', '_', '__', '___', '____', '_____', '______', '_______'],
    255    }
    256    function str_repeat(input, multiplier) {
    257        if (multiplier >= 0 && multiplier <= 7 && preformattedPadding[input]) {
    258            return preformattedPadding[input][multiplier]
    259        }
    260        return Array(multiplier + 1).join(input)
    261    }
    262 
    263    /**
    264     * export to either browser or node.js
    265     */
    266    if (typeof exports !== 'undefined') {
    267        exports.sprintf = sprintf
    268        exports.vsprintf = vsprintf
    269    }
    270    else {
    271        window.sprintf = sprintf
    272        window.vsprintf = vsprintf
    273 
    274        if (typeof define === 'function' && define.amd) {
    275            define(function() {
    276                return {
    277                    sprintf: sprintf,
    278                    vsprintf: vsprintf
    279                }
    280            })
    281        }
    282    }
    283 })(typeof window === 'undefined' ? this : window);