1 /*
2 * $LynxId: HTChunk.c,v 1.27 2012/02/07 11:28:44 tom Exp $
3 *
4 * Chunk handling: Flexible arrays
5 * ===============================
6 *
7 */
8
9 #include <HTUtils.h>
10 #include <HTChunk.h>
11
12 #include <LYLeaks.h>
13
14 /*
15 * Initialize a chunk with a certain allocation unit
16 */
HTChunkInit(HTChunk * ch,int grow)17 void HTChunkInit(HTChunk *ch, int grow)
18 {
19 ch->data = 0;
20 ch->growby = grow;
21 ch->size = 0;
22 ch->allocated = 0;
23 }
24
25 /* Create a chunk with a certain allocation unit
26 * --------------
27 */
HTChunkCreate(int grow)28 HTChunk *HTChunkCreate(int grow)
29 {
30 HTChunk *ch = typecalloc(HTChunk);
31
32 if (ch == NULL)
33 outofmem(__FILE__, "creation of chunk");
34
35 HTChunkInit(ch, grow);
36 return ch;
37 }
38
HTChunkCreateMayFail(int grow,int failok)39 HTChunk *HTChunkCreateMayFail(int grow, int failok)
40 {
41 HTChunk *ch = typecalloc(HTChunk);
42
43 if (ch == NULL) {
44 if (!failok) {
45 outofmem(__FILE__, "creation of chunk");
46 } else {
47 return ch;
48 }
49 }
50
51 assert(ch != NULL);
52
53 HTChunkInit(ch, grow);
54 ch->failok = failok;
55 return ch;
56 }
57
58 /* Create a chunk with a certain allocation unit and ensured size
59 * --------------
60 */
HTChunkCreate2(int grow,size_t needed)61 HTChunk *HTChunkCreate2(int grow, size_t needed)
62 {
63 HTChunk *ch = typecalloc(HTChunk);
64
65 if (ch == NULL)
66 outofmem(__FILE__, "HTChunkCreate2");
67
68 assert(ch != NULL);
69
70 HTChunkInit(ch, grow);
71 if (needed-- > 0) {
72 /* Round up */
73 ch->allocated = (int) (needed - (needed % (size_t) ch->growby)
74 + (unsigned) ch->growby);
75 CTRACE((tfp, "HTChunkCreate2: requested %d, allocate %u\n",
76 (int) needed, (unsigned) ch->allocated));
77 ch->data = typecallocn(char, (unsigned) ch->allocated);
78
79 if (!ch->data)
80 outofmem(__FILE__, "HTChunkCreate2 data");
81 }
82 return ch;
83 }
84
85 /* Clear a chunk of all data
86 * --------------------------
87 */
HTChunkClear(HTChunk * ch)88 void HTChunkClear(HTChunk *ch)
89 {
90 FREE(ch->data);
91 ch->size = 0;
92 ch->allocated = 0;
93 }
94
95 /* Free a chunk (and its chain, if any)
96 * ------------------------------------
97 */
HTChunkFree(HTChunk * ch)98 void HTChunkFree(HTChunk *ch)
99 {
100 HTChunk *next;
101
102 do {
103 next = ch->next;
104 FREE(ch->data);
105 FREE(ch);
106 ch = next;
107 } while (ch != NULL);
108 }
109
110 /* Realloc the chunk
111 * -----------------
112 */
HTChunkRealloc(HTChunk * ch,int growby)113 BOOL HTChunkRealloc(HTChunk *ch, int growby)
114 {
115 char *data;
116
117 ch->allocated = ch->allocated + growby;
118
119 data = (ch->data
120 ? typeRealloc(char, ch->data, ch->allocated)
121 : typecallocn(char, ch->allocated));
122
123 if (data) {
124 ch->data = data;
125 } else if (ch->failok) {
126 HTChunkClear(ch); /* allocation failed, clear all data - kw */
127 return FALSE; /* caller should check ch->allocated - kw */
128 } else {
129 outofmem(__FILE__, "HTChunkRealloc");
130 }
131 return TRUE;
132 }
133
134 /* Append a character
135 * ------------------
136 */
HTChunkPutc(HTChunk * ch,unsigned c)137 void HTChunkPutc(HTChunk *ch, unsigned c)
138 {
139 if (ch->size >= ch->allocated) {
140 if (!HTChunkRealloc(ch, ch->growby))
141 return;
142 }
143 ch->data[ch->size++] = (char) c;
144 }
145
146 /* like above but no realloc: extend to another chunk if necessary */
HTChunkPutc2(HTChunk * ch,int c)147 HTChunk *HTChunkPutc2(HTChunk *ch, int c)
148 {
149 if (ch->size >= ch->allocated) {
150 HTChunk *chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
151
152 ch->next = chunk;
153 ch = chunk;
154 HTChunkPutc(ch, UCH(c));
155 } else {
156 ch->data[ch->size++] = (char) c;
157 }
158 return ch;
159 }
160
161 /* Ensure a certain size
162 * ---------------------
163 */
HTChunkEnsure(HTChunk * ch,int needed)164 void HTChunkEnsure(HTChunk *ch, int needed)
165 {
166 if (needed <= ch->allocated)
167 return;
168 ch->allocated = needed - 1 - ((needed - 1) % ch->growby)
169 + ch->growby; /* Round up */
170 ch->data = (ch->data
171 ? typeRealloc(char, ch->data, ch->allocated)
172 : typecallocn(char, ch->allocated));
173
174 if (ch->data == NULL)
175 outofmem(__FILE__, "HTChunkEnsure");
176 }
177
178 /*
179 * Append a block of characters.
180 */
HTChunkPutb(HTChunk * ch,const char * b,int l)181 void HTChunkPutb(HTChunk *ch, const char *b, int l)
182 {
183 if (l <= 0)
184 return;
185 if (ch->size + l > ch->allocated) {
186 int growby = l - (l % ch->growby) + ch->growby; /* Round up */
187
188 if (!HTChunkRealloc(ch, growby))
189 return;
190 }
191 MemCpy(ch->data + ch->size, b, l);
192 ch->size += l;
193 }
194
195 /* like above but no realloc: extend to another chunk if necessary */
HTChunkPutb2(HTChunk * ch,const char * b,int l)196 HTChunk *HTChunkPutb2(HTChunk *ch, const char *b, int l)
197 {
198 if (l <= 0)
199 return ch;
200 if (ch->size + l > ch->allocated) {
201 HTChunk *chunk;
202 int m = ch->allocated - ch->size;
203
204 MemCpy(ch->data + ch->size, b, (unsigned) m);
205 ch->size += m;
206
207 chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
208 ch->next = chunk;
209 ch = chunk;
210 HTChunkPutb(ch, b + m, l - m);
211 } else {
212 MemCpy(ch->data + ch->size, b, (unsigned) l);
213 ch->size += l;
214 }
215 return ch;
216 }
217
218 #define PUTC(code) ch->data[ch->size++] = (char)(code)
219 #define PUTC2(code) ch->data[ch->size++] = (char)(0x80|(0x3f &(code)))
220
221 /*
222 * Append a character encoded as UTF-8.
223 */
HTChunkPutUtf8Char(HTChunk * ch,UCode_t code)224 void HTChunkPutUtf8Char(HTChunk *ch, UCode_t code)
225 {
226 int utflen;
227
228 if (TOASCII(code) < 128)
229 utflen = 1;
230 else if (code < 0x800L) {
231 utflen = 2;
232 } else if (code < 0x10000L) {
233 utflen = 3;
234 } else if (code < 0x200000L) {
235 utflen = 4;
236 } else if (code < 0x4000000L) {
237 utflen = 5;
238 } else if (code <= 0x7fffffffL) {
239 utflen = 6;
240 } else
241 utflen = 0;
242
243 if (ch->size + utflen > ch->allocated) {
244 int growby = (ch->growby >= utflen) ? ch->growby : utflen;
245
246 if (!HTChunkRealloc(ch, growby))
247 return;
248 }
249
250 switch (utflen) {
251 case 0:
252 return;
253 case 1:
254 ch->data[ch->size++] = (char) code;
255 return;
256 case 2:
257 PUTC(0xc0 | (code >> 6));
258 break;
259 case 3:
260 PUTC(0xe0 | (code >> 12));
261 break;
262 case 4:
263 PUTC(0xf0 | (code >> 18));
264 break;
265 case 5:
266 PUTC(0xf8 | (code >> 24));
267 break;
268 case 6:
269 PUTC(0xfc | (code >> 30));
270 break;
271 }
272 switch (utflen) {
273 case 6:
274 PUTC2(code >> 24);
275 /* FALLTHRU */
276 case 5:
277 PUTC2(code >> 18);
278 /* FALLTHRU */
279 case 4:
280 PUTC2(code >> 12);
281 /* FALLTHRU */
282 case 3:
283 PUTC2(code >> 6);
284 /* FALLTHRU */
285 case 2:
286 PUTC2(code);
287 break;
288 }
289 }
290
291 /* Terminate a chunk
292 * -----------------
293 */
HTChunkTerminate(HTChunk * ch)294 void HTChunkTerminate(HTChunk *ch)
295 {
296 HTChunkPutc(ch, (char) 0);
297 }
298
299 /* Append a string
300 * ---------------
301 */
HTChunkPuts(HTChunk * ch,const char * s)302 void HTChunkPuts(HTChunk *ch, const char *s)
303 {
304 const char *p;
305
306 if (s != NULL) {
307 for (p = s; *p; p++) {
308 if (ch->size >= ch->allocated) {
309 if (!HTChunkRealloc(ch, ch->growby))
310 break;
311 }
312 ch->data[ch->size++] = *p;
313 }
314 }
315 }
316
317 /* like above but no realloc: extend to another chunk if necessary */
HTChunkPuts2(HTChunk * ch,const char * s)318 HTChunk *HTChunkPuts2(HTChunk *ch, const char *s)
319 {
320 const char *p;
321
322 if (s != NULL) {
323 for (p = s; *p; p++) {
324 if (ch->size >= ch->allocated) {
325 HTChunk *chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
326
327 ch->next = chunk;
328 ch = chunk;
329 HTChunkPuts(ch, p);
330 break;
331 }
332 ch->data[ch->size++] = *p;
333 }
334 }
335 return ch;
336 }
337