/* ** sprintf.js -- POSIX sprintf(3) style formatting function for JavaScript ** Copyright (c) 2006-2007 Ralf S. Engelschall ** Partly based on Public Domain code by Jan Moesen ** Licensed under GPL ** ** $LastChangedDate$ ** $LastChangedRevision$ */ /* make sure the ECMAScript 3.0 Number.toFixed() method is available */ if (typeof Number.prototype.toFixed != "undefined") { (function(){ /* see http://www.jibbering.com/faq/#FAQ4_6 for details */ function Stretch(Q, L, c) { var S = Q if (c.length > 0) while (S.length < L) S = c+S; return S; } function StrU(X, M, N) { /* X >= 0.0 */ var T, S; S = new String(Math.round(X * Number("1e"+N))); if (S.search && S.search(/\D/) != -1) return ''+X; with (new String(Stretch(S, M+N, '0'))) return substring(0, T=(length-N)) + '.' + substring(T); } function Sign(X) { return X < 0 ? '-' : ''; } function StrS(X, M, N) { return Sign(X)+StrU(Math.abs(X), M, N); } Number.prototype.toFixed = function (n) { return StrS(this, 1, n) }; })(); } /* the sprintf() function */ sprintf = function () { /* argument sanity checking */ if (!arguments || arguments.length < 1) alert("sprintf:ERROR: not enough arguments"); /* initialize processing queue */ var argumentnum = 0; var done = "", todo = arguments[argumentnum++]; /* parse still to be done format string */ var m; while (m = /^([^%]*)%(\d+$)?([#0 +'-]+)?(\*|\d+)?(\.\*|\.\d+)?([%diouxXfFcs])(.*)$/.exec(todo)) { var pProlog = m[1], pAccess = m[2], pFlags = m[3], pMinLength = m[4], pPrecision = m[5], pType = m[6], pEpilog = m[7]; /* determine substitution */ var subst; if (pType == '%') /* special case: escaped percent character */ subst = '%'; else { /* parse padding and justify aspects of flags */ var padWith = ' '; var justifyRight = true; if (pFlags) { if (pFlags.indexOf('0') >= 0) padWith = '0'; if (pFlags.indexOf('-') >= 0) { padWith = ' '; justifyRight = false; } } else pFlags = ""; /* determine minimum length */ var minLength = -1; if (pMinLength) { if (pMinLength == "*") { var access = argumentnum++; if (access >= arguments.length) alert("sprintf:ERROR: not enough arguments"); minLength = arguments[access]; } else minLength = parseInt(pMinLength, 10); } /* determine precision */ var precision = -1; if (pPrecision) { if (pPrecision == ".*") { var access = argumentnum++; if (access >= arguments.length) alert("sprintf:ERROR: not enough arguments"); precision = arguments[access]; } else precision = parseInt(pPrecision.substring(1), 10); } /* determine how to fetch argument */ var access = argumentnum++; if (pAccess) access = parseInt(pAccess.substring(0, pAccess.length - 1), 10); if (access >= arguments.length) alert("sprintf:ERROR: not enough arguments"); /* dispatch into expansions according to type */ var prefix = ""; switch (pType) { case 'd': case 'i': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = subst.toString(10); if (pFlags.indexOf('#') >= 0 && subst >= 0) subst = "+" + subst; if (pFlags.indexOf(' ') >= 0 && subst >= 0) subst = " " + subst; break; case 'o': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = subst.toString(8); break; case 'u': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = Math.abs(subst); subst = subst.toString(10); break; case 'x': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = subst.toString(16).toLowerCase(); if (pFlags.indexOf('#') >= 0) prefix = "0x"; break; case 'X': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = subst.toString(16).toUpperCase(); if (pFlags.indexOf('#') >= 0) prefix = "0X"; break; case 'f': case 'F': subst = arguments[access]; if (typeof subst != "number") subst = 0.0; subst = 0.0 + subst; if (precision > -1) { if (subst.toFixed) subst = subst.toFixed(precision); else { subst = (Math.round(subst * Math.pow(10, precision)) / Math.pow(10, precision)); subst += "0000000000"; subst = subst.substr(0, subst.indexOf(".")+precision+1); } } subst = '' + subst; if (pFlags.indexOf("'") >= 0) { var k = 0; for (var i = (subst.length - 1) - 3; i >= 0; i -= 3) { subst = subst.substring(0, i) + (k == 0 ? "." : ",") + subst.substring(i); k = (k + 1) % 2; } } break; case 'c': subst = arguments[access]; if (typeof subst != "number") subst = 0; subst = String.fromCharCode(subst); break; case 's': subst = arguments[access]; if (precision > -1) subst = subst.substr(0, precision); if (typeof subst != "string") subst = ""; break; } /* apply optional padding */ var padding = minLength - subst.toString().length - prefix.toString().length; if (padding > 0) { var arrTmp = new Array(padding + 1); if (justifyRight) subst = arrTmp.join(padWith) + subst; else subst = subst + arrTmp.join(padWith); } /* add optional prefix */ subst = prefix + subst; } /* update the processing queue */ done = done + pProlog + subst; todo = pEpilog; } return (done + todo); }