begin ; !TOBIN: Convert Motorola object to binary

! Addresses are assumed to start at relative zero and
! to be monotonic increasing

include  "inc:util.imp"

routine  tobin
integer  sym,checksum,loc,pos,reclen,type

  routine  stop(string (255)s)
    selectoutput(0); printstring(s)
    newline; stop 
  end 

  routine  phex(integer  x)
    phex(x>>4) if  x>>4#0
    x=x&15; x=x+7 if  x>9
    printsymbol(x+'0')
  end 

  routine  scan; !Hunt to start of next record of type 1 or 2
    cycle 
      readsymbol(sym) until  sym>' '
      stop("Illegal record delimiter") unless  sym='S'
      readsymbol(type)
      returnif  type='1' or  type='2'
      exitif  type='9'
      stop("Illegal record type") unless  type='0'
      readsymbol(sym) until  sym<' '
    repeat 
    selectoutput(0); phex(loc); stop("")
  end 

  integerfn  nibble
    readsymbol(sym); sym=sym-7 if  sym>='A'
    stop("Invalid hex digit") unless  '0'<=sym<='?'
    result =sym-'0'
  end 

  integerfn  byte
  integer  b
    b=nibble<<4; b=b+nibble
    checksum=checksum+b; reclen=reclen-1; result =b
  end 

  integerfn  word
  integer  w
    w=byte<<8; result =w+byte
  end 

  pos=-1
  cycle 
    scan
    checksum=0; reclen = 0; reclen=byte-1
    stop("Record too short") if  reclen<3
    sym=byte if  type='2'; !Ignore ms byte of 3-byte address
    loc=word
    pos=loc if  pos=-1
    while  pos<loc cycle 
      pos=pos+1; printsymbol(255)
    repeat 
    cycle 
      printsymbol(byte); loc=loc+1; pos=loc
    repeatuntil  reclen<=0
    sym=byte
    stop("Checksum error") if  (checksum+1)&255#0
  repeat 
end 

string (255)parm,in,out

  onevent  3,4,9 start 
    selectoutput(0)
    printstring(event_message); newline
    stop 
  finish 

  parm = cliparam
  in = parm and  out = parm unless  parm -> in.("/").out
  selectinput(1); openinput(1,in)
  selectoutput(1); openoutput(1,out)
  tobin

endofprogram