****************************** PIPE_1.00_ASM *********************************
* a device driver extending QDOS's 'PIPE_' driver. It supports named pipes: *
* pipe_fred_1000 is an 1 k output pipe 'fred' which can be read from any job*    *
* by opening an input pipe 'pipe_fred_0' (or just 'pipe_fred')              *
* (C) Hans Lub Dolomieten 3524 VH Utrecht Netherlands  (5 may 1990)      *
***************************************************************************** 

               XDEF      first.pipe
               XDEF      dev.name
               XDEF      geef.terug
               XREF      dopipes        ; a SuperBasic proc in 'pipe_ext_asm'
               XREF      link.nul       ; links in 'NUL' device
               XREF      io.doit        ; routine for doing I/O

               INCLUDE    flp1_macro_lib
               INCLUDE    flp1_pipe_definitions

*************************** actual code **************************************

               SECTION   text

* The following code is called by SuperBasic in order to add the new
* device driver (cf p 139). This is the only part not running in supervisor
* mode.  

               move.l    #0,a0                ; on channel #0
               lea.l     tekstje,a1           ; .. a few words
               move.l    #ut.mtext,a2         ; .... should be written
               move.w    (a2),a2
               jsr       (a2)                 
               lea.l     link,a0              ; start of linkage block (p 140)
               lea.l     io.doit,a1
               lea.l     pipe.io,a2
               move.l    a1,(a2)+
               lea.l     open,a1
               move.l    a1,(a2)+
               lea.l     close,a1
               move.l    a1,(a2)+
               moveq     #mt.liod,d0
               trap      #1
               tst.l     d0
               bne.s     aargh
               jsr       link.nul
               tst.l     d0
               bne.s     aargh
               jsr       dopipes             ; link in the SB proc 'pipes'
aargh          rts




open           bra.s     op.echt             ; jump to start of code 
               dc.w      5                   ; header for e.g. QRAM/QPAC
               dc.b      'NPIPE'
               dc.w      0
op.echt        movem.l   d3/a0/a3/a6,-(a7)
               move.l    d3,d7               ; bewaar open type / chid
               lea.l     sysvar,a1
               move.l    a6,(a1)             ; bewaar basis systeemvariabelen
               bsr.l     decodeer            ; vind naam en lengte pijp
               tst.l     d0
               bne.l     op.mis              ; foute naam (of ander device)
               bsr.l     vind.andere.pijp    ; vind evt ander einde
               tst.l     d0
               bne.l     op.mis              ; geen twee kanalen aan dezelfde kant
               bsr.l     maak.ruimte         ; claim wat heap
               tst.l     d0
               bne.l     op.mis              ; 'out of memory'
               move.l    d1,ch.len(a0)       ; lengte in ch.len
               lea.l     other.pipe,a1
               clr.l     d1
               move.w    pipelen,d1
               beq.s     geen.queue          ; in- of output pipe?
               lea.l     pi.qstart(a0),a2    ; hier start queue
               clr.b     pi.ready(a0)        ; pipe nog niet klaar
               clr.b     pi.eof(a0)          ; en al helemaal niet EOF
               move.l    #io.qset,a3
               move.w    (a3),a3
               jsr       (a3)                ; maak queue
               clr.l     ch.qin(a0)          ; geen input
               move.l    a2,ch.qout(a0)      ; wel output
               tas       pi.ready(a0)        ; is altijd klaar
               tst.l     (a1)                ; is er een andere kant
               beq.s     op.verder
               move.l    (a1),a1             ; zo ja, kijk eerst of die al klaar is
               tst.l     pi.partner(a1)
               beq.s     op.vrij             ; zo nee, roep 'in use' 
               bsr.l     geef.terug          ; en geef blok weer terug
               moveq     #err.iu,d0
               bra.s     op.mis
op.vrij        lea.l     pi.qstart(a0),a3
               move.l    a3,ch.qin(a1)       ; zo ja, zet diens ch.qin
               tas       pi.ready(a1)        ; en maak hem 'ready'
               clr.b     pi.eof(a1)          ; niet meer eof
               bra.s     op.verder
