        .title  eccesup support routines for ecce
;  READIN, WRITEOUT, DELETEVM, MOVE
;  Paul McLellan  1981

        .psect  m$write,rel,con,wrt,noexe,pic,noshr

dext:   .blkb   10
dexl:   .blkw   1

        .psect  m$read,rel,con,quad,rd,pic,noexe,shr,nowrt

fskel:  $fab    fop=sqo
rskel:  $rab    mbc=16,mbf=2,rac=seq,usz=240
xskel:  $xabfhc
nskel:  $nam
eskel:
exten:  .ascii  /EXTENSION/

        .psect  m$code,exe,nowrt,con,pic,shr,quad

        .macro  status  ?l
        blbs    r0,l
        ret
l:
        .endm

; %externalintegerfn readin(%stringname file,
;                            %integer extraPages,
;                            %integername base,top,fend,limit)
; opens FILE and updates FILE to contain the complete filename
;   (FILE must be uppercase only)
; gets an area of vm and reads the file into it, starting extra
;   pages down the area of memory
; base and limit are set to the limits of the vm
; top and fend are set to the limits of the file
; records in the file are delimited by NL characters (10s)
; if the open fails, then the status returned is the failure code
;   and FILE is updated if a better estimate of the filename is got
; if all goes ok, the function returns zero
; if FILE is a null string then the memory is obtained and
; the pointers initialised in a uniform way.

        .entry  readin,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
file    =       4
extra   =       8
base    =       12
top     =       16
fend    =       20
limit   =       24

vmgot   =       0
vmwanted=       4

; get workspace off the stack
        subl    #40,sp
        movl    sp,r11

; translate EXTENSION to get the default extension
        tstb    dext
        bneq    193$
        pushal  exten
        pushl   #9
        pushal  dext
        pushl   #20
        movl    sp,r0
        $trnlog_s 8(r0),dexl,(r0)
        cmpl    r0,#ss$_normal
        beql    193$
        clrw    dexl
        movb    #1,dext

; get space for a fab, a rab, an xab and a nam block,
; then initialise the pointers.
193$:   subl    #eskel-fskel,sp         ;allocate them on the stack
        movl    sp,r10                  ;preserve base
        movc3   #eskel-fskel,fskel,(r10) ;fill in skeleton fields
        movl    file(ap),r3             ;file string address
        movzbl  (r3),r2                 ;length byte
        bneq    195$                    ;no filename (null input) ->
        clrl    r0                      ;zero length file
        brw     97$                     ;don't actually read anything
195$:   $fab_store fab=r10,fac=get,nam=nskel-fskel(r10),-
                xab=xskel-fskel(r10),fna=1(r3),fns=r2,-
                dna=dext,dns=dexl
        $rab_store rab=rskel-fskel(r10),fab=(r10),rop=rah
        $nam_store nam=nskel-fskel(r10),rsa=1(r3),rss=#127,-
                esa=1(r3),ess=#127

; now open the file for reading
        $open   fab=(r10)
        movb    nam$b_rsl+nskel-fskel(r10),r1   ;copy result length
        bneq    60$                             ;no problem
        movb    nam$b_esl+nskel-fskel(r10),r1   ;use other string
        beql    61$
60$:    movb    r1,(r3)
61$:    status                                  ;return if open failed
        $connect rab=rskel-fskel(r10)
        status

; the file is now open, so get enough virtual memory for
; the second argument of extra blocks
        movl    xab$l_hbk+xskel-fskel(r10),r0 ;number of blocks
97$:    addl    extra(ap),r0            ;size to get
        incl    r0                      ;one for luck
        ashl    #9,r0,r0                ;convert to bytes
        movl    r0,vmwanted(r11)        ;size of vm getting
        pushal  vmgot(r11)              ;arg 2
        pushal  vmwanted(r11)           ;arg1
        calls   #2,g^lib$get_vm         ;get memory
        status

; we now have all the memory we need, so copy in the entire file
        movl    vmgot(r11),@base(ap)    ;return the memory area
        addl3   vmwanted(r11),vmgot(r11),@limit(ap)
        movl    vmgot(r11),r6           ;start address of vm
        ashl    #9,extra(ap),r0         ;convert to bytes
        addl    r0,r6                   ;pass workspace
        movl    r6,@top(ap)             ;will be first byte of file
        tstb    @file(ap)               ;filename length byte
        beql    89$                     ;null file ->
