summaryrefslogtreecommitdiff
path: root/node_modules/locutus/php/strings/sscanf.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/locutus/php/strings/sscanf.js')
-rw-r--r--node_modules/locutus/php/strings/sscanf.js268
1 files changed, 268 insertions, 0 deletions
diff --git a/node_modules/locutus/php/strings/sscanf.js b/node_modules/locutus/php/strings/sscanf.js
new file mode 100644
index 0000000..32fd585
--- /dev/null
+++ b/node_modules/locutus/php/strings/sscanf.js
@@ -0,0 +1,268 @@
+'use strict';
+
+module.exports = function sscanf(str, format) {
+ // discuss at: http://locutus.io/php/sscanf/
+ // original by: Brett Zamir (http://brett-zamir.me)
+ // example 1: sscanf('SN/2350001', 'SN/%d')
+ // returns 1: [2350001]
+ // example 2: var myVar = {}
+ // example 2: sscanf('SN/2350001', 'SN/%d', myVar)
+ // example 2: var $result = myVar.value
+ // returns 2: 2350001
+ // example 3: sscanf("10--20", "%2$d--%1$d") // Must escape '$' in PHP, but not JS
+ // returns 3: [20, 10]
+
+ var retArr = [];
+ var _NWS = /\S/;
+ var args = arguments;
+ var digit;
+
+ var _setExtraConversionSpecs = function _setExtraConversionSpecs(offset) {
+ // Since a mismatched character sets us off track from future
+ // legitimate finds, we just scan
+ // to the end for any other conversion specifications (besides a percent literal),
+ // setting them to null
+ // sscanf seems to disallow all conversion specification components (of sprintf)
+ // except for type specifiers
+ // Do not allow % in last char. class
+ // var matches = format.match(/%[+-]?([ 0]|'.)?-?\d*(\.\d+)?[bcdeufFosxX]/g);
+ // Do not allow % in last char. class:
+ var matches = format.slice(offset).match(/%[cdeEufgosxX]/g);
+ // b, F,G give errors in PHP, but 'g', though also disallowed, doesn't
+ if (matches) {
+ var lgth = matches.length;
+ while (lgth--) {
+ retArr.push(null);
+ }
+ }
+ return _finish();
+ };
+
+ var _finish = function _finish() {
+ if (args.length === 2) {
+ return retArr;
+ }
+ for (var i = 0; i < retArr.length; ++i) {
+ args[i + 2].value = retArr[i];
+ }
+ return i;
+ };
+
+ var _addNext = function _addNext(j, regex, cb) {
+ if (assign) {
+ var remaining = str.slice(j);
+ var check = width ? remaining.substr(0, width) : remaining;
+ var match = regex.exec(check);
+ // @todo: Make this more readable
+ var key = digit !== undefined ? digit : retArr.length;
+ var testNull = retArr[key] = match ? cb ? cb.apply(null, match) : match[0] : null;
+ if (testNull === null) {
+ throw new Error('No match in string');
+ }
+ return j + match[0].length;
+ }
+ return j;
+ };
+
+ if (arguments.length < 2) {
+ throw new Error('Not enough arguments passed to sscanf');
+ }
+
+ // PROCESS
+ for (var i = 0, j = 0; i < format.length; i++) {
+ var width = 0;
+ var assign = true;
+
+ if (format.charAt(i) === '%') {
+ if (format.charAt(i + 1) === '%') {
+ if (str.charAt(j) === '%') {
+ // a matched percent literal
+ // skip beyond duplicated percent
+ ++i;
+ ++j;
+ continue;
+ }
+ // Format indicated a percent literal, but not actually present
+ return _setExtraConversionSpecs(i + 2);
+ }
+
+ // CHARACTER FOLLOWING PERCENT IS NOT A PERCENT
+
+ // We need 'g' set to get lastIndex
+ var prePattern = new RegExp('^(?:(\\d+)\\$)?(\\*)?(\\d*)([hlL]?)', 'g');
+
+ var preConvs = prePattern.exec(format.slice(i + 1));
+
+ var tmpDigit = digit;
+ if (tmpDigit && preConvs[1] === undefined) {
+ var msg = 'All groups in sscanf() must be expressed as numeric if ';
+ msg += 'any have already been used';
+ throw new Error(msg);
+ }
+ digit = preConvs[1] ? parseInt(preConvs[1], 10) - 1 : undefined;
+
+ assign = !preConvs[2];
+ width = parseInt(preConvs[3], 10);
+ var sizeCode = preConvs[4];
+ i += prePattern.lastIndex;
+
+ // @todo: Does PHP do anything with these? Seems not to matter
+ if (sizeCode) {
+ // This would need to be processed later
+ switch (sizeCode) {
+ case 'h':
+ case 'l':
+ case 'L':
+ // Treats subsequent as short int (for d,i,n) or unsigned short int (for o,u,x)
+ // Treats subsequent as long int (for d,i,n), or unsigned long int (for o,u,x);
+ // or as double (for e,f,g) instead of float or wchar_t instead of char
+ // Treats subsequent as long double (for e,f,g)
+ break;
+ default:
+ throw new Error('Unexpected size specifier in sscanf()!');
+ }
+ }
+ // PROCESS CHARACTER
+ try {
+ // For detailed explanations, see http://web.archive.org/web/20031128125047/http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=scanf%283%29&msection=
+ // Also http://www.mathworks.com/access/helpdesk/help/techdoc/ref/sscanf.html
+ // p, S, C arguments in C function not available
+ // DOCUMENTED UNDER SSCANF
+ switch (format.charAt(i + 1)) {
+ case 'F':
+ // Not supported in PHP sscanf; the argument is treated as a float, and
+ // presented as a floating-point number (non-locale aware)
+ // sscanf doesn't support locales, so no need for two (see %f)
+ break;
+ case 'g':
+ // Not supported in PHP sscanf; shorter of %e and %f
+ // Irrelevant to input conversion
+ break;
+ case 'G':
+ // Not supported in PHP sscanf; shorter of %E and %f
+ // Irrelevant to input conversion
+ break;
+ case 'b':
+ // Not supported in PHP sscanf; the argument is treated as an integer,
+ // and presented as a binary number
+ // Not supported - couldn't distinguish from other integers
+ break;
+ case 'i':
+ // Integer with base detection (Equivalent of 'd', but base 0 instead of 10)
+ var pattern = /([+-])?(?:(?:0x([\da-fA-F]+))|(?:0([0-7]+))|(\d+))/;
+ j = _addNext(j, pattern, function (num, sign, hex, oct, dec) {
+ return hex ? parseInt(num, 16) : oct ? parseInt(num, 8) : parseInt(num, 10);
+ });
+ break;
+ case 'n':
+ // Number of characters processed so far
+ retArr[digit !== undefined ? digit : retArr.length - 1] = j;
+ break;
+ // DOCUMENTED UNDER SPRINTF
+ case 'c':
+ // Get character; suppresses skipping over whitespace!
+ // (but shouldn't be whitespace in format anyways, so no difference here)
+ // Non-greedy match
+ j = _addNext(j, new RegExp('.{1,' + (width || 1) + '}'));
+ break;
+ case 'D':
+ case 'd':
+ // sscanf documented decimal number; equivalent of 'd';
+ // Optionally signed decimal integer
+ j = _addNext(j, /([+-])?(?:0*)(\d+)/, function (num, sign, dec) {
+ // Ignores initial zeroes, unlike %i and parseInt()
+ var decInt = parseInt((sign || '') + dec, 10);
+ if (decInt < 0) {
+ // PHP also won't allow less than -2147483648
+ // integer overflow with negative
+ return decInt < -2147483648 ? -2147483648 : decInt;
+ } else {
+ // PHP also won't allow greater than -2147483647
+ return decInt < 2147483647 ? decInt : 2147483647;
+ }
+ });
+ break;
+ case 'f':
+ case 'E':
+ case 'e':
+ // Although sscanf doesn't support locales,
+ // this is used instead of '%F'; seems to be same as %e
+ // These don't discriminate here as both allow exponential float of either case
+ j = _addNext(j, /([+-])?(?:0*)(\d*\.?\d*(?:[eE]?\d+)?)/, function (num, sign, dec) {
+ if (dec === '.') {
+ return null;
+ }
+ // Ignores initial zeroes, unlike %i and parseFloat()
+ return parseFloat((sign || '') + dec);
+ });
+ break;
+ case 'u':
+ // unsigned decimal integer
+ // We won't deal with integer overflows due to signs
+ j = _addNext(j, /([+-])?(?:0*)(\d+)/, function (num, sign, dec) {
+ // Ignores initial zeroes, unlike %i and parseInt()
+ var decInt = parseInt(dec, 10);
+ if (sign === '-') {
+ // PHP also won't allow greater than 4294967295
+ // integer overflow with negative
+ return 4294967296 - decInt;
+ } else {
+ return decInt < 4294967295 ? decInt : 4294967295;
+ }
+ });
+ break;
+ case 'o':
+ // Octal integer // @todo: add overflows as above?
+ j = _addNext(j, /([+-])?(?:0([0-7]+))/, function (num, sign, oct) {
+ return parseInt(num, 8);
+ });
+ break;
+ case 's':
+ // Greedy match
+ j = _addNext(j, /\S+/);
+ break;
+ case 'X':
+ case 'x':
+ // Same as 'x'?
+ // @todo: add overflows as above?
+ // Initial 0x not necessary here
+ j = _addNext(j, /([+-])?(?:(?:0x)?([\da-fA-F]+))/, function (num, sign, hex) {
+ return parseInt(num, 16);
+ });
+ break;
+ case '':
+ // If no character left in expression
+ throw new Error('Missing character after percent mark in sscanf() format argument');
+ default:
+ throw new Error('Unrecognized character after percent mark in sscanf() format argument');
+ }
+ } catch (e) {
+ if (e === 'No match in string') {
+ // Allow us to exit
+ return _setExtraConversionSpecs(i + 2);
+ }
+ // Calculate skipping beyond initial percent too
+ }
+ ++i;
+ } else if (format.charAt(i) !== str.charAt(j)) {
+ // @todo: Double-check i whitespace ignored in string and/or formats
+ _NWS.lastIndex = 0;
+ if (_NWS.test(str.charAt(j)) || str.charAt(j) === '') {
+ // Whitespace doesn't need to be an exact match)
+ return _setExtraConversionSpecs(i + 1);
+ } else {
+ // Adjust strings when encounter non-matching whitespace,
+ // so they align in future checks above
+ // Ok to replace with j++;?
+ str = str.slice(0, j) + str.slice(j + 1);
+ i--;
+ }
+ } else {
+ j++;
+ }
+ }
+
+ // POST-PROCESSING
+ return _finish();
+};
+//# sourceMappingURL=sscanf.js.map \ No newline at end of file