Check-in Number:
|
8 | |
Date: |
2007-Feb-15 22:36:57 (local)
2007-Feb-15 21:36:57 (UTC) |
User: | rse |
Branch: | |
Comment: |
add sprintf(3) implementation
|
Tickets: |
|
Inspections: |
|
Files: |
|
Added: javascript/sprintf.html
===================================================================
--- javascript/sprintf.html (rev 0)
+++ javascript/sprintf.html 2007-02-15 21:36:57 UTC (rev 8)
@@ -0,0 +1,48 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+ <head>
+ <title>POSIX sprintf(3) for JavaScript</title>
+ <script type="text/javascript" src="sprintf.js"></script>
+ </head>
+ <body>
+ <h1>POSIX sprintf(3) for JavaScript</h1>
+ <script type="text/javascript">
+ var tests = [
+ /* tests for %d */
+ [ "%d", 42, "42" ],
+ [ "%2d", 42, "42" ],
+ [ "%02d", 42, "42" ],
+ [ "%3d", 42, " 42" ],
+ [ "%03d", 42, "042" ],
+ [ "%-3d", 42, "42 " ],
+ [ "%-03d", 42, "42 " ],
+ [ "%d", "xx", "0" ],
+ /* tests for %x */
+ [ "%x", 10, "a" ],
+ [ "%2x", 10, " a" ],
+ [ "%02x", 10, "0a" ],
+ [ "%#02x", 10, "0xa" ],
+ [ "%#04x", 10, "0x0a" ],
+ /* tests for %f */
+ [ "%f", 4.2, "4.2" ],
+ [ "%.1f", 4.2, "4.2" ],
+ [ "%.2f", 4.2, "4.20" ],
+ [ "%8.4f", 4.12, " 4.1200" ],
+ [ "%8.4f", 4.123456789, " 4.1235" ],
+ /* tests for %s */
+ [ "%2s", "test", "test" ],
+ [ "%6s", "test", " test" ],
+ [ "%-6s", "test", "test " ],
+ ];
+ for (var i = 0; i < tests.length; i++) {
+ var output = sprintf(tests[i][0], tests[i][1]);
+ var msg = "sprintf(\""+tests[i][0]+"\", "+tests[i][1]+") = \""+output+"\"";
+ if (output != tests[i][2])
+ msg = msg + " ERROR: expected \""+tests[i][2]+"\"";
+ msg = msg + "<br/>\n";
+ document.write(msg);
+ }
+ </script>
+ </body>
+</html>
Property changes on: javascript/sprintf.html
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+LastChangedDate LastChangedRevision
\ No newline at end of property
Added: javascript/sprintf.js
===================================================================
--- javascript/sprintf.js (rev 0)
+++ javascript/sprintf.js 2007-02-15 21:36:57 UTC (rev 8)
@@ -0,0 +1,216 @@
+/*
+** sprintf.js -- POSIX sprintf(3) style formatting function for JavaScript
+** Copyright (c) 2006-2007 Ralf S. Engelschall <rse@engelschall.com>
+** Partly based on Public Domain code by Jan Moesen <http://jan.moesen.nu/>
+** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
+**
+** $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).toLowerCase();
+ 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);
+}
+
Property changes on: javascript/sprintf.js
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+LastChangedDate LastChangedRevision
\ No newline at end of property