1 /*								      HTChunk.c
2 **	CHUNK HANDLING:	FLEXIBLE ARRAYS
3 **
4 **	(c) COPYRIGHT MIT 1995.
5 **	Please first read the full copyright statement in the file COPYRIGH.
6 **	@(#) $Id$
7 **
8 ** history:	AL, HF	28 Apr 94, Now chunk->data is filled by '\0' so
9 **			that the string is terminated at any time. That makes
10 **			HTChunk_terminate not needed any more, but never mind.
11 **		EGP	15 Mar 96, Added CString conversions.
12 **
13 */
14 
15 /* Library include files */
16 #include "wwwsys.h"
17 #include "HTUtils.h"
18 #include "HTChunk.h"				         /* Implemented here */
19 
20 struct _HTChunk {
21     int		size;		/* In bytes			*/
22     int		growby;		/* Allocation unit in bytes	*/
23     int		allocated;	/* Current size of *data	*/
24     char *	data;		/* Pointer to malloced area or 0 */
25 };
26 
27 /* --------------------------------------------------------------------------*/
28 
29 /*	Create a chunk with a certain allocation unit
30 **	--------------
31 */
HTChunk_new(int grow)32 PUBLIC HTChunk * HTChunk_new (int grow)
33 {
34     HTChunk * ch;
35     if ((ch = (HTChunk  *) HT_CALLOC(1, sizeof(HTChunk))) == NULL)
36         HT_OUTOFMEM("HTChunk_new");
37     ch->growby = grow;
38     return ch;
39 }
40 
41 
42 /*	Clear a chunk of all data
43 **	--------------------------
44 **	Zero the space but do NOT HT_FREE it. We zero because we promise to have
45 **	a NUL terminated string at all times.
46 */
HTChunk_clear(HTChunk * ch)47 PUBLIC void HTChunk_clear (HTChunk * ch)
48 {
49     if (ch) {
50 	ch->size = 0;
51 	if (ch->data) memset((void *) ch->data, '\0', ch->allocated);
52     }
53 }
54 
55 
56 /*	Free a chunk
57 **	------------
58 */
HTChunk_delete(HTChunk * ch)59 PUBLIC void HTChunk_delete (HTChunk * ch)
60 {
61     if (ch) {
62 	HT_FREE(ch->data);
63     	HT_FREE(ch);
64     }
65 }
66 
HTChunk_data(HTChunk * ch)67 PUBLIC char * HTChunk_data (HTChunk * ch)
68 {
69     return ch ? ch->data : NULL;
70 }
71 
HTChunk_size(HTChunk * ch)72 PUBLIC int HTChunk_size (HTChunk * ch)
73 {
74     return ch ? ch->size : -1;
75 }
76 
HTChunk_truncate(HTChunk * ch,int length)77 PUBLIC BOOL HTChunk_truncate (HTChunk * ch, int length)
78 {
79     if (ch && length >= 0 && length < ch->size) {
80 	memset(ch->data+length, '\0', ch->size-length);
81 	ch->size = length;
82 	return YES;
83     }
84     return NO;
85 }
86 
87 /*      Set the "size" of the Chunk's data
88 **      -----------------------------------
89 ** The actual allocated length must  be at least 1 byte longer to hold the
90 ** mandatory null terminator.
91 */
HTChunk_setSize(HTChunk * ch,int length)92 PUBLIC BOOL HTChunk_setSize (HTChunk * ch, int length)
93 {
94     if (ch && length >= 0) {
95 	if (length < ch->size)
96 	    memset(ch->data+length, '\0', ch->size-length);
97 	else if (length >= ch->allocated)
98 	    HTChunk_ensure(ch, length - ch->size);
99 	ch->size = length;
100 	return YES;
101     }
102     return NO;
103 }
104 
105 /*	Create a chunk from an allocated string
106 **	---------------------------------------
107 */
HTChunk_fromCString(char * str,int grow)108 PUBLIC HTChunk * HTChunk_fromCString (char * str, int grow)
109 {
110     HTChunk * ch;
111     ch = HTChunk_new(grow);
112     if (str) {
113 	ch->data = str;			/* can't handle non-allocated str */
114 	ch->size = strlen(str);
115 	ch->allocated = ch->size + 1; /* [SIC] bobr */
116     }
117     return ch;
118 }
119 
120 /*	Create a chunk from an allocated buffer
121 **	---------------------------------------
122 */
HTChunk_fromBuffer(char * buf,int buflen,int size,int grow)123 PUBLIC HTChunk * HTChunk_fromBuffer (char * buf, int buflen, int size, int grow)
124 {
125     HTChunk * ch;
126     ch = HTChunk_new(grow);
127     if (buf) {
128 	ch->data = buf;
129 	ch->size = ch->allocated = buflen;
130 	if (size < buflen)
131 	    HTChunk_setSize(ch, size);	/* This ensures the end is 0-filled */
132     }
133     return ch;
134 }
135 
136 /*	Free a chunk but keep the data
137 **	------------------------------
138 */
HTChunk_toCString(HTChunk * ch)139 PUBLIC char * HTChunk_toCString (HTChunk * ch)
140 {
141     char * ret = 0;
142     if (ch) {
143 	ret = ch->data;
144     	HT_FREE(ch);
145     }
146     return ret;
147 }
148 
149 /*	Append a character
150 **	------------------
151 */
HTChunk_putc(HTChunk * ch,char c)152 PUBLIC void HTChunk_putc (HTChunk * ch, char c)
153 {
154     if (ch) {
155 	if (!ch->data || ch->size >= ch->allocated-1) { /* [SIC] bobr */
156 	    if (ch->data) {
157 		if ((ch->data = (char  *) HT_REALLOC(ch->data,ch->allocated+ch->growby)) == NULL)
158 		    HT_OUTOFMEM("HTChunk_putc");
159 		memset((void *) (ch->data + ch->allocated), '\0', ch->growby);
160 	    } else {
161 		if ((ch->data = (char  *) HT_CALLOC(1, ch->allocated+ch->growby)) == NULL)
162 		    HT_OUTOFMEM("HTChunk_putc");
163 	    }
164 	    ch->allocated += ch->growby;
165 	}
166 	*(ch->data+ch->size++) = c;
167     }
168 }
169 
170 /*	Append a string
171 **	---------------
172 */
HTChunk_puts(HTChunk * ch,const char * s)173 PUBLIC void HTChunk_puts (HTChunk * ch, const char * s)
174 {
175     HTChunk_putb(ch, s, (int) strlen(s));
176 }
177 
178 /*	Append a block
179 **	---------------
180 **	The string is always zero terminated
181 */
HTChunk_putb(HTChunk * ch,const char * block,int len)182 PUBLIC void HTChunk_putb (HTChunk * ch, const char * block, int len)
183 {
184     if (ch && block && len) {
185 	int needed = ch->size+len;
186 	if (needed >= ch->allocated) {
187 	    ch->allocated = needed - needed%ch->growby + ch->growby;
188 	    if (ch->data) {
189 		if ((ch->data = (char *) HT_REALLOC(ch->data, ch->allocated)) == NULL)
190 		    HT_OUTOFMEM("HTChunk_putb");
191 	        memset((void *) (ch->data + needed), '\0', ch->allocated-needed);
192 	    } else {
193 		if ((ch->data = (char *) HT_CALLOC(1, ch->allocated)) == NULL)
194 		    HT_OUTOFMEM("HTChunk_putb");
195 	    }
196 	}
197 	memcpy((void *) (ch->data+ch->size), block, len);
198 	ch->size = needed;
199     }
200 }
201 
HTChunk_terminate(HTChunk * ch)202 PUBLIC void HTChunk_terminate (HTChunk * ch)
203 {
204     HTChunk_putc(ch, '\0');
205 }
206 
207 /*	Ensure a certain size
208 **	---------------------
209 */
HTChunk_ensure(HTChunk * ch,int len)210 PUBLIC void HTChunk_ensure (HTChunk * ch, int len)
211 {
212     if (ch && len > 0) {
213 	int needed = ch->size+len;
214 	if (needed >= ch->allocated) {
215 	    ch->allocated = needed - needed%ch->growby + ch->growby;
216 	    if (ch->data) {
217 		if ((ch->data = (char  *) HT_REALLOC(ch->data, ch->allocated)) == NULL)
218 		    HT_OUTOFMEM("HTChunk_ensure");
219 	        memset((void *) (ch->data + ch->size), '\0', ch->allocated-ch->size);
220 	    } else {
221 		if ((ch->data = (char  *) HT_CALLOC(1, ch->allocated)) == NULL)
222 		    HT_OUTOFMEM("HTChunk_ensure");
223 	    }
224 	}
225     }
226 #if 0
227     if (needed <= ch->allocated) return;
228     ch->allocated = needed-1 - ((needed-1) % ch->growby)
229     			     + ch->growby; /* Round up */
230     ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated)
231 			: (char *)HT_MALLOC(ch->allocated);
232     if (ch->data == NULL) HT_OUTOFMEM(__FILE__, "HTChunk_ensure");
233 #endif
234 }
235