! Name-Server data base interrogation routines.
! J. Butler Nov 84.
! These are somewhat experimental and subject to change. Please tell me if you're
!writing material which uses them.

!to use..

!open ns db opens access to the database and returns a reference number (xno)
!for use by read ns db and close ns db.

!read ns db takes parameters.. reference no., station reference, address.
!The station reference is a station number (bottom byte) and a short/long flag
!(top bit). If the bit is clear, a short station name will be dumped in the
!8 bytes from ADDRESS, padded to right with characters <= ' '. If the bit is
!set, a 64-byte record of type ns lfm will be dumped from ADDRESS. The result
!passed back is either the length of the requested data or a -ve number denoting
!a failure.

!close ns db closes the database

!fs sname takes a station number and returns the short station name or "".
!fs lname takes a station number and returns the long station name or "".
!fs get ns info takes a station number and returns a record of type ns lfm

!%include "nsdefs.inc"
!%include "inc:fs.imp"
%conststring (15) ns file = "managr:ns.dat"
%constinteger long = 16_80000000

%string (15) %fn hdx(%integer no)
   %integer i
   %string (15) s = ""
   %for i = 0, 1, 2 %cycle
      s = tostring(no&15+'0').s; no = no>>4
   %repeat
   s = tostring(no+'0').s
   %result = s
%end

%integerfn open ns db
%string(127)cr
  cr = "S".tostring(userno+'0').ns file.tostring(nl)
  etherwrite(lsap,charno(cr,1),length(cr))
  length(cr) = etherread(lsap,charno(cr,1),255)
  %result = 0 %if charno(cr,1)='-'; !New file
  %result = charno(cr,1)-'0'
%end

%routine close ns db(%integer xno)
  %integer i
  i = fcomm('K0'+xno,"")
%end

%integerfn read ns db(%integer xno, cellno, address)
%bytearray buff(0:532)
%string(127)c
%integer count,pos,size,char,blockno,recno, ptr, celllen
  %onevent 15 %start
    %result = -1
  %finish
  %result = -2 %unless 0 <= cellno & (\long) <= max addr
  %if cellno & long = 0 %start
     celllen = 8
     blockno = cellno>>6; recno = cellno&63
  %else
     celllen = 64; cellno = cellno & (\long)
     blockno = cellno>>3+2; recno = cellno&7
  %finish
  c = "R".tostring(xno+'0').hdx(blockno).tostring(nl)
  etherwrite(lsap,charno(c,1),length(c))
  pos = addr(buff(0)); size = 0; ptr = pos
  count = etherread(lsap,buff(0),532)
  %result = -3 %if byteinteger(pos)<'0'
  %cycle
    char = byteinteger(ptr)-'0'; ptr = ptr+1
    %exitif char<0
    size = size<<4+char
  %repeat
  %result = -4 %unless size+ptr-pos=count
  count = size
  %result = -5 %unless size&(celllen-1) = 0
  %result = -6 %unless size >= (recno+1)*celllen
  pos = ptr + recno*celllen
  %for ptr = 0, 1, celllen-1 %cycle
      byteinteger(address+ptr) = byteinteger(pos+ptr)
  %repeat
  %result = celllen
%end

%string (8) %fn fs sname(%integer dte)
   %bytearray data(0:8)
   %integer xno, l
   xno = open ns db
   %result = "Open Err" %if xno <= 0

   data(0) = read ns db(xno, dte, addr(data(1)))
   data(0) = data(0)-1 %while data(0) # 0 %and data(data(0)) <= ' '
   close ns db(xno)
   %result = string(addr(data(0)))
%end

%integerfn fs get ns info(%integer dte, address)
   %integer xno, l
   xno = open ns db
   %result = 0 %if xno <= 0
   l = read ns db(xno, dte ! long, address)
   close ns db(xno)
   %result = l
%end

%string (31) %fn fs lname(%integer dte)
   %record (ns lfm) lf

   !lf_room is the byte in front of lf_lname. Use it as a string length
   lf_room = fs get ns info(dte, addr(lf))
   %result = "" %if lf_room <= 0
   lf_room = 31
   lf_room = lf_room-1 %while lf_room > 0 %and lf_lname(lf_room) <= ' '
   %result = string(addr(lf_room))
%end

%endoffile
