.
.         EMBED Command Process
.
.         This element processes the EMBED command, which allows a file to be
.         stored as an element in a program file, and subsequently
.         reconstructed as a file.
.
.
.         (C)  Copyright 1972-1978  John Walker
.
.         This software is in the public domain
.
.
          axr$
          defunct$
          fang
.
          pure      code
.
.
.         The following tag defines the 'compatibility level' of this version
.         of the EMBED command.  This level will be changed whenever a
.         nontransparent change is made to the EMBED element format.  This
.         will prevent undetected errors due to incompatible FANG
.         versions being used.
.
emformat  equ       1                   compatibility level
.
.         Commonly used registers
.
sn        equ       r9                  expected sequence number
e1        equ       r10                 first element class
e2        equ       r11                 second element class
f1        equ       r12                 first file FDT
f2        equ       r13                 second file FDT
ct        equ       r14                 user-supplied count
.
.
.         EMBED work buffer format
.
ewio      equf      0                   I/O packet to read/write program file
ewacwt    equf      6                   ACW table for scatter/gather
ewpsect   equf      8                   start of header sector block
ewl       equf      28+9                length of work buffer
.
.         EMBED header sector format  (within work buffer)
.
csent     equf      ewpsect             'EMBED$'
cid       equf      ewpsect+1           two word processor ID
ccksum    equf      ewpsect+3           checksum of data in block
csector   equf      ewpsect+4           source address in original file
cblen     equf      ewpsect+5,,h1       length of block following
cmpat     equf      ewpsect+5,,s4       compatibility level
cefb      equf      ewpsect+5,,s5       nonzero if tape end of file block
ceof      equf      ewpsect+5,,s6       nonzero if last block
cblkno    equf      ewpsect+6           block sequence number (first is 1)
cfacit    equf      ewpsect+7           first 10 words of FITEM$ of file
.                                       that was EMBEDed
ctdate    equf      ewpsect+17          TDATE$ at time of EMBED
cmaxbl    equf      ewpsect+18          largest block in file
cfill     equf      ewpsect+19          start of filler info
cfilll    equ       (ewpsect+28)-(ewpsect+18) length of filler
/.
.
.         Initial command analysis
.
embed*    lx        x9,cdbpc,x8         load link to parameter chain
          sx        x9,e1               save first element parameter
          lx        x9,pblink,x9        link to first file
          lr        f1,pbval,x9         load first file FDT
          lx        x9,pblink,x9        link to second element
          sx        x9,e2               save it for later use
          lx        x9,pblink,x9        link to second file
          lr        f2,pbval,x9         load second file FDT
          lx        x9,pblink,x9        link to optional number
          lr,u      ct,0377777          load infinite count
          la        a15,cdopts,x8       load command options
          tep,u     a15,option('M')     is the 'M' option on ?
          lr,u      ct,1                yes.  assume one file
          tz        x9                  was parameter supplied ?
          lr        ct,pbval,x9         yes.  load user-supplied count
.
.         Now we see whether the input and output specifications use
.         element selection and determine by context whether this is
.         an EMBED or EXPAND type operation.  The rules for deciding
.         are as follows:
.
.         First parameter   Second parameter     Action
.         ---------------   ----------------     ------
.
.            File               File             EMBED
.            File               Element          EMBED
.            Element            File             EXPAND
.            Element            Element          Error
.
          la        a0,e1               load first element parameter
          tnz       elall,a0            was selection specified ?
          j         ielt                yes.  input is an element
