begin ; !APM IMP Library
!** NB must not contain owns
!** Value of string FNAME must be name of MOB file
!** Some string value parameters masquerading as names
!
!IMP PRIM+PERM procedures are dealt with in one of four ways:
!  .  never called -- in-line code generated (eg store-mapping)
!  .  included in APM system and called via extracode call vector,
!     (eg floating point routines)
!  .  compiled into program as procedures (eg array access)
!  .  included in this library which is pre-loaded and referenced
!     by external call mechanism (except for CONNECT and EXTLOAD
!     which are inserted into the extracode call vector when loaded)
!
@16_1114 routine  signal(integer  code)
@16_1198 routine  phex(integer  x)
recordformat  DICT(integer  a,b,c,d)
@16_3FAC integer  cliparamad
@16_3FC0 record (dict) FILDICT
@16_3FD0 record (dict) EXTDICT
@16_3FE0 record (dict) SYSDICT
@16_117C integerfn  DEFNAME(string (255)s,record (dict)name  d,
                                integer  size)
@16_1180 integerfn  REFNAME(string (255)s,record (dict)name  d)
@16_1184 routine    TRANSNAME(integer  ref,string (255)name  s)
@16_1110 integerfn  FCOMMR(integer  c,string (255)p,
                               bytename  b,integer  max)
@16_1100 routine    ETHERWRITE(integer  port,bytename  buf,
                                   integer  size)
@16_1104 integerfn  ETHERREAD(integer  port,bytename  buf,
                                  integer  max)
!
!!!!!!!!!!!!!!!!!  Floating-point input/output  !!!!!!!!!!!!!!!!!!!!!!!
externalroutine  FREAD alias  "read"(name  v)
!Called only for reals
integer  sign=0,sym
real  value,exp
  cycle 
    sym = nextsymbol
    exit  if  sym > ' '
    skipsymbol
  repeat 
  if  sym = '-' start 
    sign = 1
    skip symbol;  sym = nextsymbol
  finish 
  value = 0
  if  sym # '.' start 
    signal  4,1,sym unless  '0' <= sym <= '9'
    cycle 
      value = value*10.0+(sym-'0')
      skip symbol;  sym = nextsymbol
    repeat  until  not  '0' <= sym <= '9'
  finish 
  if  sym = '.' start 
    exp = 10.0
    cycle 
      skip symbol;  sym = nextsymbol
      exit  unless  '0' <= sym <= '9'
      value = value+(sym-'0')/exp
      exp = exp*10.0
    repeat 
  finish 
  if  sym = '@' start 
    skipsymbol
    read(sym)
    value = value*10.0^sym
  finish 
  value = -value if  sign # 0
!  v = value
  *move v,a0
  *move value,(a0)
end ;  !fread
externalroutine  READREAL(realname  v)
  fread(v)
end 

externalroutine  PRINT(real  x, integer  n,m)
constreal  pmax = 2147483647.0
real  y,z
integer  i=0,l,count=0,sign
  sign = ' '
  sign = '-' if  x < 0
  y = |x|+0.5/10.0^m;  !modulus, rounded
  if  y > pmax start 
    count = count+1 and  y = y/10.0 until  y < 10.0
  finish 
  z = 1.0
  cycle 
    i = i+1;  z = z*10.0
  repeat  until  z > y
  spaces(n-i)
  printsymbol(sign) unless  sign = ' ' and  n <= 0
  cycle 
    z = z/10.0
    l = int pt(y/z)
    y = y-l*z
    printsymbol(l+'0')
    i = i-1
    exit  if  i+m <= 0
    print symbol('.') if  i = 0
  repeat 
  printsymbol('@') and  write(count,0) if  count # 0
end ;  !print

externalroutine  PRINTFL(real  x, integer  n)
real  y,round
integer  count=-99,sign=0
  if  x # 0 start 
    x = -x and  sign = 1 if  x < 0
   !Adjust X so that 1.0 <= rounded(X) < 10.0
    count = 0;  round = 0.5^n
    y = 1.0-round
    if  x < y start ;  !ie rounded(X) < 1.0
      count = count-1 and  x = x*10.0 until  x >= y
    finish  else  start 
      y = 10.0-round
      while  x >= y cycle ;  !ie rounded(X) > 10.0
        count = count+1;  x = x/10.0
      repeat 
    finish 
    x = -x if  sign # 0
  finish 
  print(x,1,n)
  printsymbol('@')
  write(count,0)
end ;  !printfl

externalintegerfn  int(real  r)
  result  = intpt(r+0.5)
end 

externalrealfn  fraction(real  r)
  result  = fracpt(r) if  r>=0
  result  = -fracpt(-r)
end 

externalintegerfn  round(real  r)
  result  = int(r)
end 