geen.queue     clr.l     ch.qout(a0)         ; geen output
               tst.l    (a1)                 ; is er wel een input queue?
               beq.s     geen.input
               tas       pi.ready(a0)        ; zo ja, dan pipe 'ready'
               move.l    (a1),a1
               lea.l     pi.qstart(a1),a1    ; vind input pipe
               move.l    a1,ch.qin(a0)
               bra.s     op.verder
geen.input     clr.l     ch.qin(a0)
op.verder      move.l    other.pipe,pi.partner(a0) ; this pipe knows the other
               move.l    pi.partner(a0),a1
               move.l    a0,pi.partner(a1)         ; the other knows this one
               move.l    first.pipe,pi.next(a0)
               lea.l     first.pipe,a1
               move.l    a0,(a1)
               lea.l     name,a1
               move.w    (a1),d1
               clr.w     d2
               lea.l     pi.name(a0),a2
               bsr.l     breek.uit
               tst.l     d0
               bne.s     op.mis
               movem.l   (a7)+,d3/a1/a3/a6   ; herstel regs maar niet a0
               rts
op.mis         movem.l   (a7)+,d3/a0/a3/a6
               rts

               nop                           ; vlaggetje voor Qmon

close          lea.l     first.pipe,a1       ; begin vooraan de linked list
c.weer         tst.l     (a1)
               beq.s     c.kan.niet          
               cmp.l     (a1),a0             ; en zoek deze pijp
               beq.s     c.hebbes
               move.l    (a1),a1
               lea.l     pi.next(a1),a1      ; probeer volgende
               bra.s     c.weer              
c.hebbes       move.l    pi.next(a0),(a1)    ; 'unlink' deze pijp
               tst.l     ch.qout(a0)         ; wat voor pijp?
               beq.s     c.inpipe
               tst.l     pi.partner(a0)      ; een uitlaatpijp, heeft partner ?
               beq.s     c.uit.klaar         ; zo ja, ....
               movea.l   ch.qout(a0),a2      ; zet je eigen queue dan op EOF
               move.l    #io.qeof,a1         ; (maar zet partner's partner ...
               move.w    (a1),a1             ; ... niet op 0)
               jsr       (a1)
               rts                           ; geef nog niet terug
c.inpipe       move.l    pi.partner(a0),d1   ; een inlaat, heeft partner ?
               beq.s     c.in.klaar
               move.l    d1,a1               ; zo ja, kijk eerst of partner ..
               tst.l     pi.qstart(a1)       ; al dood is
               bge.s     maak.het.uit
               move.l    a0,-(a7)            ; zo ja, save a0 op stack
               move.l    a1,a0               
               bsr.s     geef.terug          ; geef (dode) partner terug
               move.l    (a7)+,a0            ; herstel a0
               bra.s     c.in.klaar
maak.het.uit   clr.l     pi.partner(a1)      ; verwittig levende partner 
c.uit.klaar
c.in.klaar     bsr.s     geef.terug
               rts
c.kan.niet     moveq     #err.nf,d0
               rts

geef.terug     move.l    #mm.rechp,a1
               move.w    (a1),a1
               jsr       (a1)
               rts
*---------------------------------------------------------------------------
decodeer       lea.l     dev.name,a1
               move.w    (a1),d1
               moveq     #0,d2
               movea.l   a0,a1
               movea.l   a0,a5          ; bewaar naam in a5
               lea.l     name,a2
               bsr.s     breek.uit
               tst.l     d0
               beq.s     misschien
               bra.s     geen.pipe
misschien      lea.l     dev.name,a0
               sub.l     a6,a0
               lea.l     name,a1
               sub.l     a6,a1
               moveq     #ignore.case,d0
               move.l    #ut.cstr,a2
               move.w    (a2),a2
               jsr       (a2)
               tst.l     d0
               bne.s     geen.pipe
               lea.l     dev.name,a0
               move.w    (a0),d2
               movea.l   a5,a1
               bsr.s     splits
               tst.l     d0
               bne.s     fout
               lea.l     pipelen,a2
               move.w    d3,(a2)
               lea.l     name,a2
               bsr.s     breek.uit
               tst.l     d0
               bne.s     fout
               rts