/.
.
.         EMBED processing.
.
.         Since no element selection was specified on the input file, that
.         file will be embedded into the second file.  First we set up to
.         read the input file.
.
          la        a1,f1               load input file parameter
          lmj       a2,ioget            build I/O FCT for file
          lx,u      x10,,a0             get FCT in X10
          lxi       a0,f1               move FDT to A0
          ssc       a0,18               get fct, fdt in a0
          sa        a0,f1               save for later release
          sr        ct,iocount,x10      save the block count in the fct
          tnz       iomass,x10          is the input mass storage ?
          j         embtinp             no.  go set up tape input
          la,u      a0,1792             yes.  load track size block
          sa        a0,ioblen,x10       always read track sized blocks
          sz        iodrad,x10          and start at the file start
          la,u      a0,0377777          load infinite count
          sa        a0,iocount,x10      set number of tracks to read
          la        a0,cdopts,x8        load command options
          or,u      a0,option('R')      set the 'R' option for command
          sa        a1,cdopts,x8        mark no update of file position
.
.         At this point we're ready to start reading the input file.
.         We defer actually firing up input until we're verified
.         that the output file is actually a program file.  This allows
.         us to get out cleaner if there is an error.
.
embtinr   lx        x9,e2               load second element class
          la        a0,elfdt,x9         load FDT address for file
          la        a1,fdtype,a0        load type of output file
          tne,u     a1,fwad             is output word-addressable ?
          j         embowad             yes.  can't embed into it
          jtape     a1,embotap          can't embed onto tape
          bgetl     ftil                allocate BSP file table index
          sa        a0,a14              save for later reference
          la        a1,f2               load second file FDT
          dl        a4,fdin,a1          load internal name of file
          ds        a4,ftifn,a0         store into FTI
          rfti      .                   read in file table index
          j         embonpf             error.  probably not a program file
.
.         Now that we've read in the file table index, we set up
.         the embed work buffer.  This buffer contains the I/O
.         packet we use to write the output file, as well as the
.         header sector we prefix to each block written.
.
          bgetl     ewl                 allocate working buffer
          sa        a0,x9               save for use later
          la        a1,a14              reload file table index address
          dl        a2,fdin,a1          load internal file name
          ds        a2,ewio+iofn,a0     set file name in packet
          la        a2,ftiwl,a1         load next write location in file
          sa        a2,ewio+iodrad,a0   set address to start text
          sz        iostatus,a0         clear status in packet
          la,u      a2,gw$              load gather write function
          sa        a2,iofunc,a0        set function in packet
          au        a0,(2,ewacwt)       form access word table pointer
          sa        a1,ewio+ioacw,a0    set access word table pointer
          au        a0,(28,ewpsect)     form pointer to prefix sector
          sa        a1,ewacwt,a0        set to write before data
.
.         Now we build the skeleton header (prefix) sector
.
          la        a1,('EMBED$')       load sentinel for prefix sector
          sa        a1,csent,a0         store sentinel in prefix
          la        a1,('FANG  ')       load identification of processor
          la        a2,(ljsf$1 level)   load FANG level
          ds        a1,cid,a0           set identification in sector
          la,u      a1,emformat         load compatibility level identifier
          sa        a1,cmpat,a0         store in sector
.
.         Copy the FITEM$ information from the source file into the
.         prefix sector.
.
          la        a2,f1               load first file FDT
          lxi,u     a2,1                set increment to copy data
          au        a0,(1,cfacit)       get pointer to packet in header
          lr,u      r1,10               load length to move
          bt        a1,,*a2             copy FITEM$ information
          tdate$    .                   get date and time of embed
          sa        a0,,*a1             store into header
          la,u      a2,('>FANG<')       get fill for fang sectors
          lr,u      r1,cfilll           load length of filler
          bt        a1,,*a2             fill sector with constant data
          sz        cblkno,x9           zero block sequence number
          sz        ceof,x9             mark this not last block
          la        a1,ioblen,x10       load I/O block length
          sa        a1,cmaxbl,x9        set largest block read
.
.         Fire up input on source file
.
          la        a0,f1               load input file FCT, FDT
          ssl       a0,18               right justify it in a0
          sa        a0,x10              save in X10 for the duration
          lmj       a2,input            start up input reader