10$:    movl    r6,rab$l_ubf+rskel-fskel(r10) ;buffer address
        $get    rab=rskel-fskel(r10) ;get the next record
        blbs    r0,11$          ;no problem
        cmpl    #rms$_eof,r0    ;end of file
        beql    12$
        pushl   r0              ;save unlikely status
        pushal  vmgot(r11)
        pushal  vmwanted(r11)
        calls   #2,g^lib$free_vm
        popl    r0
        ret
11$:    movzwl  rab$w_rsz+rskel-fskel(r10),r0 ;record length
        addl    r0,r6           ;update pointer
        movb    #10,(r6)+               ;newline separator
        brb     10$                     ;and on to the next record

; the file has all been read, so save the final pointer
; and close the file.
12$:    $close  fab=(r10)

89$:    movl    r6,@fend(ap)                    ;end of file area
        clrl    r0                              ;success
        ret






; %externalintegerfn writeout(%stringname file,
;   %integer base,top,fend,limit)
; writes out the file and deletes the virtual memory
; it is assumed that readin has been called to set up default extension

        .entry  writeout,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
file    =       4
base    =       8
top     =       12
fend    =       16
limit   =       20

; get space for fab, rab, (xab unused) and a nam block,
; then initialise the pointers
        subl    #eskel-fskel,sp         ;allocate the space
        movl    sp,r10                  ;save the base
        movc3   #eskel-fskel,fskel,(r10) ;fill in skeleton fields
        movl    file(ap),r3             ;file string address
        movzbl  (r3),r2                 ;length byte
        subl3   top(ap),fend(ap),r4     ;number of bytes stored
        addl    #1024,r4                ;extra space for rms
        ashl    #-9,r4,r4               ;estimated filesize in blocks
        $fab_store fab=r10,fac=put,nam=nskel-fskel(r10),-
                fna=1(r3),fns=r2,alq=r4,rat=cr,fop=tef,-
                dna=dext,dns=dexl
        $rab_store rab=rskel-fskel(r10),fab=(r10),rop=wbh
        $nam_store nam=nskel-fskel(r10),rsa=1(r3),rss=#127,-
                esa=1(r3),ess=#127
; now create the file
        $create fab=(r10)
        movb    nam$b_rsl+nskel-fskel(r10),r1 ;result length
        bneq    50$             ;parsed ok
        movb    nam$b_esl+nskel-fskel(r10),r1 ;use other parse
        beql    51$
50$:    movb    r1,(r3)
51$:    status

        $connect        rab=rskel-fskel(r10)
        status

; the file is now open, so copy the entire file out
        movl    top(ap),r6              ;first byte in file
        subl3   #1,fend(ap),r7          ;last real character
10$:    subl3   r6,r7,r0                ;see if at end of area
        blequ   11$                     ;done ->
        cmpl    r0,#65535
        bleq    12$
        movl    #65535,r0
12$:    locc    #10,r0,(r6)             ;find first newline
        subl3   r6,r1,r0                ;length of record
        movl    r6,rab$l_rbf+rskel-fskel(r10) ;start of buffer
        movw    r0,rab$w_rsz+rskel-fskel(r10) ;record length
        addl3   r1,#1,r6                ;start of next record
        $put    rab=rskel-fskel(r10)    ;put out the record
        status
        brb     10$                     ;on to the next record

; the whole file is written out, so close it
11$:    $close  fab=(r10)

        pushl   limit(ap)
        pushl   base(ap)
        calls   #2,deletevm
        clrl    r0
        ret



; %externalroutine deletevm(%integer base,limit)
; delete an area of virtual memory
        .entry  deletevm,^m<>
base=4
limit=8
        subl3   base(ap),limit(ap),-(sp)
;       pushal  (sp)
        pushal  base(ap)
        pushal  4(sp) ; num-bytes
        calls   #2,g^lib$free_vm
        ret



; %externalroutine move(%integer lengthm %byteintegername from,to)
; length must be less than maxint, but may be more than 64k
        .entry  move,^m<r2,r3,r4,r5,r6>
        movl    4(ap),r6
        movl    8(ap),r1
        movl    12(ap),r3
; r6=len, r1->source; r3->dest
20$:    cmpl    r6,#65532               ;see if it can all go this time
        bleq    10$
        movc3   #65532,(r1),(r3)        ;leaves r1 beyond source, r3 dest
        subl    #65532,r6               ;decrement remaining length
        brb     20$
10$:    movc3   r6,(r1),(r3)            ;move last block
        ret

        .end
