        page ,132
        title   LQUEUE - Add an long-integer FIFO queue to BC/QB
        subttl  Copyright 1990, Editing Services Co.
        comment |

Implements a FIFO stack (circular queue, ring buffer) by adding five
procedures to QB/BC: two SUBs and three FUNCTIONs.
See LSTACK for a LIFO stack.

        DECLARE SUB      LQput (lval&)   'put an item in the queue
        DECLARE FUNCTION LQget& ()       'get an item from the queue
        DECLARE FUNCTION LQfree% ()      'TRUE if any room in queue
        DECLARE FUNCTION LQavail% ()     'TRUE if anything in queue
        DECLARE SUB      LQflush ()      'clear (empty) the queue
        |
                                                                        page +
        .model medium, basic
        .data

QPutPtr dw      0               ; pointer used for storing
QGetPtr dw      0               ; pointer used for retrieving

        .code

Qsize   equ     256             ; size of buffer (one fewer available)

LQueue  dw      (Qsize * 2) dup (-1)
                                                                        page +
Querr:: INT     4               ; report "Overflow" to BASIC

LQput           PROC lval

; Accepts a long-integer value and places it into the queue.
; Generates an Overflow Error in QB if there is no room in the queue.

        mov     bx, lval        ; get pointer to passed value
        mov     ax, [bx]        ; get actual value, low part
        mov     dx, 2[bx]
        mov     bx, QPutPtr     ; get current head
        inc     bx              ; increment it first
        cmp     bx, Qsize       ; see if off end
        jb      @f              ; no, still OK
        xor     bx, bx          ; yes, circulate the pointer
@@:     cmp     bx, QGetPtr     ; did we run into the tail?
        je      querr           ; yes: the queue is FULL
        mov     QPutPtr, bx     ; otherwise, save new head
        shl     bx, 1           ; turn head into a word pointer
        shl     bx, 1           ; then into a dword pointer
        mov     LQueue[bx], ax  ; enqueue item, low part first
        add     bx, 2
        mov     LQueue[bx], dx  ; place high part into queue
        ret

LQput           ENDP

LQget           PROC

; Removes the oldest data item from the queue.
; Generates an Overflow Error if there are no values in the queue.

        mov     bx, QGetPtr     ; get current tail
        cmp     bx, QPutPtr     ; is it at the head?
        jz      querr           ; queue is empty: Overflow error
        inc     bx              ; bump the tail pointer
        cmp     bx, Qsize       ; off end?
        jb      @f              ; no, continue
        xor     bx, bx          ; yes, circulate 
@@:     mov     QGetPtr, bx
        push    bx              ; hold this thought
        shl     bx, 1           ; turn QGetPtr into a word pointer
        shl     bx, 1           ; then into a dword pointer
        mov     ax, LQueue[bx]  ; retrieve low part value from stack
        add     bx, 2
        mov     dx, LQueue[bx]  ; retrieve high part
        pop     bx              ; element number again
        cmp     bx, QPutPtr     ; did we bump into the head?
        jne     @f              ; no, still data left
        mov     QPutPtr, 0      ; out of data, reset pointers
        mov     QGetPtr, 0
@@:     ret                     ; return retrieved value in DX:AX

LQget           ENDP

LQflush         PROC

; Empty the queue by setting the head & tail equal

        mov     QPutPtr, 0
        mov     QGetPtr, 0
        ret

LQflush         ENDP

LQfree          PROC

; Returns TRUE if there is any space left in the queue.

        mov     ax, QPutPtr
        inc     ax
        cmp     ax, Qsize
        jb      @f
        xor     ax, ax
@@:     sub     ax, QGetPtr
        jz      @f
        mov     ax, -1
@@:     ret

LQfree          ENDP

LQavail         PROC

; Returns TRUE if there are any data items waiting in the queue.

        mov     ax, QGetPtr
        sub     ax, QPutPtr
        jz      @f
        mov     ax, -1
@@:     ret

LQavail         ENDP
                                                                        page +
        end