.
.         Read buffers from the input file and set them up to be
.         written to embed element with a gather write.
.
embnext   get       iobb,x10            remove next block from input file
          tz        ibstat,a1           normal data block ?
          j         embabn              no.  handle abnormal block
          la,u      a2,ibdata,a1        load address of data in block
          lxi       a2,iblen,a1         load length of data
          sa        a2,ewacwt+1,x9      store in data part of ACW table
          la        a0,ibmsad,a1        load address block read from
          sa        a0,csector,x9       set into the prefix block
          sz        cefb,x9             mark this not tape mark
          ssl       a2,18               right justify the block length
          sa        a2,cblen,x9         store length in header sector
          la        a0,cblkno,x9        load block number
          aa,u      a0,1                increment block number
          sa        a0,cblkno,x9        update in sector
.
.         Now checksum the data read from the file
.
          la,u      a2,ibdata,a1        load start of data in buffer
          aa        a2,(1,0)            form pointer to scan data
          lr        r1,iblen,a1         load length of data
          la,u      a3,0                clear the checksum accumulator
          j         embcksme            enter checksum code
.
embcksm   xor       a3,,*a2             xor this word with previous
          ssc       a4,1                shift the result
          la        a3,a4               reload the running checksum
embcksme  jgd       r1,embcksm          loop performing checksum
          sa        a3,ccksum,x9        store block checksum in header
.
.         Write the block to the output file
.
          iow$      ewio,x9             write out the block
embwstck  tz        ewio+iostatus,x9    normal status on write ?
          j         embwerr             no.  handle write error
.
.         Update the next write address in the file
.
          la        a4,ewio+ioxfer,x9   load words written to file
          dsl       a4,36               shift down before divide
          aa,u      a5,27               round up for covered divide
          di,u      a4,28               compute sectors in block
          aa        a4,ewio+iodrad,x9   add to start address
          sa        a4,ewio+iodrad,x9   replace as next write address
          la        a0,f2               load second file fdt
          sa        a4,fdiplc,a0        update running address pointer
.
.         Now test the last block flag in the data just written.
.         If set, we close out the embed and enter the element.
.         If not, we just go back and keep on reading.
.
embterm   la        a2,iblast,a1        load last block flag
          brelp     a1                  release the data block buffer
          jz        a2,embnext          continue if more data in file
.
.         We have processed the last block.  Close out the element.
.
          la,u      a0,1                load a one
          sa        a0,ceof,x9          mark this last sector in file
          sz        cblen,x9            zero length of data in block
          sz        ccksum,x9           checksum is zero for no data
          la        a0,cblkno,x9        load current block sequence
          aa,u      a0,1                increment it
          sa        a0,cblkno,x9        replace in header sector
          la        a0,ewacwt,x9        load access word for header
          sa        a0,ewio+ioacw,x9    set as only access word
          la,u      a0,w$               load write function
          sa        a0,ewio+iofunc,x9   mark this as normal write
          iow$      ewio,x9             write the trailer block to file
          tz        ewio+iostatus,x9    normal status on write ?
          j         embwerr1            no.  edit error message
