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