externalintegerfn  trunc(real  r)
  result  = intpt(r) if  r>=0
  result  = -intpt(-r)
end 


!!!!!!!!!!!!!!!!!!!!   Stream control     !!!!!!!!!!!!!!!!!!!!!!!!

constinteger  iocbsize=16, iocbshift=4
constinteger  icb0=16_35ce, ocb0=16_360e
@16_35c6 integer  icb
@16_35ca integer  ocb

externalintegerfn  INSTREAM
  result  = (icb-icb0)>>iocbshift
end 

externalintegerfn  OUTSTREAM
  result  = (ocb-ocb0)>>iocbshift
end 

!!!!!!!!!!!!!!!!!!!!   String procedures  !!!!!!!!!!!!!!!!!!!!!!!!

externalstring (255)fn  SUBSTRING(string (255) s, integer  from,to)
string (255) t
  t = ""
  while  from <= to cycle 
    t = t.tostring(charno(s,from));  from = from+1
  repeat 
  result  = t
end 

externalintegerfn  INDEX(string (*)name  var,match)
!Return index position of first occurrence of match within string
!** to be re-coded for efficiency **
integer  i=0,j,l=length(match)
  cycle 
    result  = 0 if  i > length(var)-l
    i = i+1
    j = 0
    cycle 
      result  = i if  j = l
      j = j+1
    repeat  until  charno(var,i+j-1) # charno(match,j)
  repeat 
end 

predicate  RESOLVE(string (*)name  var,match,fore,aft)
integer  i
routine  do aft
  aft = substring(var,i+length(match),length(var)) if  addr(aft) # 0
end 
  i = index(var,match)
  false  if  i = 0
  if  addr(fore) # 0 start 
    if  addr(fore) # addr(var) start 
      fore = substring(var,1,i-1)
      do aft
    finish  else  start 
      do aft
      length(var) = i-1
    finish 
  finish  else  do aft
  true 
end 

external string (127)fn  ITOS(integer  v,p)
integer  vv,q,pos
byteintegerarray  store(0:127)
  vv = v;  vv = -vv if  vv > 0
  pos = 127
  while  vv <= -10 cycle 
    q = vv//10
    store(pos) = q*10-vv+'0';  pos = pos-1
    vv = q
  repeat 
  store(pos) = '0'-vv
  if  p <= 0 start 
    p = 128+p
  else 
    p = 128-p
    p = pos if  p > pos
    p = p-1
  finish 
  pos = pos-1 and  store(pos) = '-' if  v < 0
  while  pos > p and  pos > 1 cycle 
    pos = pos-1;  store(pos) = ' '
  repeat 
  pos = pos-1;  store(pos) = 127-pos
  result  = string(addr(store(pos)))
end 

external integer fn  STOI(string (255) S)
integer  i,k
integer  sign=0, val=0
  i = 0
  while  i < length(s) cycle 
    i = i+1;  k = charno(s,i)
    continue  if  k <= ' '
    if  k = '-' start 
      sign = 1
    else  if  '0' <= k <= '9'
      val = val<<3+val+val+k-'0'
    else 
      signal  3, 1, k
    finish 
  repeat 
  result  = val if  sign = 0
  result  = -val
end 

externalroutinespec  PRINT LINE(string (255) s)
externalroutine  PRINT LINE
  *JSR printstring
  newline
end 

externalroutine  READ LINE(string (255)name  s)
integer  k
  s = ""
  cycle 
    read symbol(k)
    return  if  k < ' '
    s = s.tostring(k)
  repeat 
end 

externalroutine  READ STRING(string (*)name  s)
integer  k
  readsymbol(k) until  k>' '
  s = ""
  cycle 
    s = s.tostring(k)
    k = nextsymbol; returnif  k<=' '
    skipsymbol
  repeat 
end 

externalstring (31)fn  DATETIME
string (31)s
  length(s) = fcommr('G'<<8,"",charno(s,1),31)
  result  = s
end 

externalstring (8)fn  DATE;                !** No owns
!%string(31)s
!  s = datetime; length(s) = 8; %result = s
  *BSR DATETIME;  !ad -> A0
  *MOVE.B #8,(A0);  !alter length
end 

externalstring (5)fn  TIME;                !** No owns
!%string(31)s
!%integer p
!  s = datetime; p = addr(s)+length(s)-5
!  byteinteger(p) = 5; %result = string(p)
  *BSR DATETIME
  *LEA 10(A0),A0;  *MOVE.B #5,(A0);  !adjust start & length
end 

!!!!!!!!!!!!!!!!!!!!!!!  Parameter processing  !!!!!!!!!!!!!!!!!!!!!!!!!!