.
.         Element text is now complete in the file.  Construct the element
.         item and enter it in the table of contents.
.
          la        a0,a14              load the file table index
          la,u      a0,ftiet,a0         point to element table
          lmj       x11,pftlen          compute size of table
          aa,u      a0,eil              add room for one more element
          tg,u      a0,bufeltt+1        does it exceed maximum ?
          la,u      a0,bufeltt          yes.  restrict to maximum table
          sa        a0,a1               save length for read of table
          aa,u      a0,eil              include space for our new element
          bgetl     .                   allocate the element table
          sa        a0,a13              save for later use
          lxi,u     a1,eil,a0           load address of table start
          la        a0,a14              load fti address
          rpfet     .                   read in element table
          j         embonpf             error.  edit message
          la        a0,a13              reload element item address
          la        a1,e2               load output element class
          la        a2,f1               load input file FDT
          dl        a4,fdfn,a2          load input file name as element
          ds        a4,eien,a0          set as default element name
          dl        a4,(ljsf$2 ' ')     load spaces for version
          ds        a4,eiver,a0         set default version of spaces
          sz        eiprea,a0           clear unused word
          sz        eiprel,a0           clear unused half word
          la        a4,ewio+iodrad,x9   load last sector written address
          aa,u      a4,1                increment for length computation
          la        a2,a14              reload file table index address
          anu       a4,ftiwl,a2         compute length of element
          la        a3,ftiwl,a2         load start address of element
          sa        a4,ftiwl,a2         update next write address
          sa        a5,eitxtl,a0        set element length in item
          sa        a3,eitxta,a0        set element start address in item
          la        a3,ctdate,x9        load time of embed
          ssc       a3,18               reverse for silly item format
          sa        a3,eitime,a0        store in element creation time
          sz        eiplnk,a0           clear links
          sz        eivlnk,a0           in the item
          sz        eiflgw,a0           clear element flag bits
          la,u      a3,ty$omn           load omnibus element type
          sa        a3,eityp,a0         set element type in item
          la,u      a3,embstyp          load embed subtype
          sa        a3,eipcod,a0        set as processor code for element
          lmj       x11,rename          rename by second specification
          la        a1,a13              load item address
          la        a0,a14              load file table index address
          etia      .                   add element to file
          j         embonpf             bsp error.  print message
          la        a0,a14              reload fti address
          wpfet     .                   write back updated element table
          j         embonpf             error.  print message
          la        a0,a14              reload fti address
          wfti      .                   write file table index back
          j         embonpf             error.  print message
.
.         All done with processing.  Release storage and exit
.
embout    la        a0,f1               load source file FDT
          ssl       a0,18               right justify the FCT
          brelp     a0                  release the FCT
          brela     .                   release all the other buffers
          complete  .                   that's all for the command
.
.         Abnormal status in block from input file.  Handle depending
.         upon the actual status received and the file type.
.
embabn    la        a0,ibstat,a1        load status from block
          tne,u     a0,sterm            software termination ?
          j         embterm             yes.  this is end indicator
          te,u      a0,1                is it end of file ?
          j         embrerr             no.  read error from file
          tz        iomass,x10          yes.  is input really a tape ?
          j         embterm             no.  ignore end of file from mass
.
.         End of file mark read from tape.  Write end of file sector
.         to allow us to reproduce the mark on the output.
.
          sz        ccksum,x9           clear the checksum word
          sz        cblen,x9            clear the block length
          sz        csector,x9          mark no source address
          sa        a0,cefb,x9          set a one in end of file block flag
          la        a0,cblkno,x9        load block sequence number
          aa,u      a0,1                increment it by one
          sa        a0,cblkno,x9        replace in header sector
          la        a4,ewio+ioacw,x9    save the access word table pointer
          la        a0,ewacwt,x9        load the access word for header
          sa        a0,ewio+ioacw,x9    store into access word in packet
          la,u      a0,w$               load write function
          sa        a0,ewio+iofunc,x9   turn into simple write
          iow$      ewio,x9             write end of file block
          la,u      a0,gw$              load gather write function
          sa        a0,ewio+iofunc,x9   replace in packet
          sa        a4,ewio+ioacw,x9    replace access word table pointer
          j         embwstck            go check status on write and continue
.
.         Write error on output program file.  Release output buffer
.         and edit an error message.
.
embwerr   la        a2,iblast,a1        load the last block flag
          brelp     a1                  release the block buffer
          sr        f2,iofdt,x9         save the fdt for message editing
          la,u      a0,ewio,x9          load I/O FCT address
          lmj       x11,iosedt          edit the error message
          jz        a2,embrerr1         sink data if not last block
          j         embout              otherwise, just exit
.
.         Write error closing the element
.
embwerr1  sr        f2,iofdt,x9         set fdt link for error message
          lmj       x11,iosedt          edit error message for I/O
          j         embout              go terminate the command
.
.         Real error status encountered.  Terminate command and quit.
.
embrerr   la        a2,iblast,a1        load last block flag
          brelp     a1                  release the block buffer
          jnz       a2,embout           terminate if last block
