
  'FORMATTING SOURCE CODE
  '======================



   =============
   class wordman
   =============

  sys    bb   'starting position
  sys    bc   'starting position of word
  sys    aa   'ascii code of word
  sys    le   'length of word
  string w    'temp word

  method skiplspace(s as string, i as sys)
  ========================================
  sys a
  if i>len(s) then exit sub
  do
    a=asc s,i
    select a
    case 0         : exit do
    case 13        : exit do 'exit at end of a line
    case 10        : exit do
    case 33 to 255 : exit do 'exit at start of word 
    end select
    i++
  end do
  end method

  method getword(string s, sys*b) as string
  =========================================
  sys a,c,d
  a=0
  bb=b
  do
    c=asc s,b
    select c
    case 0, 33 to 255 : exit do
    end select
    b++
  end do
  bc=b
  aa=c
  select c
  case 34,96 'CAPTURE QUOTES
    do
      b++
      d=asc s,b
      if d=0 or d=c then b+=1 : jmp fwd done
    end do
  end select 
  do
    c=asc s,b
    select c
    case 0 to 32    : exit do 'white space
    case 35,95      :         ' # _
    case 48 to 57   :         'numbers
    case 65 to 90   :         'capitals
    case 97 to 122  :         'lower case
    case 127 to 255 :         'higher ascii
    case else
      if b=bc then b+=1       ' self-terminating symbol
      exit do
    end select
    b++ 
  end do
  '
  done:
  '
  le=b-bc
  if le then return mid s,bc,le
  end method

  method instrword(sys i,string s,k) as sys
  =========================================
  do
    w=getword s,i
    if aa=0 then return 0
    if w=k then return bc
  end do
  end method

  method instrwordce(sys i,string s,k) as sys
  ===========================================
  do
    w=getword s,i
    if aa=0 then return 0
    if aa=58 then return i
    if w=k then return i
  end do
  end method

  end class 'wordman



  ============
  class buffer
  ============
  '
  string br    'buffer string
  sys    lb    'length of buffer
  sys    chars 'accum char count

  method get() as string
  ======================
  return left br,chars
  end method

  method append(string s)
  =======================
  sys a,le
  le=len s
  a=le+chars
  if a>lb
    br+=space(8192) 'stretch
    lb+=8192
  end if
  mid (br,chars+1)=s
  chars+=le
  end method
  '
  end class





  ==============
  class indenter
  ==============

  has wordman wm 'text word utilities
  has buffer  buf 'buffer to hold result
  '
  'SETTINGS
  sys     instep  'indent step size
  sys     lmargin 'left margin
  'SHARED STATES
  sys     lcount  'line counter
  sys     dcount  'indent counter (test)
  sys     embcmt  'embedded comment flag /* .. */
  sys     indi    'indent relative
  sys     indo    'indent accumulator

  method spacer(string t,s1,s2,sys n) as sys
  ==========================================
  sys a,b,c,le,i=1
  b=wm.instrword i,t,s1
  if b=1 'start of word
    n*=instep 'create a new indent for the next line
    if s2
      b=wm.instrword i,t,s2 'block closing on same line
    else
      b=0
    end if
    '
    if b then 'check for commented out end-blocks
      if s2="then" then
        b+=4
        wm.skiplspace t,b
        select asc t,b
        case 0,39,59 : indi=n
        end select
      end if
      a=wm.instrword 1,t,"'" : if a>0 and a<b then indi=n
      a=wm.instrword 1,t,";" : if a>0 and a<b then indi=n
    else
      indi=n
    end if 's2
    if n=0 then indo-=instep : indi=instep 'else elseif case
    if indi<0 then indo+=indi : indi=0
    if indo<0 then indo=0 'clamp min indentation
    'when indi>0 then the indent will be applied to the next line
    return 1
  end if 's1
  end method

  method clean(string s) as string
  ================================
  sys a,i,e
  string bu=s
  e=len bu
  do
    i++
    if i>e then exit do
    a=asc bu,i
    select a
    case 13,10   : 'do not replace
    case 0 to 31 : mid bu,i," " 'replace with space
    end select
  end do
  return bu
  end method

  method indent(string dat)
  =========================
  '
  sys    a,b  'temp
  sys    ex   'exit flag
  sys    pu=1 'next line position
  string s    'line string
  string t    'line string lowercase
  string bu   'cleaned dat
  '
  bu=clean dat
  do
    if ex then exit do
    a=instr pu,bu,cr
    if a=0 then ex=1 : a=1+len bu
    '
    s=mid bu,pu,a-pu  'extract line
    pu=a+len(cr)      'skip cr
    '
    do 'redocmt:
      '
      s=ltrim rtrim s 'remove previous indents and endspace
      t=lcase s       'view lowercase for keyword matching
      '
      if embcmt
        a=instr t,"*/"
        if a
          embcmt=0
        end if
        exit do
      else
        if asc(t)=47
          if asc(t,2)=42
            b=instr(3,t,"*/")
            if b
              t=mid(s,b+2)
              s=space(lmargin+indo)+left(s,b+1)
              buf.append s
              s=t
              continue do 'look at rest of line again
            else
              embcmt=1
            end if
          end if
        end if
      end if
      exit do
    end do
    '
    if     spacer(t, "(", ")",1)
    elseif spacer(t, "{", "}",1)
    elseif spacer(t, "select", "",1)
    elseif spacer(t, "sub", "",1)
    elseif spacer(t, "function", "",1)
    elseif spacer(t, "method", "",1)
    elseif spacer(t, "methods", "",1)
    elseif spacer(t, "type", "",1)
    elseif spacer(t, "class", "",1)
    elseif spacer(t, "macro", "",1)
    elseif spacer(t, "def", "",1)
    elseif spacer(t, "scope", "",1)
    elseif spacer(t, "if", "then",1)
    elseif spacer(t, "elseif", "",0)
    elseif spacer(t, "else", "",0)
    elseif spacer(t, "case", "",0)
    elseif spacer(t, "for", "next",1)
    elseif spacer(t, "do", "",1)
    elseif spacer(t, "while", "",1)
    elseif spacer(t, "end", "",-1)
    elseif spacer(t, "endif", "",-1)
    elseif spacer(t, "wend", "",-1)
    elseif spacer(t, "next", "",-1)
    elseif spacer(t, "endselect", "",-1)
    elseif spacer(t, "}", "",-1)
    end if
    '
    if s=""
      s=cr
    else
      s=space(lmargin+indo)+s+cr
      's=string(lmargin+indo," ")+s+cr
    end if
    '
    buf.append s
    indo+=indi
    if indi>0 then dcount+=1
    indi=0
    lcount+=1
  end do
  end method
  '
  end class 'indenter


  =====
  'main
  =====
  '
  '#recordof indenter
  indenter id
  id.instep=2  'indent step size
  id.lmargin=2 'left margin
 id.indent getfile "in.txt"
 'id.indent getfile "ind1.o2bas"
  putfile "out.bas",id.buf.get
 'print "ok  " id.buf.chars "  bytes  " id.lcount " lines  " id.dcount " indents"
  print id.buf.get

