      TITLE   library manipulation
      MODULE  LIBREAD
      EXPORTC RDLIB,EXTRACT,WRAOF,APPEND,WRLIB,PRBLNK
      IMPORTC LoadFile,SaveFile,GetFileInformation,WriteByte
      AREADEF data='DATA',[PIC,COMMON],DOUBLE
      AREADEF PROG,[READ,PIC,SHARED,CODE],BYTE
      AREADEF names='NAMES',[PIC,COMMON],DOUBLE
      AREADEF nnam='NNAM',[PIC,COMMON],DOUBLE
      IMPORT  NAMES,NNAM
      DEFSB   data
;
      AREA    names
mod   ALLOCD  2000
;
      AREA nnam
nmod  ALLOCD  1
;
      AREA    data
max   EQU     200000
lenl  ALLOCD  1
endl  ALLOCD  1
ans   ALLOCD  1
lena  ALLOCD  1
date  ALLOCD  2
filedat ALLOCD 4
name  EQU     filedat
lib   ALLOCB  max
;
      AREA    PROG
RDLIB                     ;read library file
      ADDR    lib,lenl    ;start address
      ADDR    lib+max,endl;end address
      MOVQD   0,nmod      ;zero # module names
;
APPEND                    ;append to library
      BSR     getl        ;get name
      SAVE    [R0,R1]     ;set up parameters
      ADDR    date,TOS    ;date-time
      ADDR    filedat,TOS ;file information
      CXP     GetFileInformation
      CMPQD   0,R0
      BGT     bad         ;file not found
      MOVD    lenl,R6     ;load point
      MOVD    endl,R7
      SUBD    R6,R7       ;length available
      CMPD    R7,filedat+8
      BLT     sick        ;file too long
      BSR     getl
      SAVE    [R6,R7]     ;address & length of buffer
      SAVE    [R0,R1]     ;name of file
      CXP     LoadFile    ;load file
      CMPQD   0,R0
      BGT     bad         ;can't load file
      MOVD    lenl,R6     ;file address
      MOVD    filedat+8,R4
      ADDD    R6,R4       ;end of file
      CMPQD   3,-1(R4)
      BNE     a1
      ADDQD   -1,R4       ;remove end-of-file mark
a1    MOVD    R4,lenl     ;store end of file address
a2    BSR     lgth        ;get module characterisics
      CMPQD   0,R5
      BGE     sick
      MOVD    nmod,R0     ;module count
      ADDR    1(R0),nmod  ;increment count
      ADDR    mod-16,R4   ;address of list
      ADDR    @16,R2      ;length of names
      ADDR    name,R3     ;location of name
a3    ADDD    R2,R4       ;pointer to next name
      ADDQD   -1,R0       ;decrement count left
      BCC     a4          ;none left
      CMPMB   R3,R4,16    ;compare names
      BHS     a3          ;loop while new name is bigger
a4    ADDQD   1,R0
      BCS     a5          ;at end of list
      ADDD    R0,R0
      ADDD    R0,R0       ;# words in rest of list
      ADDR    -4(R4)[R0:D],R1
      ADDD    R1,R2       ;address of new last word
      MOVSD   [B]         ;move up rest of list
a5    MOVMD   R3,R4,4     ;store new name
      ADDD    R5,R6       ;move to next module
      CMPD    R6,lenl
      BLT     a2
      BR      good
;
EXTRACT                  ;remove module from library
                         ;first find module
      BSR     getl       ;get name
      ADDR    lib,R6     ;address of library
e1    BSR     lgth       ;get length in R5, address of name in R7
      CMPB    R0,R7      ;compare name lengths
      BNE     e2
      ADDR    name,R2    ;name address
      SAVE    [R0,R1]
      CMPSB              ;compare names
      RESTORE [R0,R1]
      BEQ     e3         ;found module
e2    ADDD    R5,R6
      CMPD    R6,lenl
      BLT     e1         ;loop over modules
      BR      sick       ;module not found
e3;        now move module
      MOVD    R5,R0      ;length
      MOVD    R6,R1      ;address
      MOVD    lenl,R2    ;new address
      MOVD    R2,R7
      ADDD    R0,R7      ;end of extended library
      CMPD    endl,R7
      BLT     bad        ;won't go in
      MOVSB              ;move module
      MOVD    R6,R2      ;beginning of gap to fill
      ADDR    R2[R5:B],R1;end of gap
      MOVD    lenl,R0
      SUBD    R6,R0      ;length to move down
      MOVSB              ;compact library
      SUBD    R5,lenl    ;new end of library
      MOVD    R5,lena    ;length of extracted module
      BR      good