embrerr1  snonz     cdcease,x8          mark command in termination
          lmj       a2,iognf            get a dummy fct
          sa        a0,x9               save it in x9
          lmj       a2,sink             discard the input buffers
          p         iobb+ql,x9          wait for sink to complete
          brelp     x9                  release sink fct
          j         embout              go terminate the command
.
.         Tape input to EMBED.  Set up the read modes
.
embtinp   la,u      a0,'M'              load 'M' I/O option
          tep,u     a15,option('M')     was the 'M' option on the command ?
          sa        a0,ioopt,x10        set option in FCT
          j         embtinr             continue with the command
.
.         Error.  Output file is word-addressable.
.
embowad   r$dit     .                   fire up the editor
          e$msg1    embfterm            copy bad file error message
          e$msg1    emwadm              say word-addressability was bad
embofter  la        a0,f2               load output file FDT
          lmj       x11,fist            edit file and statement
          zap       .                   error the command
          brelp     x10                 release the I/O FCT
          complete  .                   terminate the command
.
.         Output file was a tape
.
embotap   r$dit     .                   fire up the editor
          e$msg1    embfterm            copy the common message
          e$msg1    emtapm              say that tape is a 'no no'
          j         embofter            go edit file type message
.
.         BSP error on output file
.
embonpf   la        a2,a14              load the FTI address
          lmj       x11,bsperp          print the error message
          j         embout              terminate the command
.
          pure      data
embfterm  'Cannot EMBED into &'
emwadm    'word-addressable &'
emtapm    'tape &'
          pure      code
/.
.
.         Expansion of EMBEDed element back into file
.
ielt      la        a1,e2               load output element specification
          tnz       elall,a1            is the output a file ?
          j         bothelt             no.  error, both are elements
          lx        x9,e1               load input element specification
          la,u      a7,0                set to select only undeleted elements
          lmj       x11,filescan        select elements from the file
          j         exbsper             error.  bsp error
          lmj       x11,eltrel          release the element table buffer
          jz        a8,expempty         skip if no elements selected
          tep       a15,(option('A'))   alphabetise before selecting ?
          lmj       x11,filesort        yes.  that's what we advertised !!
.
.         Now go through the elements selected and look for an Omnibus
.         with EMBED subtype.  We will pick the first such element we
.         find.
.
expelts   remove    cdeltq,x8           remove next selected element
          tne,u     a1,cdeltq,x8        end of queue and no find ?
          j         expempty            yes.  print 'no element selected'
          ana,u     a1,eifq             back up to head of item
          lx,u      x7,,a1              save current element in X7
          la        a0,eityp,x7         load major type of element
          la        a1,eipcod,x7        load processor code (subtype)
          tne,u     a0,ty$omn           is it Omnibus ?
          te,u      a1,embstyp          yes.  is is EMBED-created ?
          j         expskip             no.  don't select it
          j         expfelt             yes.  we've found an element
.
expskip   brelr     x7                  release this item
          j         expelts             keep on looking
.
.         We've found an element to expand.  Set up work buffer to read its
.         text.
.
expfelt   bgetl     ewl                 allocate work buffer
          sa        a0,a12              save its address
          sa        a0,x6               save for later use
          la        a1,a14              load file table index address
          dl        a2,ftifn,a1         load file name of input
          ds        a2,ewio+iofn,a0     set name in work buffer packet
          la        a2,eitxta,x7        load start address of text
          sa        a2,ewio+iodrad,a0   set address to start reading
          sz        ewio+iostatus,a0    clear status so not busy
          la,u      a2,r$               load normal read function
          sa        a2,ewio+iofunc,a0   set function in packet
          au        a0,(28,ewpsect)     load the pointer to the sector
          sa        a1,ewio+ioacw,a0    set access word in packet
          sa        a1,ewacwt,a0        put in access word table also
          lmj       x11,readembe        read in header and check status
          j         exprerp             error reading first prefix
          la        a0,csent,x6         load sentinel from block
          te        a0,('EMBED$')       is this a valid header ?
          j         expnote             no.  not an EMBED element
          sz        sn                  clear expected sequence number
          la        a1,f2               load output file FDT
          lmj       a2,ioget            build FCT to write output file
          lx        x9,a0               save the FCT address in X9
          lxi       a0,f2               load address of FDT
          ssc       a0,18               shift FDT back to low half
          sa        a0,f2               save output fct, fdt
