! Spellvk V1.0
!
!  persistent data structure
!
!  relocatable data start (4) ->
!  bytes allocated        (4)
!  total word count       (4)
!  <NL>                   (1)
!  dict start:
!  dict end:              (dict size)
!  align to 4-byte boundary (0..2)
!  relocatable data start:
!  first word pointer:
!  main index             (4*total word count)
!  last word pointer+4: !!
!  sub index starts(0:63) (4*64)
!  sub indices:           (4*total word count)
!  heap end:
!

%external %integerfn %spec  Load File (%string (255) file name,
                                     %integer      buffer size,
                                     %integer      address)
%external %routine %spec XLoad File (%string (255) file name,
                                     %integer      buffer size,
                                     %integer      address)
%external %integer %fn %spec Save File (%integer straddr,strlen,
                                     %integer     buffer size,
                                                  address)
%begin

  %string (255) heap file = "adfs::0.$.words.dict"
  %const %integer max heap size = 800 000
  %byte %array heap(0 : max heap size)
  %integer heap base = ADDR(heap(0)), heap size, heap end

! Mapped data
  %integer %name relocatable data start
  %integer %name Bytes allocated
  %integer %name total word count

  %integer first word pointer, last word pointer

  %record %format sub index ptr fm(%integer %array sub index(0:63))
  %record (sub index ptr fm) %name sub index starts


  %constant %integer max word length = 63

  %integer dict size, dict beg, dict end, subdict beg, subdict end
 ! dict size - actual no. of bytes from first A to NL after last Z
 ! dict beg - first A
 ! dict end - NL after last Z word

  %integer word beg, word end, word length
 ! word beg - first letter of word
 ! word end - NL after word
 ! word length = no. of chars in word EXCLUDING NL

  %string (63) %fn str (%integer sp)
  %string(63) s = ""
    %while BYTE(sp) # NL %cycle
      s = s.BYTE(sp); sp = sp+1
      %if LENGTH(s) =63 %start
        printstring(nl."Argh!! - string too long".nl)
        %result=s
      %finish
    %repeat
    %result = s
  %end

  %routine Load indices
    %constant %integer os length index = 2
    %record %format osfile array fm (%c
      %integer %array element (0:3) %c
    )
    %record (osfile array fm) osfile array
    %record %format Time stamp fm (%integer low, high)
    %record (time stamp fm) time stamp
    %external %integer %fn %spec XGet file information(%c
      %record (osfile array fm) %name osfile array, 
      %record (time stamp fm) %name time stamp,
      %string (255) file name)

    %integer success = XGet file information(osfile array,
                                             time stamp,
                                             heap file)
    %if success # 1 %then %start
      printstring("Dictionary unavailable - should be ".heap file.nl)
    %finish
    heap size = osfile array_element(os length index)
    ! ALIGN
    heap base = (heap base+3) & (\3)
    XLoad file(heap file, heap size, heap base)

    INTEGER(heapbase)=INTEGER(heapbase)+heapbase
    Relocatable data start == INTEGER(heapbase)
    Bytes allocated == INTEGER(heapbase+4)
    total word count == INTEGER(heapbase+8)
    heap end = heap base+bytes allocated
    dict beg = heap base+13
    %integer ptr
    %for ptr=relocatable data start,4,((heap end-4)+3)&(\3) %cycle
     INTEGER(ptr)=INTEGER(ptr)+heap base
    %repeat
    dict end = relocatable data start
    dict end = dict end-1 %until BYTE(dict end)=NL
    { dict beg & dict end really shouldn't be needed }
    first word pointer = relocatable data start
    last word pointer = relocatable data start+(4*total word count)-4
    sub index starts == RECORD(last word pointer+4)
  %end


  %predicate Exists(%integer target beg, %integer target length)
  %integer splitp, i, word ptr, target ptr, tmp1,tmp2,tmp3
    subdict beg=sub index starts_sub index(target length)
    subdict end=sub index starts_sub index(target length+1)-4
    %cycle
      %if subdict beg > subdict end %then %false
tmp1=subdict beg
tmp2=subdict end
tmp3=tmp2-tmp1
%if tmp3<0 %start
printstring("????")
%finish
tmp3=tmp3//4
tmp3=tmp3//2
tmp3=tmp3*4
splitp=tmp1+tmp3
%unless subdict beg <= splitp<=subdict end %start
printstring("!!!!".NL)
%monitor
%stop
%finish
      word beg = INTEGER(splitp); word ptr=word beg; target ptr=target beg
      %for i = 0,1,target length-1 %cycle
        %if BYTE(word ptr)>BYTE(target ptr) %then %start
          subdict end = splitp-4; ->continue2
        %finish
        %if BYTE(word ptr)<BYTE(target ptr) %then %start
          subdict beg = splitp+4; ->continue2
        %finish
        word ptr=word ptr+1;target ptr=target ptr+1
      %repeat
      %true
continue2:
    %repeat
  %end

!***************** MAIN PROG ***************

  Load indices

%byte %array literal(0:63), target(0:63)
%integer ttchan
  %external %integer %fn %spec XFindOutput(%string(255) str)
  ttchan = xfindoutput("RAWVDU:")

  %integer buffptr,endptr
  %integer buff

%routine printsymbol(%integer i)
  %external %routine %spec XSWriteByte(%integer c,i)
  XSWriteByte(ttchan,i)
%end

%integerfn nextsym
  %result=BYTE(buffptr)
%end

%routine skipsym
  buffptr=buffptr+1
%end
  
%predicate endinp
  %true %if buffptr=endptr
  %false
%end

!*************************************************************************

%external %integer %fn %spec  Proc ID (%routine X)

%external %routine %spec Stop(%integer res)

%external %integer %fn %spec Verbosity Required(%integer Handle)

%external %integer %fn %spec ArgumentInit(%c
  %integer %name Handle,
  %string(255) keyString,
  %integer Input wanted, Output wanted,
  %string(255) Identification,
  %integer Help proc)

%external %integer %fn %spec XGetPresence(%c
  %string(255) key,
  %integer Handle)

%external %integer %fn %spec XGetStateArg(%c
  %string(255) key,
  %integer Handle)

%external %integer %fn %spec XGetCardinalArg(%c
  %string(255) key,
  %integer Index,
  %integer Handle)

%external %integer %fn %spec XGetStringArg(%c
  %string(*) %name argument,
  %string(255) Key,
  %integer Index,
           handle)

%external %integer %fn %spec XGetNumberOfValues(%c
  %string(255) Key,
  %integer handle)

%integer string length, handle, result, verbosity level, i, j


%routine Help
  printstring("SpellCk - spelling checker V1.0".snl)
  printstring(snl)
  printstring("  -input file".snl)
  printstring(snl)
%end

%string (255) %fn  sub string (%string (255) s, %integer first, last)
   %integer i
   %string (255) sub
   sub = ""
   %for i = first, 1, last %cycle
      sub = sub. char no (s, i)
   %repeat
   %result = sub
%end

%string(255) params, source, list, object, dummy, file
{-------------------------------------------------------------------------}

  result = ArgumentInit(%c
                handle,
                "INput=FROM/A/E",     %c
                0 , 0,
                "SpellCk V1.0 (c) Graham Toal",
                Proc ID(Help))
  %if result < 0 %then Stop(result)

  verbosity level = Verbosity Required(handle)

  string length = XGetStringArg(file, "INPUT", 1, handle)
  %for j = string length, -1, 1 %cycle
    charno(file, j) = charno(file, j-1)
  %repeat
  length(file) = string length
  source = file
printstring("Loading ".source.nl)
!*************************************************************************
    %constant %integer os length index = 2
    %record %format osfile array fm (%c
      %integer %array element (0:3) %c
    )
    %record (osfile array fm) osfile array
    %record %format Time stamp fm (%integer low, high)
    %record (time stamp fm) time stamp
    %external %integer %fn %spec XGet file information(%c
      %record (osfile array fm) %name osfile array, 
      %record (time stamp fm) %name time stamp,
      %string (255) file name)

    %integer success = XGet file information(osfile array,
                                             time stamp,
                                             source)
    %if success # 1 %then %start
      printstring("Dictionary unavailable - should be ".heap file.nl)
    %finish

  %integer FILE SIZE = osfile array_element(os length index)
  %byte %array zzz(0:FILE SIZE+1)
  buffptr=ADDR(zzz(0))
  endptr=buffptr+FILE SIZE
  success = loadfile(source, FILE SIZE, buffptr)
  %if success < 0 %then %start
    Print string("Cannot load ".source.nl)
    %stop
  %finish

!*************************************************************************



%routine transfer garbage
%integer sym
  %cycle
    %exit %if endinp
    sym = nextsym
    %if 'a'<=sym<='z' %or 'A'<=sym<='Z' %then %exit
    %if 32<=sym<=126 %then Print symbol(sym) %else printsymbol(32)
    skipsym
    %if sym=NL %then printsymbol(10) %and printsymbol(13)
  %repeat
%end

%routine Read Word ;! Assert - next char IS a letter
%integer sym, i = 0
  %cycle
    %exit %if endinp
    sym = nextsym
    %unless 'a'<=sym<='z' %or 'A'<=sym<='Z' %then %exit
    skipsym
    literal(i) = sym
    target(i) = sym!32
    i=i+1
  %repeat
  word length = i
  target(i)=NL; literal(i)=NL
%end

%routine print word(%byte %array %name t)
  %string(255) s = str(ADDR(t(0)))
  %integer i
  %for i = 1,1,length(s) %cycle
    printsymbol(charno(s,i))
  %repeat
%end
%constant %integer on = 1, off = 0
%routine Highlight(%integer onoff)
  %if onoff=on %then %start
    printsymbol(17);printsymbol(0);printsymbol(17);printsymbol(129)
  %else
    printsymbol(17);printsymbol(1);printsymbol(17);printsymbol(128)
  %finish
%end

%routine Check
  %cycle
    Transfer Garbage
    %exit %if endinp
    Read Word
    %if %not exists(ADDR(target(0)),word length) %start
      Highlight(on)
      Print word(literal)
      Highlight(off)
    %else
      Print word(literal)
    %finish
    %exit %if endinp
  %repeat
%end

Check

%endofprogram