externalstring (255)fn  CLIPARAM
!Gives effect of VAX/VMS function for obtaining command parameters
string (255) s
!  %if cliparamad>0 %start
    s = string(cliparamad)
    result  = "" if  shortinteger(cliparamad)=511
    result  = s unless  s=""
!  %finish
  skip symbol while  nextsymbol = ' '
  read line(s)
  result  = s
end 

!!!!!!!!!!!!!!!!!!!!!!  File connection  !!!!!!!!!!!!!!!!!!!!!!!!!

recordformat  CONNINFO(integer  memstart,fstart,flim,memlim)
externalroutine  CONNECT(string (255)name  f,record (conninfo)name  d)
!Read in the file F to space allocated on the heap
! Allocate a total of D_FSTART + fsize + D_MEMLIM bytes
! and align file to D_FSTART within this space;
! D_MEMSTART := start of space;  D_FSTART := D_FSTART+D_MEMSTART
! D_FLIM := D_FSTART+fsize;  D_MEMLIM := D_MEMLIM+D_FLIM
@16_35C4 short   uno
@16_372C byte    cylock
@16_372D byte    fsport
integer  i,j,xno,len,blocks,pos,fsize,fpos,original
string (255) fscomm

routine  lock
  cylock = cylock+1
end 

routine  unlock
  returnif  cylock=0
  cylock = cylock-1
  cylock = 0 and  signal  0,1 if  cylock=128
end 

routine  GET(integername  v)
!Extract numeric info from FSCOMM
integer  k
  v = 0
  cycle 
    i = i+1;  k = charno(fscomm,i)
    i = i-1 if  k < ' '
    k = k-'0'
    return  if  k < 0
    v = v<<4+k
  repeat 
end 

routine  READ FILE(integer  ok)
integer  j
  unless  fsize=0 start 
    if  fpos#0 start 
      j = fsize-4
      while  j>=0 cycle 
        j = j-4; integer(pos) = integer(fpos)
        pos = pos+4; fpos = fpos+4
      repeat 
      j = j+4-1
      while  j>=0 cycle 
        j = j-1; byteinteger(pos) = byteinteger(fpos)
        pos = pos+1; fpos = fpos+1
      repeat 
    else 
      cycle 
        j = 512; j = fsize if  fsize<j
        j = etherread(fsport,byteinteger(pos),j)
        pos = pos+j if  ok # 0;  fsize = j unless  fsize=0
      repeatuntil  j#512
    finish 
  finish 
  unlock
end 

if  f # "" start 
  j = refname(f,fildict); fpos = 0
  if  j>0 and  integer(j)>0 start ; !File already in store
    fpos = integer(j); fsize = integer(j+4)-fpos
    fpos = 0 if  fsize<=0
  finish 
  if  fpos=0 start ;                !Read file from filestore
    lock
    fscomm = "Z".tostring(uno+'0').f.tostring(nl)
    etherwrite(fsport,charno(fscomm,1),length(fscomm))
    len = etherread(fsport,charno(fscomm,1),255);!Read response
    if  charno(fscomm,1) = '-' start 
      unlock
      event_extra = charno(fscomm,2)-'0'
      charno(fscomm,2) = len-2
      event_message = string(addr(charno(fscomm,2)))
      signal(16_39)
    finish 
    i = 0
    get(blocks);  get(fsize)
    fsize = blocks<<9-fsize;  !size of file in bytes
  finish 
finish  else  fsize = 0
!Allocate space
  *MOVE D6,pos;  *MOVE A7,j;  !**Heap -><- Stack **
  if  pos+fsize+d_fstart+d_memlim >= j start ;  !no space
    read file(0)
    event_message = "*No space to connect ".f
    signal(16_49)
  finish 
  pos = pos-256;                !HP displaced by 256
  d_memstart = pos
  pos = pos+d_fstart;  d_fstart = pos
  read file(1)
  d_flim = pos
  pos = pos+d_memlim;  d_memlim = pos
  pos = (pos+259)&(¬3);  !aligned
  *MOVE pos,D6
end 

externalroutine  CONNECT FILE(string (255) f, integer  mode,
                                integername  start,len)
record (conninfo) r
  r = 0;  connect(f,r);  start = r_fstart;  len = r_flim-start
end 

!!!!!!!!!!!!!!!!!!!!!!!  External loading  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!

routine  EXTLOAD
  *MOVE 4(A7),A3;  !**allow for LINK**
