Skip to content

Commit

Permalink
sprintf() and CPString +stringWithFormat
Browse files Browse the repository at this point in the history
[cappuccino#34 state:resolved]
  • Loading branch information
Tom Robinson committed Sep 13, 2008
1 parent 6c7ee73 commit 39afdd5
Showing 1 changed file with 204 additions and 1 deletion.
205 changes: 204 additions & 1 deletion Foundation/CPString.j
Expand Up @@ -116,7 +116,36 @@ var CPStringHashes = new objj_dictionary();
*/
- (id)initWithString:(CPString)aString
{
return aString + "";
return String(aString);
}

/*
Initializes a string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated.
@param format the format to be used, printf-style
@return the initialized <objj>CPString</objj>
*/
- (id)initWithFormat:(CPString)format, ...
{
if (!format)
[CPException raise:CPInvalidArgumentException
reason:"stringWithString: the format can't be 'nil'"];

self = sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
return self;
}

/*
Creates a new string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated.
@param format the format to be used, printf-style
@return the initialized <objj>CPString</objj>
*/
+ (id)stringWithFormat:(CPString)format, ...
{
if (!format)
[CPException raise:CPInvalidArgumentException
reason:"stringWithString: the format can't be 'nil'"];

return sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
}

/*
Expand Down Expand Up @@ -473,3 +502,177 @@ CPNumericSearch


String.prototype.isa = CPString;


// sprintf:

var sprintfFormatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cdieEfgGosuxXpn%])", "g");
var sprintfTagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cdieEfgGosuxXpn%])");

/**
Creates a new string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated.
@param format the format to be used, printf-style
@return the initialized <objj>CPString</objj>
*/
function sprintf(format)
{
var format = arguments[0],
tokens = format.match(sprintfFormatRegex),
index = 0,
result = "",
arg = 1;

for (var i = 0; i < tokens.length; i++)
{
var t = tokens[i];
if (format.substring(index, index + t.length) != t)
{
return result;
}
index += t.length;

if (t.charAt(0) != "%")
{
result += t;
}
else
{
var subtokens = t.match(sprintfTagRegex);
if (subtokens.length != 8 || subtokens[0] != t)
{
return result;
}

var percentSign = subtokens[1],
flags = subtokens[2],
widthString = subtokens[3],
precisionString = subtokens[4],
length = subtokens[6],
specifier = subtokens[7];

var width = null;
if (widthString == "*")
width = arguments[arg++];
else if (widthString != "")
width = Number(widthString);

var precision = null;
if (precisionString == ".*")
precision = arguments[arg++];
else if (precisionString != "")
precision = Number(precisionString.substring(1));

var leftJustify = (flags.indexOf("-") >= 0);
var padZeros = (flags.indexOf("0") >= 0);

var subresult = "";

if (RegExp("[diufeExXo]").test(specifier))
{
var num = Number(arguments[arg++]);

var sign = "";
if (num < 0)
{
sign = "-";
}
else
{
if (flags.indexOf("+") >= 0)
sign = "+";
else if (flags.indexOf(" ") >= 0)
sign = " ";
}

if (specifier == "d" || specifier == "i" || specifier == "u")
{
var number = String(Math.abs(Math.floor(num)));

subresult = sprintf_justify(sign, "", number, "", width, leftJustify, padZeros)
}

if (specifier == "f")
{
var number = String((precision != null) ? Math.abs(num).toFixed(precision) : Math.abs(num));
var suffix = (flags.indexOf("#") >= 0 && number.indexOf(".") < 0) ? "." : "";

subresult = sprintf_justify(sign, "", number, suffix, width, leftJustify, padZeros);
}

if (specifier == "e" || specifier == "E")
{
var number = String(Math.abs(num).toExponential(precision != null ? precision : 21));
var suffix = (flags.indexOf("#") >= 0 && number.indexOf(".") < 0) ? "." : "";

subresult = sprintf_justify(sign, "", number, suffix, width, leftJustify, padZeros);
}

if (specifier == "x" || specifier == "X")
{
var number = String(Math.abs(num).toString(16));
var prefix = (flags.indexOf("#") >= 0 && num != 0) ? "0x" : "";

subresult = sprintf_justify(sign, prefix, number, "", width, leftJustify, padZeros);
}

if (specifier == "o")
{
var number = String(Math.abs(num).toString(8));
var prefix = (flags.indexOf("#") >= 0 && num != 0) ? "0" : "";

subresult = sprintf_justify(sign, prefix, number, "", width, leftJustify, padZeros);
}

if (RegExp("[A-Z]").test(specifier))
subresult = subresult.toUpperCase();
else
subresult = subresult.toLowerCase();
}
else
{
var subresult = "";

if (specifier == "%")
subresult = "%";
else if (specifier == "c")
subresult = String(arguments[arg++]).charAt(0);
else if (specifier == "s")
subresult = String(arguments[arg++]);
else if (specifier == "p" || specifier == "n")
{
arg++;
subresult = "";
}

subresult = sprintf_justify("", "", subresult, "", width, leftJustify, false);
}

result += subresult;
}
}
return result;
}

var sprintf_justify = function(sign, prefix, string, suffix, width, leftJustify, padZeros)
{
var length = (sign.length + prefix.length + string.length + suffix.length);
if (leftJustify)
{
return sign + prefix + string + suffix + sprintf_pad(width - length, " ");
}
else
{
if (padZeros)
return sign + prefix + sprintf_pad(width - length, "0") + string + suffix;
else
return sprintf_pad(width - length, " ") + sign + prefix + string + suffix;
}
}

var sprintf_pad = function(n, ch)
{
var result = "";
for (var i = 0; i < n; i++)
result += ch;
return result;
}

0 comments on commit 39afdd5

Please sign in to comment.