Printf

To the best of my ability, this replicates the printf() function as it exists in other languages. Generally speaking, you write a string with some format specifiers, and then send it the variables, rather than having to concatenate a bunch of strings and conversions together.
%[align][width][.precision]flag
Align supports -, =, + for left, center, and right align.
Width will pad spaces if the result string doesn't fit. It doesn't crop one.
Precision limits decimal spaces of a float. 0 makes it an integer
Flag determines input type, with %s string, %d integer, %f float, %v vector, and %r rotation supported.
A vector or rotation will have pad/align/precision applied to each of its sub-parts, rather than the whole thing. This just made more sense to me. And yes technically, this is sprintf, but I did add a printf function to ownersay the results. 
= Code =
string pad(string value, integer width, string alignment)
{
 integer len = llStringLength(value);
 if (width > len)
 {
 string spacers = " ";
 while (llStringLength(spacers) < width-len) // This works fastest with a maxed width constant, but can be dynamic
 spacers += spacers; // Expand spacers while necessary
 spacers = llGetSubString(spacers, 0, width-len-1);
 
 if (alignment == "-") // left align
 return value+spacers;
 else if (alignment == "+") // right align
 return spacers+value;
 else if (alignment == "=") // center align
 return llInsertString(spacers, (width-len)/2, value);
 }
 return value;
}
string fix(float value, integer precision)
{//Set the decimal precision of a float. Technically only affects decimal places
 if (precision < 1) precision = -1;
 if (precision > 6) precision = 6;
 return llGetSubString((string)value, 0, precision-7);
}
printf(string input, list values)
{
 llOwnerSay(sprintf(input, values));
}
string sprintf(string input, list values)
{
 integer iValue; // Which value will replace
 integer iValues = llGetListLength(values); // Number of values to replace
 for (iValue = 0; iValue < iValues; iValue++)
 {
 integer index = llSubStringIndex(input, "%"); // "%=99.9v " tag found
 
 if (~index)
 {
 string buffer = llGetSubString(input, index, index+12); // A few chars past % into a buffer
 integer bufferLen = llSubStringIndex(buffer, " "); // A space or newline ends buffer
 if (!~bufferLen)
 bufferLen = llSubStringIndex(buffer, "\n");
 buffer = llGetSubString(buffer, 0, bufferLen); // Trim buffer to new length
 
 integer alignIndex;
 string alignment = "+"; // Default to right align
 
 if (~llSubStringIndex(buffer, "=")) // Center align
 alignment = "=";
 else if (~llSubStringIndex(buffer, "-")) // Left align
 alignment = "-";
 else if (~llSubStringIndex(buffer, "+")) // Right align
 alignment = "+";
 else
 alignIndex--; // There is no symbol, move index back for (integer) typecast later //*/
 
 integer width = (integer)llGetSubString(buffer, 2+alignIndex, -1);
 integer precision = 0; 
 integer dot = llSubStringIndex(buffer, "."); // Location of period, if any
 if (~dot) // If there is a dot, the integer which follows is our precision
 precision = (integer)llGetSubString(buffer, 1+dot, -1);
 
 string formatted; // Result of formatting to replace into string
 
 if (~llSubStringIndex(buffer, "f")) // if type == float
 {
 float value = llList2Float(values, iValue);
 formatted = fix(value, precision); 
 }
 else if (~llSubStringIndex(buffer, "v")) // if type == vector
 {
 vector value = (vector)llList2String(values, iValue);
 formatted = (string)["<", pad(fix(value.x, precision), width, alignment), ",",
 pad(fix(value.y, precision), width, alignment), ",",
 pad(fix(value.z, precision), width, alignment), ">"];
 }
 else if (~llSubStringIndex(buffer, "r")) // if type == rotation
 {
 rotation value = (rotation)llList2String(values, iValue);
 formatted = (string)["<", pad(fix(value.x, precision), width, alignment), ",",
 pad(fix(value.y, precision), width, alignment), ",",
 pad(fix(value.z, precision), width, alignment), ",",
 pad(fix(value.s, precision), width, alignment), ">"];
 } // Because of typecasting in a list, "s" and "d" are identical, so catch all at the end
 else formatted = llList2String(values, iValue);
 
 // insert formatted value back into source string, and a space
 input = llInsertString(llDeleteSubString(input, index, index+bufferLen),index, pad(formatted, width, alignment)+" ");
 // cant use this, faster but we only want to replace one value, this does all.
 //input = llDumpList2String(llParseStringKeepNulls(input, [llGetSubString(input, index, index+bufferLen)], []), pad(formatted, width, alignment)+" ");
 }
 }
 return input;
}
default
{
 state_entry()
 {
 printf("This script has been running for %0.2f seconds.", [llGetTime()]);
 }
}
= Example with testing functions included =
integer TRIALS = 5000;
string pad(string value, integer width, string alignment)
{
 integer len = llStringLength(value);
 if (width > len)
 {
 string spacers = " ";
 while (llStringLength(spacers) < width-len) // This works fastest with a maxed width constant, but can be dynamic
 spacers += spacers; // Expand spacers while necessary
 spacers = llGetSubString(spacers, 0, width-len-1);
 
 if (alignment == "-") // left align
 return value+spacers;
 else if (alignment == "+") // right align
 return spacers+value;
 else if (alignment == "=") // center align
 return llInsertString(spacers, (width-len)/2, value);
 }
 return value;
}
string fix(float value, integer precision)
{//Set the decimal precision of a float. Technically only affects decimal places
 integer pre = (integer)value;
 // WARNING !! Rounding is occurring here: Not rounding left 69.1 as 69.099998 => 69.0
 integer post = llRound(llPow(10,precision)*(value-pre)); // In linux, rounding is expected behavior
 if (precision > 0)
 return (string)pre + "." + llGetSubString((string)post+"0000000", 0, precision-1);
 return (string)pre;
}
printf(string input, list values)
{
 llOwnerSay(sprintf(input, values));
}
string sprintf(string input, list values)
{
 integer iValue; // Which value will replace
 integer iValues = llGetListLength(values); // Number of values to replace
 for (iValue = 0; iValue < iValues; iValue++)
 {
 integer index = llSubStringIndex(input, "%"); // "%=99.9v " tag found
 
 if (~index)
 {
 string buffer = llGetSubString(input, index, index+12); // A few chars past % into a buffer
 integer bufferLen = llSubStringIndex(buffer, " "); // A space or newline ends buffer
 if (!~bufferLen)
 bufferLen = llSubStringIndex(buffer, "\n");
 buffer = llGetSubString(buffer, 0, bufferLen); // Trim buffer to new length
 
 integer alignIndex;
 string alignment = "+"; // Default to right align
 
 if (~llSubStringIndex(buffer, "=")) // Center align
 alignment = "=";
 else if (~llSubStringIndex(buffer, "-")) // Left align
 alignment = "-";
 else if (~llSubStringIndex(buffer, "+")) // Right align
 alignment = "+";
 else
 alignIndex--; // There is no symbol, move index back for (integer) typecast later //*/
 
 integer width = (integer)llGetSubString(buffer, 2+alignIndex, -1);
 integer precision = 0; 
 integer dot = llSubStringIndex(buffer, "."); // Location of period, if any
 if (~dot) // If there is a dot, the integer which follows is our precision
 precision = (integer)llGetSubString(buffer, 1+dot, -1);
 
 string formatted; // Result of formatting to replace into string
 
 if (~llSubStringIndex(buffer, "f")) // if type == float
 {
 float value = llList2Float(values, iValue);
 formatted = fix(value, precision); 
 }
 else if (~llSubStringIndex(buffer, "v")) // if type == vector
 {
 vector value = (vector)llList2String(values, iValue);
 formatted = (string)["<", pad(fix(value.x, precision), width, alignment), ",",
 pad(fix(value.y, precision), width, alignment), ",",
 pad(fix(value.z, precision), width, alignment), ">"];
 }
 else if (~llSubStringIndex(buffer, "r")) // if type == rotation
 {
 rotation value = (rotation)llList2String(values, iValue);
 formatted = (string)["<", pad(fix(value.x, precision), width, alignment), ",",
 pad(fix(value.y, precision), width, alignment), ",",
 pad(fix(value.z, precision), width, alignment), ",",
 pad(fix(value.s, precision), width, alignment), ">"];
 } // Because of typecasting in a list, "s" and "d" are identical, so catch all at the end
 else formatted = llList2String(values, iValue);
 
 // insert formatted value back into source string, and a space
 input = llInsertString(llDeleteSubString(input, index, index+bufferLen),index, pad(formatted, width, alignment)+" ");
 // cant use this, faster but we only want to replace one value, this does all.
 //input = llDumpList2String(llParseStringKeepNulls(input, [llGetSubString(input, index, index+bufferLen)], []), pad(formatted, width, alignment)+" ");
 }
 }
 return input;
}
testPad() // string pad(string value, integer width, string alignment)
{ // 5000 trials completed in 7.71 seconds, 1.5 ms each.
 string TEST_STRING = "ABC";
 integer WIDTH_LIMIT = 60; // Max whitespace for padding test
 integer i; 
 integer j;
 float t1 = llGetTime();
 for (i = 0; i < TRIALS; i+= 3) // One for each align, so skip 3
 {
 j = i % WIDTH_LIMIT;
 pad(TEST_STRING, j+0, "-"); // Left align
 pad(TEST_STRING, j+1, "="); // Center align
 pad(TEST_STRING, j+2, "+"); // Right align
 }
 float t2 = llGetTime();
 llOwnerSay(sprintf("%d trials completed in %0.2f seconds, %0.3f ms each.", [TRIALS, t2-t1, 1E3*(t2-t1)/TRIALS]));
}
testFix() // string fix(float value, integer precision)
{ // 5000 trials completed in 23.67 seconds, 4.7 ms each.
 integer i; 
 integer j;
 float t1 = llGetTime();
 for (i = 0; i < TRIALS; i++)
 for (j = 0; j <= 6; j++) // Precision is meaningless past 6 in lsl
 fix(i, j);
 float t2 = llGetTime();
 llOwnerSay(sprintf("%d trials completed in %0.2f seconds, %0.3f ms each.", [TRIALS, t2-t1, 1E3*(t2-t1)/TRIALS]));
}
testSprintf()
{
 float t1 = llGetTime();
 list tests = [ sprintf("%12.5r", [ZERO_ROTATION]),
 sprintf("%12.0r", [ZERO_ROTATION]),
 sprintf("%0.5r", [ZERO_ROTATION]),
 sprintf("%12.r", [ZERO_ROTATION]),
 sprintf("%.5r", [ZERO_ROTATION]),
 sprintf("%.r", [ZERO_ROTATION]),
 sprintf("%r", [ZERO_ROTATION]),
 sprintf("%-12r", [ZERO_ROTATION]),
 sprintf("%=12r", [ZERO_ROTATION]),
 sprintf("%+12r", [ZERO_ROTATION]),
 sprintf("%12.5v", [ZERO_VECTOR]),
 sprintf("%12.0v", [ZERO_VECTOR]),
 sprintf("%0.5v", [ZERO_VECTOR]),
 sprintf("%12.v", [ZERO_VECTOR]),
 sprintf("%.5v", [ZERO_VECTOR]),
 sprintf("%.v", [ZERO_VECTOR]),
 sprintf("%v", [ZERO_VECTOR]),
 sprintf("%-12v", [ZERO_VECTOR]),
 sprintf("%=12v", [ZERO_VECTOR]),
 sprintf("%+12v", [ZERO_VECTOR]),
 sprintf("%12.5f", [0]),
 sprintf("%12.0f", [0]),
 sprintf("%0.5f", [0]),
 sprintf("%12.f", [0]),
 sprintf("%.5f", [0]),
 sprintf("%.f", [0]),
 sprintf("%f", [0]),
 sprintf("%-12f", [0]),
 sprintf("%=12f", [0]),
 sprintf("%+12f", [0]),
 sprintf("%12.5d", [0]),
 sprintf("%12.0d", [0]),
 sprintf("%0.5d", [0]),
 sprintf("%12.d", [0]),
 sprintf("%.5d", [0]),
 sprintf("%.d", [0]),
 sprintf("%d", [0]),
 sprintf("%-12d", [0]),
 sprintf("%=12d", [0]),
 sprintf("%+12d", [0]),
 sprintf("%12.5s", ["Test"]),
 sprintf("%12.0s", ["Test"]),
 sprintf("%0.5s", ["Test"]),
 sprintf("%12.s", ["Test"]),
 sprintf("%.5s", ["Test"]),
 sprintf("%.s", ["Test"]),
 sprintf("%12s", ["Test"]),
 sprintf("%-12s", ["Test"]),
 sprintf("%=12s", ["Test"]),
 sprintf("%+12s", ["Test"])];
 
 integer i;
 integer len = llGetListLength(tests);
 string out;
 for (i = 0; i < len; i++)
 {
 if (!(llList2String(tests, i) == llList2String(results, i)))
 out += "\n"+sprintf("Test #%d, %s != %s", [i, llList2String(tests, i), llList2String(results, i)]);
 }
 float t2 = llGetTime();
 if (out)
 llOwnerSay("Failures: " + out);
 else llOwnerSay(sprintf("%d tests passed in %.2f seconds with an average run time of %.2f ms",[len, t2-t1, 1000*(t2-t1)/len]));
}
// Answers to the test
list results = [// rots
 "< 0.00000, 0.00000, 0.00000, 1.00000> ",
 "< 0, 0, 0, 1> ",
 "<0.00000,0.00000,0.00000,1.00000> ",
 "< 0, 0, 0, 1> ",
 "<0.00000,0.00000,0.00000,1.00000> ",
 "<0,0,0,1> ",
 "<0,0,0,1> ",
 "<0 ,0 ,0 ,1 > ",
 "< 0 , 0 , 0 , 1 > ",
 "< 0, 0, 0, 1> ",
 // vectors
 "< 0.00000, 0.00000, 0.00000> ",
 "< 0, 0, 0> ",
 "<0.00000,0.00000,0.00000> ",
 "< 0, 0, 0> ",
 "<0.00000,0.00000,0.00000> ",
 "<0,0,0> ",
 "<0,0,0> ",
 "<0 ,0 ,0 > ",
 "< 0 , 0 , 0 > ",
 "< 0, 0, 0> ",
 // Floats
 " 0.00000 ",
 " 0 ",
 "0.00000 ",
 " 0 ",
 "0.00000 ",
 "0 ",
 "0 ",
 "0 ",
 " 0 ",
 " 0 ",
 // Integers
 " 0 ",
 " 0 ",
 "0 ",
 " 0 ",
 "0 ",
 "0 ",
 "0 ",
 "0 ",
 " 0 ",
 " 0 ",
 " Test ",
 " Test ",
 "Test ",
 " Test ",
 "Test ",
 "Test ",
 " Test ",
 "Test ",
 " Test ",
 " Test "];
default
{
 state_entry()
 {
 testPad();
 testFix();
 testSprintf();
 printf("This script has been running for %0.2f seconds.", [llGetTime()]);
 }
}
= Notes / Copyright =
You are free to replicate or otherwise use this code to your heart's content.
If you have suggestions for optimization, I'm all ears.