geen.pipe      moveq     #err.nf,d0
fout           rts
*-------------------------------------------------------------------------
*    breek.uit
*         VOOR                               NA
*    d0                                      foutkode
*    d1.w    = lengte deelstring             bedorven  (-1)
*    d2.w    = offset deelstring             bewaard
*    a1     -> hele string                   bewaard
*    a2     -> bestemming                    (1 voorbij laatste letter)

breek.uit      lea.l     2(a1,d2.w),a3       ; a3 -> begin deelstring
               move.w    d2,d3
               add.w     d1,d3               
               sub.w     (a1),d3             ; past deelstring in hele str?
               bgt.s     te.lang
               move.w    d1,(a2)+
               cmpi.w    #max.len,d1
               bgt.s     te.lang             ; of is deelstring te lang?
               bra.s     br.begin
br.weer        move.b    (a3)+,(a2)+         ; kopieer letter voor letter
br.begin       dbra      d1,br.weer
               clr.l     d0                  ; O.K.
               rts
te.lang        moveq     #-1,d0              ; niet O.K.
               rts

*---------------------------------------------------------------------------
* splits
*                                  d0   = foutkode
*                                  d1   = lengte beginstuk (excl de laatste _)
*    d2.w = offset   (meestal 4)   na eerste '_'
*                                  d3   = waarde getal
*    a1 -> hele string  (bv 19,'pipe_freds_pipe_987')
*

is.getal       MACRO     ea,wel,niet
               cmpi.b    #'0',[ea]
               blt.s     [niet]
               cmpi.b    #'9',[ea]
               bgt.s     [niet]
               IFSTR     [wel] = NIKS GOTO KLAAR
               bra.s     [wel]
KLAAR          MACLAB
               ENDM

               dc.b      'OEI'
splits         lea.l     2(a1,d2.w),a3       ; a3 -> begin deelstring
               move.w    (a1),d4
               sub.w     d2,d4               ; d4 = resterende lengte
               blt.s     sp.mislukt          ; offset voorbij string
               beq.s     sp.verder           ; pipe (anonieme inpijp)
               cmpi.b    #'_',(a3)+
               bne.s     sp.mislukt
               subq.w    #1,d4               ; een letter minder te tellen
               addq.w    #1,d2               ; nieuwe offset na de '_'
               is.getal  (a3) sp.verder sp.start  ; pipe_123 (anonieme uitpijp)
sp.ok          cmpi.b    #'_',(a3)+          ; zoek underscore
sp.start       dbeq      d4,sp.ok
sp.misschien   tst.w     d4  
               ble.s     sp.verder           ; string is op  (of laatste was _)
               is.getal  (a3) NIKS sp.start
sp.verder      move.w    (a1),d1             ; d1 = totale lengte -
               sub.w     d2,d1               ;        offset -
               sub.w     d4,d1               ;          resterend gedeelte 
               subq.w    #1,d1               ;     (d4 = rest - 1)
               bge.s     sp.d1.ok
               clr.w     d1                  ; -1 wordt 0 (bij anonime pijpen)
sp.d1.ok       clr.l     d3                  ; zet d3 vast op 0 
               tst.w     d4                  ; string op?
               blt.s     nul                 ; dus pipe_x = pipe_x_ = pipe_x_0
               bra.s     getal               ; begin getal te berekenen
sp.nog.s
               is.getal  (a3)  NIKS   genoeg  ; is volgende wel een cijfer?  
               clr.w     d5
               move.b    (a3)+,d5            ; d5 = ASCII cijfer
               sub.b     #'0',d5             ; d5 = cijfer
               mulu      #10,d3
               add.w     d5,d3               ; d3 = d3 * 10 + cijfer
               cmpi.l    #$7FFF,d3           ; niet te groot? 
               bgt.s     overflow
getal          dbra      d4,sp.nog.s       
genoeg             
nul            cmpi.l    #1,d3
               beq.s     sp.mag.niet
               clr.l     d0
               rts

sp.mislukt     moveq     #err.nf,d0
               rts
overflow       moveq     #err.or,d0
               rts
sp.mag.niet    moveq     #err.or,d0
               rts


*---------------------------------------------------------------------------