;
WRAOF                    ;write out extracted module
      BSR     getl
      MOVD    lenl,TOS   ;address of module
      MOVD    lena,TOS   ;length of module
      BR      wr1
;
WRLIB                    ;write library
      BSR     getl
      ADDR    lib,TOS    ;address of library
      MOVD    lenl,TOS
      SUBD    4(SP),TOS  ;length of library
wr1   SAVE    [R0,R1]
      CXP     SaveFile
      CMPQD   0,R0
      BGT     bad       ;bad write
      BR      good
;
PRBLNK                   ;print blank
      ADDR    @32,TOS
      CXP     WriteByte
      RXP     4
;
;         utilities
;
getl                     ;get input name and length
      MOVD    0(12(SP)),R0
      MOVD    0(R0),R1   ;address of NAME in R1
      MOVD    4(R0),R0   ;length of NAME in R0
g1    CMPB    =' ',-1(R1)[R0:B]
      BNE     g2         ;found non-blank
      ACBD    -1,R0,g1
g2    RET     0
;
lgth                     ;find length of module at R6
                         ;length returned in R5
                         ;length of name in R7
                         ;name in 'name' padded with blanks
      CMPMB   R6,intro,5 ;check fixed words
      BNE     badl
      TBITB   =0,5(R6)
      BFC     genf       ;general format module
      MOVB    6(R6),R3   ;1st byte of length in R3
      ADDR    7(R6),R7   ;next address in R7
      CBITB   =7,R3
      BFS     l1         ;not single byte length
      MOVZBD  R3,R5      ;length in R5
      BR      finl
l1    CBITB   =6,R3
      BFS     l2         ;not 2-byte length
      ADDQD   1,R7       ;next address in R7
      MOVZBD  R3,R5      ;msb of length in R5
      ASHD    =8,R5
      MOVB    7(R6),R5   ;lsb of length in R5
      BR      finl
l2    CBITB   =5,R3
      BFS     l4         ;not '4'-byte length
      ADDQD   3,R7       ;next address in R7
      MOVB    R3,R5      ;msb of length in R5
      MOVQD   -3,R3
l3    ASHD    =8,R5
      MOVB    R7[R3:B],R5;other bytes of length
      ACBD    1,R3,l3
      BR      finl
l4    MOVD    7(R6),R5    ;length in R5
      ADDQD   4,R7        ;next address in R7
finl  CMPQB   2,-1(R6)[R5:B]
      BNE     badl        ;check ending
      ADDR    name,R2
      SAVE    [R0,R1]
      MOVD    ='    ',R0
      MOVD    R0,0(R2)    ;blank out name
      MOVD    R0,4(R2)
      MOVD    R0,8(R2)
      MOVD    R0,12(R2)
      MOVZBD  0(R7),R0    ;length of name
      ADDR    @16,R3
      CMPD    R0,R3
      BLE     l5
      MOVD    R3,R0       ;limit length to 16
l5    ADDR    1(R7),R1    ;address of name
      MOVD    R0,R7       ;length of name
      MOVSB               ;store module name
      RESTORE [R0,R1]
      RET     0
badl  MOVQD   -1,R5
      RET     0
genf                       ; find length of general format module
      ADDR    6(R6),R7     ;address of name
      MOVD    R6,R5
      MOVD    lenl,R3
f1    CMPQB   2,0(R5)
      ADDQD   1,R5
      BEQ     f2
      CMPD    R5,R3
      BLT     f1
      BR      badl
f2    CMPD    R5,R3
      BEQ     f3
      CMPMB   R5,intro,5
      BNE     f1
f3    SUBD    R6,R5
      RET     0
;
bad   MOVQD   -1,ans      ;bad,  return -1
      BR      fin
sick  MOVQD   1,ans       ;sick, return +1
      BR      fin
good  MOVQD   0,ans       ;good, return 0
fin   ADDR    ans,R0
      RXP     4
;
intro DCB     1           ;module header bytes
      DCS     'PbE2'
      END
