From 1d2c2f182ba2002cce9c67a9d157fab2a03f3758 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 24 Feb 2013 11:51:14 -0600 Subject: [PATCH] first attempt at an sprintf function. --- example/tput.js | 2 + lib/tput.js | 110 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/example/tput.js b/example/tput.js index c9adf7b..35240a4 100644 --- a/example/tput.js +++ b/example/tput.js @@ -7,6 +7,8 @@ var tput = Tput({ console.log('Max colors: %d.', tput.max_colors); +//process.stdout.write(Tput.sprintf('%-10s\n', 'hello')); + //console.log(tput.info); //tput.compile(); diff --git a/lib/tput.js b/lib/tput.js index db2e314..c5c11a2 100644 --- a/lib/tput.js +++ b/lib/tput.js @@ -551,8 +551,8 @@ Tput.prototype._compile = function(val) { // as in printf, flags are [-+#] and space. Use a `:' to allow the // next character to be a `-' flag, avoiding interpreting "%-" as an // operator. - // e.g. %:-d %+d %#x %+10d - if (read(/^%(:-|[+# ])?(\d+(?:\.\d+)?)?([doxXs])/)) { + // if (read(/^%(:-|[+# ])?(\d+(?:\.\d+)?)?([doxXs])/)) { + if (read(/^%((?::-|[+# ]){1,4})?(\d+(?:\.\d+)?)?([doxXs])/)) { // echo('sprintf("'+ cap[0].replace(':-', '-') + '", stack.pop())'); // var flag = cap[1], width = cap[2], type = cap[3]; echo('stack.pop()'); @@ -968,6 +968,107 @@ function merge(a, b) { return a; } +/** + * sprintf + * http://www.cplusplus.com/reference/cstdio/printf/ + */ + +function sprintf(src) { + var params = Array.prototype.slice.call(arguments, 1) + , rule = /%([\-+# ]{1,4})?(\d+(?:\.\d+)?)?([doxXsc])/g + , i = 0; + + return src.replace(rule, function(_, flag, width, type) { + var flags = flag.split('') + , param = params[i++] || '' + , initial = param + , width = +width + , opt = {} + , pre = ''; + + switch (type) { + case 'd': // signed int + param = (+param).toString(10); + break; + case 'o': // unsigned octal + param = (+param).toString(8); + break; + case 'x': // unsigned hex int + param = (+param).toString(16); + break; + case 'X': // unsigned hex int uppercase + param = (+param).toString(16).toUppercase(); + break; + case 's': // string + break; + case 'c': // char + // Should return here? + param = isFinite(param) + ? String.fromCharCode(param) + : param[0]; + break; + } + + flags.forEach(function(flag) { + switch (flag) { + // left-justify by width + case '-': + opt.left = true; + break; + // always precede numbers with their signs + case '+': + opt.signs = true; + break; + // used with o, x, X - value is preceded with 0, 0x, or 0X respectively. + // used with a, A, e, E, f, F, g, G - forces written output to contain + // a decimal point even if no more digits follow + case '#': + opt.hexpoint = true; + break; + // if no sign is going to be written, black space in front of the value + case ' ': + opt.space = true; + break; + } + }); + + if (opt.signs) { + if (+initial >= 0) { + pre += '+'; + } + } + + if (opt.space) { + if (!opt.signs && +initial >= 0) { + param = ' ' + param; + } + } + + if (opt.hexpoint) { + switch (type) { + case 'o': // unsigned octal + pre += '0'; + break; + case 'x': // unsigned hex int + pre += '0x'; + break; + case 'X': // unsigned hex int uppercase + pre += '0X'; + break; + } + } + + if (opt.left) { + if (width > (pre.length + param.length)) { + width -= pre.length + param.length; + pre = Array(width + 1).join(' ') + pre; + } + } + + return pre + param; + }); +} + /** * Aliases */ @@ -1515,4 +1616,7 @@ Tput.strings = [ * Expose */ -module.exports = Tput; +exports = Tput; +exports.sprintf = sprintf; + +module.exports = exports;