muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* fifo.c */
/* $Id: fifo.c,v 1.2 1992/10/11 15:15:57 nils Exp $ */

#include <stdio.h>
#include "externs.h"
#include "nalloc.h"
#include "fifo.h"
#include "db.h"
#include "config.h"

#define NULL 0

static NALLOC *na=NULL; /* fifo memory allocation */

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' || c=='\r') /* accept either \n or \r */
	    {
	      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);  
}

/*main()
  {
  char buff[100];
  int a;
  FIFO *fi=fi_open(NULL,20000);
  char *s="This\nIs\nA test\nof the\nemergency\ncat\neating system\n";
  while(1)
  {
  for(a=0;a<(rand() & 15);a++)
  fi_write(fi,s,strlen(s));
  while(fi_gets(fi,buff,100) && ((rand() & 31)!=1))
  printf("[[%s]]\n",buff);
  }
  }*/