.
.         Now build the pseudo-input FCT used to pass blocks to the
.         output file.  Note that this FCT must be initialised with the
.         properties of the original EMBEDed file so that address
.         translation for WAD files will operate correctly.
.
          lmj       a2,iognf            build dummy FCT
          lx        x10,a0              save its address in X10
          la        a0,cfacit+fdeqt,x6  load equipment type of original file
          la        a0,eqttab,a0        load equipment type table entry
          tep,u     a0,epmass           mass storage type ?
          snonz     iomass,x10          yes.  mark this mass storage
          tep,u     a0,epwad            is it word-addressable ?
          snonz     iowad,x10           yes.  mark it word-addressable
          tz        iomass,x10          was input mass storage ?
          tnz       iomass,x9           yes.  was output ?
          j         expotp              no.  check for tape involvement
          la,u      a0,'D'              yes.  load duplicate addresses mode
expsiop   sa        a0,ioopt,x9         set mode of output process
          lmj       a2,output           fire up the output process
.
.         Now that we're all initialised, we set up to do the scatter
.         reads we'll actually use to read the text.
.
          la,u      a0,,x6              load the work buffer address
          aa        a0,(2,ewacwt)       form access word table pointer
          sa        a0,ewio+ioacw,x6    set in access word in packet
          la,u      a0,scr$             load scatter read function
          sa        a0,ewio+iofunc,x6   change to scatter read text
          la        a0,cmaxbl,x6        load maximum length of blocks in file
          sa,h1     a0,ewacwt+1,x6      plug in length of data access word
.
.         If the 'T' option is on the command, edit a message describing
.         the original source of the file being expanded.
.
          top,u     a15,option('T')     does user want file origin info ?
          j         exprnext            no.  go start loading data
          r$dit     .                   fire up the editor
          e$msg     loading             edit the file load message
          lx,u      x5,cfacit,x6        load packet describing input file
          e$fd2     fdqual,x5           edit file qualifier
          e$char    '*'                 edit asterisk before name
          e$fd2     fdfn,x5             edit file name
          la,h2     a3,6,x5             load the F-CYCLE word
          and,u     a3,07777            isolate the absolute cycle
          tz        a4                  temporary file ?
          tne,u     a4,1                no.  is it cycle one ?
          j         exptcyc1            yes.  Don't edit it
          e$char    '('                 edit open parenthesis
          e$decv    a4                  edit the f-cycle
          e$char    ')'                 edit closing parenthesis
exptcyc1  e$msgr    .                   copy to element being loaded
          sx        x9,ct               save output file FCT
          lx        x9,x7               load current element item
          lmj       x6,edena            edit element name being expanded
          e$msgr    .                   copy to file containing element
          la        a0,f1               load FDT of input file
          lmj       x11,fist            append file and statement
          lx        x9,ct               restore output file FCT
          lx        x6,a12              restore the work buffer
          j         exprnext            go read the first data block
.
.         Now we process the data from the element.  As we tear the
.         blocks apart, they are queued to the output process.
.
expnext   la        a0,sn               load sequence number
          aa,u      a0,1                increment it
          sa        a0,sn               update sequence number
          te        a0,cblkno,x6        is this the expected block ?
          j         expseqer            no.  print sequence error message
.
.         See if entire block was read O.K.
.
          la        a0,ewio+ioxfer,x6   load I/O words transferred count
          ana,u     a0,28               back off prefix block length
          tle       a0,cblen,x6         was entire block read ?
          j         expincb             no.  error in file
