/* -*-mode: C; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */ /* * Copyright 2009 by Eric House (xwords@eehouse.org). All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef USE_BUFQUEUE #include "bufqueue.h" #ifdef CPLUS extern "C" { #endif static XP_U16 roundUp( XP_U16 num ) { /* Keep ptrs word-aligned so can case to XP_U16* */ return (num + 1) & 0xFFFE; } #ifdef DEBUG static void printQueue( const BufQueue* bq ) { XP_U16 head = bq->head; XP_U16 counter; for ( counter = 0; head < bq->tail; ++counter ) { XP_U16 len = *(XP_U16*)&bq->base[head]; XP_LOGF( "item %d, len %d", counter, len ); head += roundUp( len + 2 ); } } #else # define printQueue( bq ) #endif static XP_Bool haveSpace( const BufQueue* bq, XP_U16 len ) { return (bq->tail + len + 2) < bq->bufSize; } static void shiftDown( BufQueue* bq ) { if ( bq->head > 0 ) { XP_ASSERT( bq->tail > bq->head ); XP_MEMMOVE( bq->base, &bq->base[bq->head], bq->tail - bq->head ); bq->tail -= bq->head; bq->head = 0; } } void bqInit( BufQueue* bq, XP_U8* buf, XP_U16 buflen ) { bq->base = buf; bq->bufSize = buflen; bq->head = bq->tail = 0; } XP_Bool bqAdd( BufQueue* bq, const XP_U8* buf, XP_U16 len ) { XP_Bool success = XP_FALSE; if ( !haveSpace( bq, len ) ) { shiftDown( bq ); } success = haveSpace( bq, len ); if ( success ) { XP_U8* tailp = &bq->base[bq->tail]; *(XP_U16*)tailp = len; XP_MEMCPY( tailp+2, buf, len ); bq->tail += roundUp(len + 2); } printQueue( bq ); return success; } XP_Bool bqGet( BufQueue* bq, const XP_U8** buf, XP_U16* len ) { XP_Bool have = bq->head < bq->tail; if ( have ) { *len = *(XP_U16*)&bq->base[bq->head]; *buf = &bq->base[bq->head+2]; } return have; } void bqRemoveOne( BufQueue* bq ) { XP_U16 len; XP_ASSERT( bq->head != bq->tail ); len = *(XP_U16*)&bq->base[bq->head]; bq->head += roundUp( len + 2 ); XP_ASSERT( bq->head <= bq->tail ); /* can we reset for free */ if ( bq->head == bq->tail ) { bq->head = bq->tail = 0; } } void bqRemoveAll( BufQueue* bq ) { bq->head = bq->tail = 0; } #ifdef CPLUS } #endif #endif /* USE_BUFQUEUE */