]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_dbufmore.c
uLUt: ul_dbuff_cat do at least partial copy if a space for all data cannot be allocated.
[ulut.git] / ulut / ul_dbufmore.c
1 /*******************************************************************
2   uLan Utilities Library - C library of basic reusable constructions
3
4   ul_dbufmore.c - more functions for dynamically allocated buffer
5
6   (C) Copyright 2001-2004 by Pavel Pisa - Originator
7   (C) Copyright 2003-2004 by Frantisek Vacek - Originator
8
9   The uLan utilities library can be used, copied and modified under
10   next licenses
11     - GPL - GNU General Public License
12     - LGPL - GNU Lesser General Public License
13     - MPL - Mozilla Public License
14     - and other licenses added by project originators
15   Code can be modified and re-distributed under any combination
16   of the above listed licenses. If contributor does not agree with
17   some of the licenses, he/she can delete appropriate line.
18   Warning, if you delete all lines, you are not allowed to
19   distribute source code and/or binaries utilizing code.
20   
21   See files COPYING and README for details.
22
23  *******************************************************************/
24 #include <string.h>
25 #include "ul_utmalloc.h"
26 #include "ul_dbuff.h"
27
28 #ifdef UL_DBUFF_LOGGING
29 #include "ul_log.h"
30 extern UL_LOG_CUST(ulogd_dbuff)
31 #endif /*UL_DBUFF_LOGGING*/
32
33 typedef unsigned char byte;
34
35 //#undef DEBUG
36
37 /**
38  * ul_dbuff_set_capacity - change capacity of buffer to at least @new_capacity
39  * @buf: buffer structure
40  * @new_capacity: new capacity
41  *
42  * Returns real capacity of reallocated buffer
43  */
44 int ul_dbuff_set_capacity(ul_dbuff_t *buf, int new_capacity)
45 {
46     if(new_capacity < 0) new_capacity = 0;
47     #ifdef UL_DBUFF_LOGGING
48     int old_capacity = buf->capacity;
49     #endif
50     if(buf->flags & UL_DBUFF_IS_STATIC) {
51         if(!buf->data || !buf->capacity) {
52             buf->capacity = sizeof(buf->sbuff);
53             buf->data = buf->sbuff;
54         }
55     }
56     else{
57         if(new_capacity <= UL_DBUFF_SLEN) {
58             if((buf->data) && (buf->data != buf->sbuff)) {
59                 // dynamic storage -> static
60                 unsigned long c = buf->capacity;
61                 if(c > sizeof(buf->sbuff)) c = sizeof(buf->sbuff);
62                 memcpy(buf->sbuff, buf->data, c);
63                 free(buf->data);
64             }
65             buf->capacity = sizeof(buf->sbuff);
66             buf->data = buf->sbuff;
67         }
68         else if(new_capacity != buf->capacity) {
69             if(buf->data == buf->sbuff) {
70                 // static storage -> dynamic
71                 buf->data = malloc((size_t)new_capacity);
72                 if(buf->data != NULL) {
73                     memcpy(buf->data, buf->sbuff, buf->capacity);
74                     buf->capacity = new_capacity;
75                 }
76                 else {
77                     buf->capacity = 0;
78                 }
79             }
80             else {
81                 // dynamic storage -> dynamic
82                 unsigned char *new_data;
83                 new_data = realloc(buf->data, (size_t)new_capacity);
84                 if(buf->data != NULL) {
85                     buf->capacity = new_capacity;
86                     buf->data = new_data;
87                 }
88                 else {
89                     /* Old data are not changed if realloc fails, capacity remains at old value */
90                     #ifdef UL_DBUFF_LOGGING
91                     ul_logdeb("realloc buffer to %d failed\n", new_capacity);
92                     #endif
93                 }
94             }
95         }
96     }
97     if(buf->len > buf->capacity) buf->len = buf->capacity;
98     #ifdef UL_DBUFF_LOGGING
99     ul_logdeb("capacity changed from %d to %ld, required %d\n", old_capacity, buf->capacity, new_capacity);
100     #endif
101     return buf->capacity;
102 }                                                                               
103
104 /**
105  * ul_dbuff_set_len - sets a new len of the buffer, change the capacity if neccessary 
106  * @buf: buffer structure
107  * @new_len: new desired buffer length
108  *
109  * Returns new buffer length
110  */
111 int ul_dbuff_set_len(ul_dbuff_t *buf, int new_len)
112 {
113     if(new_len < 0) new_len = 0;
114     if(new_len > buf->capacity) {
115         unsigned long new_cap = UL_DBUFF_SLEN;
116         for(; new_cap < new_len; new_cap <<= 1);
117         ul_dbuff_set_capacity(buf, new_cap);
118     }
119     if(new_len > buf->capacity) {
120         /*buf->data = buf->sbuff;*/
121         /*strncpy(buf->data, "set_len ERROR", buf->capacity);*/
122         new_len = buf->capacity;
123     }
124     buf->len = new_len;
125     return buf->len;
126 }
127  
128 /**
129  * ul_dbuff_cpy - copies bytes to buffer and change its capacity if neccessary like memset
130  * @buf: buffer structure
131  * @b: appended bytes
132  * @n: number of apended bytes
133  *
134  * Returns: length of buffer
135  */
136 int ul_dbuff_set(ul_dbuff_t *buf, byte b, int n)
137 {
138     ul_dbuff_set_len(buf, n);
139     memset(buf->data, b, buf->len);
140     return buf->len;
141 }
142
143 /**
144  * ul_dbuff_cpy - copies bytes to buffer and change its capacity if neccessary 
145  * @buf: buffer structure
146  * @b: appended bytes
147  * @n: number of apended bytes
148  *
149  * Returns: length of buffer
150  */
151 int ul_dbuff_cpy(ul_dbuff_t *buf, const void *b, int n)
152 {
153     if(b == NULL) return 0;
154     ul_dbuff_set_len(buf, n);
155     memcpy(buf->data, b, buf->len);
156     return buf->len;
157 }
158
159 /**
160  * ul_dbuff_cat - appends bytes at end of buffer and change its capacity if neccessary 
161  * @buf: buffer structure
162  * @b: appended bytes
163  * @n: number of apended bytes
164  *
165  * Returns: length of buffer
166  */
167 int ul_dbuff_cat(ul_dbuff_t *buf, const void *b, int n)
168 {
169     unsigned long old_len = buf->len;
170     unsigned long new_len = old_len + n;
171     if(b == NULL) return 0;
172     if(new_len == ul_dbuff_set_len(buf, new_len)) {
173         memcpy(buf->data + old_len, b, n);
174     } else {
175         if (old_len < buf->len)
176             memcpy(buf->data + old_len, b, buf->len - old_len);
177        #ifdef UL_DBUFF_LOGGING
178         ul_logdeb("ul_dbuff_cat: set_len(%lu) error, old_len == %lu\n, act len == %lu\n", new_len, old_len, buf->len);
179        #endif
180     }
181     return buf->len;
182 }
183
184 /**
185  * ul_dbuff_strcat - appends str at dhe end of buffer and change its capacity if neccessary 
186  * @buf: buffer structure
187  * @str: string to append
188  *
189  * Returns number length of buffer (including terminating '\0')
190  */
191 inline int ul_dbuff_strcat(ul_dbuff_t *buf, const char *str)
192 {
193     /*
194     #ifdef UL_DBUFF_LOGGING
195     if(buf->len > 0) ul_logdeb("ul_dbuff_strcat: '%s' + '%s'\n", buf->data, str);
196     else ul_logdeb("ul_dbuff_strcat: '' + %s\n", str);
197     #endif
198     */
199     if(str == NULL) return 0;
200     if(buf->len > 0 && buf->data[buf->len-1] == '\0') { 
201         /* #ifdef UL_DBUFF_LOGGING
202         ul_logdeb("ul_dbuff_strcat: terminating zero found at %ld, after '%c'\n", buf->len-1, buf->data[buf->len - 2]);
203         #endif
204         */
205         ul_dbuff_set_len(buf, buf->len - 1);
206     }
207     #ifdef UL_DBUFF_LOGGING
208     if(buf->len > 0 && buf->data[buf->len-1] != '\0') {
209         ul_logerr("ul_dbuff_strcat: terminating zero not found at %ld, found '%c'\n", buf->len-1, buf->data[buf->len-1]);
210     }
211     #endif
212     /* #ifdef UL_DBUFF_LOGGING
213     ul_dbuff_cat(buf, str, strlen(str) + 1);
214     ul_logdeb("ul_dbuff_strcat: returning '%s'\n", buf->data);
215     return buf->len;
216     #else
217     return ul_dbuff_cat(buf, str, strlen(str) + 1);
218     #endif */
219     return ul_dbuff_cat(buf, str, strlen(str) + 1);
220 }
221  
222 /**
223  * ul_dbuff_strcpy - copy str to the buffer and change its capacity if neccessary 
224  * @buf: buffer structure
225  * @str: string to copy
226  *
227  * Returns number length of buffer (including terminating '\0')
228  */
229 inline int ul_dbuff_strcpy(ul_dbuff_t *buf, const char *str)
230 {
231     ul_dbuff_set_len(buf, 0);
232     return ul_dbuff_strcat(buf, str);
233 }
234  
235 /**
236  * ul_dbuff_append_byte - appends byte at dhe end of buffer and change its capacity if neccessary 
237  * @buf: buffer structure
238  * @b: appended byte
239  *
240  * Returns number length of buffer (including terminating '\0')
241  */
242 inline int ul_dbuff_append_byte(ul_dbuff_t *buf, unsigned char b)
243 {
244     return ul_dbuff_cat(buf, &b, 1);
245 }
246  
247 /**
248  * ul_dbuff_ltrim - remove all white space characters from the left 
249  * @buf: buffer structure
250  *
251  * Return: new length of buffer
252  */
253 int ul_dbuff_ltrim(ul_dbuff_t *buf)
254 {
255         byte *pb = buf->data;
256     int i, j;
257         for(i=0; pb[i]<=' ' && i<buf->len; i++);
258         if(i > 0) {
259                 for(j=i, i=0; j<buf->len; j++, i++) pb[i] = pb[j];
260         buf->len = i;
261         }
262         return buf->len;
263 }
264
265 /**
266  * ul_dbuff_rtrim - remove all white space characters from the right
267  * @buf: buffer structure
268  *
269  * if buffer is terminated by '\0', than is also terminated after rtrim
270  *
271  * Return: new length of buffer
272  */
273 int ul_dbuff_rtrim(ul_dbuff_t *buf)
274 {
275     int i = buf->len - 1;
276     unsigned char *pb = buf->data;
277     int terminated = 0;
278     if(i < 0) return buf->len;
279     if(pb[i] == '\0') terminated = 1;
280     for(; i>=0; i--) {
281                 if(pb[i]>' ') {
282             i++;
283             if(terminated) pb[i++] = '\0';
284             buf->len = i;
285             break;
286         }
287         }
288         return buf->len;
289 }
290
291 /**
292  * ul_dbuff_trim - remove all white space characters from the right and from the left 
293  * @buf: buffer structure
294  *
295  * Returns number length of buffer (including terminating '\0')
296  */
297 int ul_dbuff_trim(ul_dbuff_t *buf)
298 {
299     ul_dbuff_rtrim(buf);
300     return ul_dbuff_ltrim(buf);
301 }
302
303 /**
304  * ul_dbuff_cpos - searches string for char 
305  * @buf:   searched dbuff
306  * @what:  char to find
307  * @quote: skip str areas quoted in quote chars<br>
308  *         If you want to ignore quotes assign '\0' to quote in function call 
309  *
310  * Return: position of what char or negative value
311  */
312 int ul_dbuff_cpos(const ul_dbuff_t *buf, unsigned char what, unsigned char quote)
313 {
314     int in_quotes = 0;
315     int ret;
316     unsigned char *bytes = buf->data;
317     for(ret = 0; ret < buf->len; ret++) {
318         if(bytes[ret] == quote) {
319             in_quotes = !in_quotes;
320             continue;
321         }
322         if(bytes[ret] == what && !in_quotes) {
323             break;
324         }
325     }
326     if(ret >= buf->len) ret = -1;
327     return ret;
328 }
329
330 /**
331  * ul_str_cpos - searches string for char 
332  * @str:   zero terminated string
333  * @what:  char to find
334  * @quote: skip str areas quoted in quote chars
335  *         If you want to ignore quotes assign '\0' to quote in function call 
336  *
337  * Return: position of what char or negative value
338  */
339 int ul_str_cpos(const unsigned char *str, unsigned char what, unsigned char quote)
340 {
341     int in_quotes = 0;
342     int ret;
343     for(ret = 0; str[ret]; ret++) {
344         if(str[ret] == quote) {
345             in_quotes = !in_quotes;
346             continue;
347         }
348         if(str[ret] == what && !in_quotes) {
349             break;
350         }
351     }
352     if(!str[ret]) ret = -1;
353     return ret;
354 }
355
356 /**
357  * ul_str_pos - searches string for substring
358  * @str:   zero terminated string
359  * @what:  string to find
360  * @quote: skip str areas quoted in quote chars
361  *         If you want to ignore quotes assign '\0' to quote in function call 
362  *
363  * Return: position of what string or negative value
364  */
365 int ul_str_pos(const unsigned char *str, const unsigned char *what, unsigned char quote)
366 {
367     int in_quotes = 0;
368     int ret;
369     for(ret = 0; str[ret]; ret++) {
370         if(str[ret] == quote) {
371             in_quotes = !in_quotes;
372             continue;
373         }
374         if(!in_quotes) {
375             int i;
376             for(i=0; str[ret + i]==what[i] && what[i]; i++);
377             if(!what[i]) return ret;
378         }
379     }
380     return -1;
381 }
382
383 /**
384  * ul_str_ncpy - copies string to the buffer
385  * @to:         buffer where to copy str
386  * @from:       zero terminated string
387  * @buff_size:  size of the @to buffer (including terminating zero)
388  *
389  * Standard strncpy function have some disadvatages 
390  * (ie. do not append term. zero if copied string doesn't fit in to buffer, fills whole rest of buffer with zeros)
391  *
392  * Returns strlen(to) or negative value in case of error
393  */
394 int ul_str_ncpy(unsigned char *to, const unsigned char *from, int buff_size)
395 {
396     int i;
397     if(!to || !from) return -1;
398     if(buff_size <= 0) return -2;
399     for(i=0; i<buff_size-1 && from[i]; i++) to[i] = from[i];
400     to[i] = '\0';
401     return i;
402 }
403
404 /**
405  * ul_dbuff_cut_pos - cut first @n bytes from @fromdb and copies it to @todb.
406  * If @n is greater than fromdb.len whole @fromdb is copied to @todb.
407  * If @n is negative position to cut is counted from the end of @fromdb.
408  * If @n is zero @fromdb stays unchanged and todb is resized to len equal zero.
409  * @fromdb: buffer to cut from
410  * @todb:   buffer to copy to
411  * @n:      position where to cut
412  */
413 void ul_dbuff_cut_pos(ul_dbuff_t *fromdb, ul_dbuff_t *todb, int n)
414 {
415     int newlen;
416     if(n < 0) n = fromdb->len + n;
417     if(n < 0) n = 0;
418     if(n > fromdb->len) n = fromdb->len;
419     newlen = fromdb->len - n;
420     ul_dbuff_cpy(todb, fromdb->data, n);
421     memmove(fromdb->data, fromdb->data + n, fromdb->len - n);
422     ul_dbuff_set_len(fromdb, newlen);
423 }
424
425 /**
426  * ul_dbuff_cut - cuts bytes before delimiter + delimiter char from @fromdb and copies tham to the @todb
427  * If @fromdb doesn't contain delimiter @todb is trimmed to zero length.
428  * @fromdb: buffer to cut from
429  * @todb:   buffer to copy to
430  * @delimiter: delimiter char
431  * @quote:   quoted delimiters are ignored, @quote can be '\0', than it is ignored.
432  */
433 void ul_dbuff_cut_delimited(ul_dbuff_t *fromdb, ul_dbuff_t *todb, char delimiter, char quote)
434 {
435     int pos = ul_dbuff_cpos(fromdb, delimiter, quote);
436     if(pos < 0) pos = -1;
437     ul_dbuff_cut_pos(fromdb, todb, pos+1);
438 }
439
440 /**
441  * ul_dbuff_cut_token - cuts not whitespaces from %fromdb to %todb.
442  *                      Leading whitespaces are ignored. Cut string is trimmed.
443  * @fromdb: buffer to cut from
444  * @todb:   buffer to copy to
445  */
446 void ul_dbuff_cut_token(ul_dbuff_t *fromdb, ul_dbuff_t *todb)
447 {
448     const unsigned char *pc = (unsigned char*)fromdb->data;
449     int pos;
450     /* skip leading white spaces */
451     for(pos=0; pc[pos]>0 && pc[pos]<=' ' && pos<fromdb->len; pos++);
452     /* skip token */
453     for(; pc[pos]>' ' && pos<fromdb->len; pos++);
454     ul_dbuff_cut_pos(fromdb, todb, pos);
455     ul_dbuff_trim(todb);
456 }
457
458 /**
459  * ul_dbuff_export - Copies data from %srcdb to the buffer %dest.
460  * @srcdb: source dbuff
461  * @dest: destination buffer
462  * @maxlen: maximum number of bytes to copy
463  * 
464  * Returns: the number of bytes copied.
465  */
466 int ul_dbuff_export(ul_dbuff_t *srcdb, void *dest, int maxlen)
467 {
468     int len;
469     if (!dest) return 0;
470     len = srcdb->len < maxlen ? srcdb->len : maxlen;
471     memcpy(dest, srcdb->data, len);
472     return len;
473 }