.
.         This is a normal data block.  Checksum the data and compare
.         against checksum saved in file.
.
          lr        r1,cblen,x6         load length of data
          la,h2     a2,ewacwt+1,x6      load data block start
          aa        a2,(1,0)            get pointer to scan data
          la,u      a0,0                clear the checksum
          j         expcksme            enter the checksum loop
.
expcksm   xor       a0,,*a2             xor new word with running ckecksum
          ssc       a1,1                shift circularly
          la        a0,a1               move down into running total
expcksme  jgd       r1,expcksm          loop for all words
          te        a0,ccksum,x6        is the ckecksum correct ?
          j         expcksmb            no.  invalid checksum on block
.
.         Data is good.  Form the block header.
.
          la,h2     a1,ewacwt+1,x6      load address of data block
          ana,u     a1,ibdata           back up to block header
          la,u      a0,0                load normal status
          tz        cefb,x6             was this a tape end of file mark ?
          la,u      a0,1                yes.  set end of file status
          sa        a0,ibstat,a1        set status into block buffer
          sz        iblast,a1           mark this not the last block
          sz        ibafc,a1            clear abnormal frame count
          sx        x6,ibiop,a1         set back pointer to I/O FCT
          la        a0,csector,x6       load sector address of source
          sa        a0,ibmsad,a1        set into address of block
          la        a0,cblen,x6         load length of block
          jz        a0,expzerb          skip if no data in block
          sa        a0,iblen,a1         set length in block buffer
          put       iobb,x10            pass block to output process
          lx        x6,a12              reload embed work buffer address
.
.         Update the next read address in the input file
.
expzerr   la        a0,cblen,x6         load length of block read
          dsl       a0,36               shift into double word quantity
          aa,u      a1,28+27            add header sector and round up
          di,u      a0,28               compute sectors in this block
          aa        a0,ewio+iodrad,x6   add to running address
          sa        a0,ewio+iodrad,x6   replace in the I/O packet
          la        a1,f1               load input file FDT
          sa        a0,fdiplc,a1        update running address pointer
.
.         If the block just processed is the last, go to closeout code.
.         Otherwise, read the next text block and continue.
.
          tz        ceof,x6             do more blocks follow ?
          j         expdone             no.  all done with element
exprnext  la        a0,cmaxbl,x6        load maximum block size
          aa,u      a0,ibdata           add data block header length
          bget      .                   allocate block buffer
          aa,u      a0,ibdata           advance to data in buffer
          sa,h2     a0,ewacwt+1,x6      set buffer address in ACW table
          lmj       x11,readembe        read text from file
          j         exprer              error.  terminate expansion
          la        a0,csent,x6         load sentinel from block
          tne       a0,('EMBED$')       is this an embed block ?
          j         expnext             yes.  continue processing file
          j         expbsent            no.  bad sentinel
.
.         Release the data buffer when zero length block read
.
expzerb   brelp     a1                  release the block buffer
          j         expzerr             continue processing normally
.
.         All data has been sent.  Place a termination buffer on the
.         output queue and run down output.
.
expdone   bget      ibdata              allocate termination buffer
          la        a1,a0               copy address of buffer
          la,u      a0,sterm            load software termination status
          sa        a0,ibstat,a1        set status in buffer
          snonz     iblast,a1           flag thid as the last buffer
          put       iobb,x10            place on output queue to terminate
          p         iobb+ql,x9          wait for output to complete
          brelp     x9                  release the output FCT
          brelp     x10                 release the input FCT
expout1   brela     .                   release all other storage
          complete  .                   complete the command
.
.         Set up tape output
.
expotp    la,u      a0,'M'              load 'M' I/O option
          j         expsiop             go set up I/O option
