[comp.lang.clu] Generalised integer unparse routine.

scc@cl.cam.ac.uk (Stephen Crawley) (01/31/89)

I found that I needed a routine for unparsing integers in hexadecimal with
leading zero padding.  The MIT libraries include a routine i_hunparse,
but it is too simple minded for the job in hand.  So I've written a routine
i_unparse() that solves the general problem.  

-- Steve

================
%% Unparse an integer into a string.
%%   'i' is the number to be unparsed.
%%   'base' is the base for the number which must be in the
%%       range 2 <= base <= 36.
%%   'width' is the minimum width for the result string.
%%   If 'zero_fill' is TRUE the result is padded with zeros to the left.
%%   If 'left_adjust' is TRUE the result is padded with spaces to the right.
%%   Otherwise the result is padded with spaces to the left hand.


i_unparse = PROC (i, base, width: int, zero_fill, left_adjust: bool) 
	    RETURNS (string) SIGNALS (bad_args)
  ac = array[char]
  OWN digits: string := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

  IF base <= 1 COR base > string$size(digits) COR 
     width < 0 COR width > 2**16 - 1 THEN
    SIGNAL bad_args
    END
  
  hi: int := width
  fill: char := ' '
  IF width = 0 THEN
      hi := 20
      left_adjust := FALSE
      zero_fill := FALSE
    ELSEIF zero_fill THEN
      fill := '0'
      left_adjust := FALSE
    END
  chars: ac := ac$fill(1, hi, fill)
  pos: int := hi
  IF i = 0 THEN
      chars[pos] := '0'
      pos := pos - 1
    ELSE
      negative: bool := i < 0
      IF negative THEN i := -i END
	EXCEPT WHEN overflow:
	  %% Phooey!!! MIN_INT can't be negated!
	  %% Do the 1st loop iteration by steam.
	  i := -(i + 1)
	  d: int := i // base + 1
	  i := i / base
	  IF d = base THEN
	    d := 0
	    i := i + 1
	    END
	  chars[pos] := digits[d + 1]
	  pos := pos - 1
          END

      %% Build the digits
      WHILE i > 0 DO
	digit: char := digits[i // base + 1]
	i := i / base
	IF pos > 0 THEN
            chars[pos] := digit
	  ELSE
            ac$addl(chars, digit)
	  END
        pos := pos - 1
        END

      %% Prepend the '-' sign before the 1st digit
      IF negative THEN
        IF pos <= 0 THEN
	    ac$addl(chars, '-')
	    pos := pos - 1
          ELSEIF zero_fill THEN
	    chars[1] := '-'
	    pos := 0
	  ELSE
	    chars[pos] := '-'
	    pos := pos - 1
	  END
	END 
    END

  %% Left adjust by shuffling the chars down and filling with ' 's
  IF left_adjust CAND pos > 0 THEN
    FOR j: int IN int$from_to(1, hi - pos) DO
      chars[j] := chars[j + pos]
      END
    FOR j: int IN int$from_to(hi - pos + 1, hi) DO
      chars[j] := ' '
      END
    END
  IF width = 0 CAND pos > 0 THEN ac$trim(chars, pos + 1, hi - pos) END
  RETURN (string$ac2s(chars))
  END i_unparse
================
%% Unparse an integer in hexadecimal

i_hunparse = PROC (i: int) RETURNS (string)
  RETURN (i_unparse(i, 16, 0, FALSE, FALSE))
  END i_hunparse
================
%% Unparse an integer in octal

i_ounparse = PROC (i: int) RETURNS (string)
  RETURN (i_unparse(i, 8, 0, FALSE, FALSE))
  END i_ounparse