-- MovieScript "PHPTextLib" --@ Version 1.0.0 --@ Author Luke Wigley luke at meccamedialight com au --@ Created Tuesday, 29th January 2005, 1:09 pm ;) -------------------------------------------------------------------------------------------------------------- --@ DESCRIPTION -- Script for creating a PHP-like global sprintf() function that returns a string formatted according to -- the given format string. -- -- The format string is composed of zero or more directives: ordinary characters (excluding %) that are -- copied directly to the result, and conversion specifications, each of which results in fetching its -- own parameter. -- -- See http://au2.php.net/manual/en/function.sprintf.php for a description -- of the parameter string (though note that not all parameters are implemented) --@ EXAMPLE USE -- on testPrint -- -- debugStr = return & sprintf("%'-30s\n"," [Example 1] --") & return -- s = "monkey" -- t = "many monkeys" -- -- debugStr = debugStr & sprintf("[%s]\n",s) -- standard string output -- debugStr = debugStr & sprintf("[%10s]\n",s) -- right-justification with spaces -- debugStr = debugStr & sprintf("[%-10s]\n",s) -- left-justification with spaces -- debugStr = debugStr & sprintf("[%010s]\n",s) -- zero-padding works on strings too -- debugStr = debugStr & sprintf("[%'#10s]\n",s) -- use the custom padding character '#' -- debugStr = debugStr & sprintf("[%10.10s]\n", t) -- left-justification but with a cutoff of 10 characters -- -- -- debugStr = debugStr & return & return & sprintf("%'-30s\n"," [Example 2] --") & return -- -- debugStr = debugStr & sprintf("$%%01.2f = $%01.2f\n", 123.123456789) -- floating numbers -- debugStr = debugStr & sprintf("%%01.6f = %01.6f\n", .123456789) -- floating numbers -- debugStr = debugStr & sprintf("%%u = '%u'\n", 43951789) -- unsigned integers -- debugStr = debugStr & sprintf("%%u = '%u'\n", -43951789) -- unsigned integers -- debugStr = debugStr & sprintf("%%d = '%d'\n", 43951789) -- standard integers -- debugStr = debugStr & sprintf("%%+d = '%+d'\n", 43951789) -- signed integers -- debugStr = debugStr & sprintf("%%+d = '%+d'\n", -43951789) -- signed integers -- debugStr = debugStr & sprintf("%%x = '%x'\n", 43951789) -- hexadecimal representation -- debugStr = debugStr & sprintf("%%X = '%X'\n", 43951789) -- hexadecimal representation -- debugStr = debugStr & sprintf("%%b = '%b'\n", 43951789) -- binary -- -- debugStr = debugStr & return & return & sprintf("%'-30s\n"," [Example 3] --") & return -- -- debugStr = debugStr & sprintf("There are %d monkeys in the %s\n", 5, "trees") -- debugStr = debugStr & sprintf("%04d-%02d-%02d\n", (the systemDate).year, (the systemDate).month, (the systemDate).day) -- -- -- debugStr = debugStr & return & sprintf("%'-30s\n","-") -- put debugStr & return --end --@VERSION HISTORY -- -- v.1.0.0 First go. --@ NOTES -- this movie script needs to be named "PHPTextLib" -- printing unsigned decimals doesn't really work (in this implementation, is just prints the abs() value) --@ TO DO: -- Argument swapping, and some more type specifiers (Octal numbers, scientific notation) -- --@ DEPENDENCIES --Script("NumberLib") -- for converting strings to numbers etc -------------------------------------------------------------------------------------------------------------- property __Transforms on sprintf () this = script("PHPTextLib") if the paramCount > 1 then formatControlStr = param(1) typeSpecifiers = [] repeat with i = 2 to the paramCount typeSpecifiers.append(param(i)) end repeat else return "" -- parameter error end if out = [""] mx = formatControlStr.char.count i = 0 tsIdx = [1] repeat while i < mx i = i + 1 k = formatControlStr.char[i] if k = "\" then -- escape the next char if i < mx then i = i + 1 nk = formatControlStr.char[i] if nk <> "\" then case(nk) of "r", "n": out[1] = out[1] & return "t": out[1] = out[1] & tab otherwise out[1] = out[1] & nk end case else if i < mx then i = i + 1 nk = formatControlStr.char[i] out[1] = out[1] & nk end if end if else if k ="%" then -- get the control i = this._GetConversionSpec(formatControlStr, i+1, mx, out,typeSpecifiers, tsIdx) else out[1] = out[1] & k end if end repeat return out[1] end on _GetConversionSpec (this, formatControlStr, startChar, mx, out, typeSpecifiers, tsIdx) -- check literal % char nk = formatControlStr.char[startChar] if nk = "%" then out[1] = out[1]&"%" return startChar end if -- check sign if "+-" contains nk then sign = nk startChar = startChar + 1 nk = formatControlStr.char[startChar] else sign = "" end if -- padding if nk = "0" or nk = " " then padding = nk startChar = startChar + 1 nk = formatControlStr.char[startChar] else if nk = "'" then if startChar < mx then startChar = startChar + 1 padding = formatControlStr.char[startChar] startChar = startChar + 1 nk = formatControlStr.char[startChar] else padding = "" end if else padding = "" end if -- align align = #right nk = formatControlStr.char[startChar] if nk = "-" then align = #left startChar = startChar + 1 nk = formatControlStr.char[startChar] end if -- Width if "0123456789" contains nk then n = nk repeat while startChar < mx startChar = startChar + 1 nk = formatControlStr.char[startChar] if "0123456789" contains nk then n = n & nk else exit repeat end repeat minWidth = integer(n) else minWidth = -1 end if -- Precision if nk = "." then n = "" repeat while startChar < mx startChar = startChar + 1 nk = formatControlStr.char[startChar] if "0123456789" contains nk then n = n & nk else exit repeat end repeat Precision = integer(n) else Precision = the maxInteger end if -- Type Specifier if voidP(this.getAProp(#__Transforms)) then this.__Transforms = ["u": #_ToUnsignedDecimal, "d": #_ToSignedDecimal, "f":#_ToFloat, "s":#_ToString, "X": #_ToHex, "x": #_ToHexLower, "b": #_ToBinary] end if typeSpecifier = this.__Transforms.getAProp(nk) if voidP(typeSpecifier) then put #error else out[1] = out[1]& call(typeSpecifier, this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) end if return startChar end on _ToString (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) r = "" & (typeSpecifiers[tsIdx[1]]) if padding= "" then padding = " " if minWidth > -1 then if align = #left or sign = "-" then w = length(r) + 1 repeat with i = w to minWidth r = r & padding end repeat else w = length(r) + 1 repeat with i = w to minWidth r = padding & r end repeat end if end if if length(r) > Precision then r = r.char[1..Precision] end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToUnsignedDecimal (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) -- for negative numbers, it just drops the minus sign (not how PHP does it) i = GetNumber(typeSpecifiers[tsIdx[1]], #Integer, VOID) -- if i < 0 then i = i + 65536 -- r = ""& abs(i) -- padding if padding <> "" then repeat while length(r)< minWidth r = padding & r end repeat end if -- min width if minWidth > -1 then if align = #left then w = length(r) + 1 repeat with i = w to minWidth r = r & " " end repeat else w = length(r)+ 1 repeat with i = w to minWidth r = " " & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToFloat (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) Precision = min(12, Precision) -- director's limit? r = "" & GetNumber(typeSpecifiers[tsIdx[1]], #Float, VOID, Precision) -- &__GetFloat(typeSpecifiers[tsIdx[1]], Precision) -- padding if padding <> "" then repeat while length(r)< minWidth r = padding & r end repeat end if -- min width if minWidth > -1 then minWidth = minWidth + Precision if align = #left then w = length(r) repeat with i = w to minWidth r = r & " " end repeat else w = length(r) repeat with i = w to minWidth r = " " & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToSignedDecimal (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) -- put sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx i = GetNumber(typeSpecifiers[tsIdx[1]], #Integer, VOID) if sign <> "" AND i > 0 then r= "+"&i else r= "" & i -- padding if padding <> "" then repeat while length(r)< minWidth r = padding & r end repeat end if -- min width if minWidth > -1 then if align = #left then w = length(r)+1 repeat with i = w to minWidth r = r & " " end repeat else w = length(r)+1 repeat with i = w to minWidth r = " " & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToHex (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) r = GetNumber(typeSpecifiers[tsIdx[1]], #Hex, VOID, FALSE) if padding= "" then padding = " " if minWidth > -1 then if align = #left then w = length(r) repeat with i = w to minWidth r = r & padding end repeat else w = length(r) repeat with i = w to minWidth r = padding & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToHexLower (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) r = GetNumber(typeSpecifiers[tsIdx[1]], #Hex, VOID, TRUE) if padding= "" then padding = " " if minWidth > -1 then if align = #left then w = length(r) repeat with i = w to minWidth r = r & padding end repeat else w = length(r) repeat with i = w to minWidth r = padding & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on _ToBinary (this, sign, padding, align, minWidth, Precision, typeSpecifiers, tsIdx) r = GetNumber(typeSpecifiers[tsIdx[1]], #Binary, VOID) if padding= "" then padding = " " if minWidth > -1 then if align = #left then w = length(r) repeat with i = w to minWidth r = r & padding end repeat else w = length(r) repeat with i = w to minWidth r = padding & r end repeat end if end if tsIdx[1] = tsIdx[1]+ 1 return r end on __GetInteger (aThing) return GetNumber(aThing, #Integer) end on __GetFloat (aThing, precision) return GetNumber(aThing, #Float) end on __GetHexString (aThing, userLower) return GetNumber(aThing, #Hex, VOID, userLower) end on __GetBinary (aThing) return GetNumber(aThing, #Binary, VOID) end