home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_08_05 / 8n05035a < prev    next >
Text File  |  1990-04-18  |  13KB  |  288 lines

  1. /*
  2. prb.c - Packetized Ring Buffer demonstration
  3.  
  4. (c) Copyright 1989, 1990 Martin J. Stitt
  5. */
  6.  
  7. #include <alloc.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10.  
  11. typedef unsigned char byte;
  12. typedef unsigned int word;
  13.  
  14. typedef struct {
  15.   word prb_totbytes;     /* define the ring buffer's size */
  16.   byte *prb_base;        /* ptr to base of buffer */
  17.   byte *prb_head;        /* head ptr - from which data is read */
  18.   byte *prb_tail;        /* tail ptr - at which data is written */
  19.   word prb_free;         /* amount of free space in the buffer */
  20.   word prb_eobofs;       /* offset of byte just past the eob */
  21.   byte prb_packets;      /* number of records in the buffer */
  22.   byte prb_use_rectype;  /* indicates use of two byte headers */
  23.   word prb_overflow;     /* indicates when a record is too large */
  24.   byte prb_max_dsize;    /* maximum size for record's data */
  25.   } prb_type;
  26.  
  27. /*- prb_init -----------------------------------------------------------
  28. entry parms:    ptr to a partially initialized prb structure
  29.         prb_base must point to an allocated buffer
  30.         prb_totbytes must be its size
  31.         prb_use_rectype must be assigned
  32. exit parms:    function return value != 0 when the last buffer
  33.         offset is 0xFFFF
  34. notes: call before writing and reading.  can recall later to flush the
  35. ring buffer.  can ignore return value on sucessive calls.
  36. ------------------------------------------------------------------------*/
  37. word prb_init(prb_type *b) {
  38.  
  39.   b->prb_head = b->prb_base;                 /* initialize the pointers */
  40.   b->prb_tail = b->prb_base;                 /* to flush the buffer */
  41.   b->prb_free = b->prb_totbytes;
  42.   b->prb_packets = 0;
  43.   b->prb_max_dsize = 255-1;                  /* -1 for the header byte */
  44.   if(b->prb_use_rectype) b->prb_max_dsize--; /* if using 2 byte header */
  45.   b->prb_overflow = 0;
  46.   b->prb_eobofs = (word) b->prb_base + b->prb_totbytes;
  47.   return((b->prb_eobofs == 0) ? 1 : 0);
  48.   }
  49.  
  50. /*- prb_write_data ---------------------------------------------------------
  51. entry parms:    ptr to buffer structure
  52.         ptr to caller's data, size of caller's data
  53.         record type code (ignored if prb_use_rectype == 0)
  54. exit parms:    function return value != 0 if overflow
  55. ------------------------------------------------------------------------*/
  56. word prb_write_data(prb_type *b, void *idata, byte dsize, byte rectype) {
  57.  
  58.   byte csize;                     /* data bytes to xfer */
  59.   byte psize;                     /* total packet size */
  60.   word block1;                    /* bytes before wrap of tail */
  61.   byte need_wrap;                 /* flags need for a 2 part xfer */
  62.   word adjust_head;               /* bytes to advance the head ptr */
  63.   word head2end;                  /* bytes before wrap of head */
  64.  
  65.   if(dsize == 0) return(1);       /* anything to insert? */
  66.   if(dsize > b->prb_max_dsize) return(1); /* don't allow oversized data */
  67.   psize = dsize+1;                /* +1 for the pkt size header byte */
  68.   if(b->prb_use_rectype) {        /* if using a record type */ 
  69.     psize++;                      /* account for header byte */
  70.     }
  71.   if(psize > b->prb_totbytes) {   /* if record too large for buffer */ 
  72.     if(psize < b->prb_overflow) { /* record overflow unless another */
  73.       b->prb_overflow = psize;    /* larger recorded */
  74.       }
  75.     return(1);                    /* indicate a problem */
  76.     }
  77.   while(psize > b->prb_free) {    /* while not enough free room */ 
  78.     b->prb_free += *b->prb_head;  /* adjust free to show deletion */
  79.     b->prb_packets--;             /* adjust accounting of pkts */
  80.     adjust_head = *b->prb_head;   /* fetch size of pkt to be deleted */
  81.     head2end = b->prb_eobofs - (word) b->prb_head; /* calc bytes till wrap */
  82.     if(adjust_head > head2end) {  /* will deletion involve a wrap? */ 
  83.       adjust_head -= head2end;    /* calc bytes in second portion */
  84.       b->prb_head = b->prb_base;  /* wrap around */
  85.       }
  86.     b->prb_head += adjust_head;   /* advance the head pointer */
  87.     if((word) b->prb_head == b->prb_eobofs) {  /* if pkt deleted just fit */ 
  88.       b->prb_head = b->prb_base;  /* need to wrap */
  89.       }
  90.     }
  91.   block1 = b->prb_eobofs - (word) b->prb_tail; /* calc size of 1st block */
  92.   b->prb_packets++;               /* update accounting of pkts */
  93.   b->prb_free -= psize;           /* update accounting of free space */
  94.   csize = psize-1;                /* sub 1 for pkt size header byte */
  95.   *(b->prb_tail++) = psize;       /* write header byte, advance tail */
  96.   need_wrap = 0;                  /* initialize flag */
  97.   if(psize > block1) {            /* if won't all fit in 1st block */ 
  98.     need_wrap = 1;                /* write remainder in 2nd block */
  99.     csize = block1-1;             /* -1 for header already written */
  100.     if(csize == 0) {              /* if block1 only had 1 byte */ 
  101.       b->prb_tail = b->prb_base;  /* do the wrap now */
  102.       need_wrap = 0;              /* don't need to wrap later */
  103.       csize = psize-1;            /* -1 for header already written */
  104.       }
  105.     }
  106.   if(b->prb_use_rectype) {        /* if type code to be inserted */ 
  107.     *(b->prb_tail++) = rectype;   /* insert it now and advance tail */
  108.     csize--;                      /* account for type code */
  109.     if(csize == 0) {              /* if block1 only had 2 bytes */ 
  110.       b->prb_tail = b->prb_base;  /* do the wrap now */
  111.       need_wrap = 0;              /* don't need to wrap later */
  112.       csize = psize-2;            /* account for 2 bytes in header */
  113.       }
  114.     }
  115.   memmove(b->prb_tail,idata,csize);     /* insert csize bytes into buffer */
  116.   b->prb_tail += csize;                 /* advance tail past new data */
  117.   if(need_wrap)    {                       /* if more data left to insert */ 
  118.     b->prb_tail = b->prb_base;          /* wrap the tail back around */
  119.     (byte) idata += csize;              /* advance the caller's pointer */
  120.     memmove(b->prb_tail,idata,(psize-block1)); /* insert the remaining data */
  121.     b->prb_tail += (psize-block1);
  122.     }
  123.   if(b->prb_eobofs == (word) b->prb_tail) { /* if blk went just up to end */ 
  124.     b->prb_tail = b->prb_base;              /* need to wrap tail back around */
  125.     }
  126.   return(0);                                /* indicate success */
  127.   }
  128.  
  129. /*- prb_read_rectype ---------------------------------------------------
  130. entry parms:    ptr to buffer structure
  131.         address of byte to receive rectype
  132. exit parms:    function return value is data size
  133.         0 means buffer is empty
  134.  
  135. notes: presumes all ring buffer records contain a rectype byte in 
  136. their header.  if the buffer is empty, the rectype value returned 
  137. will be garbage.
  138. ------------------------------------------------------------------------*/
  139. byte prb_read_rectype(prb_type *b, byte *rectype) {
  140.  
  141.   byte *tptr;                         /* local scratch pointer */
  142.  
  143.   if(b->prb_packets == 0) return(0);  /* anything in buffer? */
  144.   tptr = b->prb_head + 1;             /* point to the record type code */
  145.   if(b->prb_eobofs == (word) tptr) {  /* need to wrap to read */ 
  146.     tptr = b->prb_base;               /* the 2nd byte? */
  147.     }
  148.   *rectype = *tptr;                   /* transfer rectype to caller */
  149.   return(*b->prb_head-2);             /* return the record size */
  150.   }
  151.  
  152. /*- prb_read_data -----------------------------------------------------------
  153. entry parms:    ptr to buffer structure
  154.         address of buffer to receive record contents
  155. exit parms:    function return value is data size
  156.         0 means buffer is empty
  157.  
  158. notes: presumes caller has referenced any recorded rectype and has 
  159. supplied a pointer to a large enough buffer.  *prb_head can be
  160. referenced to verify the size requirement.
  161. ------------------------------------------------------------------------*/
  162. byte prb_read_data(prb_type *b, void *dest) {
  163.  
  164.   byte dsize;                       /* data bytes in packet */
  165.   byte csize;                       /* bytes to transfer */
  166.   byte rsize;                       /* bytes left when need 2 xfers */
  167.   word block1;                      /* bytes before wrap */
  168.  
  169.   if(b->prb_packets == 0) return(0); /* make sure buffer has data */
  170.   b->prb_free += *b->prb_head;      /* adjust free to show deletion */
  171.   b->prb_packets--;                 /* adjust accounting of packets */
  172.   rsize = 0;                        /* init remainder var */
  173.   csize = *b->prb_head;             /* fetch the record size */
  174.   dsize = csize - 1;                /* record the data size */
  175.   block1 = b->prb_eobofs - (word) b->prb_head; /* calc size of 1st block */
  176.   if(csize > block1) {              /* if a wrap will be required */ 
  177.     rsize = csize - block1;         /* calculate the remainder */
  178.     csize = block1;                 /* adjust csize to do 1st blk only */
  179.     }
  180.   csize--;                          /* account for record size header */
  181.   b->prb_head++;                    /* step past record size header */
  182.   if(csize == 0) {                  /* if done with 1st block already */ 
  183.     b->prb_head = b->prb_base;      /* wrap the head back around */
  184.     csize = rsize;                  /* start accounting with remainder */
  185.     rsize = 0;                      /* signal that wrap has been done */
  186.     }
  187.   if(b->prb_use_rectype) {          /* if using a two byte header */ 
  188.     b->prb_head++;                  /* step past the record type */
  189.     csize--;                        /* adjust accounting */
  190.     dsize--;                        /* adjust accounting */
  191.     if(csize == 0) {                /* if done with 1st block */ 
  192.       b->prb_head = b->prb_base;    /* wrap the head back around */
  193.       csize = rsize;                /* start accounting with remainder */
  194.       rsize = 0;                    /* signal that wrap has been done */
  195.       }
  196.     }
  197.   memmove(dest,b->prb_head,csize);  /* tranfer 1st block to caller */
  198.   b->prb_head += csize;             /* advance head past copied data */
  199.   if(rsize != 0) {                  /* if any remainder in a 2nd block */ 
  200.     b->prb_head = b->prb_base;      /* wrap the head back around */
  201.     (byte) dest += csize;           /* advance dest past copied data */
  202.     memmove(dest,b->prb_head,rsize); /* transfer the 2nd block */
  203.     b->prb_head += rsize;           /* advance head past copied data */
  204.     }
  205.   if(b->prb_eobofs == (word) b->prb_head) { /* if blk went just up to end */ 
  206.     b->prb_head = b->prb_base;      /* need to wrap head back around */
  207.     }
  208.   return(dsize);                    /* report the data size */
  209.   }
  210.  
  211. /*------------------------------- main ------------------------------*/
  212.  
  213. main() {
  214.  
  215.   prb_type sample;                      /* record to hold buffer data */
  216.   byte workbuf[256];                    /* general purpose buffer */
  217.   byte rlen;                            /* size of data in read records */
  218.   word x,y;                             /* general purpose words */
  219.   byte rectype;                         /* type of record being read */
  220.  
  221.   sample.prb_totbytes = 100;
  222.   sample.prb_use_rectype = 0;
  223.   if((sample.prb_base = malloc(sample.prb_totbytes)) == NULL) {
  224.     printf("\nInsufficient memory\n");
  225.     exit(1);
  226.     }
  227.   if(prb_init(&sample) != 0) {          /* make sure position is ok */ 
  228.     printf("\nBuffer ends at FFFF\n");
  229.     exit(1);
  230.     }
  231.  
  232.   /* 
  233.   write some strings into the buffer.  since all packets will hold
  234.   the same type of data, the rectype field is not used.
  235.   */
  236.  
  237.   strcpy(workbuf,"1234567890123456789012345678901234567890123456789");
  238.   prb_write_data(&sample,workbuf,strlen(workbuf),0);
  239.   strcpy(workbuf,"123456789012345678901234567890123456789012345678");
  240.   prb_write_data(&sample,workbuf,strlen(workbuf),0);
  241.   strcpy(workbuf,"this will cause a wrap");
  242.   prb_write_data(&sample,workbuf,strlen(workbuf),0);
  243.  
  244.   /* dump the buffer's contents */
  245.  
  246.   printf("\n\n");
  247.   while((rlen = prb_read_data(&sample,workbuf)) != 0) {
  248.     *(workbuf+rlen) = 0;                /* add string terminator */
  249.     puts(workbuf);
  250.     }
  251.  
  252.   /*
  253.   write some differing types of records.  text strings will be 
  254.   identified by a rectype of 0 and integers with a rectype of 1.
  255.   */
  256.  
  257.   sample.prb_use_rectype = 1;
  258.   prb_init(&sample);    /* flush buffer and activate record types */
  259.   strcpy(workbuf,"text is rectype 0");
  260.   prb_write_data(&sample,workbuf,strlen(workbuf),0);
  261.   x = 0x1234;
  262.   prb_write_data(&sample,&x,2,1);
  263.   strcpy(workbuf,"more text");
  264.   prb_write_data(&sample,workbuf,strlen(workbuf),0);
  265.   prb_write_data(&sample,"can send a literal string",25,0);
  266.   prb_write_data(&sample,"but must count its chars",24,0);
  267.   prb_write_data(&sample,"this will cause a wrap",22,0);
  268.  
  269.   /* dump the buffer's contents */
  270.  
  271.   printf("\n\n");
  272.   while((rlen = prb_read_rectype(&sample,&rectype)) != 0) {
  273.     switch(rectype) {
  274.     case 0:                             /* deal with string records */
  275.       prb_read_data(&sample,workbuf);
  276.       *(workbuf+rlen) = 0;              /* add a string terminator */
  277.       printf("rectype 0: %s\n",workbuf);
  278.       break;
  279.     case 1:                             /* deal with integer records */
  280.       prb_read_data(&sample,&y);
  281.       printf("rectype 1: %04X\n",y);
  282.       break;
  283.     default:
  284.       printf("\nError - undefined rectype: %d\n",rectype);
  285.       }
  286.     }
  287.   }
  288.