* vind.andere.pijp
*
* IN (niets)        UIT d0 = foutkode (als er al twee  zulke pijpen zijn, of 
*                                       deze is hetzelfde type)
*                       a2 -> defblok van andere kant   (ook in  other.pipe)

vind.andere.pijp
               move.w    name,d0
               beq.s     ap.anonym
               lea.l     first.pipe,a2       ; begin vooraan de linked list
ap.weer        move.l    (a2),a2
               cmpa.l    #0,a2
               beq.s     ap.ok               ; NULL pointer is einde lijst
               lea.l     pi.name(a2),a0      ; vergelijk nieuwe naam ....
               lea.l     name,a1             ; ... met naam van pijp in lijst
               sub.l     a6,a0               ; maak pointers .....
               sub.l     a6,a1               ;  ...... relatief
               moveq     #ignore.case,d0     ; let niet op details
               move.l    #ut.cstr,a3
               move.w    (a3),a3
               jsr       (a3)
               tst.l     d0                  ; zijn namen gelijk?
               beq.s     ap.hebbes           ; ga dan verder
               lea.l     pi.next(a2),a2      ; zoek anders volgende in lijst
               bra.s     ap.weer

ap.hebbes      tst.l     pi.partner(a2)      ; heeft pijp al een partner?
               bne.s     ap.bezet            ; jammer dan.
               move.w    pipelen,d0          ; zo nee, vergeljk type (in/uit)
               move.l    ch.qout(a2),d1      ; dus –f d0, –f d1, niet beide
               tst.w     d0                  ; (EOR instruktie niet bruikbaar)
               bne.s     ap.uit
               tst.l     d1
               bne.s     ap.ok
               bra.s     ap.bezet            ; twee inlaatpijpen
ap.uit         tst.l     d1
               bne.s     ap.bezet            ; twee uitlaten
ap.ok          clr.l     d0                  ; foutkode O.K.
               lea.l     other.pipe,a1
               move.l    a2,(a1)             ; bewaar a2 in other.pipe
               rts
ap.bezet       moveq     #err.ae,d0
               rts

               dc.b      'ARRGH!'
ap.anonym      move.w    pipelen,d0
               beq.s     ap.inpipe
               sub.l     a2,a2              ; anonieme uitpijp, geen andere kant
               bra.s     ap.ok
ap.inpipe      move.l    a0,-(sp)            ; save a0
               clr.l     d0                  ; MT.INF
               trap      #1
               asl.w     #2,d7               ; d7 *= 4
               move.l    sv.chbas(a0),a0     ; a0 -> kanaaltabel
               move.l    0(a0,d7.w),d0       ; d0 -> kanaal defblok
               ble.s     ap.mis              ; al gesloten
               move.l    d0,a2               ; a2 -> kanaal defblok andere kant
               swap      d7
               cmp.w     ch.tag(a2),d7       ; check tag
               bne.s     ap.mis
               lea.l     link(pc),a1         ; check pipe-ness
               cmpa.l    ch.drivr(a2),a1 
               bne.s     ap.mis
               move.l    (sp)+,a0
               bra.s     ap.ok

ap.mis         move.l    (sp)+,a0
               moveq     #err.bp,d0               
               rts

************************* MAAK.RUIMTE ***********************************

maak.ruimte    move.l    #pi.qstart,d1
               clr.l     d2
               move.w    pipelen,d2
               beq.s     lengte.0
               add.l     d2,d1
               add.l     #q.queue,d1
lengte.0       move.l    sysvar,a6
               move.l    #mm.alchp,a0
               move.w    (a0),a0
               jsr       (a0)
               rts


          SECTION   data

tekstje     STRING$ {'named PIPE driver v. 1.00',10,'(C) Hans Lub, [.DATE].',10}
dev.name       dc.w 4
               dc.b 'pipe    '
               
sysvar         ds.l 1
first.pipe     dc.l 0
other.pipe     dc.l 0
name           ds.w 1
               ds.b max.len
pipelen        ds.w 1

link           dc.l 0          ; this block of 4 longwords is linked into ..
pipe.io        ds.l 1          ; .. the device driver list     
pipe.open      ds.l 1
pipe.close     ds.l 1               


     END
