1 /*
2 buffer.c
3 last touched in Par 1.53.0
4 last meaningful change in Par 1.50
5 Copyright 1993, 1996 Adam M. Costello
6 
7 This is ANSI C code (C89).
8 
9 additem(), copyitems(), and nextitem() rely on the fact that
10 sizeof (char) is 1.  See section A7.4.8 of The C Programming
11 Language, Second Edition, by Kerninghan and Ritchie.
12 
13 */
14 
15 
16 #include "buffer.h"  /* Makes sure we're consistent with the prototypes. */
17 
18 #include "errmsg.h"
19 
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #undef NULL
25 #define NULL ((void *) 0)
26 
27 #ifdef DONTFREE
28 #define free(ptr)
29 #endif
30 
31 
32 struct buffer {
33   struct block *firstblk, /* The first block.                    */
34                *current,  /* The last non-empty block, or        */
35                           /* firstblk if all are empty.          */
36                *nextblk;  /* The block containing the item to be */
37                           /* returned by nextitem(), or NULL.    */
38   int nextindex;          /* Index of item in nextblock->items.  */
39   size_t itemsize;        /* The size of an item.                */
40 };
41 
42 typedef struct block {
43   struct block *next;  /* The next block, or NULL if none.              */
44   void *items;         /* Storage for the items in this block.          */
45   int maxhere,         /* Number of items that fit in *items.           */
46       numprevious,     /* Total of numhere for all previous blocks.     */
47       numhere;         /* The first numhere slots in *items are filled. */
48 } block;
49 
50 
newbuffer(size_t itemsize,errmsg_t errmsg)51 buffer *newbuffer(size_t itemsize, errmsg_t errmsg)
52 {
53   buffer *buf;
54   block *blk;
55   void *items;
56   int maxhere;
57 
58   maxhere = 124 / itemsize;
59   if (maxhere < 4) maxhere = 4;
60 
61   buf = malloc(sizeof (buffer));
62   blk = malloc(sizeof (block));
63   items = malloc(maxhere * itemsize);
64   if (!buf || !blk || !items) {
65     strcpy(errmsg,outofmem);
66     goto nberror;
67   }
68 
69   buf->itemsize = itemsize;
70   buf->firstblk = buf->current = buf->nextblk = blk;
71   buf->nextindex = 0;
72   blk->next = NULL;
73   blk->numprevious = blk->numhere = 0;
74   blk->maxhere = maxhere;
75   blk->items = items;
76 
77   *errmsg = '\0';
78   return buf;
79 
80 nberror:
81 
82   if (buf) free(buf);
83   if (blk) free(blk);
84   if (items) free(items);
85   return NULL;
86 }
87 
88 
freebuffer(buffer * buf)89 void freebuffer(buffer *buf)
90 {
91   block *blk, *tmp;
92 
93   blk = buf->firstblk;
94   while (blk) {
95     tmp = blk;
96     blk = blk->next;
97     if (tmp->items) free(tmp->items);
98     free(tmp);
99   }
100 
101   free(buf);
102 }
103 
104 
clearbuffer(buffer * buf)105 void clearbuffer(buffer *buf)
106 {
107   block *blk;
108 
109   for (blk = buf->firstblk;  blk;  blk = blk->next)
110     blk->numhere = 0;
111 
112   buf->current = buf->firstblk;
113 }
114 
115 
additem(buffer * buf,const void * item,errmsg_t errmsg)116 void additem(buffer *buf, const void *item, errmsg_t errmsg)
117 {
118   block *blk, *new;
119   void *items;
120   int maxhere;
121   size_t itemsize = buf->itemsize;
122 
123   blk = buf->current;
124 
125   if (blk->numhere == blk->maxhere) {
126     new = blk->next;
127     if (!new) {
128       maxhere = 2 * blk->maxhere;
129       new = malloc(sizeof (block));
130       items = malloc(maxhere * itemsize);
131       if (!new || !items) {
132         strcpy(errmsg,outofmem);
133         goto aierror;
134       }
135       blk->next = new;
136       new->next = NULL;
137       new->maxhere = maxhere;
138       new->numprevious = blk->numprevious + blk->numhere;
139       new->numhere = 0;
140       new->items = items;
141     }
142     blk = buf->current = new;
143   }
144 
145   memcpy( ((char *) blk->items) + (blk->numhere * itemsize), item, itemsize );
146 
147   ++blk->numhere;
148 
149   *errmsg = '\0';
150   return;
151 
152 aierror:
153 
154   if (new) free(new);
155   if (items) free(items);
156 }
157 
158 
numitems(buffer * buf)159 int numitems(buffer *buf)
160 {
161   block *blk = buf->current;
162   return blk->numprevious + blk->numhere;
163 }
164 
165 
copyitems(buffer * buf,errmsg_t errmsg)166 void *copyitems(buffer *buf, errmsg_t errmsg)
167 {
168   int n;
169   void *r;
170   block *blk, *b;
171   size_t itemsize = buf->itemsize;
172 
173   b = buf->current;
174   n = b->numprevious + b->numhere;
175   if (!n) return NULL;
176 
177   r = malloc(n * itemsize);
178   if (!r) {
179     strcpy(errmsg,outofmem);
180     return NULL;
181   }
182 
183   b = b->next;
184 
185   for (blk = buf->firstblk;  blk != b;  blk = blk->next)
186     memcpy( ((char *) r) + (blk->numprevious * itemsize),
187             blk->items, blk->numhere * itemsize);
188 
189   *errmsg = '\0';
190   return r;
191 }
192 
193 
rewindbuffer(buffer * buf)194 void rewindbuffer(buffer *buf)
195 {
196   buf->nextblk = buf->firstblk;
197   buf->nextindex = 0;
198 }
199 
200 
nextitem(buffer * buf)201 void *nextitem(buffer *buf)
202 {
203   void *r;
204 
205   if (!buf->nextblk || buf->nextindex >= buf->nextblk->numhere)
206     return NULL;
207 
208   r = ((char *) buf->nextblk->items) + (buf->nextindex * buf->itemsize);
209 
210   if (++buf->nextindex >= buf->nextblk->maxhere) {
211     buf->nextblk = buf->nextblk->next;
212     buf->nextindex = 0;
213   }
214 
215   return r;
216 }
217