printf() for lingo

Being a newcomer to Adobe Director 11 and it's implementation of lingo, I went in search of a printf() function to assist the formating of numerical data. The only version I found had little in common with the ansi C printf, so I wrote my own.


Source Script

on printf formatStr, varList
  outStr = ""
  vi = 1  -- set for first in varList
  repeat with i = 1 to formatStr.length
    c1 = formatStr.char[i]
    n1 = charToNum(c1)
    case n1 of
      37  -- %
        if vi > count(varList) then
          alert "ERROR No enough variables to match format" & formatStr
        end if
        v = varList[vi]
        --put "Var #" & string(vi) & "= " & string(v)
        vi = vi + 1
        p = 0 -- places before decimal point
        n = 0 -- number accumulator
        decimal_found = False
        leading_zeros = False
        left_justify = False
        repeat with j = i + 1 to formatStr.length
          c2 = formatStr.char[j]
          n2 = charToNum(c2)
          -- convert uppercase to lowercase
          if n2 >= 65 and n2 <= 90 then
            n2 = n2 + 32
            c2 = numtoChar(n2)
          end if
          --put "Next format letter" & c2
          -- is this a numeral
          if n2 >= 48 and n2 <= 57 then
            if n2 = 48 and n = 0 and not decimal_found then
              leading_zeros = True
              --put "Leading zeros"
            end if
            n = n*10 + n2 - 48
          else  
            case c2 of
              "%"
                outStr = outStr & "%"
              "." -- decimal point
                decimal_found = True
                p = n
                n = 0
              "-"
                left_justify = True
              "*"
                -- use next variable as format number
                if not integerP(v) then
                  alert "ERROR Variable type does not match integer format" & formatStr
                end if
                n = v
                vi = vi + 1
              "c"
                --put "Character type places" & n
                if not stringP(v) then
                  alert "ERROR Variable type does not match string format" & formatStr
                end if
                vStr = v
                i = j
                exit repeat
              "s"
                --put "String type places" & n
                if not stringP(v) then
                  alert "ERROR Variable type does not match string format" & formatStr
                end if
                vStr = v
                i = j
                exit repeat
              "d"
                --put "Decimal type Places" & n
                if not integerP(v) then
                  alert "ERROR Variable type does not match integer format" & formatStr
                end if
                vStr = string(v)
                i = j
                exit repeat
              "f"
                --put "Float type Places" & p & " Decimals" & n
                if not integerP(v) and not floatP(v) then
                  alert "ERROR Variable type does not match float format" & formatStr
                end if
                vStr = string(v)
                if decimal_found then 
                  --put "Raw",vStr
                  dn = offset(".",vStr)
                  dp = vStr.length - dn
                  --put "Decimal places" & dp
                  if dp > n then
                    --put "remove excess decimal places"  
                    vStr = vStr.char[1..vStr.length - (dp-n)]
                  else
                    if dp < n then
                      --put "add extra decimal places"
                      repeat with pi = 1 to dp-n
                        vStr = vStr & "0"
                      end repeat
                    end if
                  end if
                end if
                i = j
                exit repeat
              otherwise
                alert "ERROR Format not recognised" & formatStr
            end case
          end if
        end repeat
        if not decimal_found then
          p = n
        end if
        --put "Raw variable" & vStr
        -- left justify puts vStr first
        if left_justify then
          outStr = outStr & vStr
        end if
        -- pad the output if necessary
        if vStr.length < p then
          repeat with pi = 1 to p - vStr.length
            if leading_zeros then
              outStr = outStr & "0"
            else
              outStr = outStr & " "
            end if
          end repeat
        end if
        -- normal right justify
        if not left_justify then
          outStr = outStr & vStr
        end if
        -- put string(i)
        -- put string(formatStr.length)
      otherwise
        -- put "Non format" & c1
        outStr = outStr & c1
    end case
    -- ready to look for the next problem
  end repeat
  return outStr
end

Usage

string = printf(format_string,list_of_variables)

Format_string currently supports %[-][0][# or *][.# or .*][d, f or s] where # is an integer. For an explanation of printf() format consult any C text book, but basically:

Naturally some of these work in combination and others don't.

In use this lingo printf() is really more like sprintf(str,...) from C, printf() from Matlab or format % tuple from python, in that the function returns a string rather than printing directly to the stdout path and that the arguments are passed to it in a list.

As an example consider the following code:

member("CountDown").text = printf("%02d:%02d:%02d",[h,m,s])

where h, m and s are integers representing hours, minutes and seconds. This might be printed out as 00:00:00.


To Do

I can't see any reason why it would be usefull to add the %u (unsigned) or %p (pointer) formats.

Please contact me with any improvements you would care to offer.