Spaces:
Configuration error
Configuration error
| /* | |
| * extsprintf.js: extended POSIX-style sprintf | |
| */ | |
| var mod_assert = require('assert'); | |
| var mod_util = require('util'); | |
| /* | |
| * Public interface | |
| */ | |
| exports.sprintf = jsSprintf; | |
| exports.printf = jsPrintf; | |
| exports.fprintf = jsFprintf; | |
| /* | |
| * Stripped down version of s[n]printf(3c). We make a best effort to throw an | |
| * exception when given a format string we don't understand, rather than | |
| * ignoring it, so that we won't break existing programs if/when we go implement | |
| * the rest of this. | |
| * | |
| * This implementation currently supports specifying | |
| * - field alignment ('-' flag), | |
| * - zero-pad ('0' flag) | |
| * - always show numeric sign ('+' flag), | |
| * - field width | |
| * - conversions for strings, decimal integers, and floats (numbers). | |
| * - argument size specifiers. These are all accepted but ignored, since | |
| * Javascript has no notion of the physical size of an argument. | |
| * | |
| * Everything else is currently unsupported, most notably precision, unsigned | |
| * numbers, non-decimal numbers, and characters. | |
| */ | |
| function jsSprintf(fmt) | |
| { | |
| var regex = [ | |
| '([^%]*)', /* normal text */ | |
| '%', /* start of format */ | |
| '([\'\\-+ #0]*?)', /* flags (optional) */ | |
| '([1-9]\\d*)?', /* width (optional) */ | |
| '(\\.([1-9]\\d*))?', /* precision (optional) */ | |
| '[lhjztL]*?', /* length mods (ignored) */ | |
| '([diouxXfFeEgGaAcCsSp%jr])' /* conversion */ | |
| ].join(''); | |
| var re = new RegExp(regex); | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var flags, width, precision, conversion; | |
| var left, pad, sign, arg, match; | |
| var ret = ''; | |
| var argn = 1; | |
| mod_assert.equal('string', typeof (fmt)); | |
| while ((match = re.exec(fmt)) !== null) { | |
| ret += match[1]; | |
| fmt = fmt.substring(match[0].length); | |
| flags = match[2] || ''; | |
| width = match[3] || 0; | |
| precision = match[4] || ''; | |
| conversion = match[6]; | |
| left = false; | |
| sign = false; | |
| pad = ' '; | |
| if (conversion == '%') { | |
| ret += '%'; | |
| continue; | |
| } | |
| if (args.length === 0) | |
| throw (new Error('too few args to sprintf')); | |
| arg = args.shift(); | |
| argn++; | |
| if (flags.match(/[\' #]/)) | |
| throw (new Error( | |
| 'unsupported flags: ' + flags)); | |
| if (precision.length > 0) | |
| throw (new Error( | |
| 'non-zero precision not supported')); | |
| if (flags.match(/-/)) | |
| left = true; | |
| if (flags.match(/0/)) | |
| pad = '0'; | |
| if (flags.match(/\+/)) | |
| sign = true; | |
| switch (conversion) { | |
| case 's': | |
| if (arg === undefined || arg === null) | |
| throw (new Error('argument ' + argn + | |
| ': attempted to print undefined or null ' + | |
| 'as a string')); | |
| ret += doPad(pad, width, left, arg.toString()); | |
| break; | |
| case 'd': | |
| arg = Math.floor(arg); | |
| /*jsl:fallthru*/ | |
| case 'f': | |
| sign = sign && arg > 0 ? '+' : ''; | |
| ret += sign + doPad(pad, width, left, | |
| arg.toString()); | |
| break; | |
| case 'x': | |
| ret += doPad(pad, width, left, arg.toString(16)); | |
| break; | |
| case 'j': /* non-standard */ | |
| if (width === 0) | |
| width = 10; | |
| ret += mod_util.inspect(arg, false, width); | |
| break; | |
| case 'r': /* non-standard */ | |
| ret += dumpException(arg); | |
| break; | |
| default: | |
| throw (new Error('unsupported conversion: ' + | |
| conversion)); | |
| } | |
| } | |
| ret += fmt; | |
| return (ret); | |
| } | |
| function jsPrintf() { | |
| var args = Array.prototype.slice.call(arguments); | |
| args.unshift(process.stdout); | |
| jsFprintf.apply(null, args); | |
| } | |
| function jsFprintf(stream) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| return (stream.write(jsSprintf.apply(this, args))); | |
| } | |
| function doPad(chr, width, left, str) | |
| { | |
| var ret = str; | |
| while (ret.length < width) { | |
| if (left) | |
| ret += chr; | |
| else | |
| ret = chr + ret; | |
| } | |
| return (ret); | |
| } | |
| /* | |
| * This function dumps long stack traces for exceptions having a cause() method. | |
| * See node-verror for an example. | |
| */ | |
| function dumpException(ex) | |
| { | |
| var ret; | |
| if (!(ex instanceof Error)) | |
| throw (new Error(jsSprintf('invalid type for %%r: %j', ex))); | |
| /* Note that V8 prepends "ex.stack" with ex.toString(). */ | |
| ret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack; | |
| if (ex.cause && typeof (ex.cause) === 'function') { | |
| var cex = ex.cause(); | |
| if (cex) { | |
| ret += '\nCaused by: ' + dumpException(cex); | |
| } | |
| } | |
| return (ret); | |
| } | |