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