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