| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 | 
							- /*
 
-  * 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);
 
- }
 
 
  |