integer  lmax=-1, errors=0
{%integer level=0
record (conninfo)array  LOADED(0:63)
string (255) fid

routine  LOAD(integer  p,a)
integer  i,q,r,e,b,fref,idref
record (conninfo)name  L
{%integer count=0
{spaces(level)
  while  shortinteger(p) # 0 cycle ;  !For each ref
{printstring(string(p))
    idref = refname(string(p),extdict);  !lookup in ext dict
    if  idref <= 0 start 
      printstring("*Unknown external: ".string(p));  newline
      errors = errors+1
    finish  else  start 
      fref = integer(idref)
      i = -1
      cycle 
        i = i+1;  l == loaded(i)
        if  i > lmax start ;  !first use of this file
          lmax = i;  l = 0;  !new cell
{printstring("=>")
{         %if integer(fref) <= 0 %start;  !not permanently loaded
            transname(fref,fid);  !recover name of file
{printstring(fid);  newline
            connect(fid,l);  !read it in
            l_memstart = fref
{%for i = 0,1,lmax %cycle
{  space;  phex(loaded(i)_memstart)
{  newline %if i&7 = 7
{%repeat
{newline
            i = l_flim-2
            i = i+shortinteger(i);  !entry point
            b = l_flim-6-shortinteger(i+6)<<1;  !start of owns
            l_flim = b
            if  i+60 < b start ;  !ext specs present
{level = level+2;  newline
              load(i+40,b)
{level = level-2;  spaces(level)
            finish 
          finish  else  start 
{           l_fstart = integer(fref);  l_memstart = fref
{         %finish
        finish 
      repeat  until  l_memstart = fref
      q = l_fstart+2;  !start of externals
      e = 0
      while  byteinteger(q) < 12 cycle ;  !find & set Q to end
        e = q if  string(q) = string(p)
        q = q+20
      repeat 
      if  e = 0 start 
        printstring("*".string(p)." no longer valid");  newline
        stop 
      finish 
      if  integer(p+12) # integer(e+12) start 
        if  (integer(p+12)!!integer(e+12))&4#0 start 
          printstring("*Class mismatch for ".string(p)); newline
          stop 
        finish 
!       printstring("*Type mismatch for ".string(p));  newline
!       %stop
      finish 
      r = integer(p+16)+a;  !disp of ref + A6
      if  integer(p+12)&4 # 0 start ;  !procedure
        shortinteger(r) = 16_2C7C;  !MOVE.L #xxxxxxxx,A6
        integer(r+2) = l_flim;  !start of owns
        shortinteger(r+6) = 16_4EF9;  !JMP xxxxxxxx
        integer(r+8) = q+integer(e+16);  !entry-point
      finish  else  start 
        integer(r) = l_flim+integer(e+16)
{phex(integer(r))
      finish 
    finish 
    p = p+20
{%if shortinteger(p) # 0 %start
{  printsymbol(',');  count = count+1
{  newline %and spaces(level) %and count = 0 %if count = 6
{%finish
  repeat 
{newline
end 
  *MOVE A3,D0; *ADDQ #4,D0
  *MOVE A6,D1
  *BSR load
  stop  if  errors # 0
end 

!Parameter records:
recordformat  INFO(string (255) name,
                   integer  addr,short  size,flags,
                   record (info)name  link)
!Base record
recordformat  PAMINFO(byte  groupsep,keyflag, short  allflags,
                    record (info)name  chain)
external record (paminfo)map  PAM
record (paminfo)name  p
predicate  ok(record (info)name  p)
integer  q
  *move d6,q
  while  p ## nil cycle 
    false  unless  16_800000 < addr(p) < q and  addr(p)&1 = 0
    p == p_link
  repeat 
  true 
end 
  p == record(refname("PAM_INFO",sysdict))
  if  addr(p) <= 0 start 
    p == record(defname("PAM_INFO",sysdict,sizeof(p)))
    p_chain == nil;  p_allflags = 0
    p_groupsep = '/';  p_keyflag = '-'
  finish 
  p_chain == nil and  p_allflags = 0 if  not  ok(p_chain)
  result  == p
end 

!Branch table entry displacement addresses:
constinteger  connted=16_11BA, loadted=16_11BE, resolted=16_11B6
conststring (19)FNAME="I:LIB.MOB"
@16_3ff0 integer  freebot
integer  i,j

!Insert CONNECT, EXTLOAD & RESOLVE

  j = shortinteger(connted)+connted+2
  *lea connect,a0
  *move.l a0,i
  integer(j) = i

  j = shortinteger(loadted)+loadted+2
  *lea extload,a0
  *move.l a0,i
  integer(j) = i

  j = shortinteger(resolted)+resolted+2
  *lea resolve,a0
  *move.l a0,i
  integer(j) = i

!Install entry-points

  j = refname(fname,fildict)
  printstring(fname." not in dict!") and  stop  if  j <= 0
  i = integer(j)+2
  while  1<=byteinteger(i)<=11 cycle 
    integer(defname(string(i),extdict,8)) = j
    i = i+20
  repeat 

!Lock file in store
  freebot = integer(j+4)+4

  printstring("IMPLIB loaded"); printsymbol(nl)
endofprogram