home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Tools / Serial / kserve.mac < prev    next >
Encoding:
Text File  |  1998-03-16  |  56.7 KB  |  2,493 lines

  1.     .title    KSERVE
  2.     .enabl    lc
  3. ;++
  4. ;
  5. ; Kermit console server.
  6. ;
  7. ; Allows KERMIT communication with a microcomputer
  8. ; connected in place of the CTY (TT:).
  9. ;
  10. ; By John Wilson.
  11. ;
  12. ; 23-Oct-88    Created.
  13. ; 04-Dec-90    Added directory command.
  14. ; 10-Dec-90    Receive (from us) command.
  15. ; 24-Jan-92    Generate attribute packets.
  16. ;
  17. ;--
  18.     .mcall    .close,.dstat,.exit,.fetch,.print
  19.     .mcall    .purge,.releas,.ttinr,.ttyout,.wait
  20. ;
  21. eis$$=    1    ;NZ => processor has EIS
  22. rt11$$=    1    ;NZ => OS is RT-11
  23. ;
  24. soh=    1    ;SOH character is ^A
  25. binlin=    0    ;NZ => we have an 8-bit line
  26.         ;Z => 7-bit line, will need QBIN escape
  27. ;
  28. bufsiz=    4000        ;buffer size, in bytes
  29. ;
  30. .enter=    emt+375
  31. .lookup=emt+375
  32. .rctrlo=emt+355
  33. .read=    emt+375
  34. .readw=    emt+375
  35. .write=    emt+375
  36. ;
  37.     .asect
  38. .=    44
  39.     .word    50000    ;set LC, noecho bits in JSW
  40.     .psect
  41. ;
  42. attr=    10        ;CAPAS bit for attribute packets
  43. ;
  44. lf=    12
  45. cr=    15
  46. ;
  47. start:    ; gentlemen, start your engines!
  48.     mov    #<^RDK >,defdev    ;initial default device
  49.     clrb    binfil        ;not binary files
  50.     ; init packet parameters
  51.     movb    #cr,eol        ;init eol
  52.     clrb    npad        ;no pads
  53.     movb    #77.,maxl    ;MAXL=80. (-header/checksum)
  54. loop:    clrb    seq        ;always packet 0 in command wait
  55.     mov    #1,lchk        ;check type is 1 until SEND-INIT
  56.     mov    #chk1,checka
  57.     call    getpac        ;get a packet
  58.     bcc    10$        ;handle it
  59.     call    nak        ;NAK it
  60.     br    loop        ;loop
  61. 10$:    movb    r1,seq        ;accept whatever they think we're at
  62.     mov    #cmds,r2    ;pt at table
  63.     mov    #ncmds,r3    ;# entries
  64. 20$:    cmp    r0,(r2)+    ;is this it?
  65.     beq    30$        ;yes
  66.     tst    (r2)+        ;no, skip addr
  67.     sob    r3,20$        ;loop
  68.     movb    r0,pnsc        ;save char
  69.     mov    #pns,r0        ;pt at string
  70.     call    err        ;send error
  71.     br    loop        ;loop
  72. 30$:    call    @(r2)+        ;go
  73.     br    loop        ;loop
  74. ;
  75. cmds:    .word    'G,genric    ;GENERIC
  76.     .word    'I,init        ;INITIALIZE
  77.     .word    'K,kcmd        ;KERMIT command
  78.     .word    'R,send        ;RECEIVE-INIT
  79.     .word    'S,receiv    ;SEND-INIT
  80. ncmds=    <.-cmds>/4
  81.     .sbttl    generic commands
  82. ;+
  83. ;
  84. ; Generic commands (actual command in data field).
  85. ;
  86. ;-
  87. genric:    ; unpack data field
  88.     mov    #buf1,bufptr    ;set up ptr
  89.     mov    #80.,bufctr    ;let's be reasonable
  90.     jsr    r1,iunpk    ;unpack
  91.      .word    secrts        ;don't flush
  92.     bcs    10$        ;error
  93.     mov    #buf1,r5    ;init ptr
  94.     mov    bufptr,r4    ;calc length
  95.     sub    r5,r4
  96.     beq    20$        ;0, who cares
  97.     movb    (r5)+,r0    ;get command byte
  98.     dec    r4        ;count it
  99.     mov    #gcmds,r2    ;pt at list
  100.     mov    #ngcmds,r3    ;number of entries
  101. 10$:    cmp    r0,(r2)+    ;is this it?
  102.     beq    30$        ;yes
  103.     tst    (r2)+        ;skip address
  104.     sob    r3,10$        ;loop
  105.     movb    r0,cnsc        ;save char
  106.     mov    #cns,r0        ;pt at string
  107.     jmp    err        ;send error, return
  108. 20$:    ; null packet
  109.     jmp    ack        ;just ack it, ignore, return
  110. 30$:    jmp    @(r2)+        ;dispatch
  111. ;
  112. gcmds:    .word    'C,cwd
  113.     .word    'D,direct
  114.     .word    'F,finish
  115.     .word    'L,logout
  116.     .word    'U,usage
  117. ngcmds=    <.-gcmds>/4
  118. ;+
  119. ;
  120. ; Change working directory.
  121. ;
  122. ; For RT-11 V4.0 this will just mean set default device,
  123. ; since I don't know anything about the subdisks in V5.
  124. ;
  125. ;-
  126. cwd:    tst    r4        ;any data field?
  127.     beq    20$        ;no
  128.     mov    #buf1,bufptr    ;set up ptr
  129.     mov    #80.,bufctr    ;good length
  130.     jsr    r1,iunpk    ;unpack
  131.      .word    secrts        ;don't flush
  132.     bcs    40$        ;error
  133.     ; parse it
  134.     mov    #buf1,r5    ;ptr
  135.     movb    (r5)+,r4    ;get 2nd length byte
  136.     sub    #40,r4        ;unchar()
  137.     beq    20$        ;length byte is 0, skip
  138.     add    r5,r4        ;skip to end
  139.     clrb    (r4)        ;.asciz
  140.     call    rad50        ;parse
  141.     tst    r0        ;end?
  142.     beq    10$        ;yes
  143.     cmp    r0,#':        ;must be colon
  144.     bne    40$        ;no
  145.     tstb    (r5)        ;followed by end?
  146.     bne    40$        ;no
  147. 10$:    ; see if it's a valid dev name
  148.     mov    r1,fbuf        ;save dev name
  149.     .dstat    #dstat,#fbuf    ;see if it's OK
  150.     bcs    40$        ;nope
  151.     mov    fbuf,defdev    ;it's the new default
  152.     br    30$        ;skip
  153. 20$:    mov    #<^RDK >,defdev    ;set it back to DK:
  154. 30$:    ; echo back the name
  155.     mov    #ddev,r5    ;pt at string
  156.     mov    #ddev1,r4    ;pt at dev name
  157.     mov    defdev,r1    ;get name
  158.     call    r50nbl        ;convert it
  159.     movb    #':,(r4)+    ;colon
  160.     movb    #cr,(r4)+    ;crlf
  161.     movb    #lf,(r4)+
  162.     sub    r5,r4
  163.     call    ldatn        ;make data field
  164.     call    ldatf        ;fix r4, r5
  165.     jmp    ack1        ;ack, return
  166. 40$:    mov    #bdn,r0        ;bad device name
  167.     jmp    err
  168. ;+
  169. ;
  170. ; Directory listing.
  171. ;
  172. ;-
  173. direct:    movb    #1,dirall    ;assume we're showing everything
  174.     clrb    dirnon        ;actually show it
  175.     mov    defdev,wlddev    ;default device
  176.     tst    r4        ;filespec given?
  177.     beq    40$        ;no
  178.     ; unpack data field
  179.     mov    #buf1,bufptr    ;set up ptr
  180.     mov    #80.,bufctr    ;let's be reasonable
  181.     jsr    r1,iunpk    ;unpack
  182.      .word    secrts        ;don't flush
  183.     bcs    10$        ;error
  184.     ; parse it
  185.     mov    #buf1,r5    ;ptr
  186.     movb    (r5)+,r4    ;get 2nd length byte
  187.     sub    #40,r4        ;unchar()
  188.     beq    40$        ;length byte is 0, skip
  189.     add    r5,r4        ;skip to end
  190.     clrb    (r4)        ;.asciz, r4 is NZ for PWILD
  191.     call    pwild        ;parse wildcard
  192.     bcc    30$        ;skip if OK
  193. 10$:    ; invalid
  194.     mov    #bfs,r0        ;bad file spec
  195.     jmp    err        ;send error packet, return
  196. 20$:    rts    pc
  197. 30$:    clrb    dirall        ;we're matching some wildcard
  198. 40$:    ; do the SEND-INIT thing
  199.     call    iparms        ;init parms
  200.     call    sparms        ;prepare ours
  201.     mov    #'S,r0        ;SEND-INIT
  202.     call    makpac        ;make a packet
  203.     call    sndack        ;send it, get ACK
  204.     bcs    20$        ;punt
  205.     call    rparms        ;get their parms
  206.     call    fparms        ;finish up
  207.     ; send a blank text header
  208.     mov    #'X,r0        ;type
  209.     call    sndsmp        ;send it
  210.     bcs    20$        ;error
  211.     ; set up for dir read
  212.     call    dirini        ;init dir read
  213.     bcs    120$        ;err, punt
  214.     mov    #txbuf+3,-(sp)    ;init LDAT parms
  215.     movb    maxl,r0
  216.     mov    r0,-(sp)
  217. 50$:    ; process next segment
  218.     call    dirseg        ;get next seg
  219.     bcs    110$        ;err or end
  220. 60$:    ; display next file
  221.     mov    #buf2,r4    ;output line buf
  222.     mov    (r5)+,r1    ;convert first word
  223.     beq    50$        ;end of seg, get next
  224.     call    r50
  225.     mov    (r5)+,r1    ;2nd word
  226.     call    r50
  227.     movb    #'.,(r4)+    ;point
  228.     mov    (r5)+,r1    ;extension
  229.     call    r50
  230.     mov    #10,r3        ;column counter
  231.     add    r3,r4        ;skip past end of field
  232.     mov    (r5)+,r1    ;get length of file
  233.     mov    #10.,r2        ;radix
  234. 70$:    clr    r0        ;0-extend
  235.     div    r2,r0        ;divide
  236.     bis    #'0,r1        ;convert remainder
  237.     movb    r1,-(r4)    ;save
  238.     dec    r3        ;count it
  239.     mov    r0,r1        ;copy
  240.     bne    70$        ;loop if there's more
  241. 80$:    movb    #' ,-(r4)    ;pad with blanks
  242.     sob    r3,80$        ;loop
  243.     add    #10,r4        ;skip to end of field
  244.     mov    (r5)+,r3    ;get date
  245.     beq    100$        ;meaningless, never mind
  246.     movb    #' ,(r4)+    ;2 more blanks
  247.     movb    #' ,(r4)+
  248.     mov    r3,r1        ;copy date
  249.     ash    #-5,r1        ;right 5
  250.     bic    #^C37,r1    ;isolate low 5
  251.     call    dec2        ;day as 2-dig decimal
  252.     mov    r3,r1        ;save
  253.     swab    r3        ;put month in low byte
  254.     bic    #^C74,r3    ;isolate month*4
  255.     add    #months-4,r3    ;index to -Month-
  256.     mov    #5,r0        ;count
  257. 90$:    movb    (r3)+,(r4)+    ;copy a byte
  258.     sob    r0,90$        ;loop
  259.     bic    #^C37,r1    ;isolate year
  260.     add    #72.,r1        ;what's so special about 1972?
  261.     cmp    r1,#100.    ;they should have just kept
  262.     blo    .+6        ;the last 2 digs of year (7 bits)
  263.      sub    #100.,r1    ;handle 2000+ AD (ha!)
  264.     call    dec2        ;convert
  265. 100$:    movb    #cr,(r4)+    ;crlf
  266.     movb    #lf,(r4)+
  267.     ; send this line to the toy computer
  268.     mov    (sp)+,r2    ;restore LDAT parms
  269.     mov    (sp)+,r1
  270.     mov    r5,-(sp)    ;save dir ptr
  271.     mov    #buf2,r5    ;begn of line
  272.     sub    r5,r4        ;length
  273.     call    sdat        ;send data
  274.     mov    (sp)+,r5    ;[restore r5]
  275.     bcs    220$        ;punt
  276.     mov    r1,-(sp)    ;save
  277.     mov    r2,-(sp)
  278.     br    60$        ;loop
  279. 110$:    ; end or error
  280.     beq    130$        ;end, skip
  281.     add    #4,sp        ;flush stack
  282. 120$:    mov    #ioerr,r0    ;pt at msg
  283.     jmp    err        ;bitch, return
  284. 130$:    ; end of listing
  285.     call    dirsum        ;get dir summary
  286.     ; send summary to the toy computer
  287.     mov    (sp)+,r2    ;restore LDAT parms
  288.     mov    (sp)+,r1
  289.     call    sdat        ;send data
  290.     bcs    210$        ;punt
  291.     mov    #txbuf+3,r5    ;pt at buf
  292.     mov    r1,r4        ;copy end
  293.     sub    r5,r4        ;find it
  294.     beq    200$        ;none
  295.     mov    #'D,r0        ;packet type
  296.     call    makpac        ;make it
  297.     call    sndack        ;send, get ACK
  298.     bcs    210$        ;punt
  299. 200$:    mov    #'Z,r0        ;end of file
  300.     call    sndsmp
  301.     bcs    210$        ;punt
  302.     mov    #'B,r0        ;break
  303.     call    sndsmp        ;(don't worry about errors)
  304. 210$:    rts    pc
  305. 220$:    ; retry limit reached, punt
  306.     .close    #0        ;close dir
  307.     rts    pc
  308. ;
  309.     .enabl    lsb
  310. 10$:    ; flush output buffer
  311.     mov    r5,-(sp)    ;save buf posn
  312.     mov    r4,-(sp)
  313.     mov    #txbuf+3,r5    ;pt at buf
  314.     mov    r1,r4        ;copy end
  315.     sub    r5,r4        ;find it
  316.     mov    #'D,r0        ;packet type
  317.     call    makpac        ;make a packet
  318.     call    sndack        ;send it, get ACK
  319.     bcs    20$        ;failed, skip
  320.     mov    (sp)+,r4    ;restore
  321.     mov    (sp)+,r5
  322.     mov    #txbuf+3,r1    ;reinit
  323.     movb    maxl,r2
  324. sdat:    call    ldat        ;continue loading
  325.     bcs    10$        ;full again, loop
  326. 20$:    rts    pc
  327.     .dsabl    lsb
  328. ;
  329. dec2:    ; number in r1 to convert 2-digit decimal
  330.     clr    r0        ;0-extend
  331.     div    #10.,r0        ;divide
  332.     bis    #'0,r0        ;convert high dig
  333.     movb    r0,(r4)+
  334.     bis    #'0,r1        ;convert low dig
  335.     movb    r1,(r4)+
  336.     rts    pc
  337. ;
  338. decv:    ; convert variable-width decimal no. in r1
  339.     cmp    r1,#10.        ;do we need to recurse?
  340.     blo    10$        ;no
  341.     clr    r0        ;0-extend
  342.     div    #10.,r0        ;divide
  343.     mov    r1,-(sp)    ;save remainder
  344.     mov    r0,r1        ;copy quotient
  345.     call    decv        ;recurse
  346.     mov    (sp)+,r1    ;restore remainder
  347. 10$:    bis    #'0,r1        ;convert
  348.     movb    r1,(r4)+    ;save
  349.     rts    pc
  350. ;+
  351. ;
  352. ; Convert a radix-50 word to a 3-character ASCII string.
  353. ;
  354. ; r1    word
  355. ; r4    buffer ptr
  356. ;
  357. ;-
  358. r50:    clr    r0        ;0-extend
  359.     div    #50,r0        ;divide
  360.     mov    r1,r2        ;save remainder
  361.     mov    r0,r1        ;copy
  362.     clr    r0        ;0-extend
  363.     div    #50,r0        ;divide
  364.     movb    r50t(r0),(r4)+    ;first char
  365.     movb    r50t(r1),(r4)+    ;second
  366.     movb    r50t(r2),(r4)+    ;third
  367.     rts    pc
  368. ;+
  369. ;
  370. ; Finish/logout.
  371. ;
  372. ; ACK and kill the server.
  373. ;
  374. ;-
  375. finish:
  376. logout:    call    ack        ;ACK it
  377.     .exit            ;bye
  378. ;+
  379. ;
  380. ; Disk usage.
  381. ;
  382. ;-
  383. usage:    mov    defdev,wlddev    ;copy dev name
  384.     movb    #1,dirall    ;look at all files
  385.     movb    #1,dirnon    ;but don't bother making a list
  386.     call    dirini        ;init dir I/O
  387.     bcs    20$        ;err
  388. 10$:    call    dirseg        ;scan next segment
  389.     bcc    10$        ;loop until all done
  390.     bne    20$        ;err
  391.     call    dirsum        ;make dir summary
  392.     ; send to toy computer
  393.     call    ldatn        ;load data field
  394.     call    ldatf        ;fix for ACK1
  395.     jmp    ack1        ;ACK, return
  396. 20$:    ; I/O error
  397.     mov    #ioerr,r0    ;point
  398.     jmp    err        ;bitch, return
  399. ;+
  400. ;
  401. ; Make a summary of a directory scan.
  402. ;
  403. ; On return:
  404. ; r5    ptr to line (#buf2)
  405. ; r4    length
  406. ;
  407. ;-
  408. dirsum:    mov    #buf2,r4    ;pt at buf2
  409.     ; display # of files
  410.     mov    files,r1    ;print # files
  411.     call    decv
  412.     mov    #tfile,r0    ;string
  413. 10$:    movb    (r0)+,(r4)+    ;copy
  414.     bne    10$
  415.     dec    r4
  416.     dec    files        ;files=1?
  417.     beq    20$        ;yes
  418.      movb    #'s,(r4)+    ;s
  419. 20$:    ; display # of blks used
  420.     movb    #',,(r4)+    ;,
  421.     movb    #' ,(r4)+
  422.     mov    used,r1        ;print # blks in use
  423.     call    decv
  424.     mov    #tblk,r0    ;string
  425. 30$:    movb    (r0)+,(r4)+    ;copy
  426.     bne    30$
  427.     dec    r4
  428.     dec    used        ;used=1?
  429.     beq    40$        ;yes
  430.      movb    #'s,(r4)+    ;s
  431. 40$:    movb    (r0)+,(r4)+    ;copy " in use"
  432.     bne    40$
  433.     dec    r4
  434.     tstb    dirall        ;showing frees too?
  435.     beq    60$        ;no
  436.     ; display # of free blks
  437.     movb    #',,(r4)+    ;,
  438.     movb    #' ,(r4)+
  439.     mov    free,r1        ;print # free blks
  440.     call    decv
  441.     mov    #tfree,r0    ;string
  442. 50$:    movb    (r0)+,(r4)+    ;copy
  443.     bne    50$
  444.     dec    r4
  445. 60$:    movb    #cr,(r4)+    ;crlf
  446.     movb    #lf,(r4)+
  447.     mov    #buf2,r5    ;begn of line
  448.     sub    r5,r4        ;length
  449.     rts    pc
  450. ;
  451.     .sbttl    initialize parameters
  452. ;+
  453. ;
  454. ; Takes parms as usual, responds with ours.
  455. ;
  456. ;-
  457. init:    call    iparms        ;init parm negotiation
  458.     call    rparms        ;process the ones we got
  459.     call    sparms        ;set up the ones to send
  460.     call    ack1        ;send them
  461.     jmp    fparms        ;finish up, return
  462.     .sbttl    kermit command
  463. ;+
  464. ;
  465. ; Handle what would normally be keyboard commands.
  466. ;
  467. ;-
  468. kcmd:    mov    #buf1,bufptr    ;set up ptr
  469.     mov    #132.,bufctr    ;good length
  470.     clrb    buf1        ;start with nothing
  471.     tst    r4        ;is that all there is?
  472.     beq    10$        ;yep
  473.     jsr    r1,iunpk    ;unpack
  474.      .word    secrts        ;don't flush
  475.     bcs    20$        ;error
  476.     clrb    @bufptr        ;zap end
  477. 10$:    mov    #buf1,r5    ;ptr
  478.     mov    #cmdtab,r4    ;pt at table
  479.     call    parskw        ;look up keyword
  480.     bcs    what        ;error
  481.     jmp    ack        ;null, just ACK
  482. 20$:    mov    #toolng,r0    ;pt at msg
  483.     jmp    err        ;punt, return
  484. ;+
  485. ;
  486. ; Echo back the keyword we didn't understand.
  487. ;
  488. ;-
  489. what:    bcc    20$        ;keyword was just missing
  490.     mov    #buf1,r5    ;pt at buf
  491.     mov    r5,r4        ;copy
  492. 10$:    movb    (r3)+,(r4)+    ;copy keyword
  493.     sob    r2,10$
  494.     movb    #'?,(r4)+    ;huh?
  495.     movb    #'?,(r4)+
  496.     movb    #cr,(r4)+    ;eol
  497.     movb    #lf,(r4)+
  498.     sub    r5,r4        ;find length
  499.     call    ldatn        ;make a packet
  500.     call    ldatf        ;get length
  501.     mov    #'E,r0        ;packet type
  502.     call    makpac        ;make packet
  503.     jmp    putpac        ;send it
  504. 20$:    mov    #mkw,r0        ;missing keyword
  505.     jmp    err
  506. ;
  507. cmdtab:    .asciz    <2>/SET/<0>
  508.     .word    set
  509. ;    .asciz    <2>/SHOW/
  510. ;    .word    show
  511.     .word    0
  512. ;+
  513. ;
  514. ; Set stuff.
  515. ;
  516. ;-
  517. set:    mov    #settab,r4    ;pt at table
  518.     call    parskw        ;parse a keyword
  519.     br    what        ;complain
  520. ;
  521. settab:    .asciz    <1>/FILE/
  522.     .word    setfil
  523.     .word    0
  524. ;+
  525. ;
  526. ; Set file.
  527. ;
  528. ;-
  529. setfil:    mov    #stftab,r4    ;pt at table
  530.     call    parskw        ;parse a keyword
  531.     br    what        ;complain
  532. ;
  533. stftab:    .asciz    <1>/TYPE/
  534.     .word    stftyp
  535.     .word    0
  536. ;+
  537. ;
  538. ; Set file type.
  539. ;
  540. ;-
  541. stftyp:    mov    #ftptab,r4    ;pt at table
  542.     call    parskw        ;parse a keyword
  543.     br    what        ;complain
  544. ;
  545. ftptab:    .asciz    <1>/BINARY/
  546.     .word    setbin
  547.     .asciz    <1>/TEXT/
  548.     .word    settxt
  549.     .word    0
  550. ;+
  551. ;
  552. ; Set file type binary.
  553. ;
  554. ;-
  555. setbin:    movb    #377,binfil    ;yep
  556.     jsr    r5,reply    ;reply
  557.     .asciz    /Binary mode set.  All bytes will be transferred./<cr><lf>
  558.     .even
  559. ;+
  560. ;
  561. ; Set file type text.
  562. ;
  563. ;-
  564. settxt:    clrb    binfil        ;yep
  565.     jsr    r5,reply    ;reply
  566.     .asciz    /Text mode set.  Trailing nulls will be stripped./<cr><lf>
  567.     .even
  568. ;+
  569. ;
  570. ; Send a reply.
  571. ;
  572. ; Called through r5 with in-line .asciz string.
  573. ;
  574. ;-
  575. reply:    tst    (sp)+        ;lose old r5
  576.     mov    r5,r4        ;copy
  577. 10$:    tstb    (r4)+        ;count
  578.     bne    10$
  579.     dec    r4        ;back up
  580.     sub    r5,r4        ;find length
  581.     call    ldatn        ;build data field
  582.     call    ldatf        ;set up r4, r5
  583.     jmp    ack1        ;send reply, return
  584. ;+
  585. ;
  586. ; Parse a keyword and dispatch on it.
  587. ;
  588. ; r5    ptr to current posn in .asciz string
  589. ; r4    ptr to dispatch table
  590. ;
  591. ; If the keyword is OK, we flush the return addr and
  592. ; jump to the routine.  Otherwise we return C=1.
  593. ; We return C=0 if there was nothing left on the line.
  594. ;
  595. ;-
  596. parskw:    movb    (r5)+,r0    ;get next char
  597.     beq    100$        ;eol
  598.     cmp    r0,#<' >    ;blank or cc?
  599.     blos    parskw        ;yes, ignore
  600. 10$:    dec    r5        ;back up
  601.     mov    r5,r3        ;copy
  602. 20$:    movb    (r5)+,r0    ;get next char
  603.     beq    30$        ;eol
  604.     cmp    r0,#<' >    ;blank or cc?
  605.     blos    30$        ;yes
  606.     cmp    r0,#'a        ;lower case?
  607.     blo    20$        ;no
  608.     cmp    r0,#'z
  609.     bhi    20$
  610.     bic    #40,r0        ;convert
  611.     movb    r0,-1(r5)
  612.     br    20$
  613. 30$:    dec    r5        ;back up
  614.     mov    r5,r2        ;copy
  615.     sub    r3,r2        ;find length
  616. 40$:    ; search dispatch table for string
  617.     movb    (r4)+,r0    ;get min length to match
  618.     beq    90$        ;end of list
  619.     cmpb    r2,r0        ;long enough to match?
  620.     blo    80$        ;no, skip
  621.     mov    r3,r1        ;copy addr
  622.     mov    r2,r0        ;and len
  623. 50$:    cmpb    (r1)+,(r4)+    ;same?
  624.     bne    70$        ;no
  625.     sob    r0,50$        ;loop
  626. 60$:    tstb    (r4)+        ;skip to end of string
  627.     bne    60$        ;loop
  628.     inc    r4        ;round to even
  629.     bic    #1,r4
  630.     tst    (sp)+        ;toss return addr
  631.     jmp    @(r4)+        ;dispatch
  632. 70$:    dec    r4        ;might have been end of string
  633. 80$:    tstb    (r4)+        ;skip to end
  634.     bne    80$        ;loop
  635.     add    #3,r4        ;+2, round to even
  636.     bic    #1,r4
  637.     br    40$        ;loop
  638. 90$:    sec            ;invalid
  639.     rts    pc
  640. 100$:    clc            ;eol
  641.     rts    pc
  642.     .sbttl    receive a file
  643. ;+
  644. ;
  645. ; Receive a file from the toy computer.
  646. ;
  647. ;-
  648. receiv:    call    iparms        ;init parm negotiation
  649.     call    rparms        ;process theirs
  650.     call    sparms        ;prepare ours
  651.     call    ack1        ;send them
  652.     call    fparms        ;finish up
  653. 10$:    ; start next file
  654.     call    getpac        ;get a packet
  655.     bcc    20$        ;got it
  656. ;;;;; heuristic:
  657. ; if we just ACKed with our parameters, and changed CHKT to
  658. ; something other than '1, see if this packet would seem good
  659. ; if it were a SEND-INIT with CHKT=1.  if so, re-ACK with CHKT=1.
  660. ;;; we'll have to make sure GETPAC actually read a whole
  661. ;;; packet and that the checksum was the only problem.
  662.     call    nak        ;nope
  663.     br    10$        ;loop
  664. 20$:    cmpb    r1,seq        ;current packet?
  665.     bne    30$        ;no, must be previous
  666.     cmp    r0,#'F        ;FILE-HEADER?
  667.     beq    50$        ;yes
  668.     cmp    r0,#'B        ;BREAK?
  669.     bne    40$        ;no, skip
  670.     jmp    ack        ;ACK it and return to loop
  671. 30$:    call    reack        ;re-ACK
  672.     br    10$        ;try again
  673. 40$:    ; protocol violation
  674.     movb    r0,pvlc        ;save char
  675.     mov    #pvl,r0        ;pt at string
  676.     jmp    err        ;error packet
  677. 50$:    ; starting a new file
  678.     mov    #buf1,bufptr    ;set up for unpacking
  679.     mov    #bufsiz-1,bufctr ;allow for ^@ at end
  680.     jsr    r1,iunpk    ;unpack
  681.      .word    secrts        ;don't flush
  682.     clrb    @bufptr        ;mark end
  683.     mov    #buf1,r5    ;pt at filename
  684.     call    file        ;parse filename, get handler
  685.     bcc    60$        ;skip
  686.     mov    #bfs,r0        ;bad filespec
  687.     jmp    err        ;bitch, return
  688. 60$:    ; set up for file output
  689.     mov    #buf2,wca    ;set core addr
  690.     mov    #bufsiz/2,wwc    ;word count
  691.     clr    wblk        ;init blk #
  692.     mov    #buf1,cbuf    ;current buf
  693.     mov    #buf1,bufptr    ;pointer
  694.     mov    #bufsiz,bufctr    ;and free count
  695.     ; return the file name we're using
  696.     mov    #buf2,r4    ;output line buf
  697.     mov    #fbuf,r5
  698.     mov    (r5)+,r1    ;dev:
  699.     call    r50nbl
  700.     movb    #':,(r4)+
  701.     mov    (r5)+,r1    ;filename
  702.     call    r50nbl
  703.     mov    (r5)+,r1
  704.     call    r50nbl
  705.     movb    #'.,(r4)+    ;.
  706.     mov    (r5)+,r1    ;ext
  707.     call    r50nbl
  708.     mov    #buf2,r5    ;pt
  709.     sub    r5,r4        ;find length
  710.     call    ldatn        ;encode
  711.     call    ldatf        ;fix for ACK1
  712.     call    ack1        ;ACK, give filename
  713. 70$:    ; slurp attribute packet(s)
  714.     call    getpac        ;get a packet
  715.     bcs    80$
  716.     cmpb    r1,seq        ;is this curr pkt?
  717.     bne    90$        ;no, must be previous
  718.     cmp    r0,#'A        ;attribute packet?
  719.     bne    100$        ;no
  720.     ; handle attributes
  721.  
  722. ;;;;;;;;;;;
  723.  
  724.     call    ack        ;ACK
  725.     br    70$
  726. 80$:    call    nak        ;NAK it
  727.     br    70$        ;try again
  728. 90$:    call    reack        ;re-ACK previous pkt
  729.     br    70$
  730. 100$:    ; not 'A packet, open file
  731.     mov    r0,-(sp)    ;save
  732.     call    ldev        ;make sure we have the dev handler
  733.     bcs    120$        ;shouldn't happen
  734.     mov    #earea,r0    ;point at it
  735.     .enter            ;open the file
  736.     mov    (sp)+,r0    ;[restore]
  737.     bcs    110$        ;error
  738.     clr    -(sp)        ;initial flags
  739.     mov    #1,-(sp)    ;initial repeat count
  740.     br    150$        ;groovy, go see if it was 'D or 'Z
  741. 110$:    mov    #ucf,r0        ;unable to create file
  742.     br    130$
  743. 120$:    mov    #bdn,r0        ;bad device name
  744. 130$:    jmp    err        ;bitch, return
  745. 140$:    ; read (another) data packet
  746.     call    getpac        ;get a packet
  747.     bcs    160$        ;bad, skip
  748.     cmpb    r1,seq        ;is this curr pkt?
  749.     bne    170$        ;no, must be previous
  750. 150$:    cmp    r0,#'D        ;data?
  751.     beq    180$
  752.     cmp    r0,#'Z        ;eof?
  753.     beq    190$
  754.     mov    r0,r1        ;save
  755.     .purge    #1        ;reset the file
  756.     add    #4,sp        ;flush stack
  757.     cmp    r0,#'E        ;error packet?
  758.     beq    .+6
  759.      jmp    40$        ;no, protocol violation
  760.     rts    pc        ;gracefully punt
  761. 160$:    ; bad checksum or timeout
  762.     call    nak        ;nak it
  763.     br    140$        ;more
  764. 170$:    ; they resent the previous packet
  765.     call    reack        ;re-ACK previous packet
  766.     br    140$        ;more
  767. 180$:    ; data packet
  768.     mov    r4,-(sp)    ;save length & ptr
  769.     mov    r5,-(sp)
  770.     call    ack        ;ACK the packet
  771.     mov    (sp)+,r5    ;restore
  772.     mov    (sp)+,r4
  773.     beq    140$        ;length=0, ignore
  774.     mov    (sp)+,r3    ;restore flags
  775.     mov    (sp)+,r2
  776.     jsr    r1,unpack    ;unpack packet
  777.      .word    wrbuf        ;flush routine
  778.     bcs    220$        ;flush error
  779.     mov    r2,-(sp)    ;save flags
  780.     mov    r3,-(sp)
  781.     br    140$        ;get next packet
  782. 190$:    ; eof, flush buffer and close file
  783.     tst    r4        ;is there a data field in the Z packet?
  784.     beq    .+4
  785.      movb    (r5),r4        ;get 1st char
  786.     mov    r4,-(sp)    ;save
  787.     call    ack        ;ACK the ^Z
  788.     mov    (sp)+,r4    ;restore
  789.     mov    #bufsiz,r0    ;find # bytes in buf
  790.     sub    bufctr,r0
  791.     beq    200$        ;none, skip
  792.     inc    r0        ;round up
  793.     asr    r0        ;/2=wc
  794.     mov    r0,wwc        ;save
  795.     clrb    @bufptr        ;zap odd byte, if any (at least 1 byte free)
  796.     mov    cbuf,wca    ;core addr
  797.     .wait    #1        ;finish previous
  798.     mov    #warea,r0    ;EMT area
  799.     .write            ;write last buffer
  800.     bcs    210$        ;error
  801. 200$:    add    #4,sp        ;purge stack
  802.     cmp    r4,#'D        ;delete the file?
  803.     bne    230$        ;no
  804.     ; Z/D, delete the file (user aborted or something)
  805.     .purge    #1        ;purge the file
  806.     jmp    10$        ;start next
  807. 210$:    ; error writing file
  808.     add    #4,sp        ;flush stack
  809. 220$:    .purge    #1        ;purge the file
  810.     mov    #werr,r0    ;pt at string
  811.     jmp    err        ;send, return
  812. 230$:    ; keep the file
  813.     .close    #1        ;close the file
  814. ;;; now's the time to apply 'A packets and set the date etc.
  815.     jmp    10$        ;start next
  816. ;
  817. wrbuf:    ; flush buffer
  818.     .wait    #1        ;wait for previous transfer
  819.     mov    wca,r0        ;get previous buf addr
  820.     mov    cbuf,wca    ;reset to current
  821.     mov    r0,cbuf        ;prev is now current
  822.     mov    r0,bufptr    ;set ptr
  823.     mov    #bufsiz,bufctr    ;and counter
  824.     mov    #warea,r0    ;queue a write
  825.     .write
  826.     bcs    10$        ;just punt if C=1
  827.     add    #bufsiz/1000,wblk ;update blk #, C=0
  828. 10$:    rts    pc
  829. ;
  830. secrts:    ; dummy flush routine for IUNPK/UNPACK
  831.     sec            ;flush failed
  832.     rts    pc
  833.     .sbttl    send file(s)
  834. ;+
  835. ;
  836. ; Send file(s) to the toy computer.
  837. ;
  838. ;-
  839. send:    tst    r4        ;filespec given?
  840.     beq    20$        ;no
  841.     ; unpack data field
  842.     mov    #buf1,bufptr    ;set up ptr
  843.     mov    #80.,bufctr    ;let's be reasonable
  844.     jsr    r1,iunpk    ;unpack
  845.      .word    secrts        ;don't flush
  846.     bcs    10$        ;error
  847.     ; parse it
  848.     clrb    @bufptr        ;zap end
  849.     mov    #buf1,r5    ;pt at string
  850.     clr    r4        ;no weird defaults
  851.     call    pwild        ;parse wildcard
  852.     bcc    20$        ;skip if OK
  853. 10$:    ; invalid
  854.     mov    #bfs,r0        ;bad file spec
  855.     jmp    err        ;send error packet, return
  856. 20$:    ; set up for dir lookup
  857.     clrb    dirall        ;we aren't showing everything
  858.     clrb    dirnon        ;but give me the filenames
  859. ;;; don't bother with any of this if it's a char device
  860.     call    dirini        ;get psyched
  861.     bcs    60$        ;error opening dev
  862.     ; make sure at least 1 match exists
  863. 30$:    call    dirseg        ;get next segment
  864.     bcs    40$        ;error
  865.     tst    (r5)        ;anything?
  866.     beq    30$        ;no, try next seg
  867.     br    80$        ;OK, skip
  868. 40$:    bne    60$        ;I/O err
  869.     ; file not found
  870.     tstb    wldflg        ;were we in a wildcard search?
  871.     beq    50$        ;no
  872.     mov    #nomtch,r0    ;no matches found
  873.     br    70$
  874. 50$:    mov    #fnf,r0        ;file not found
  875.     br    70$
  876. 60$:    ; I/O error
  877.     mov    #ioerr,r0
  878. 70$:    jmp    err        ;later
  879. 80$:    ; do the SEND-INIT thing
  880.     mov    r5,-(sp)    ;save file ptr
  881.     call    iparms        ;init parms
  882.     call    sparms        ;prepare ours
  883.     mov    #'S,r0        ;SEND-INIT
  884.     call    makpac        ;make a packet
  885.     call    sndack        ;send it, get ACK
  886.     bcs    130$        ;punt
  887.     call    rparms        ;get their parms
  888.     call    fparms        ;finish up
  889.     mov    (sp)+,r5    ;recover r5
  890.     br    100$        ;go send first file
  891. 90$:    ; handle next dir segment
  892.     call    dirseg        ;get next
  893.     bcc    100$        ;OK
  894.     bne    60$        ;I/O error
  895.     mov    #'B,r0        ;break transmission
  896.     jmp    sndsmp        ;tell them, return (ignore err)
  897. 100$:    ; handle next file
  898.     mov    #fbuf+2,r3    ;.LOOKUP buf
  899.     mov    #buf2,r4    ;output line buf
  900.     mov    (r5)+,r1    ;convert first word
  901.     beq    90$        ;end of seg, get next
  902.     mov    r1,(r3)+    ;save in fbuf
  903.     call    r50nbl
  904.     mov    (r5)+,r1    ;2nd word
  905.     mov    r1,(r3)+
  906.     call    r50nbl
  907.     movb    #'.,(r4)+    ;point
  908.     mov    (r5)+,r1    ;extension
  909.     mov    r1,(r3)
  910.     call    r50nbl
  911.     mov    r5,-(sp)    ;save r5
  912.     mov    #buf2,r5    ;pt
  913.     sub    r5,r4        ;find length
  914.     ; open the file
  915.     mov    #larea,r0    ;pt at area
  916. ;;; mov #wlddev,2(r0) ;;;;;;; open the whole device
  917.     .lookup            ;try to open file for input
  918.     bcs    120$        ;guess not
  919.     ; OK, send FILE-HEADER packet
  920.     call    ldatn        ;go
  921.     call    ldatf        ;fix
  922.     mov    #'F,r0        ;FILE-HEADER
  923.     call    makpac        ;make packet
  924.     call    sndack        ;send it
  925.     bcs    130$        ;punt
  926.     ; should we send file attributes?
  927. ;; br 110$ ;;; no attributes when sending whole device
  928. ;;; is it a char dev?
  929. ;;;    b<yes>    110$        ;don't send attr pack
  930.     bitb    #attr,capas    ;sending attribute packets?
  931.     bne    140$        ;yes
  932. 110$:    add    #4,(sp)        ;no, skip size and date
  933.     br    160$        ;go send file
  934. 120$:    ; .LOOKUP error
  935.     mov    #uof,r0        ;unable to open file
  936.     tst    (sp)+        ;flush r5
  937.     jmp    err        ;later
  938. 130$:    ; retry limit reached, punt quietly
  939.     tst    (sp)+        ;lose dir tab ptr
  940.     rts    pc        ;timed out
  941. 140$:    ; send ATTRIBUTE packet
  942.     mov    (sp),r5        ;get ptr
  943.     ; size in K
  944.     mov    #txbuf+3,r4    ;init ptr, skip size
  945.     movb    #'!,(r4)+    ;length
  946.     inc    r4        ;skip length of length
  947.     mov    (r5)+,r1    ;get file size
  948.     add    #1,r1        ;round up, C=0 (or 1 if 200000)
  949.     ror    r1        ;(blks+1)/2 = K bytes
  950.     call    decv        ;convert (r4=txbuf+3+2)
  951.     mov    r4,r0        ;copy
  952.     sub    #txbuf+3+2-40,r0 ;find char(width of field)
  953.     movb    r0,txbuf+3+1    ;poke it back
  954.     ; date of creation
  955.     mov    (r5)+,r3    ;get date
  956.     beq    150$        ;no date, don't send any
  957.     movb    #'#,(r4)+    ;date [& time - RT doesn't save times]
  958.     movb    #8.+40,(r4)+    ;length=8.
  959.     mov    r3,r1        ;copy date
  960.     bic    #^C37,r1    ;isolate year
  961.     mov    r3,r0        ;copy again (include RT V5 32s bit)
  962.     ash    #-10.,r0    ;shift b15 to b5
  963.     bic    #^C40,r0    ;isolate
  964.     bis    r0,r1        ;OR it in
  965.     add    #1972.,r1    ;origin is 1972
  966.     call    decv        ;convert it (will always be 4 digits)
  967.     mov    r3,r1        ;copy date again
  968.     ash    #-10.,r1    ;right 10.
  969.     bic    #^C17,r1    ;isolate month
  970.     call    dec2        ;convert
  971.     mov    r3,r1        ;copy yet again
  972.     ash    #-5,r1        ;right 5
  973.     bic    #^C37,r1    ;isolate day
  974.     call    dec2        ;convert
  975. 150$:    ; machine/OS
  976.     movb    #'.,(r4)+    ;machine/OS
  977.     movb    #2+40,(r4)+    ;length=2
  978.     movb    #'D,(r4)+    ;DEC
  979. .iif ne rt11$$,    movb #'B,(r4)+    ;PDP-11/RT-11
  980.     ; send it
  981.     mov    r5,(sp)        ;update
  982.     mov    #txbuf+3,r5    ;pt at begn
  983.     sub    r5,r4        ;length
  984.     mov    #'A,r0        ;type
  985.     call    makpac        ;build the packet
  986.     call    sndack        ;send it
  987.     bcs    130$        ;punt
  988.     ; skip this file if they refused it
  989.     tst    r4        ;OK?
  990.     beq    160$        ;yep
  991.     cmpb    (r5),#'Y    ;OK?
  992.     bne    260$        ;no, do next file
  993. 160$:    ; read initial bufferload
  994.     clr    rblk        ;start at begn
  995.     mov    #bufsiz/2,rwc    ;initial wc
  996.     mov    #buf1,rca    ;initial buf
  997.     mov    #buf2,cbuf    ;next buf
  998.     mov    #rarea,r0    ;read begn of file
  999.     .read            ;do it
  1000.     bcc    170$        ;skip if OK
  1001.     tst    r0        ;err=read from EOF?
  1002.     beq    250$        ;yes, null file, send ^Z
  1003. ;;; br 230$ ;;;;;; don't care if whole dev
  1004.     br    230$        ;no, I/O error
  1005. 170$:    mov    r0,rlen        ;so we know what to expect
  1006.     mov    #txbuf+3,r1    ;for LDAT
  1007.     movb    maxl,r2
  1008. 180$:    ; swap buffers
  1009.     mov    rlen,r4        ;get # words expected
  1010.     beq    240$        ;eof, skip
  1011.     asl    r4        ;# bytes
  1012.     .wait    #1        ;wait for next buffer to fill
  1013.     mov    rca,r5        ;pt at this buf
  1014.     mov    cbuf,rca    ;old curr buf will be next buf
  1015.     mov    r5,cbuf        ;next buf is now curr buf
  1016.     add    #bufsiz/1000,rblk ;update blk #
  1017.     mov    #rarea,r0    ;start next buffer reading
  1018.     .read            ;do it
  1019.     bcc    190$        ;OK
  1020.     tst    r0        ;rd from eof?
  1021. ;;;;; sending whole dev, don't care
  1022. ;; clr r0 ;;;;;;
  1023.     bne    230$        ;no, I/O error
  1024. ;;;;
  1025. 190$:    mov    r0,rlen        ;# words expected
  1026.     tstb    binfil        ;binary file?
  1027.     bne    210$        ;yes
  1028.     ; scan off trailing nulls
  1029.     mov    r4,r3        ;copy length
  1030.     add    r5,r3        ;pt past end of blk
  1031. 200$:    tstb    -(r3)        ;back 1
  1032.     bne    210$        ;skip
  1033.     sob    r4,200$        ;loop
  1034.     br    180$        ;all nulls, loop
  1035. 210$:    ; send next buffer
  1036.     call    ldat        ;convert
  1037.     bcc    180$        ;it fit, loop
  1038.     mov    r4,-(sp)    ;save input ptr
  1039.     mov    r5,-(sp)
  1040.     call    ldatf        ;get addr, len
  1041.     mov    #'D,r0        ;DATA packet
  1042.     call    makpac        ;build it
  1043.     call    sndack        ;send it, get ACK (C set)
  1044.     mov    (sp)+,r5    ;[restore]
  1045.     mov    (sp)+,r4
  1046.     mov    #txbuf+3,r1    ;[init for next packet]
  1047.     movb    maxl,r2
  1048.     bcc    210$        ;(C set by SNDACK) around for more
  1049. 220$:    ; too many retries
  1050.     .close    #1        ;close file
  1051.     tst    (sp)+        ;lose r5
  1052.     rts    pc
  1053. 230$:    ; read error
  1054.     .close    #1        ;close
  1055.     tst    (sp)+        ;lose r5
  1056.     mov    #rerr,r0    ;err msg
  1057.     jmp    err
  1058. 240$:    ; end of file, flush last packet
  1059.     call    ldatf        ;get addr, len
  1060.     tst    r4        ;anything?
  1061.     beq    250$        ;no
  1062.     mov    #'D,r0        ;DATA packet
  1063.     call    makpac        ;build it
  1064.     call    sndack        ;send it, get ACK
  1065.     bcs    220$        ;oh well nice try
  1066. 250$:    ; send END-OF-FILE
  1067.     mov    #'Z,r0        ;send END-OF-FILE
  1068.     call    sndsmp
  1069.     bcs    220$        ;oh sure, NOW you wuss out
  1070. 260$:    .close    #1        ;close the file
  1071.     mov    (sp)+,r5    ;restore ptr
  1072.     jmp    100$        ;handle next file
  1073.     .sbttl    file-related routines
  1074. ;+
  1075. ;
  1076. ; Partially parse a wildcard and prepare for wildcard search.
  1077. ;
  1078. ; R5    ptr to .asciz string.
  1079. ; R4    NZ => default filename/ext to * if missing,
  1080. ;    Z => each is blank if missing,
  1081. ;    *but* if the filename.ext is blank (except possibly
  1082. ;    for a device) then we write nothing either way.
  1083. ;
  1084. ; Return WLDDEV and WILD set up, device loaded (name at FBUF).
  1085. ; C=1    wildcard contained invalid characters or bad format
  1086. ;    (two extensions, wildcard in device name, whatever)
  1087. ;
  1088. ; WLDFLG (byte) is set to non-zero (actually the # of wildcard chars)
  1089. ; if the filespec actually is a wildcard.  If WLDFLG=0, then it's
  1090. ; just a filename, parse it with FILE.
  1091. ;
  1092. ;-
  1093. pwild:    clr    wlddev        ;no device yet
  1094. 10$:    mov    #wild,r1    ;point at buf
  1095.     clr    r2        ;no .'s yet
  1096.     clr    r3        ;no wildcard chars either
  1097. 20$:    ; get next char
  1098.     movb    (r5)+,r0    ;get a char
  1099.     beq    110$        ;end, skip
  1100.     cmp    r0,#<' >    ;blank?
  1101.     beq    20$        ;ignore
  1102.     cmp    r0,#':        ;device name?
  1103.     beq    90$        ;yes
  1104.     cmp    r0,#'?        ;RSTS-style wildcard?
  1105.     beq    70$        ;change to %
  1106.     cmp    r0,#'a        ;lower case?
  1107.     blo    30$        ;no
  1108.     cmp    r0,#'z        ;hm?
  1109.     bhi    30$        ;no
  1110.     bic    #40,r0        ;yes, convert
  1111.     br    40$        ;we know char is OK
  1112. 30$:    ; make sure char is OK
  1113.     cmp    r0,#<' >    ;blank?
  1114.     beq    20$        ;yes, ignore
  1115.     cmp    r0,#'.        ;. is OK, once
  1116.     beq    50$
  1117.     cmp    r0,#'%        ;wildcards are OK
  1118.     beq    80$
  1119.     cmp    r0,#'*
  1120.     beq    80$
  1121.     cmp    r0,#'0        ;digits are OK
  1122.     blo    100$
  1123.     cmp    r0,#'9
  1124.     blos    40$
  1125.     cmp    r0,#'A        ;letters are OK
  1126.     blo    100$
  1127.     cmp    r0,#'Z
  1128.     bhi    100$
  1129. 40$:    movb    r0,(r1)+    ;save
  1130.     br    20$        ;loop
  1131. 50$:    ; .
  1132.     tst    r2        ;is this the first .?
  1133.     bne    100$        ;no
  1134.     tst    r4        ;should we use default filename?
  1135.     beq    60$        ;no
  1136.     cmp    r1,#wild    ;is there any need?
  1137.     bne    60$        ;no
  1138.     movb    #'*,(r1)+    ;yes, save it
  1139. 60$:    inc    r2        ;set "." flag
  1140.     br    40$
  1141. 70$:    ; ? as wildcard (= %)
  1142.     movb    #'%,r0        ;replace ? with %
  1143. 80$:    inc    r3        ;wildcard
  1144.     br    40$        ;loop
  1145. 90$:    ; device name
  1146.     tst    wlddev        ;do we have one already?
  1147.     bne    100$        ;yes, error
  1148.     clrb    (r1)        ;mark end
  1149.     mov    r5,-(sp)    ;save ptr
  1150.     mov    #wild,r5    ;pt at dev name
  1151.     call    rad50        ;parse it
  1152.     mov    (sp)+,r5    ;restore
  1153.     tst    r0        ;stopped on nul?
  1154.     bne    100$        ;no, bad filename
  1155.     mov    r1,wlddev    ;save
  1156.     bne    10$        ;there was something
  1157.     mov    defdev,wlddev    ;set default anyway, don't allow ":DEV:"
  1158.     br    10$        ;get filename
  1159. 100$:    sec            ;bad filename
  1160.     rts    pc
  1161. 110$:    ; end of filespec
  1162.     tst    wlddev        ;did we ever get a device?
  1163.     bne    120$        ;yes
  1164.      mov    defdev,wlddev    ;no, use default
  1165. 120$:    ; make sure handler is loaded
  1166.     mov    wlddev,fbuf    ;copy
  1167.     call    ldev        ;load it
  1168.     bcs    140$        ;punt on err
  1169.     ; add ".*" to name if we're using default wildcards
  1170.     tst    r4        ;should we add ".*" if no ext?
  1171.     beq    130$        ;no
  1172.     tst    r2        ;was there an ext?
  1173.     bne    130$        ;yes
  1174.     cmp    r1,#wild    ;totally null name?
  1175.     beq    130$        ;yes, leave it alone
  1176.     movb    #'.,(r1)+    ;.*
  1177.     movb    #'*,(r1)+
  1178. 130$:    movb    r3,wldflg    ;remember whether it's a wildcard
  1179.     clrb    (r1)        ;C=0, mark end
  1180. 140$:    rts    pc
  1181. ;+
  1182. ;
  1183. ; Init for directory search.
  1184. ;
  1185. ; C=1 on directory open error.
  1186. ;
  1187. ;-
  1188. dirini:    clr    free        ;no free blks yet
  1189.     clr    used        ;no used blks either
  1190.     clr    files        ;and no files
  1191.     ; open disk non-file-structured to get dir
  1192.     mov    #ludir,r0    ;open the device
  1193.     .lookup            ;(non-file-structured)
  1194.     ; The directory should start at block 6, but SSM says that in case
  1195.     ; it's different the correct starting block no. should be read from
  1196.     ; the word at offset 724 in the home block (block 1).
  1197.     ; But, if the volume was initialized under RSTS/E by the FIT utility
  1198.     ; (like my SY:), this field is set to ASCII blanks.
  1199.     ; So, I'll hard code to block 6.  Sorry.
  1200.     ; DIR.SAV 4.0 can read my SY: so it seems that it doesn't worry about
  1201.     ; home+724 either.
  1202.     mov    #1,segnxt    ;next seg will be #1
  1203.     rts    pc
  1204. ;+
  1205. ;
  1206. ; Process next segment of directory.
  1207. ;
  1208. ; On return:
  1209. ; C=0    OK, MATLST contains 0-terminated list of files
  1210. ; C=1    Z=1    no more dir segments (dir has been closed)
  1211. ; C=1    Z=0    dir read error
  1212. ;
  1213. ; r5 pts to all the matches we found in this segment.
  1214. ; There are up to 72. entries (the max possible # of file entries in a
  1215. ; segment) of the following format:
  1216. ; .rad50 /filnamext/
  1217. ; .word size, date
  1218. ;
  1219. ; If DIRALL (byte) .ne.0, all files are copied (no wildcard comparison is
  1220. ; performed), and empty blocks are copied as
  1221. ; ".EMPTY." with no date.
  1222. ;
  1223. ; If DIRNON (byte) .ne.0, no files are copied.  This is used to compute disk
  1224. ; usage without bothering to copy all the filenames all over the place.
  1225. ;
  1226. ;-
  1227. dirseg:    mov    segnxt,r0    ;get segment to read
  1228.     beq    110$        ;none, skip
  1229.     call    getseg        ;get it
  1230.     bcs    100$
  1231.     mov    #matlst,-(sp)    ;pt at match list
  1232. 10$:    ; process next directory entry
  1233.     mov    (r5)+,r0    ;get status word
  1234.     bit    #4000,r0    ;end of segment?
  1235.     bne    90$
  1236.     bit    #1000,r0    ;empty block?
  1237.     bne    80$
  1238.     bit    #2000,r0    ;permanent?
  1239.     beq    60$        ;no
  1240.     tstb    dirnon        ;showing nothing?
  1241.     bne    50$
  1242.     tstb    dirall        ;showing everything?
  1243.     bne    20$
  1244.     ; check this entry for wildcard match
  1245.     mov    r5,-(sp)    ;save
  1246.     mov    #buf2,r4    ;pt at buf
  1247.     mov    (r5)+,r1    ;convert filename
  1248.     call    r50nbl
  1249.     mov    (r5)+,r1
  1250.     call    r50nbl
  1251.     movb    #'.,(r4)+    ;.
  1252.     mov    (r5),r1        ;extension
  1253.     call    r50nbl
  1254.     clrb    (r4)
  1255.     mov    #wild,r5    ;pt at pattern
  1256.     mov    #buf2,r4    ;test string
  1257.     call    match        ;match?
  1258.     mov    (sp)+,r5    ;[restore]
  1259.     bcs    70$
  1260. 20$:    ; match, save this entry
  1261.     add    6(r5),used    ;count as used
  1262.     inc    files        ;bump count
  1263. 30$:    mov    (sp)+,r4    ;get ptr back
  1264.     mov    (r5)+,(r4)+    ;copy filename
  1265.     mov    (r5)+,(r4)+
  1266.     mov    (r5)+,(r4)+    ;extension
  1267.     mov    (r5)+,(r4)+    ;length
  1268.     tst    (r5)+        ;skip tentative file info
  1269.     mov    (r5)+,(r4)+    ;get date
  1270.     mov    r4,-(sp)    ;save
  1271. 40$:    add    extbyt,r5    ;skip extra bytes, if any
  1272.     br    10$        ;loop
  1273. 50$:    add    6(r5),used    ;count the file's blocks
  1274.     inc    files        ;count it
  1275.     br    70$        ;skip
  1276. 60$:    add    6(r5),free    ;count tentative files as free
  1277. 70$:    ; skip this entry
  1278.     add    #14,r5        ;skip
  1279.     br    40$
  1280. 80$:    ; < UNUSED > block
  1281.     add    6(r5),free    ;update # free blks
  1282.     tstb    dirall        ;showing everything?
  1283.     beq    70$        ;no, skip this
  1284.     mov    r5,r0        ;copy
  1285.     mov    #<^R.EM>,(r0)+    ;.EMPTY.
  1286.     mov    #<^RPTY>,(r0)+
  1287.     clr    (r0)
  1288.     clr    6(r0)        ;zap date
  1289.     br    30$        ;go display
  1290. 90$:    ; end of segment
  1291.     mov    #matlst,r5    ;pt at match list
  1292.     mov    (sp)+,r4    ;restore ptr
  1293.     clr    (r4)        ;mark end, C=0
  1294.     rts    pc
  1295. 100$:    ; I/O error
  1296.     .close    #0        ;close the dir
  1297.     clz            ;Z=0
  1298.     sec            ;C=1
  1299.     rts    pc
  1300. 110$:    ; end of dir
  1301.     .close    #0        ;close the dir
  1302.     +sec!sez        ;C=1, Z=1 (no more segs)
  1303.     rts    pc
  1304. ;+
  1305. ;
  1306. ; Get dir segment in r0.
  1307. ;
  1308. ;-
  1309. getseg:    asl    r0        ;*2
  1310.     add    #4,r0        ;blks 6,7 are seg 1
  1311.     mov    r0,dirblk    ;copy ptr
  1312.     mov    #rddir,r0    ;get (next) segment
  1313.     .readw            ;read
  1314.     bcs    10$        ;bugged
  1315.     mov    buf1+6,extbyt    ;no. of extra bytes (FIT uses for RSTS RTSNAM)
  1316.     clr    free        ;no frees yet (C=0)
  1317.     mov    buf1+2,segnxt    ;save link to next
  1318.     mov    #buf1+12,r5    ;pt at begn of seg
  1319. 10$:    rts    pc
  1320. ;+
  1321. ;
  1322. ; Check for a wildcard match.
  1323. ;
  1324. ; % matches exactly one character.
  1325. ; * matches 0 or more characters.
  1326. ;
  1327. ; Wildcards may not span the ".".
  1328. ;
  1329. ; r5    .asciz /wildcard/
  1330. ; r4    .asciz /name to check/
  1331. ;
  1332. ; C=0 if they matched, C=1 if not.
  1333. ;
  1334. ;-
  1335. match:    movb    (r5)+,r0    ;get a char
  1336.     beq    20$        ;end of name
  1337.     cmp    r0,#'%        ;match one char?
  1338.     beq    30$        ;yes
  1339.     cmp    r0,#'*        ;match 0 or more chars?
  1340.     beq    40$        ;yes
  1341.     cmpb    r0,(r4)+    ;same?
  1342.     beq    match        ;yes
  1343. 10$:    sec            ;no
  1344.     rts    pc
  1345. 20$:    tstb    (r4)        ;did both end at once?  (C=0)
  1346.     bne    10$        ;no
  1347.     rts    pc
  1348. 30$:    ; % match one character
  1349.     movb    (r4)+,r0    ;get it
  1350.     beq    10$        ;end
  1351.     cmp    r0,#'.        ;don't skip to extension
  1352.     bne    match
  1353.     br    10$
  1354. 40$:    ; * match 0 or more characters
  1355.     mov    r5,-(sp)    ;save
  1356.     mov    r4,-(sp)
  1357.     call    match        ;recurse
  1358.     bcc    50$        ;got it
  1359.     mov    (sp)+,r4    ;restore
  1360.     mov    (sp)+,r5
  1361.     movb    (r4)+,r0    ;skip a char
  1362.     beq    10$        ;lose
  1363.     cmp    r0,#'.        ;extension separator?
  1364.     beq    10$        ;yep, don't skip that
  1365.     br    40$        ;recurse
  1366. 50$:    add    #4,sp        ;flush stack (C=0)
  1367.     rts    pc
  1368. ;+
  1369. ;
  1370. ; Convert a radix-50 word to a 0- to 3-character ASCII string.
  1371. ; Stop at first blank (all chars to right should be blank too).
  1372. ;
  1373. ; r1    word
  1374. ; r4    buffer ptr
  1375. ;
  1376. ;-
  1377. r50nbl:    clr    r0        ;0-extend
  1378.     div    #50,r0        ;divide
  1379.     mov    r1,r2        ;save remainder
  1380.     mov    r0,r1        ;copy
  1381.     clr    r0        ;0-extend
  1382.     div    #50,r0        ;divide
  1383.     movb    r50tnb(r0),(r4)+ ;first char
  1384.     beq    10$        ;whoops
  1385.     movb    r50tnb(r1),(r4)+ ;second
  1386.     beq    10$
  1387.     movb    r50tnb(r2),(r4)+ ;third
  1388.     beq    10$
  1389.     rts    pc
  1390. 10$:    dec    r4        ;back up
  1391.     rts    pc
  1392. ;+
  1393. ;
  1394. ; Parse a filename, save in FBUF.
  1395. ;
  1396. ; On entry:
  1397. ; r5    source pointer
  1398. ;
  1399. ; C=1 if filename is bad.
  1400. ;
  1401. ;-
  1402. file:    mov    #fbuf,r4    ;point at filename area
  1403.     mov    defdev,(r4)+    ;set default device
  1404.     clr    (r4)+        ;zap file & ext
  1405.     clr    (r4)+
  1406.     clr    (r4)
  1407.     sub    #4,r4        ;back up to filename
  1408.     ; file or device name first
  1409.     call    rad50        ;get it
  1410.     cmp    r0,#':        ;device?
  1411.     bne    10$        ;no
  1412.     mov    r1,-2(r4)    ;set it
  1413.     call    rad50        ;get filename
  1414. 10$:    mov    r1,(r4)+    ;it must be the filename
  1415.     mov    r2,(r4)+
  1416.     cmp    r0,#'.        ;extension given?
  1417.     bne    20$        ;no
  1418.     call    rad50        ;yes, eat it
  1419.     mov    r1,(r4)        ;save it
  1420. 20$:    ; r0 should be blank, tab or null here
  1421.     cmp    r0,#<' >    ;blank or ctrl char?
  1422.     bhi    30$        ;no, bugged
  1423.     clc            ;OK
  1424.     rts    pc
  1425. 30$:    sec            ;error return
  1426.     rts    pc
  1427. ;+
  1428. ;
  1429. ; Parse a radix-50 string.
  1430. ;
  1431. ; r5    source pointer
  1432. ;
  1433. ; On return:
  1434. ; r0    char we stopped on
  1435. ; r1    1st 3 chars of string
  1436. ; r2    2nd 3 chars of string
  1437. ; r5    points to char in r0 +1
  1438. ;
  1439. ;-
  1440. rad50:    clr    r1        ;init buf
  1441.     clr    r2
  1442.     call    chr50        ;get a char
  1443.     bcs    20$        ;yow
  1444.     asl    r0        ;lookup 1st char
  1445.     mov    rad50a(r0),r1    ;get it
  1446.     call    chr50        ;get 2nd
  1447.     bcs    20$        ;end of string
  1448.     asl    r0        ;lookup 2nd
  1449.     add    rad50b(r0),r1
  1450.     call    chr50        ;3rd
  1451.     bcs    20$
  1452.     add    r0,r1
  1453.     call    chr50        ;4th
  1454.     bcs    20$
  1455.     asl    r0
  1456.     mov    rad50a(r0),r2
  1457.     call    chr50        ;5th
  1458.     bcs    20$
  1459.     asl    r0
  1460.     add    rad50b(r0),r2
  1461.     call    chr50        ;6th
  1462.     bcs    20$
  1463.     add    r0,r2
  1464. 10$:    call    chr50        ;skip anything left
  1465.     bcc    10$
  1466. 20$:    rts    pc
  1467. ;+
  1468. ;
  1469. ; Get a char and cvt to radix 50 in r0.
  1470. ;
  1471. ; C=1 if we failed, char in r0.
  1472. ;
  1473. ;-
  1474. chr50:    movb    (r5)+,r0    ;get it
  1475.     cmp    r0,#<' >    ;blank?
  1476.     beq    chr50        ;yes, ignore
  1477.     cmp    r0,#'0        ;digit?
  1478.     blo    10$
  1479.     cmp    r0,#'9
  1480.     blos    20$
  1481.     cmp    r0,#'A        ;u.c. letter?
  1482.     blo    10$
  1483.     cmp    r0,#'Z
  1484.     blos    30$
  1485.     cmp    r0,#'a        ;l.c. letter?
  1486.     blo    10$
  1487.     cmp    r0,#'z
  1488.     blos    40$
  1489. 10$:    sec            ;error return
  1490.     rts    pc
  1491. 20$:    ; digit
  1492.     sub    #'0-<^R  0>,r0    ;convert (C=0)
  1493.     rts    pc
  1494. 30$:    ; upper case letter
  1495.     sub    #'A-<^R  A>,r0    ;convert (C=0)
  1496.     rts    pc
  1497. 40$:    ; lower case letter
  1498.     sub    #'a-<^R  A>,r0    ;convert (C=0)
  1499.     rts    pc
  1500. ;+
  1501. ;
  1502. ; Make sure the device at FBUF is loaded.
  1503. ;
  1504. ; C=1 if invalid dev.
  1505. ;
  1506. ;-
  1507. ldev:    .dstat    #dstat,#fbuf    ;see if handler is loaded
  1508.     bcs    20$        ;invalid
  1509.     tst    dstat+4        ;is it loaded?
  1510.     bne    20$        ;yes (C=0 from TST)
  1511.     ; device is non-resident, load it in
  1512.     tst    device        ;is there a device already?
  1513.     beq    10$        ;no
  1514.     .releas    #device        ;yes, release it
  1515. 10$:    .fetch    #devhnd,#fbuf    ;no, load it (set C)
  1516.     mov    fbuf,device    ;save device name
  1517. 20$:    rts    pc
  1518. ;
  1519.     .sbttl    packet-level routines
  1520.     .rem    $
  1521.  
  1522. Packet format:
  1523.  
  1524. +-----------------------------------+
  1525. | soh | len | seq | typ | dat | chk |
  1526. +-----------------------------------+
  1527.  
  1528. soh = start-of-header character
  1529. len = <length of seq through chk inclusive> +40
  1530. seq = <sequence number mod 100> +40
  1531. typ = type (ascii char)
  1532. dat = data field (variable length, may be null)
  1533. chk = 1, 2, or 3 byte checksum or CRC of len through dat inclusive
  1534. $
  1535. ;+
  1536. ;
  1537. ; Init SEND-INIT parms for negotiation.
  1538. ;
  1539. ;-
  1540. iparms:
  1541. .if ne binlin
  1542.     movb    #'Y,mqbin    ;QBIN is OK with me but not needed
  1543. .iff
  1544.     movb    #'&,mqbin    ;QBIN not OK
  1545. .endc
  1546.     clrb    chkt        ;CHKT not decided yet
  1547.     clrb    mchkt        ;I haven't voted either
  1548.     clrb    rept        ;no REPT char yet
  1549.     movb    #'~,mrept    ;I'd like to
  1550.     rts    pc
  1551. ;+
  1552. ;
  1553. ; Finish SEND-INIT parms processing.
  1554. ;
  1555. ;-
  1556. fparms:    ; make the CHKT change actually happen
  1557.     movb    chkt,r0        ;get check type
  1558.     mov    r0,lchk        ;save length
  1559.     asl    r0        ;*2
  1560.     mov    checks-2(r0),checka ;look up routine to do checks
  1561.     ; fix MAXL to be max data field size
  1562.     movb    maxl,r0        ;get MAXL
  1563.     sub    #2,r0        ;don't count seq or typ
  1564.     sub    lchk,r0        ;or checksum
  1565.     movb    r0,maxl        ;save
  1566.     rts    pc
  1567. ;+
  1568. ;
  1569. ; Prepare our SEND-INIT parms.
  1570. ;
  1571. ; Returns with:
  1572. ; r5    data field
  1573. ; r4    length
  1574. ;
  1575. ;-
  1576. sparms:    tstb    mchkt        ;have they specified MCHKT?
  1577.     bne    10$        ;yes
  1578.      movb    #'1,mchkt    ;no, my default is 1
  1579. 10$:    mov    #mparms,r5    ;ptr
  1580.     mov    #nmprms,r4    ;length
  1581.     rts    pc
  1582. ;+
  1583. ;
  1584. ; Process SEND-INIT parms received from them.
  1585. ;
  1586. ; On entry:
  1587. ; r5    data field (with space for padding)
  1588. ; r4    length
  1589. ;
  1590. ;-
  1591. rparms:    ; pad with blanks so we'll use defaults as appropriate
  1592.     mov    #' ,r1        ;handy constant
  1593.     mov    #nparms,r3    ;expected max length
  1594.     sub    r4,r3        ;find # missing parms
  1595.     blos    20$        ;they must be a later version
  1596.     add    r5,r4        ;pt at end
  1597. 10$:    movb    r1,(r4)+    ;pad
  1598.     sob    r3,10$
  1599. 20$:    ; read the parms
  1600.     mov    #maxl,r4    ;point at param table
  1601.     ; MAXL=80.
  1602.     movb    (r5)+,r0    ;get MAXL
  1603.     sub    r1,r0        ;unchar()
  1604.     bne    .+6        ;specified
  1605.      mov    #80.,r0        ;default
  1606.     movb    r0,(r4)+
  1607.     ; TIME=5
  1608.     movb    (r5)+,r0    ;get TIME
  1609.     sub    r1,r0        ;unchar()
  1610.     bne    .+6        ;given
  1611.      mov    #5,r0        ;def
  1612.     movb    r0,(r4)+
  1613.     ; NPAD=0
  1614.     movb    (r5)+,r0    ;get NPAD
  1615.     sub    r1,r0        ;unchar()
  1616.     movb    r0,(r4)+
  1617.     ; PADC=^@
  1618.     movb    (r5)+,r0    ;get char
  1619.     asl    r1        ;*2=100
  1620.     xor    r1,r0        ;ctl()
  1621.     movb    r0,(r4)+
  1622.     ; EOL=cr
  1623.     movb    (r5)+,r0    ;get char
  1624.     asr    r1        ;/2=40 again
  1625.     sub    r1,r0        ;unchar()
  1626.     bne    .+6        ;given
  1627.      mov    #cr,r0        ;default
  1628.     movb    r0,(r4)+
  1629.     ; QCTL=#
  1630.     movb    (r5)+,r0    ;get char
  1631.     cmp    r0,r1        ;given?  (blank?)
  1632.     bne    .+6        ;no
  1633.      movb    #'#,r0        ;default
  1634.     movb    r0,(r4)+
  1635.     ; QBIN=N
  1636.     movb    (r5)+,r0    ;get char
  1637. .if ne binlin
  1638.     movb    #'N,mqbin    ;assume they don't want to QBIN
  1639. .endc
  1640.     cmp    r0,r1        ;defaulted?
  1641.     beq    30$
  1642.     cmp    r0,#'Y        ;up to us?
  1643.     beq    30$
  1644.     cmp    r0,#'N        ;they don't want to?
  1645.     beq    30$        ;(we're screwed if BINLIN=0)
  1646.     movb    r0,mqbin    ;they want to, remember what
  1647.     br    40$        ;skip
  1648. 30$:    ; our decision, tell them what we've already assumed
  1649. .if ne binlin
  1650.     clr    r0        ;zap QBIN
  1651. .iff
  1652.     mov    #'&,r0        ;we want to use &
  1653. .endc
  1654. 40$:    movb    r0,(r4)+
  1655.     ; CHKT=1 or what they say if they went first
  1656.     movb    (r5)+,r0    ;get it
  1657.     cmp    r0,r1        ;default (=1)?
  1658.     beq    50$        ;yes
  1659.     sub    #'1,r0        ;find value (0,1,2)
  1660.     cmp    r0,#2        ;valid?
  1661.     blos    60$        ;yes
  1662. 50$:    clr    r0        ;no
  1663. 60$:    inc    r0        ;+1 (1,2,3)
  1664.     movb    mchkt,r2    ;have we already voted?
  1665.     bne    70$        ;yes
  1666.     ; they're going first, so their vote wins
  1667.     movb    r0,(r4)+    ;save
  1668.     add    #'0,r0        ;convert back
  1669.     movb    r0,mchkt    ;we'll agree
  1670.     br    90$
  1671. 70$:    ; we already decided, if they agree that's it, otherwise 1
  1672.     sub    #'0,r2        ;convert
  1673.     cmp    r0,r2        ;do they agree?
  1674.     beq    80$        ;yes
  1675.     movb    #'1,mchkt    ;no, we'll use 1
  1676.     mov    #1,r0
  1677. 80$:    movb    r0,(r4)+
  1678. 90$:    ; REPT=none
  1679.     movb    (r5)+,r0    ;get their char
  1680.     movb    r0,mrept    ;I'll agree if I haven't already
  1681.     cmp    r0,r1        ;will we do it?
  1682.     bne    .+4        ;yes
  1683.      clr    r0        ;no
  1684.     movb    r0,(r4)+
  1685.     ; CAPAS=none
  1686.     movb    (r5)+,r0    ;get theirs
  1687.     sub    r1,r0        ;UNCHAR()
  1688.     movb    r0,(r4)+    ;save bits
  1689.     rts    pc
  1690. ;+
  1691. ;
  1692. ; Send error packet.
  1693. ;
  1694. ; r0    ptr to .asciz msg
  1695. ;
  1696. ;-
  1697. err:    incb    seq        ;seq +1
  1698.     bicb    #^C77,seq    ;isolate low 6
  1699.     mov    r0,r5        ;copy
  1700.     mov    r0,r4        ;twice
  1701. 10$:    tstb    (r4)+        ;count
  1702.     bne    10$
  1703.     dec    r4        ;-1
  1704.     sub    r5,r4        ;length
  1705.     call    ldatn        ;load packet
  1706.     call    ldatf        ;fix for MAKPAC
  1707.     mov    #'E,r0        ;type=ERROR
  1708.     call    makpac        ;make packet
  1709.     jmp    putpac        ;send it, return
  1710. ;+
  1711. ;
  1712. ; Send an ACK for the current packet.
  1713. ;
  1714. ;-
  1715. ack:    clr    r4        ;no data
  1716.     mov    #txbuf+3,r5    ;space for header stuff
  1717. ack1:    ; enter with data field at (r5), length in r4
  1718.     mov    #'Y,r0        ;type=ACK
  1719.     call    makpac        ;make a packet
  1720.     mov    r5,ackdat    ;save data
  1721.     mov    r4,acklen
  1722.     incb    seq        ;bump seq
  1723.     bicb    #^C77,seq    ;mod 100
  1724.     jmp    putpac        ;send it, return
  1725. ;+
  1726. ;
  1727. ; Resend ACK for previous packet.
  1728. ;
  1729. ;-
  1730. reack:    mov    ackdat,r5    ;get ptr
  1731.     mov    acklen,r4    ;and length
  1732.     jmp    putpac        ;send it
  1733. ;+
  1734. ;
  1735. ; Send a NAK for the current packet.
  1736. ;
  1737. ;-
  1738. nak:    mov    #'N,r0        ;NAK
  1739.     clr    r4        ;no data
  1740.     mov    #txbuf+3,r5    ;space for header stuff
  1741.     call    makpac        ;make a packet
  1742.     jmp    putpac        ;send it, return
  1743. ;+
  1744. ;
  1745. ; Load data field.
  1746. ;
  1747. ; r5    data to load
  1748. ; r4    length of data
  1749. ; r2    length of buffer
  1750. ; r1    buffer addr
  1751. ;
  1752. ; Each code is as follows:
  1753. ; .byte    '~,count+40    ;repeat count if rept.ne.0
  1754. ; .byte    '&        ;8th-bit-quote if b7=1 and qbin.ne.0
  1755. ; .byte    '#        ;ctrl-char-quote if needed ('# is my choice)
  1756. ; .byte    char        ;char, with quoted bits trimmed
  1757. ;
  1758. ; Returns C=1 if output buf is full, in which case it's possible
  1759. ; that not all of the data were transferred (r5, r4 updated).
  1760. ;
  1761. ; The LDATN entry sets up r1 and r2 to start a new packet.
  1762. ; The LDATF entry converts r1, r2 returned from LDAT into r4, r5
  1763. ; needed by MAKPAC, assuming we were using TXBUF as the buffer.
  1764. ;
  1765. ;-
  1766. ldatn:    ; set up for new packet
  1767.     mov    #txbuf+3,r1    ;usual initial values for r1, r2
  1768.     movb    maxl,r2
  1769.     ;br    ldat
  1770. ;
  1771. ldat:    tst    r4        ;nothing to do?
  1772.     beq    170$        ;C=0 from TST
  1773.     br    150$        ;jump into loop
  1774. 10$:    ; dry run to see if this char will fit in the packet
  1775.     ; (we worry about this only when we're within 5 chars of full)
  1776.     movb    (r5),r0        ;get next char
  1777.     ; 1 char for the char itself
  1778.     mov    #1,r3        ;length so far
  1779.     ; 2 chars for repeat prefix
  1780.     tstb    rept        ;do we do compression?
  1781.     beq    20$
  1782.     cmp    r4,#3        ;at least 3 chars left?
  1783.     blo    20$
  1784.     cmpb    r0,1(r5)    ;next one the same?
  1785.     bne    20$
  1786.     cmpb    r0,2(r5)    ;what about the one after?
  1787.     bne    20$
  1788.     add    #2,r3        ;yep, compression takes 2 chars
  1789. 20$:    ; 1 char for 8th bit quote
  1790.     tstb    qbin        ;do we quote 8th bit?
  1791.     beq    30$
  1792.     tstb    r0        ;8th bit set?
  1793.     bpl    30$
  1794.     inc    r3        ;yes, add 1 char
  1795. 30$:    ; 1 char for ctrl quote or flag quote
  1796.     bic    #^C177,r0    ;trim to 7
  1797.     cmp    r0,#177        ;ctrl char?
  1798.     beq    40$
  1799.     cmp    r0,#40
  1800.     blo    40$
  1801.     cmpb    r0,#'#        ;flag?
  1802.     beq    40$
  1803.     cmpb    r0,qbin
  1804.     beq    40$
  1805.     cmpb    r0,rept
  1806.     bne    50$
  1807. 40$:    inc    r3        ;add 1 char
  1808. 50$:    cmp    r2,r3        ;enough space?
  1809.     blo    170$        ;no, return C=1
  1810. 60$:    ; we're sure we have enough space, really do it
  1811.     movb    (r5)+,r0    ;get the char
  1812.     tstb    rept        ;try to compress?
  1813.     beq    90$
  1814.     cmp    r4,#3        ;.GE.3 chars?
  1815.     blo    90$
  1816.     cmpb    r0,(r5)        ;.GE.3 in a row the same?
  1817.     bne    90$
  1818.     cmpb    r0,1(r5)
  1819.     bne    90$
  1820.     ; at least 3 in a row, do a repeat count
  1821.     add    #2,r5        ;skip the next 2
  1822.     sub    #2,r4        ;eat them
  1823.     mov    #3,r3        ;init count
  1824. 70$:    cmp    r4,#1        ;anything left?  (r4 is still +1 here)
  1825.     beq    80$        ;no
  1826.     cmpb    r0,(r5)        ;yes, is it the same?
  1827.     bne    80$
  1828.     inc    r5        ;yes, eat it
  1829.     dec    r4        ;count it
  1830.     inc    r3        ;rept count +1
  1831.     cmp    r3,#94.        ;field full?
  1832.     blo    70$        ;no, loop
  1833. 80$:    movb    rept,(r1)+    ;save flag
  1834.     add    #40,r3        ;char(count)
  1835.     movb    r3,(r1)+
  1836.     sub    #2,r2        ;count
  1837. 90$:    ; quote 8th bit
  1838.     tstb    qbin        ;binary quoting?
  1839.     beq    100$
  1840.     tstb    r0        ;does it need it?
  1841.     bpl    100$
  1842.     movb    qbin,(r1)+    ;yes
  1843.     dec    r2
  1844.     bic    #^C177,r0    ;isolate low 7
  1845. 100$:    ; quote control chars
  1846.     mov    r0,r3        ;copy
  1847.     bic    #^C177,r3    ;trim
  1848.     cmpb    r3,#177        ;DEL?
  1849.     beq    110$
  1850.     cmpb    r3,#40        ;ctrl char?
  1851.     bhis    120$
  1852. 110$:    mov    #100,r3        ;get 100
  1853.     xor    r3,r0        ;ctl(r0)
  1854.     br    130$        ;go quote
  1855. 120$:    ; see if it's a flag char
  1856.     ; we got #@ above so r3 can't be nul - OK to cmpb to QBIN & REPT
  1857.     cmpb    r3,#'#        ;qctl?
  1858.     beq    130$
  1859.     cmpb    r3,qbin        ;qbin?
  1860.     beq    130$
  1861.     cmpb    r3,rept        ;rept?
  1862.     bne    140$
  1863. 130$:    movb    #'#,(r1)+    ;qctl
  1864.     dec    r2
  1865. 140$:    ; write the char itself
  1866.     movb    r0,(r1)+    ;write it
  1867.     dec    r2
  1868.     dec    r4        ;dec count
  1869.     beq    160$        ;done, skip
  1870. 150$:    cmp    r2,#5        ;could we overrun?
  1871.     bhis    60$        ;no, don't worry
  1872.     br    10$        ;yes, be careful
  1873. 160$:    clc            ;no flush needed yet
  1874. 170$:    rts    pc        ;(C set up)
  1875. ;
  1876. ldatf:    ; convert r1, r2 from LDAT into r4, r5 for MAKPAC
  1877.     mov    #txbuf+3,r5    ;point
  1878.     mov    r1,r4        ;copy
  1879.     sub    r5,r4        ;get length
  1880.     rts    pc
  1881. ;+
  1882. ;
  1883. ; Unpack the data field of a text packet.
  1884. ;
  1885. ; Handles all escapes, and as long as r2 and r3 are preserved parsing may be
  1886. ; preserved around packet boundaries, which means that escape sequences may be
  1887. ; broken between packets.  After not mentioning whether this can happen in the
  1888. ; first few versions, the 6th edition of the Kermit spec says it can't, so we
  1889. ; won't generate them but we'll receive them OK.
  1890. ;
  1891. ; On entry:
  1892. ; r2    escape bits:  200 if & encountered, 100 if # encountered
  1893. ; r3    repeat count, or -1 if next char is char(repeat count)
  1894. ; r4    length of input packet buffer
  1895. ; r5    input packet buffer
  1896. ;
  1897. ; BUFPTR contains the current output buffer addr
  1898. ; BUFCTR contains the # of free bytes in the buf at bufptr
  1899. ;
  1900. ; Call is through r1:
  1901. ;    jsr    r1,unpack
  1902. ;    .word    flush
  1903. ;    ... returns here, C=1 if flush error
  1904. ;
  1905. ; FLUSH is the addr of a routine which is called when BUFCTR reaches 0.  It
  1906. ; should start the old buf flushing and set up BUFPTR,BUFCTR to point to a
  1907. ; fresh buffer for subsequent data.  R0 may be destroyed by the routine, all
  1908. ; others must be preserved.  If the routine returns C=1, UNPACK returns
  1909. ; immediately with C=1.
  1910. ;
  1911. ; The initial values for r2 and r3 are 0 and 1, respectively
  1912. ; (no escapes yet and no repeat so we'll write 1 byte).
  1913. ; Call IUNPK instead to set these up.
  1914. ;
  1915. ;-
  1916. iunpk:    ; come here to init flags
  1917.     clr    r2        ;no escapes
  1918.     mov    #1,r3        ;repeat count = 1
  1919. unpack:    ; come here with flags already initted
  1920.     tst    r4        ;anything to unpack?
  1921.     beq    60$        ;no
  1922. 10$:    movb    (r5)+,r0    ;get next char
  1923.     tst    r3        ;expecting repeat count?
  1924.     bmi    90$        ;yes
  1925.     cmpb    r0,rept        ;repeat flag?
  1926.     beq    80$
  1927.     cmpb    r0,qbin        ;8th-bit flag (if any)?
  1928.     beq    100$
  1929.     cmpb    r0,qctl        ;ctrl flag?
  1930.     beq    110$
  1931. 20$:    xor    r0,r2        ;we've finished the char, flip bits
  1932. 30$:    ; save r2, r3 times
  1933.     movb    r2,@bufptr    ;put in buf
  1934.     inc    bufptr        ;bump ptr
  1935.     dec    bufctr        ;any space left?
  1936.     beq    70$        ;no, queue write
  1937. 40$:    sob    r3,30$        ;loop
  1938.     clr    r2        ;re-init flags
  1939.     inc    r3        ;count=1
  1940. 50$:    sob    r4,10$        ;loop
  1941. 60$:    tst    (r1)+        ;skip flush addr, C=0
  1942.     rts    r1
  1943. 70$:    ; go flush buffer
  1944.     call    @(r1)        ;flush
  1945.     bcc    40$        ;loop if ok
  1946.     tst    (r1)+        ;skip flush addr
  1947.     sec            ;C=1
  1948.     rts    r1
  1949. 80$:    ; repeat flag
  1950.     bit    #100,r2        ;quoted?
  1951.     bne    120$        ;yes
  1952.     mov    #-1,r3        ;no, next char is count
  1953.     br    50$        ;get it
  1954. 90$:    ; repeat count
  1955.     sub    #40,r0        ;unchar
  1956.     mov    r0,r3        ;save
  1957.     br    50$        ;get next
  1958. 100$:    ; 8th bit flag
  1959.     bit    #100,r2        ;quoted?
  1960.     bne    120$        ;yes
  1961.     bis    #200,r2        ;no, set 8th bit
  1962.     br    50$        ;C4
  1963. 110$:    ; ctrl flag
  1964.     bit    #100,r2        ;quoted?
  1965.     bne    120$        ;yes
  1966.     bis    #100,r2        ;no, set ctrl bit
  1967.     br    50$        ;C4
  1968. 120$:    bic    #100,r2        ;clear flag (quoted, not ctrl)
  1969.     br    20$        ;save char
  1970. ;+
  1971. ;
  1972. ; Send a simple packet and get an ACK for it.
  1973. ;
  1974. ; Enter with packet type in r0.
  1975. ;
  1976. ; Exit with things set up from SNDACK.
  1977. ;
  1978. ;-
  1979. sndsmp:    mov    #txbuf+3,r5    ;ptr
  1980.     clr    r4        ;no data
  1981.     call    makpac        ;make a packet
  1982.     ;br    sndack        ;send it, get ACK
  1983. ;+
  1984. ;
  1985. ; Send a packet and get an ACK for it.
  1986. ;
  1987. ; Enter with r4, r5 set up for PUTPAC.
  1988. ;
  1989. ; Return with C=1 = retry count exhausted,
  1990. ; C=0 = things are OK (getpac regs), seq updated.
  1991. ;
  1992. ;-
  1993. sndack:    mov    #10.,-(sp)    ;retry count
  1994. 10$:    call    putpac        ;send
  1995.     mov    r4,-(sp)    ;save
  1996.     mov    r5,-(sp)
  1997.     call    getpac        ;get a packet
  1998.     bcc    30$        ;got one
  1999. 20$:    mov    (sp)+,r5    ;restore
  2000.     mov    (sp)+,r4
  2001.     dec    (sp)        ;give up yet?
  2002.     bne    10$        ;no
  2003.     tst    (sp)+        ;yes, flush
  2004.     sec            ;C=1
  2005.     rts    pc
  2006. 30$:    cmp    r0,#'Y        ;ACK?
  2007.     bne    40$        ;no
  2008.     cmpb    r1,seq        ;correct sequence #?
  2009.     beq    50$        ;yes, skip
  2010. 40$:    cmp    r0,#'N        ;NAK?
  2011.     bne    20$        ;no, keep trying
  2012.     inc    r1        ;seq+1
  2013.     bic    #^C77,r1    ;mod 100'
  2014.     cmpb    r1,seq        ;NAK for next packet?
  2015.     bne    20$        ;no, keep trying
  2016.     clr    r4        ;shouldn't be any data
  2017. 50$:    incb    seq        ;bump seq
  2018.     bicb    #^C77,seq    ;mod 100'
  2019.     add    #6,sp        ;purge stack, C=0
  2020.     rts    pc
  2021. ;+
  2022. ;
  2023. ; Make a packet.
  2024. ;
  2025. ; On entry:
  2026. ;
  2027. ; r0    packet type
  2028. ; r4    length of dat
  2029. ; r5    ptr to dat (must have 3 bytes free at each end)
  2030. ;
  2031. ; On return:
  2032. ;
  2033. ; r4    length of packet
  2034. ; r5    ptr to packet
  2035. ;
  2036. ;-
  2037. makpac:    movb    r0,-(r5)    ;save typ
  2038.     movb    seq,r0        ;get seq #
  2039.     add    #40,r0        ;char(seq)
  2040.     movb    r0,-(r5)    ;save seq
  2041.     add    #2,r4        ;count both
  2042.     mov    r4,r0        ;copy
  2043.     add    lchk,r0        ;add length of check
  2044.     mov    r0,-(sp)    ;save
  2045.     add    #40,r0        ;take char(len)
  2046.     movb    r0,-(r5)    ;save len
  2047.     mov    r5,r1        ;copy ptr
  2048.     inc    r4        ;count length field
  2049.     add    r4,r1        ;add length
  2050.     mov    r5,-(sp)    ;save
  2051.     call    @checka        ;compute check
  2052.     mov    (sp)+,r5    ;restore
  2053.     mov    (sp)+,r4
  2054.     inc    r4        ;count length
  2055.     rts    pc
  2056. ;+
  2057. ;
  2058. ; Send a packet.
  2059. ;
  2060. ; On entry,
  2061. ;
  2062. ; r4    length of len through chk fields
  2063. ; r5    ptr to len field
  2064. ;
  2065. ; Preserves r4 and r5.
  2066. ;
  2067. ;-
  2068. putpac:    .rctrlo            ;might have received ^O in line noise
  2069.     movb    npad,r1        ;get # pads to send
  2070.     beq    20$        ;none
  2071.     movb    padc,r0        ;get char
  2072. 10$:    .ttyout            ;write one
  2073.     sob    r1,10$        ;loop
  2074. 20$:    .ttyout    #soh        ;write SOH
  2075.     mov    r4,r2        ;copy
  2076.     mov    r5,r3
  2077. 30$:    movb    (r3)+,r0    ;get next char
  2078.     .ttyout            ;write it
  2079.     sob    r2,30$        ;loop
  2080.     movb    eol,r0        ;write eol char
  2081.     .ttyout
  2082.     rts    pc
  2083. ;+
  2084. ;
  2085. ; Receive a packet.
  2086. ;
  2087. ; On return:
  2088. ;
  2089. ; If successful, C=0 and
  2090. ;
  2091. ; r0    packet type
  2092. ; r1    packet sequence number
  2093. ; r4    length of data field
  2094. ; r5    ptr to data field
  2095. ;
  2096. ; C=1 on timeout, bad checksum, or obviously invalid length.
  2097. ;
  2098. ;-
  2099. getpac:    jsr    r5,gtmout    ;get mark
  2100.      .word    50$        ;whoops
  2101.     cmp    r0,#soh        ;is this mark?
  2102.     bne    getpac        ;loop if not
  2103.     mov    #rxbuf,r5    ;pt at buf
  2104.     mov    r5,r4        ;copy
  2105.     jsr    r5,gtmout    ;get length
  2106.      .word    50$        ;whoops
  2107.     movb    r0,(r4)+    ;save
  2108.     sub    #40,r0        ;unchar(len)
  2109.     cmp    r0,#136        ;valid?
  2110.     bhi    50$        ;nope, don't rape core
  2111.     mov    lchk,r1        ;get length of check
  2112.     add    #2,r1        ;+2 (seq, typ)
  2113.     cmp    r0,r1        ;too small for null data field?
  2114.     blo    50$        ;yes, forget it
  2115.     mov    r0,r1        ;copy length
  2116. 10$:    jsr    r5,gtmout    ;get a char
  2117.      .word    50$        ;whoops
  2118.     movb    r0,(r4)+    ;save the char
  2119.     sob    r1,10$        ;loop
  2120.     ; got the whole thing, check it
  2121.     sub    r5,r4        ;find length
  2122.     sub    lchk,r4        ;don't check the check
  2123.     mov    r4,-(sp)    ;save
  2124.     mov    r5,-(sp)
  2125.     mov    #chkbuf,r1    ;pt at buf
  2126.     call    @checka        ;check the packet
  2127.     mov    r5,r2        ;copy check ptr
  2128.     mov    (sp)+,r5    ;restore
  2129.     mov    (sp)+,r4
  2130.     sub    r3,r1        ;back up
  2131. 20$:    cmpb    (r1)+,(r2)+    ;right?
  2132.     bne    40$        ;no
  2133.     sob    r3,20$        ;loop
  2134. 30$:    inc    r5        ;skip LEN
  2135.     movb    (r5)+,r1    ;get seq
  2136.     sub    #40,r1        ;unchar
  2137.     bcs    50$        ;whoops
  2138.     bit    #^C77,r1    ;must fit in 6 bits
  2139.     bne    50$        ;doesn't, error
  2140.     movb    (r5)+,r0    ;get type
  2141.     sub    #3,r4        ;update length (C=0)
  2142.     rts    pc
  2143. 40$:    ; bad check -- if check type .NE. 1-char-checksum, see if the packet
  2144.     ; would have been valid if it were;  this way we can recover from them
  2145.     ; losing our half of parms negotiation
  2146. ;;; we may want to limit this check to cases when it could happen, otherwise
  2147. ;;; we'll blindly accept bad packets 1/256th of the time
  2148.     mov    lchk,r0        ;get check type
  2149.     cmp    r0,#1        ;=1?
  2150.     beq    50$        ;yes, no point in being cute
  2151.     add    r0,r4        ;fix length
  2152.     dec    r4        ;to include everything but 1-char-checksum
  2153.     mov    r4,-(sp)    ;save
  2154.     mov    r5,-(sp)
  2155.     mov    #chkbuf,r1    ;pt at buf
  2156.     call    chk1        ;call 1-char-checksum routine
  2157.     mov    r5,r2        ;save
  2158.     mov    (sp)+,r5    ;restore
  2159.     mov    (sp)+,r4
  2160.     cmpb    (r1),(r2)    ;match?
  2161.     beq    30$        ;yes, continue processing
  2162. 50$:    sec            ;error return
  2163.     rts    pc
  2164. ;
  2165. gtmout:    ; get char with timeout
  2166.     .ttinr            ;try to get a char
  2167.     bcs    gtmout        ;loop
  2168.     tst    (r5)+        ;skip return
  2169.     rts    r5
  2170. ;+
  2171. ;
  2172. ; Check routines.
  2173. ;
  2174. ; On entry:
  2175. ;
  2176. ; r1    buffer to put check in
  2177. ; r4    length of len through dat fields
  2178. ; r5    len field of packet to check
  2179. ;
  2180. ; On return:
  2181. ;
  2182. ; r1    updated
  2183. ; r3    length of check generated
  2184. ; r5    end of region checked
  2185. ;
  2186. ;-
  2187. chk1:    ; 1-byte checksum
  2188.     ; chk = <<sum+<<sum/100>&3>>&77>+40 (sum is 8-bit sum of chars)
  2189.     clr    r2        ;init sum
  2190. 10$:    movb    (r5)+,r0    ;get a char
  2191.     add    r0,r2        ;add it in
  2192.     sob    r4,10$        ;loop
  2193.     mov    r2,r0        ;copy
  2194.     rolb    r2        ;left 3
  2195.     rolb    r2
  2196.     rolb    r2
  2197.     bic    #^C3,r2        ;isolate <7:6>
  2198.     add    r2,r0        ;find total
  2199.     bic    #^C77,r0    ;isolate <5:0>
  2200.     add    #40,r0        ;char(chk)
  2201.     movb    r0,(r1)+    ;save
  2202.     mov    #1,r3        ;length
  2203.     rts    pc
  2204. ;
  2205. chk2:    ; 2-byte checksum
  2206.     ; chk1 = sum&77+40, chk2 = <sum_-6>&77+40 (sum is 12-bit sum of chars)
  2207.     clr    r2        ;init sum
  2208. 10$:    clr    r0        ;clear high
  2209.     bisb    (r5)+,r0    ;get a char
  2210.     add    r0,r2        ;add it in
  2211.     sob    r4,10$        ;loop
  2212.     mov    r0,r2        ;copy
  2213.     bic    #^C77,r0    ;low 6 bits
  2214.     add    #40,r0        ;char()
  2215.     movb    r0,(r1)+    ;save
  2216.     asl    r2        ;left 2
  2217.     asl    r2
  2218.     swab    r2        ;and right 8 = right 6
  2219.     bic    #^C77,r2    ;high 6 bits
  2220.     add    #40,r2        ;char()
  2221.     movb    r2,(r1)+    ;save
  2222.     mov    #2,r3        ;length
  2223.     rts    pc
  2224. ;
  2225. chk3:    ; 3-byte CRC (requires EIS)
  2226.     ; algorithm stolen from MS-Kermit V2.24
  2227.     ; (written by Columbia University)
  2228.     clr    r2        ;init
  2229. 10$:    movb    (r5)+,r0    ;get next
  2230. .if ne eis$$
  2231.     xor    r2,r0        ;XOR low byte of old value
  2232. .iff
  2233.     mov    r2,r3        ;save
  2234.     bis    r2,r0        ;find IOR
  2235.     com    r2        ;find AND
  2236.     bic    r2,r3
  2237.     bic    r3,r0        ;(r2!r0)&^C(r2&r0)
  2238. .endc
  2239.     bic    #^C377,r0    ;isolate
  2240.     asl    r0        ;*2
  2241.     mov    crc(r0),r0    ;get bits
  2242.     clrb    r2        ;running total right 8.
  2243.     swab    r2
  2244. .if ne eis$$
  2245.     xor    r0,r2        ;find new value
  2246. .iff
  2247.     mov    r0,r3        ;save
  2248.     bis    r0,r2        ;IOR
  2249.     com    r0        ;AND
  2250.     bic    r0,r3
  2251.     bic    r3,r2        ;XOR
  2252. .endc
  2253.     sob    r4,10$        ;yay
  2254. .if ne eis$$
  2255.     mov    r2,r3        ;copy
  2256.     ash    #-6,r2        ;right 6
  2257.     mov    r2,r0
  2258.     ash    #-6,r0        ;again
  2259. .iff
  2260.     mov    r2,r3        ;copy
  2261.     mov    r2,r0
  2262.     swab    r0        ;right 12. (right 8., right 4)
  2263.     asr    r0
  2264.     asr    r0
  2265.     asr    r0
  2266.     asr    r0
  2267.     asl    r2        ;right 6. (left 2, right 8.)
  2268.     asl    r2
  2269.     swab    r2
  2270. .endc
  2271.     bic    #^C17,r0    ;<15:12>
  2272.     bis    #40,r0        ;char()
  2273.     movb    r0,(r1)+
  2274.     bic    #^C77,r2    ;<11:6>
  2275.     add    #40,r2        ;char()
  2276.     movb    r2,(r1)+
  2277.     bic    #^C77,r3    ;<5:0>
  2278.     add    #40,r3        ;char()
  2279.     movb    r3,(r1)+
  2280.     mov    #3,r3        ;length
  2281.     rts    pc
  2282. ;
  2283. crc:    .word    1,2,3,4        ;this table will be 256. words
  2284. ;
  2285.     .rem    %
  2286.     xor    dx,dx        ;init crc
  2287.     mov    bh,dl        ;bh=0
  2288. kchk3a:    lodsb            ;get next byte
  2289.     xor    al,dl        ;XOR in old value
  2290.     mov    dl,dh        ;right 8 bits
  2291.     mov    dh,al        ;save low byte
  2292.     mov    bl,al        ;copy
  2293.     and    bl,17        ;isolate low 4
  2294.     shl    bl,1        ;*2
  2295.     mov    ax,ds:crc1[bx]    ;get low part
  2296.     mov    bl,dh        ;copy again
  2297.     shr    bl,1        ;right-justify high nibble, *2
  2298.     shr    bl,1
  2299.     shr    bl,1
  2300.     and    bl,36        ;isolate
  2301.     xor    ax,ds:crc2[bx]    ;bitwise add get high part
  2302.     mov    dh,ah        ;copy high half
  2303.     xor    dl,al        ;bitwise add low half
  2304.     loop    kchk3a        ;loop
  2305.     mov    bx,dx        ;copy
  2306.     mov    cl,6        ;bit count
  2307.     shr    bx,cl        ;right 6
  2308.     mov    ax,bx        ;one more time
  2309.     shr    ax,cl        ;right 6
  2310.     or    al,40        ;take char(CRC<15:12>)
  2311.     mov    [di],al        ;save it
  2312.     inc    di        ;+1
  2313.     and    bl,77        ;isolate CRC<6:11>
  2314.     add    bl,40        ;take char()
  2315.     mov    [di],bl        ;save
  2316.     inc    di        ;+1
  2317.     and    dl,77        ;isolate CRC<5:0>
  2318.     add    dl,40        ;take char()
  2319.     mov    [di],dl        ;save
  2320.     inc    di        ;+1
  2321.     mov    cl,3        ;byte count=3
  2322.     ret
  2323. %
  2324.     .sbttl    pure data
  2325. ;
  2326. rad50a:    ; 1st char rad50 lookup table
  2327.     .rad50    "   A  B  C  D  E  F  G  "
  2328.     .rad50    "H  I  J  K  L  M  N  O  "
  2329.     .rad50    "P  Q  R  S  T  U  V  W  "
  2330.     .rad50    "X  Y  Z  $  .     0  1  "
  2331.     .rad50    "2  3  4  5  6  7  8  9  "
  2332. ;
  2333. rad50b:    ; 2nd char rad50 lookup table
  2334.     .rad50    "    A  B  C  D  E  F  G "
  2335.     .rad50    " H  I  J  K  L  M  N  O "
  2336.     .rad50    " P  Q  R  S  T  U  V  W "
  2337.     .rad50    " X  Y  Z  $  .     0  1 "
  2338.     .rad50    " 2  3  4  5  6  7  8  9 "
  2339. ;
  2340. checks:    .word    chk1,chk2,chk3
  2341. ;
  2342. larea:    .byte    1,1    ;.LOOKUP, channel = 1
  2343.     .word    fbuf    ;filename
  2344.     .word    -1    ;start at head posn on magtape
  2345. ;
  2346. ludir:    .byte    0,1    ;.LOOKUP, channel = 0
  2347.     .word    wlddev    ;ptr to device name
  2348.     .word    0    ;(only for MT:)
  2349. ;
  2350. r50t:    .ascii    " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789"
  2351. r50tnb:    .ascii    <0>"ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789"
  2352. ;
  2353. months:    .ascii    "-Jan-Feb-Mar-Apr-May-Jun-Jul-Aug-Sep-Oct-Nov-Dec-"
  2354. ;
  2355. ; strings for dirsum
  2356. tfile:    .asciz    " file"
  2357. tblk:    .asciz    " block"
  2358.     .asciz    " in use"    ;must follow tblk
  2359. tfree:    .asciz    " free"
  2360. ;
  2361. bfs:    .asciz    'Bad file specification.'
  2362. bdn:    .asciz    'Bad device name.'
  2363. nomtch:    .asciz    'No matching files found.'
  2364. fnf:    .asciz    'File not found.'
  2365. ucf:    .asciz    'Unable to create file.'
  2366. uof:    .asciz    'Unable to open file.'
  2367. werr:    .asciz    'Error writing file.'
  2368. rerr:    .asciz    'Error reading file.'
  2369. ioerr:    .asciz    'I/O error.'
  2370. toolng:    .asciz    'Line too long.'
  2371. mkw:    .asciz    'Missing keyword.'
  2372. ;
  2373.     .sbttl    some of both
  2374. ;
  2375.     .even
  2376. ;
  2377. earea:    .byte    1,2    ;.ENTER, channel = 1
  2378.      .word    fbuf    ;dblk
  2379. elen:    .word    -1    ;length=max (or value if we know)
  2380.     .word    -1    ;add file at EOT if magtape
  2381. ;
  2382. device:    .word    0    ;currently loaded device handler, or 0 if none
  2383. lchk:    .word    1    ;length of checksum (bytes)
  2384. checka:    .word    chk1    ;addr of routine to compute checksum
  2385. ;
  2386. warea:    .byte    1,11    ;.WRITE, channel = 1
  2387. wblk:    .word        ;blk #
  2388. wca:    .word        ;core address
  2389. wwc:    .word        ;word count
  2390.     .word    1    ;no crtn
  2391. ;
  2392. rarea:    .byte    1,10    ;.READ, channel = 1
  2393. rblk:    .word        ;blk #
  2394. rca:    .word        ;core address
  2395. rwc:    .word        ;word count
  2396.     .word    1    ;no crtn
  2397. ;
  2398. rddir:    .byte    0,10    ;.READ, channel = 0
  2399. dirblk:    .word        ;blk #
  2400.     .word    buf1    ;core addr
  2401.     .word    1000    ;word cnt (dir segments are 2 blks)
  2402.     .word    0    ;wait for completion
  2403. ;
  2404. wrdir:    .byte    0,11    ;.WRITE, channel=0
  2405. wdrblk:    .word        ;blk #
  2406.     .word    buf1    ;core addr
  2407.     .word    1000    ;word cnt (2 blocks)
  2408.     .word    0    ;wait for completion
  2409. ;
  2410. wlddev:    .word        ;dev name for dir search
  2411.     .word    0,0,0    ;no filename or ext
  2412. ;
  2413.     .blkb    3    ;for len, seq, typ
  2414. mparms:    ; my parameters
  2415.     .byte    94.+40    ;MAXL (anything's OK with us)
  2416.     .byte    5+40    ;TIME (line speed should be only problem)
  2417.     .byte    0+40    ;NPAD (no pad chars)
  2418.     .byte    '@    ;PADC (doesn't matter)
  2419.     .byte    cr+40    ;EOL (doesn't matter)
  2420.     .byte    '#    ;QCTL (hard-coded - doesn't really matter)
  2421. mqbin:    .byte        ;QBIN (only if one of us needs it)
  2422. mchkt:    .byte        ;CHKT (whatever they want, or 1 byte)
  2423. mrept:    .byte        ;REPT (repeat char)
  2424.     .byte    attr+40    ;CAPAS (attr packets OK)
  2425. nmprms=    .-mparms
  2426.     .blkb    3    ;for check
  2427. ;
  2428. pns:    .ascii    'Packet type "'
  2429. pnsc:    .byte
  2430.     .asciz    '" not supported.'
  2431. ;
  2432. cns:    .ascii    'Generic command "'
  2433. cnsc:    .byte
  2434.     .asciz    '" not supported.'
  2435. ;
  2436. pvl:    .ascii    'Packet type "'
  2437. pvlc:    .byte
  2438.     .asciz    '" invalid at this point.'
  2439. ;
  2440. ddev:    .ascii    'Default device is now '
  2441. ddev1:    .blkb    3+1+2        ;<ddu>:<crlf>
  2442. ;
  2443.     .sbttl    pure storage
  2444. ;
  2445.     .even
  2446. defdev:    .blkw        ;default device name (.rad50)
  2447. fbuf:    .blkw    4    ;device, filename, extension
  2448. dstat:    .blkw    4    ;.DSTAT area
  2449. ackdat:    .blkw        ;ptr to last ACK packet
  2450. acklen:    .blkw        ;length of last ACK packet
  2451. ; directory stuff:
  2452. extbyt:    .blkw        ;extra bytes per dir entry
  2453. files:    .blkw        ;no. of files in dir listing
  2454. used:    .blkw        ;total no. blks in use
  2455. free:    .blkw        ;total no. < UNUSED > blks
  2456. segnxt:    .blkw        ;next segment in dir
  2457. ;
  2458. seq:    .blkb    1    ;packet sequence #
  2459. txbuf:    .blkb    3+91.+3    ;tx packet buffer
  2460. rxbuf:    .blkb    91.+3    ;rx packet buffer
  2461. chkbuf:    .blkb    3    ;check buffer (for generated rx check)
  2462. wild:    .blkb    91.+1    ;wildcard buffer for GD and R
  2463. wldflg:    .blkb        ;NZ => WILD contains at least 1 wildcard char
  2464. dirall:    .blkb        ;NZ => show all dir entries (no wildcard check)
  2465. dirnon:    .blkb        ;NZ => don't build dir entry table (usage check)
  2466. binfil:    .blkb        ;NZ => don't trim NULs from ends of file blks
  2467. ;
  2468. maxl:    .blkb        ;maximum packet length (bytes)
  2469. time:    .blkb        ;packet timeout (seconds)
  2470. npad:    .blkb        ;no. of pad characters
  2471. padc:    .blkb        ;pad character (if npad.ne.0)
  2472. eol:    .blkb        ;eol char
  2473. qctl:    .blkb        ;ctrl char quote
  2474. qbin:    .blkb        ;8th bit quote
  2475. chkt:    .blkb        ;check type
  2476. rept:    .blkb        ;repeat char
  2477. capas:    .blkb        ;extra capabilities
  2478. nparms=    .-maxl
  2479. ;
  2480.     .even
  2481. cbuf:    .blkw        ;current buffer in double-buffering
  2482. rlen:    .blkw        ;number of words reading into next buffer
  2483. bufptr:    .blkw        ;ptr into buffer
  2484. bufctr:    .blkw        ;ctr in buffer
  2485. ;
  2486. matlst:    .blkw    72.*5+1    ;wildcard match list, up to 72. entries + zero
  2487. ;
  2488. buf1:    .blkb    bufsiz    ;buffers
  2489. buf2:    .blkb    bufsiz
  2490. ;
  2491. devhnd=    .        ;device handlers go here
  2492.     .end    start
  2493.