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