!! Routine MODIFY for modifying object files.
!! Compile with PARM(FREE)
!! SOAP parameters = [¬BC,LL=90,XN=4,LC=125,CT=46]
!!
external  routine  spec  disconnect alias  "S#DISCONNECT"(string  (31) file, integer  name  flag)
external  routine  spec  destroy alias  "S#DESTROY"(string  (31) file, integer  name  flag)
external  routine  spec  setwork alias  "S#SETWORK"(integer  name  ad, len)
external  routine  spec  lput alias  "S#LPUT"(integer  type, p1, p2, p3)
external  routine  spec  uctranslate alias  "S#UCTRANSLATE"(integer  ad, len)
external  integer  map  spec  comreg alias  "S#COMREG"(integer  n)
external  routine  spec  changefilesize alias  "S#CHANGEFILESIZE"(string  (31) file, integer  size,
   integer  name  flag)
external  routine  spec  clear(string  (255) s)
external  routine  spec  newgen alias  "S#NEWGEN"(string  (31) f1, f2, integer  name  flag)
external  routine  spec  prompt(string  (255) s)
external  integer  fn  spec  outpos
external  string  fn  spec  uinfs(integer  entry)
external  string  fn  spec  time
external  string  fn  spec  date
external  routine  spec  define(string  (255) s)
external  string  fn  spec  itos alias  "S#ITOS"(integer  i)
external  integer  fn  spec  pstoi alias  "S#PSTOI"(string  (63) s)
external  routine  spec  psysmes alias  "S#PSYSMES"(integer  root, flag)
external  routine  spec  setpar alias  "S#SETPAR"(string  (255) s)
external  string  fn  spec  spar alias  "S#SPAR"(integer  n)
record  format  rrf(integer  conad, filetype, datastart, dataend)
external  routine  spec  connect alias  "S#CONNECT"(string  (31) file, integer  mode, hole, prot,
   record  (rrf) name  rr, integer  name  flag)
external  routine  spec  outfile alias  "S#OUTFILE"(string  (31) file, integer  size, hole, prot,
   integer  name  conad, flag)
external  routine  spec  modpdfile alias  "S#MODPDFILE"(integer  ep, string  (31) pdfile, string  (11) memb,
   string  (31) infile, integer  name  flag)
external  routine  spec  move alias  "S#MOVE"(integer  len, from, to)
external  string  fn  spec  ucstring(string  (255) s)
record  format  relf(integer  link, n, relad)
record  format  ofmf(integer  start, l, prop)
record  format  centf(integer  link, loc, string  (31) iden)
record  format  dentf(integer  link, disp, l, a, string  (31) iden)
record  format  creff(integer  link, refloc, string  (31) iden)
record  format  dreff(integer  link, refarray, l, string  (31) iden)
record  format  commef(integer  link, string  (31) iden)

external  routine  modify(string  (255) s)
   const  integer  common bit= x'80000000'
   const  integer  yes=1
   const  integer  no=0
   const  string  (1) snl= "
"
   integer  areacode, areadisp, basecode, basedisp, n
   integer  flag, outbase, loc, link, ad, conad, refarray
   integer  i, j, p1, p2, p3, topicmn, codeattributes, relarea
   integer  worktop, workbase, workpt, common, stlist
   integer  histbeg, histsize, dt, refloc, relad, newsize, maxsize
   integer  all, newrec, reqblock, codelength, glalength, bind
   integer  common entry head, omfdiags, add history, create common
   integer  codestart, glastart, stackstart, codesegs, glasegs, stacksegs
   integer  currlist, xtype, found
   const  byte  integer  array  codesite(1:6)=     120,110,100,90,80,70
   const  integer  last segment= 191
   byte  integer  array  vm map(35:last segment)
   integer  name  linkname, llinkname, currlinkname
   integer  array  base(1:7);            !AREA START ADDRESSES IN FILE 'OUTF'
   integer  array  lbase(1:7);           !AREA START ADDRESSES WHEN LOADED
   integer  array  arealength(1:8);      !FOR TERMINATION CALL TO LPUT
   string  (63) s1, s2, list, op, infile, outf, pd, u1, u2
   string  (255) newhist, line
   integer  array  format  ldataaf(0:15)
   integer  array  name  ldata
   record  (centf) name  cent
   record  (dentf) name  dent
   record  (ofmf) array  format  ofmaf(1:7)
   record  (ofmf) array  name  ofm
   record  (creff) name  cref
   record  (dreff) name  dref
   record  (relf) name  rel
   record  (commef) name  comme
   record  (rrf) r
   const  integer  max operations= 19
   switch  oper(1:max operations)
   const  string  (12) array  keyword(1:max operations)= c 
"RENAME","REDIRECT","RENAMEDATA","REDIRECTDATA","ALIAS","MAKEDYNAMIC",
 "MAKESTATIC","SUPPRESS","RETAIN","SUPPRESSDATA","RETAINDATA",
 "SATISFYREFS","SATISFYDATA","FUSECODE","FUSEGLA","BIND","COMMONENTRY",
 "NOHISTORY","CREATECOMMON"
   const  string  (28) array  heading(1:max operations)= c 
"Renamed procedure entries","Redirected procedure refs",
 "Renamed data entries","Redirected data refs",
 "Aliased procedure entries","Procedure refs made dynamic",
 "Procedure refs made static","Suppressed procedure entries",
 "Retained procedure entries","Suppressed data entries",
 "Retained data entries","Satisfied procedure refs",
 "Satisfied data refs","","","","Created COMMON entries","",""
   const  string  (15) array  prom(1:max operations)= c 
