/* fifo.c */
#include "fifo.h"
#include "nalloc.h"
#define NULL 0
static NALLOC *na = NULL;
FIFO *fi_open(fi, size)
FIFO *fi;
int size;
{
FIFO *ifi = fi;
if (!fi)
fi = (FIFO *) malloc(sizeof(FIFO));
fi->maxblk = size / FI_BSIZE;
fi->hoff = fi->toff = 0;
fi->blocks = 0;
if(!na)
na = na_open(sizeof(FI_BLK));
fi->head = fi->tail = (FI_BLK *) na_get(na);
fi->flags = (ifi) ? 0 : FI_FREE;
return (fi);
}
void fi_close(fi)
FIFO *fi;
{
FI_BLK *t, *t1;
fi->tail->next = NULL;
for (t = fi->head; t; t = t1) {
t1 = t->next;
na_free(na, t);
}
if (fi->flags & FI_FREE)
free(fi);
}
void fi_flush(fi)
FIFO *fi;
{
FI_BLK *t, *t1;
fi->tail->next = NULL;
for (t = fi->head; t; t = t1) {
t1 = t->next;
na_free(na, t);
}
fi->head = fi->tail = (FI_BLK *) na_get(na);
fi->toff = fi->hoff = 0;
}
/* write returns 0 for total failure or 1 for success no inbetweens */
int fi_write(fi, buff, size)
FIFO *fi;
char *buff;
int size;
{
if (fi->blocks > fi->maxblk)
return (0);
while (size) {
int asize;
asize = (size > (FI_BSIZE - fi->toff)) ? FI_BSIZE - fi->toff : size;
memcpy(&fi->tail->blk[fi->toff], buff, asize);
fi->toff += asize;
buff += asize;
size -= asize;
/* see if we need to add a new block */
if (fi->toff == FI_BSIZE) {
fi->tail = (fi->tail->next = (FI_BLK *) na_get(na));
fi->blocks++;
fi->toff = 0;
}
}
/* used by fi_gets to know if fifo has been updated */
fi->flags |= FI_CHANGE;
return (1);
}
/* remove # of characters from fifo with no read */
void fi_munch(fi, size)
FIFO *fi;
int size;
{
while (size && ((fi->head != fi->tail) || (fi->toff != fi->hoff))) {
int asize = ((fi->head == fi->tail) ? fi->toff : FI_BSIZE) - fi->hoff;
if (asize > size)
asize = size;
fi->hoff += asize;
size -= asize;
/* if head at end of block then move to next and free it */
if (fi->hoff == FI_BSIZE) {
FI_BLK *next = fi->head->next;
fi->hoff = 0;
na_free(na, fi->head);
fi->blocks--;
fi->head = next;
}
}
}
/* returns a pointer + # of available chars, munch # of chars used after */
int fi_rread(fi, buf)
FIFO *fi;
char **buf;
{
*buf = &fi->head->blk[fi->hoff];
return (((fi->head == fi->tail) ? fi->toff : FI_BSIZE) - fi->hoff);
}
/*
* get a string from fifo terminated by \n, returns pointer on sucess or 0 on
* failure, Note: \n is not included in string
*/
char *fi_gets(fi, buff, size)
FIFO *fi;
char *buff;
int size;
{
char *s;
FI_BLK *blk;
int off;
int munch = 0;
size--;
/* don't try again until fifo updated */
if ((fi->flags & FI_FAILED) && !(fi->flags & FI_CHANGE))
return (0);
fi->flags &= ~(FI_FAILED & FI_CHANGE);
/* scan fifo for \n */
s = buff;
blk = fi->head;
off = fi->hoff;
while (size) {
int asize = ((blk == fi->tail) ? fi->toff : FI_BSIZE) - off;
if (asize > size)
asize = size;
size -= asize;
while (asize) {
char c;
c = *s++ = blk->blk[off++];
munch++;
asize--;
/* finally found it */
if (c == '\n') {
s[-1] = 0;
fi_munch(fi, munch);
return (buff);
}
}
/* no luck */
if (size && (blk == fi->tail)) {
fi->flags |= FI_FAILED;
return (0);
}
/* next block */
blk = blk->next;
off = 0;
}
*s++ = 0;
fi_munch(fi, munch);
return (buff);
}