.
.         Read data from program file and check status
.
.         This routine permits an 05 or 022 status so long as at
.         at least 28 words are transferred.  This allows us to
.         read ahead the maximum block length without errorring
.         when we pass the actual end of the file.
.
readembe  iow$      ewio,x6             read a block of data
          tnz       ewio+iostatus,x6    normal completion on read ?
          j         1,x11               yes.  return to caller
          la        a0,ewio+iostatus,x6 load the I/O status
          te,u      a0,5                was it end of data ?
          tne,u     a0,022              no.  How about end of file ?
          j         $+2                 yes.  check transfer count
          j         0,x11               no.  return to error exit
          la        a0,ewio+ioxfer,x6   load the words transferred
          tg,u      a0,28               is it at least one sector ?
          j         1,x11               yes.  consider it normal
          j         0,x11               no.  ran out of data
.
.         Error.  Both specficiations specify elements.
.
bothelt   r$dit     .                   fire up the editor
          e$msg     bothem              copy the error message
          lmj       x11,ist             append the statement number
          zap       .                   error the command
          complete  .                   complete the command
.
.         BSP error scanning file
.
exbsper   la        a2,a14              load FTI address
          lmj       x11,bsperp          edit the BSP error message
          zap       .                   error the command
          j         expout1             return to complete command
.
.         Bad sentinel in first block
.
expnote   r$dit     .                   fire up the editor
          lx        x9,x7               load the element item
          lmj       x6,edena            edit element name
          e$msg     expnotm             edit the not embed error message
          lmj       x11,ist             append statement number
expribe   zap       .                   error the command
          j         expout1             go complete the command
.
.         Bad sentinel while loading file
.
expbsent  r$dit     .                   fire up the editor
          e$msg     expbsen             copy the error message
          sx        x9,ct               save the I/O FCT address
          e$fd1     csent,x6            edit the current sentinel
          e$msgr    .                   copy to element name
expeden   lx        x9,x7               load current element item
          lmj       x6,edena            edit the element name
          lx        x9,ct               restore I/O FCT address
          e$msgr    .                   copy to file and statement
          la        a0,f1               load input file FDT
          lmj       x11,fist            append file and statement
exprout   lx        x6,a12              restore work buffer address
          la,h2     a0,ewacwt+1,x6      load the I/O buffer address
          ana,u     a0,ibdata           back up to start of buffer
          brelp     a0                  release the I/O buffer
          zap       .                   error the command
          j         expdone             go terminate the command
.
.         Sequence error
.
expseqer  r$dit     .                   fire up the editor
          e$msg     expbseq             copy the error message
expdatar  sx        x9,ct               save the I/O FCT address
          j         expeden             go edit the element name
.
.         Checksum error
.
expcksmb  r$dit     .                   fire up the editor
          e$msg     expcksmm            copy the error message
          j         expdatar            go to common data error code
.
.         No element selected
.
expempty  r$dit     .                   fire up the editor
          e$msg     noesem              copy the error message
          la        a0,f1               load FDT for input file
          lmj       x11,fist            append the file and statement
          zap       .                   error the command
          j         expout1             get out of the command
.
.         Incomplete block read from file
.
expincb   r$dit     .                   fire up the editor
          e$msg     expincm             copy the incomplete message
          j         expdatar            go to common data error code
.
.         Error reading file preamble
.
exprerp   sr        f1,iofdt,x6         set the FDT pointer in the I/O FCT
          la,u      a0,ewio,x6          load the I/O packet addresss
          lmj       x11,iosedt          edit the I/O status
          j         expribe             go to common error code
.
.         Error reading text of file
.
exprer    sr        f1,iofdt,x6         save the FDT pointer in I/O FCT
          la,u      a0,ewio,x6          load the I/O packet address
          lmj       x11,iosedt          edit the I/O status
          j         exprout             go finish the command
.
          pure      data
loading   'Restoring ! from element ! of !'
bothem    'Both specifications are elements.  Cannot EMBED !'
expnotm   ' is not am EMBEDed file !'
expbsen   'Bad sentinel ''!'' in ! of !'
expbseq   'Sequence error in ! of !'
expcksmm  'Checksum error in ! of !'
noesem    'No element selected from !'
expincm   'Incomplete data block in ! of !'
.
.
          end