"Proc ent pair","Proc ref pair","Data ent pair","Data ref pair",
 "Proc ent pair","Proc ref list","Proc ref list","Proc ent list",
 "Proc ent list","Data ent list","Data ent list","Proc ref list",
 "Data ref list","","","","COMMONref list","",""
   const  byte  integer  array  hex(0:15)= c 
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

   string  (8) fn  htos(integer  value, places)
      string  (8) s
      integer  i
      i = 64-4*places
      *ld_s; *lss_places; *st_(dr  )
      *inca_1; *std_ tos ; *std_ tos 
      *lss_value; *luh_0; *ush_i
      *mpsr_x'24';                       ! SET CC=1
      *supk_ l  =8
      *ld_ tos ; *ands_ l  =8, 0, 15;    ! THROW AWAY ZONE CODES
      *lss_hex+4; *luh_x'18000010'
      *ld_ tos ; *ttr_ l  =8
      result  = s
   end ;                                 !OF HTOS

   integer  fn  free stream
      external  routine  spec  definfo(integer  chan, string  name  file, integer  name  stat)
      integer  i, stat
      string  (31) file
      for  i = 1, 1, 80 cycle 
         definfo(i, file, stat)
         if  stat=0 then  result  = i
      repeat 
      result  = 0
   end 

   routine  error(integer  root, flag)
      selectoutput(0)
      close stream(stlist)
      clear(itos(stlist))
      psysmes(root, flag)
      stop 
   end ;                                 !OF ERROR

   routine  report(string  (255) mess)
      selectoutput(0)
      printstring(mess)
      newline
      selectoutput(stlist)
   end ;                                 !OF REPORT

   routine  mprint(string  (31) s)
      if  outpos+length(s)>72 then  newline
      printstring(s)
      space until  (outpos//12)*12=outpos
   end ;                                 !OF MPRINT

   integer  fn  check area(integer  seg, len)
      integer  i
      if  len<=0 then  result  = 1
      cycle  i = seg, 1, seg+len-1
         if  35<=i<=last segment and  vm map(i)=0 then  vm map(i) = 1 else  result  = 1
      repeat 
      result  = 0
   end ;                                 !OF CHECK AREA

   routine  getline(string  name  s)
      while  s="" cycle 
         skipsymbol while  nextsymbol=nl or  nextsymbol=' '
         s = s.tostring(nextsymbol) and  skipsymbol until  nextsymbol=nl
         s = s1.s2 while  s->s1.(" ").s2; !REMOVE SPACES
         uctranslate(addr(s)+1, length(s))
      repeat 
   end ;                                 !OF GETLINE

   routine  getstring(string  name  s1, s2, integer  count)
      cycle 
         getline(line)
         if  line->s1.(",").line then  start 
            if  count=1 then  ->err
            if  count=0 then  return 
            if  line="" or  line->s2.(",").line then  ->err
            s2 = line
            line = ""
            return 
         finish  else  start 
            s1 = line
            line = ""
            if  s1=".END" then  return 
            if  count=0 then  line = ".END" and  return 
            if  count=1 then  return 
         finish 
err:
         report("Fault - wrong no of params")
         line = ""
      repeat 
   end ;                                 !OF GETSTRING

   integer  fn  workpos
      if  workpt+48>=worktop then  start ; !NEED MORE SPACE
         worktop = worktop+4096
         changefilesize("T#MODWORK", worktop-workbase, flag)
         if  flag#0 then  error(10, flag); !REQUEST STOP
      finish 
      workpt = workpt+48
      result  = workpt-48
   end ;                                 !OF WORKPOS

   integer  fn  matchs(string  (255) s1, s2)
      if  ucstring(s1)=ucstring(s2) then  result  = yes
      result  = no
   end ;                                 !OF MATCHS

   routine  find iden(string  (31) iden, integer  list1, list2, offset)
!! finds a name within two lists of records, offset gives
!! no of bytes from the start of the record to the name
      integer  list
      offset = offset+outbase
      cycle  list = list1, 1, list2;     !LISTHEADS 1, 4, 7&8, 9
         linkname == ldata(list)
         while  linkname#0 cycle 
            if  matchs(iden, string(offset+linkname))=yes then  return 
            !FOUND
            linkname == integer(outbase+linkname)
         repeat 
      repeat 
   end ;                                 !OF FIND IDEN

   integer  fn  pattstring(string  (31) name, string  name  x1, x2)
!     Gives result:
!        1     *x1*
!        2     *x2
!        3     x1*x2   or   x1*
!        4     *
!        5     name

      if  name->x1.("*").x2 start 
         if  x1#"" then  result  = 3
         if  x2="" then  result  = 4
         if  x2->x1.("*") then  result  = 1 else  result  = 2
      finish  else  result  = 5
   end ;                                 !of pattstring

   routine  amend iden(integer  list1, list2, offset, string  (15) entry or ref, op)
!! reads name,newname pairs until .end
!! searches given lists for newname to check for a duplicate.
!! offset gives no of bytes before iden string for the current record type
!! creates a new record in the work area to contain the new name
!! unless alias is specified, discards the old record
!! Also does renames on all entries using pattern matching (like files command)
      integer  newrec, i, typep, typeq, list, found, offbase
      string  (63) p1, p2, q1, q2, r1
      const  byte  integer  array  check(1:5)= 2,4!8!16,4!8!16,4!8,32

      string  fn  match iden(string  (63) name)
         switch  sw(1:5)
         ->sw(typep)
sw(1):
sw(3):
         unless  name->r1.(p1).name then  result  = ""
         if  typep=1 then  result  = r1.q1.name
         if  r1#"" then  result  = ""
sw(2):
         if  length(name)<length(p2) then  result  = ""
         r1 = name
         length(r1) = length(r1)-length(p2)
         if  name=r1.p2 then  result  = q1.r1.q2 else  result  = ""
sw(4):
         result  = q1.name.q2
sw(5):
         if  s1=name then  result  = s2 else  result  = ""
      end ;                              !of match iden

      offbase = offset+outbase
      cycle 
         found = 0
         getstring(s1, s2, 2);           !OLDNAME,NEWNAME
         if  length(s1)>31 or  length(s2)>31 then  report("Fault - names too long") and  continue 
         if  s1=".END" then  exit 
         typep = pattstring(s1, p1, p2)
         typeq = pattstring(s2, q1, q2)
         if  (check(typep)>>typeq)&1=1 start 
            cycle  list = list1, 1, list2
               linkname == ldata(list)
               while  linkname#0 cycle 
                  r1 = match iden(ucstring(string(offbase+linkname)))
                  if  r1#"" start 
                     printstring(string(offbase+linkname)." -> ".r1.snl)
                     newrec = workpos;   !ADDR OF RECORD IN WORK AREA
                     move(offset, outbase+linkname, newrec); !COPY RECORD
                     if  length(r1)>31 then  length(r1) = 31
                     string(newrec+offset) = r1; !NOW ADJUST LINKED LIST
                     if  op#"ALIAS" then  linkname = newrec-outbase else  integer(outbase+linkname) = newrec-outbase
                     found = 1
                     if  typep=5 and  op#"REDIRECT" then  ->out
                  finish 
                  linkname == integer(outbase+linkname)
               repeat 
            repeat 
            if  found=0 then  report("Fault - ".entry or ref." ".s1." not found")
         finish  else  report("Fault - inconsistent names")
out:
      repeat 
      newline
   end ;                                 !OF AMEND LIST

   routine  getnext(integer  first, last, offset, string  (15) entry or ref)
      string  (63) r1, r2
      string  name  s
      switch  sw(1:4)
      if  s1=".START" start 
         xtype = 0
         found = 0
         currlist = first
         llinkname == ldata(first)
      finish 
      if  xtype=0 or  xtype=5 start 
         getstring(s1, s2, 0)
         xtype = pattstring(s1, u1, u2)
      finish 
      if  xtype=5 start ;                !not a mask
         if  s1=".END" then  return 
         unless  s1=".ALL" start 
            findiden(s1, first, last, offset)
            if  linkname=0 then  start 
               report("Fault - ".entry or ref." ".s1." not found")
               s1 = "#"
            finish  else  currlinkname == linkname
            return 
         finish  else  xtype = 4
      finish 
      cycle 
         cycle 
            if  llinkname#0 then  exit 
            if  currlist=last start 
               if  found=0 start 
                  report("Fault - no ".entry or ref." found for ".s1)
                  s1 = "#"
                  xtype = 0
               finish  else  s1 = ".END"
               return 
            finish 
            currlist = last
            llinkname == ldata(last)
         repeat 
         currlinkname == llinkname
         llinkname == integer(outbase+llinkname)
         s == string(outbase+currlinkname+offset)
         ->sw(xtype)
sw(1):
sw(3):
         unless  s->r1.(u1).r2 then  continue 
         if  xtype=1 then  ->sw(4)
         if  r1#"" then  continue 
sw(2):
         if  length(s)<length(u2) then  continue 
         r1 = s
         length(r1) = length(r1)-length(u2)
         unless  s=r1.u2 then  continue 
sw(4):
         found = 1
         return 
      repeat 
   end ;                                 !OF GETNEXT

   routine  swop refs(integer  from, to)
!! moves a procedure reference between the dynamic list and
!! the static list
      integer  savelink
      s1 = ".START"
      cycle 
         getnext(from, from, 8, "proc ref"); !READ OR FIND NEXT PROC REF
         if  s1=".END" then  exit ;      !END OF LIST
         if  s1#"#" then  start ;        !NAME FOUND
again:      mprint(string(outbase+currlinkname+8))
            savelink = integer(outbase+currlinkname); !@ OF NEXT RECORD
            integer(outbase+currlinkname) = ldata(to); !RECORD POINTS TO NEW LIST
            ldata(to) = currlinkname;    !NEW LIST HEAD POINTS TO RECORD
            currlinkname = savelink;     !OLD LIST BYPASSES RECORD
            if  xtype#5 then  llinkname == currlinkname else  start 
               findiden(s1, from, from, 8); !CHECK FOR DUPLICATE REF
               if  linkname#0 then  currlinkname == linkname and  ->again
            finish 
         finish 
      repeat 
   end ;                                 !OF SWOP REFS

   routine  change visibility(integer  list, nameoffset, wordoffset, string  (15) proc or data, action)
!! sets or unsets a retain bit in procedure or data entries
      integer  word
      s1 = ".START"
      cycle 
         getnext(list, list, nameoffset, proc or data); !TAKE NAMES ONE AT A TIME
         if  s1=".END" then  exit 
         if  s1#"#" then  start ;        !FOUND
            word = outbase+currlinkname+wordoffset; !WHERE BIT IS TO BE CHANGED
            if  action="suppress" then  integer(word) = integer(word)!x'40000000' else  c 
               integer(word) = integer(word)&x'BFFFFFFF'
            mprint(string(outbase+currlinkname+nameoffset))
         finish 
      repeat 
      newline
   end ;                                 !OF CHANGE VISIBILITY

   routine  fuse relocate(integer  oldarea, newarea, disp)
      integer  p, n, i
      integer  name  baseloc
      link = ldata(14);                  !RELOC REQUESTS
      while  link#0 cycle 
         p = outbase+link+8
         n = integer(outbase+link+4)
         cycle  i = 1, 1, n*2;           !TWO WORDS MODIFIED PER ENTRY
            baseloc == integer(p)
            basecode = baseloc>>24
            basedisp = baseloc&x'FFFFFF'
            if  basecode=oldarea then  start 
               basecode = newarea
               basedisp = basedisp+disp
               baseloc = (basecode<<24)!basedisp
            finish 
            p = p+4
         repeat 
         link = integer(outbase+link)
      repeat 
   end ;                                 !OF FUSE RELOCATE
!!
!!
   setpar(s)
   infile = spar(1)
   outf = spar(2)
   list = spar(3)
   if  outf="" then  outf = infile
   if  outf->s1.("_").s2 then  pd = outf and  outf = "" else  pd = ""
   if  outf="" or  outf=infile then  outf = "T#MODLPUT"
   !FILE CREATED BY LPUT
   if  list="" then  list = "T#MODLIST"
   stlist = free stream
   define(itos(stlist).",".list)
   selectoutput(stlist)
   printstring(snl."Modify file ".infile)
   if  outf#"T#MODLPUT" then  printstring(" -> ".outf)
   printstring(" at ".time." on ".date)
   newlines(2)
   connect(infile, 0, 0, 0, r, flag)
   if  flag#0 then  error(8, flag);      !REQUEST STOP
   conad = r_conad
   if  integer(conad+12)#1 then  report("Invalid filetype") and  stop 
   dt = conad+20;                        !@ OF PACKED DATE&TIME FOR FILE HISTORY
   outfile("T#MODCOPY", r_dataend, 0, 0, outbase, flag)
   if  flag#0 then  error(10, flag);     !REQUEST STOP
   move(integer(conad), conad, outbase); !COPY OBJECT FILE
   ldata == array(outbase+integer(outbase+24), ldataaf); !LOAD DATA
   ofm == array(outbase+integer(outbase+28)+4, ofmaf); !OBJECT FILE MAP
   if  ldata(5)#0 then  start 
      selectoutput(0)
      printstring("Modify fails - ".infile." is a bound object file".snl)
      return 
   finish 
   if  ldata(0)>14 and  ldata(15)#0 then  start 
      omfdiags = ldata(15)
   finish  else  omfdiags = 0
   arealength(8) = 0
   cycle  i = 1, 1, 7
      base(i) = outbase+ofm(i)_start;    !MAP OBJECT FILE AREAS
      arealength(i) = ofm(i)_l;          !NOTE SIZE FOR LPUT CALL
      arealength(8) = arealength(8)+arealength(i); !GRAND TOTAL
   repeat 
   code attributes = ofm(1)_prop;        !MUST COPY TO OUTPUT FILE
!!
!!now prepare to accept params
!!
   outfile("T#MODWORK", 4096, 257<<10, 0, workbase, flag)
   if  flag#0 then  error(10, flag);     !REQUEST STOP
   workpt = workbase+32;                 !POINTER TO FREE WORKSPACE
   worktop = workbase+4096;              !TOP OF WORKSPACE
   bind = 0; common entry head = 0
   add history = 1; create common = 0
   cycle 
      prompt("Operation:")
      line = ""
      op = ""
      getline(op)
      exit  if  op="CLOSE"
      if  op->s1.("BIND").s2 and  s1="" then  op = s2 and  ->oper(16)
      cycle  i = 1, 1, max operations
         if  op=keyword(i) then  start 
            newlines(2)
            if  heading(i)#"" then  printstring(heading(i).":".snl.snl)
            prompt(prom(i).":")
            ->oper(i)
         finish 
      repeat 
      report("Fault - unknown command ".op)
      ->next op
oper(1):                                 !RENAME PROCEDURE ENTRY
      amend iden(1, 1, 8, "proc entry", ""); !1,1=PROC ENTRY LIST,8=OFFSET
      ->next op
oper(2):                                 !REDIRECT PROCEDURE REFERENCE
      amend iden(7, 8, 8, "proc ref", "REDIRECT"); !7,8=PROC REF LISTS,8=OFFSET
      ->next op
oper(3):                                 !RENAME DATA ENTRIES
      amend iden(4, 4, 16, "data entry", ""); !4,4=DATA ENTRY LIST,16=OFFSET
      ->next op
oper(4):                                 !REDIRECT DATA REFERENCES
      amend iden(9, 9, 12, "data ref", ""); !9,9=DATA REF LIST,12=OFFSET
      ->next op
oper(5):                                 !ALIAS PROCEDURE ENTRIES
      amend iden(1, 1, 8, "proc entry", "ALIAS"); !1,1=PROC ENTRY LIST,8=OFFSET
      ->next op
oper(6):                                 !MAKE PROC REF DYNAMIC
      swop refs(7, 8);                   !FROM 7 TO 8
      ->next op
oper(7):                                 !MAKE PROC REFS STATIC
      swop refs(8, 7);                   !FROM 8 TO 7
      ->next op
oper(8):                                 !SUPPRESS PROCEDURE ENTRIES
      change visibility(1, 8, 4, "proc entry", "suppress"); !LIST1,NAMEOFFSET=8,WORDOFFSET=4
      ->next op
oper(9):                                 !RETAIN PROCEDURE ENTRIES
      change visibility(1, 8, 4, "proc entry", "retain")
      ->next op
oper(10):                                !SUPPRESS DATA ENTRIES
      change visibility(4, 16, 12, "data entry", "suppress")
      !LIST4,NAMEOFFSET=16,WORDOFFSET=12
      ->next op
oper(11):                                !RETAIN DATA ENTRIES
      change visibility(4, 16, 12, "data entry", "retain")
      ->next op
oper(12):                                !SATISFY PROCEDURE REFS
      s1 = ".START"
      cycle 
         getnext(7, 8, 8, "ref");        !READ OR FIND NEXT PROC REF
         if  s1=".END" then  exit ;      !END OF LIST
         if  s1="#" then  ->next12;      !REF NOT FOUND
again12: cref == record(outbase+currlinkname)
         find iden(cref_iden, 1, 1, 8);  !SEARCH EP LIST FOR NAME
         if  linkname#0 then  start ;    !NAME FOUND
            cent == record(outbase+linkname)
            loc = base((cref_refloc>>24)&x'3F')+cref_refloc&x'FFFFFF'
            integer(loc) = x'B1000000';  !FILL DR0
            integer(loc+4) = cent_loc&x'FFFFFF'
            newrec = workpos;            !GET RECORD FROM WORK AREA FOR RELOCATION
            integer(newrec) = ldata(14); !MERGE WITH RELOC REQUEST LIST
            ldata(14) = newrec-outbase
            integer(newrec+4) = 1;       !SINGLE RELOCATION REQUEST
            integer(newrec+8) = cref_refloc+4; !WORD TO BE RELOCATED
            integer(newrec+12) = cent_loc&x'3F000000'; !RELOCATION VALUE CODE
            currlinkname = integer(outbase+currlinkname)
            !REMOVE REF FROM LIST
            mprint(cref_iden)
            if  xtype#5 then  llinkname == currlinkname else  start 
               findiden(s1, 7, 8, 8);    !CHECK FOR DUPLICATE REF
               if  linkname#0 then  currlinkname == linkname and  ->again12
            finish 
         finish  else  start 
            if  xtype#4 then  report("Fault - no entry found for ref ".cref_iden)
         finish 
next12:
      repeat 
      newline
      ->next op
oper(13):                                !SATISFY DATA REFS
      s1 = ".START"
      cycle 
         getnext(9, 9, 12, "ref");       !R OR FIND NEXT DATA REF
         if  s1=".END" then  exit ;      !END OF LIST
         if  s1="#" then  ->next13;      !REF NOT FOUND
         dref == record(outbase+currlinkname)
         find iden(dref_iden, 4, 4, 16); !SEARCH DATA ENTRY LIST FOR NAME
         if  linkname#0 then  start ;    !NAME FOUND
            refarray = (dref_refarray&x'7FFFFFFF')+outbase
            common = dref_refarray&x'80000000'; !NOTE COMMON BIT
            n = integer(refarray);       !NO OF LOCATIONS REQUIRING ENTRY
            dent == record(outbase+linkname); !MAP DATA ENTRY RECORD
            reqblock = workpos;          !GET SOME SPACE
            integer(reqblock) = ldata(14); !CREATE NEW RELOC REQUEST BLOCK
            ldata(14) = reqblock-outbase; !ADD TO LIST
            integer(reqblock+4) = n;     !NO OF REQUESTS FOLLOWING
            j = reqblock+8
            i = 1
            cycle  refloc = refarray+4, 4, refarray+(n*4)
               loc = base(integer(refloc)>>24)+integer(refloc)&x'FFFFFF'
               integer(loc) = integer(loc)+dent_disp; !ADD OFFSET OF ENTRY
               i = i+1
               if  i=7 then  i = workpos and  i = 1
               integer(j) = integer(refloc); !MAKE RELOCATION REQUEST
               integer(j+4) = (dent_a<<24)&x'3F000000'
               j = j+8
            repeat 
            currlinkname = integer(outbase+currlinkname)
            !REMOVE REF FROM LIST
            if  xtype#5 then  llinkname == currlinkname; !AVOID MOVING CURR IN GETNEXT
            mprint(dref_iden)
         finish  else  start 
            if  xtype#4 then  report("Fault - no data entry found for ref ".dref_iden)
         finish 
next13:
      repeat 
      newline
      ->next op
oper(14):                                !FUSE CODE
      codelength = arealength(1)
      arealength(1) = codelength+arealength(4); !ADD SST LENGTH TO CODE LENGTH
      arealength(4) = 0;                 !COLLAPSE SST
      ofm(4)_l = 0
      fuse relocate(4, 1, codelength)
      printstring("Code fused".snl)
      ->next op
oper(15):                                !FUSE GLA
      glalength = arealength(2)
      arealength(2) = glalength+arealength(5); !ADD UST LENGTH TO GLA LENGTH
      arealength(5) = 0;                 !COLLAPSE UST
      fuse relocate(5, 2, glalength)
      link = ldata(4);                   !DATA ENTRIES LISTHEAD
      while  link#0 cycle 
         dent == record(outbase+link)
         if  (dent_a&x'FF')=5 then  start ; !ENTRY IN UST
            dent_a = dent_a-3;           !CHANGE TO GLA
            dent_disp = dent_disp+glalength
         finish 
         link = dent_link
      repeat 
      printstring("GLA fused".snl)
      ->next op
oper(16):                                !BIND FILE
      if  bind#0 then  report("Fault - BIND already called") and  ->next op
      if  op="" then  i = 1 else  i = pstoi(op)
      link = ldata(9);                   !SCAN DATA REFS
      topicmn = 0;                       !HOW MUCH INITCMN
      while  link#0 cycle 
         dref == record(link+outbase)
         if  dref_refarray&common bit#0 start 
            findiden(dref_iden, 4, 4, 16); !SEARCH DATA EP LIST
            if  linkname=0 then  topicmn = topicmn+dref_l
         finish 
         link = dref_link
      repeat 
      j = integer(conad)+topicmn+256+workpt-workbase; !CURRENT SIZE+INITCMN+HIST+WORK
      codesegs = (j+1<<18-1)>>18
      glasegs = (ofm(2)_l+ofm(3)_l+ofm(5)_l+ofm(6)_l+1<<18-1)>>18
      stacksegs = 1
      stackstart = 190;                  !ALWAYS AT THIS SEGMENT
      if  0<i<7 start 
         codestart = codesite(i)
         glastart = codestart+codesegs
      finish  else  start 
         if  op->s1.(",").s2 start 
            codestart = pstoi(s1)
            glastart = pstoi(s2)
            j = glastart-codestart
            if  codesegs<j then  codesegs = j
         finish  else  report("Fault - invalid parameters") and  ->next op
      finish 
      cycle  j = 35, 1, last segment
         vm map(j) = 0
      repeat 
      flag = check area(codestart, codesegs)
      if  flag=0 then  flag = check area(glastart, glasegs)
      if  flag=0 then  flag = check area(stackstart, stacksegs+1)
      if  flag#0 then  report("Fault - cannot fit code/gla/stack as requested") and  ->next op
      printstring(snl.snl."File bound:".snl."
    Codestart=".itos(codestart)."
    Glastart=".itos(glastart)."
    Stackstart=".itos(stackstart).snl)
      codestart = codestart<<18
      glastart = glastart<<18
      stackstart = stackstart<<18+32
      lbase(1) = ofm(1)_start+codestart; !START OF LOADED CODE
      lbase(2) = glastart+ofm(3)_l;      !START OF LOADED GLA
      lbase(3) = glastart;               !START OF LOADED PLT
      lbase(4) = ofm(4)_start+codestart; !START OF LOADED SST
      lbase(5) = lbase(2)+ofm(2)_l;      !START OF LOADED UST
      lbase(6) = lbase(5)+ofm(5)_l;      !START OF INIT COMMON
      lbase(7) = stackstart;             !START OF LOADED INIT STACK
      bind = i
      ->next op
oper(17):                                !CREATE DATA ENTRIES FOR COMMON REFS IN BOUND FILE
      s1 = ".START"
      cycle 
         getnext(9, 9, 12, "COMMON ref"); !SEARCH DATA REF LIST
         if  s1=".END" then  exit 
         if  s1#"#" start ;              !FOUND
            dref == record(outbase+currlinkname)
            if  dref_refarray&common bit#0 start 
               comme == record(workpos)
               comme_link = common entry head; !ADD TO LINKED LIST
               common entry head = addr(comme_link)
               comme_iden = dref_iden;   !JUST REQUIRE THE NAME
               mprint(dref_iden)
            finish  else  start 
               if  xtype#4 then  report("Fault - ".dref_iden." is not a COMMON ref")
            finish 
         finish 
      repeat 
      newline
      ->next op
oper(18):                                !REMOVE FILE HISTORY
      add history = 0
      printstring("History removed".snl)
      ->next op
oper(19):                                !CREATE COMMON AREAS
      create common = 1
next op:

   repeat 
!!
!!all input processed, now resolve refs and relocate for bind
!!first initialise lput, then can pass unresolved refs to it
!!
   i = 0
   setwork(i, j);                        !CREATE WORK FILE
   outfile(outf, 4000, 0, 0, conad, flag); !TO SEE IF WE CAN CREATE IT
   if  flag#0 then  error(10, flag);     !REQUEST STOP
   comreg(52) = addr(outf)
   comreg(24) = 0;                       !ZERO RETURN CODE
   lput(0, 0, 0, 0);                     !INITIALISATION CALL
!!
!!tell users of misuse of create common and comon entry
!!
   if  bind=0 start 
      if  common entry head#0 then  report("COMMON ENTRY applies only to bound files") and  return 
   finish  else  start 
      if  create common#0 then  report("CREATE COMMON applies only to unbound files") and  return 
   finish 
!!
!!deal with procedure entries to be retained (or main entry)
!!
   flag = 1
   link = ldata(1)
   while  link#0 cycle 
      cent == record(outbase+link)
      unless  cent_loc>>30=1 then  start ; !RETAIN, OR MAIN BIT SET
         p1 = (cent_loc>>24&x'3F')!(cent_loc&x'80000000')
         !AND IN MAIN BIT
         p2 = cent_loc&x'FFFFFF';        !DISP
         p3 = addr(cent_iden);           !NAME
         lput(11, p1, p2, p3)
         flag = 0;                       !AT LEAST ONE ENTRY FOUND
      finish 
      link = cent_link
   repeat 
!!
!!for bind, try to satisfy ext refs internally - else make lput calls for them
!!
   cycle  i = 7, 1, 8;                   !STATIC THEN DYNAMIC REFS
      link = ldata(i)
      while  link#0 cycle 
         cref == record(link+outbase);   !EXT REF RECORD
         if  bind#0 then  start 
            findiden(cref_iden, 1, 1, 8); !SEARCH EP LIST
            if  linkname#0 then  start ; !CAN SATISFY
               cent == record(outbase+linkname)
               loc = base(cref_refloc>>24)+cref_refloc&x'FFFFFF'
               integer(loc) = x'B1000000'; !FILL DR0, DR1
               integer(loc+4) = lbase((cent_loc>>24)&x'3F')+cent_loc&x'FFFFFF'
               !PROPAGATE RELOCATION REQUEST:
               lput(19, cref_refloc>>24, (cref_refloc&x'FFFFFF')+4, (cent_loc>>24)&x'3F')
               ->next ref
            finish 
         finish 
         p1 = cref_refloc>>24;           !AREA
         p2 = cref_refloc&x'FFFFFF';     !DISP
         p3 = addr(cref_iden);           !NAME
         lput(i+5, p1, p2, p3)
next ref:
         link = cref_link
      repeat 
   repeat 
!!
!!now pass data entries to lput
!!
   link = ldata(4)
   while  link#0 cycle 
      dent == record(outbase+link)
      if  dent_a&x'40000000'=0 then  start ; !NOT SUPPRESSED
         flag = 0;                       !AT LEAST ONE ENTRY LEFT
         p1 = (dent_a&x'3F')<<24!dent_l
         p2 = dent_disp
         p3 = addr(dent_iden)
         lput(14, p1, p2, p3);           !NOTE DATA ENTRY
      finish 
      link = dent_link
   repeat 
   if  flag#0 then  start 
      report("Fatal error - no entry in file")
      return 
   finish 
! PASS LIST11 REFS THROUGH UNALTERED MEANTIME.
! N.B. LIFTING THIS RESTRICTION WOULD REQUIRE A MAJOR REWRITE
   link = ldata(11)
   while  link#0 cycle 
      cref == record(outbase+link)
      p1 = cref_refloc>>24
      p2 = cref_refloc&x'FFFFFF'
      p3 = addr(cref_iden)
      lput(22, p1, p2, p3)
      link = cref_link
   repeat 
!!
!!now deal with data refs - for bind, try to satisfy internally
!!and add init common to gla if required
!!otherwise make lput calls
!!
   link = ldata(9)
   topicmn = ofm(6)_l;                   !TOP OF INITIALISED COMMON
   newline
   while  link#0 cycle 
      dref == record(link+outbase)
      refarray = (dref_refarray&x'7FFFFFFF')+outbase
      common = dref_refarray&x'80000000'; !NOTE COMMON BIT
      n = integer(refarray)
      refloc = refarray+4
      p3 = addr(dref_iden)
      if  bind#0 then  start 
         findiden(dref_iden, 4, 4, 16);  !SEARCH DATA EP LIST
         if  linkname=0 then  start ;    !NOT FOUND
            if  matchs(dref_iden, "ICL9CEAUXST")=yes then  start ; !SPECIAL CASE - REF TO AUX STACK
               cycle  n = 1, 1, n
                  p1 = integer(refloc)&x'FF000000'!dref_l
                  p2 = integer(refloc)&x'FFFFFF'
                  lput(15, p1, p2, p3);  !REMAKE CALL FOR AUX STACK
                  refloc = refloc+4
               repeat 
               ->next dref
            finish 
            if  common#0 then  start ;   !CREATE COMMON AREA
               lput(36, dref_l, topicmn, 0); !FILL WITH ZEROS
               ad = topicmn+lbase(6)
               relarea = 2;              !RELOCATE ICMN WRT GLA SEGMENT
               printstring("ICMN area created for ".dref_iden."   Length =")
               write(dref_l, 1); newline
               i = common entry head;    !CHECK IF WE WANT TO GENERATE AN ENTRY
               while  i#0 cycle 
                  comme == record(i)
                  if  matchs(comme_iden, dref_iden)=yes start ; !FOUND, GENERATE ENTRY
                     lput(14, (6<<24)!dref_l, topicmn, p3)
                     exit 
                  finish 
                  i = comme_link
               repeat 
               topicmn = (topicmn+dref_l+7)&x'fffffff8'; !RESET TOP
            finish  else  ->lput dref
         finish  else  start 
            dent == record(outbase+linkname)
            relarea = dent_a&x'FF'
            ad = lbase(relarea)+dent_disp
         finish 
         cycle  n = 1, 1, n;             !NOW RELOCATE REFS
            p1 = integer(refloc)>>24;    !AREA CONTAINING WORD
            p2 = integer(refloc)&x'FFFFFF'; !OFFSET OF WORD
            loc = base(p1)+p2;           !ADDRESS OF WORD
            integer(loc) = integer(loc)+ad; !RELOCATE WORD
            lput(19, p1, p2, relarea);   !PROPAGATE RELOCATION REQUEST
            refloc = refloc+4
         repeat 
      finish  else  start ;              !BIND NOT SET
         if  create common=1 and  common#0 start 
            findiden(dref_iden, 4, 4, 16); !CHECK DATA ENTRIES
            if  linkname=0 start ;       !NO ENTRY FOUND
               lput(36, dref_l, topicmn, 0); !CREATE COMMON AREA
               lput(14, (6<<24)!dref_l, topicmn, p3); !CREATE DATA ENTRY
               printstring("ICMN area created for ".dref_iden."   Length =")
               write(dref_l, 1); newline
               topicmn = topicmn+dref_l
            finish 
         finish 
lput dref:

         cycle  n = 1, 1, n
            p1 = (integer(refloc)&x'FF000000')!dref_l
            p2 = integer(refloc)&x'FFFFFF'
            if  common=0 then  lput(15, p1, p2, p3) else  lput(10, p1, p2, p3)
            refloc = refloc+4
         repeat 
      finish 
next dref:

      link = dref_link
   repeat 
!!
!! now deal with relocation requests
!!
   link = ldata(14)
   while  link#0 cycle 
      rel == record(link+outbase)
      relad = addr(rel_relad)
      cycle  n = 1, 1, rel_n;            !NO OF RELOCATION ENTRIES IN THIS BLOCK
         areacode = integer(relad)>>24
         areadisp = integer(relad)&x'FFFFFF'
         basecode = integer(relad+4)>>24
         basedisp = integer(relad+4)&x'FFFFFF'
         loc = base(areacode)+areadisp
         integer(loc) = integer(loc)+basedisp
         if  bind#0 then  integer(loc) = integer(loc)+lbase(basecode)
         lput(19, areacode, areadisp, basecode); !PROPAGATE EVEN FOR BOUND FILE
         relad = relad+8
      repeat 
      link = rel_link
   repeat 
!!
!!pass rest of object file to lput
!!
   arealength(8) = arealength(8)+topicmn-ofm(6)_l; !ADJUST GRAND TOTAL
   cycle  i = 1, 1, 7
      lput(30+i, arealength(i), 0, base(i)); !PASS EACH AREA
   repeat 
   arealength(6) = topicmn;              !NOW UPDATE FOR ANY EXTRA COMMON CREATED
   lput(7, 32, 0, addr(arealength(1)));  !CURRENT FILE IS COMPLETE
!!
!!now add history to completed file
!!
   if  comreg(24)#0 start 
      report("LPUT fails to create output file")
      return 
   finish 
   histbeg = ldata(12)+outbase;          !NOTE THIS BEFORE MAPPING LDATA TO NEW FILE
   connect(outf, 3, 0, 0, r, flag);      !SOME LPUTS DISCONNECT!!
   if  flag#0 start 
      report("Cannot reconnect file")
      error(1000, flag)
      return 
   finish 
   conad = r_conad
   ldata == array(conad+integer(conad+24), ldataaf); !MAPPED TO NEW FILE
   newsize = integer(conad)
   if  add history=1 start 
      histsize = histbeg;                !FIND END OF OLD HISTORY DATA
      if  histsize>0 start 
         histsize = histsize+2+byteinteger(histsize+1) while  byteinteger(histsize)#0
      finish 
      histsize = histsize-histbeg;       !LENGTH OF DATA
      unless  infile->s1.(".").s2 then  infile = uinfs(1).".".infile
      if  bind#0 start 
         newhist = "Bound object file
From object : ".infile."
Fixed site  : ".htos(codestart, 8)." ".htos(glastart, 8)." ".htos(stackstart, 8)
      finish  else  start 
         newhist = "Modified object file
From object : ".infile
      finish 
      n = integer(r_conad);              !NOW CHECK FILE IS BIG ENOUGH
      maxsize = (n+4095)//4096*4096
      newsize = (histsize+length(newhist)+3+n+4095)//4096*4096
      if  newsize>maxsize then  start 
         changefilesize(outf, newsize, flag); !EXTEND FILE
         if  flag=261 then  start ;      !VM HOLE TOO SMALL
            disconnect(outf, flag)
            changefilesize(outf, newsize, flag)
         finish 
         if  flag=0 then  connect(outf, 3, 0, 0, r, flag)
         if  flag#0 then  report("Cannot add history") and  error(1000, flag)
         integer(r_conad+8) = newsize
      finish 
      conad = r_conad
      ldata == array(conad+integer(conad+24), ldataaf)
      ldata(12) = integer(conad);        !HISTORY STARTS AT END OF FILE
      j = conad+integer(conad);          !END OF THE FILE
      byteinteger(j) = 8;                !GENERAL TEXT RECORD
      string(j+1) = newhist;             !ADD NEW HISTORY TEXT
      j = j+2+length(newhist)
      byteinteger(j) = 6;                !DATE FROM ORIGINAL FILE
      byteinteger(j+1) = 4;              !LENGTH OF PACKED D&T
      move(4, dt, j+2);                  !MOVE FROM FILE HEADER
      j = j+6
      move(histsize, histbeg, j);        !ADD OLD HISTORY
      j = j+histsize
      integer(j) = 0;                    !END OF HISTORY
      integer(conad) = j+1-conad;        !SET NEW LENGTH OF FILE
   finish 
!!
!!
   if  bind#0 then  start 
      ldata(5) = codestart;              !VALUES FOR THE LOADER
      ldata(6) = glastart
      ldata(10) = stackstart
   finish  else  start ;                 !COPY CODE ATTRIB EXCEPT FOR BOUND FILE
      i = conad+integer(conad+28)+12;    !@ OF CODE ATTR IN OFM
      integer(i) = code attributes
   finish 
   !!
   !! copy across any omf diagnostic records
   !!
   if  omfdiags#0 then  start 
      j = omfdiags+outbase
      while  halfinteger(j)#0 cycle ;    !FIND END OF OMF DIAGS
         j = j+halfinteger(j)
      repeat 
      j = j+2;                           !INCLUDE TERMINATOR
      j = j-omfdiags-outbase;            !SIZE OF DIAGNOSTICS
      n = integer(r_conad)
      maxsize = (n+4095)//4096*4096
      newsize = (n+j+4095)//4096*4096
      if  newsize>maxsize then  start 
         changefilesize(outf, newsize, flag)
         !EXTEND FILE
         if  flag=261 then  start ;      !VM HOLE TOO SMALL
            disconnect(outf, flag)
            changefilesize(outf, newsize, flag)
         finish 
         if  flag=0 then  connect(outf, 3, 0, 0, r, flag)
         if  flag#0 then  start 
            report("Cannot add OMF diagnostics")
            error(1000, flag)
            return 
         finish 
         integer(r_conad+8) = newsize
      finish 
      conad = r_conad
      ldata == array(conad+integer(conad+24), ldataaf)
      ldata(0) = 15 if  ldata(0)<15
      ldata(15) = integer(conad);        !DIAGS START AT END OF FILE
      move(j, outbase+omfdiags, conad+ldata(15))
      integer(conad) = integer(conad)+j
   finish 
   disconnect(outf, flag)
   if  bind#0 and  (newsize+(1<<18)-1)>>18>codesegs then  c 
      report("Failure - new object file will not fit in specified site") and  return 
   if  outf="T#MODLPUT" start 
      if  pd->s1.("_").s2 start 
         modpdfile(2, s1, s2, "", flag); !DESTROY MEMBER
         modpdfile(1, s1, s2, "T#MODLPUT", flag)
      finish  else  newgen("T#MODLPUT", infile, flag)
      if  flag#0 then  error(10, flag)
   finish 
   if  flag=0 then  report("OK") and  printstring(snl."Modify successful".snl)
   select output(0)
   close stream(stlist)
   clear(itos(stlist))
   destroy("T#MODLPUT", flag)
   destroy("T#MODWORK", flag)
end ;                                    !OF MODIFY
end  of  file