        page ,132
        title   IQUEUE - Add an 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 ISTACK for a LIFO stack.

        DECLARE SUB      IQput (intval%) 'put an item in the queue
        DECLARE FUNCTION IQget% ()       'get an item from the queue
        DECLARE FUNCTION IQfree% ()      'TRUE if any room in queue
        DECLARE FUNCTION IQavail% ()     'TRUE if anything in queue
        DECLARE SUB      IQflush ()      '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)

IQueue  dw      Qsize dup (0)
                                                                        page +
Querr:: INT     4               ; report "Overflow" to BASIC

IQput           PROC ival

; Accepts an integer value and places it into the queue.
; Generates an Overflow Error in QB if there is no room in the queue.

        mov     bx, ival        ; get pointer to passed value
        mov     ax, [bx]        ; get actual value
        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
        mov     IQueue[bx], ax  ; place item into queue
        ret

IQput           ENDP
                                                                        page +
IQget           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
        shl     bx, 1           ; turn QGetPtr into a word pointer
        mov     ax, IQueue[bx]  ; retrieve value from stack
        shr     bx, 1           ; element number again
        cmp     bx, QPutPtr     ; did we bump into the head?
        jne     @f              ; no, still data left
        mov     QPutPtr, 0      ; yes, out of data now...
        mov     QGetPtr, 0      ; reset the pointers
@@:     ret                     ; return retrieved value

IQget           ENDP
                                                                        page +
IQflush         PROC

; Empty the queue by setting the head & tail equal

        mov     QPutPtr, 0
        mov     QGetPtr, 0
        ret

IQflush         ENDP

IQfree          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

IQfree          ENDP

IQavail         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

IQavail         ENDP
                                                                        page +
        end

