str.c

00001 /* 
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. - All rights reserved.  
00003  */
00004 
00005 #include <stdlib.h>
00006 #include <errno.h>
00007 #include <toolbox/str.h>
00008 #include <toolbox/misc.h>
00009 #include <toolbox/carpal.h>
00010 #include <toolbox/memory.h>
00011 
00012 enum { BLOCK_SIZE = 64 };
00013 
00014 /* null strings will be bound to the null char* */
00015 static char null_cstr[1] = { 0 };
00016 static char *null = null_cstr;
00017 
00018 /* internal string struct */
00019 struct u_string_s
00020 {
00021     char *data;
00022     size_t data_sz;     /* total malloc'c bytes starting from .data */
00023     size_t data_len;    /* strlen(3) of the NUL-terminated string */
00024     size_t shift_cnt;   /* (internal) used by the realloc algorithm */
00025 };
00026 
00027 static int u_string_do_vprintf (u_string_t *, int, const char *, va_list);
00028 
00083 char *u_string_detach_cstr (u_string_t *s)
00084 {
00085     char *tmp;
00086 
00087     dbg_return_if (s == NULL, NULL);
00088 
00089     tmp = s->data;
00090 
00091     u_free(s);
00092 
00093     return tmp;
00094 }
00095 
00106 int u_string_trim (u_string_t *s)
00107 {
00108     dbg_return_if (s == NULL, ~0);
00109 
00110     if (s->data_len > 0)
00111     {
00112         u_trim(s->data);
00113         s->data_len = strlen(s->data);
00114     }
00115 
00116     return 0;
00117 }
00118 
00130 int u_string_set_length (u_string_t *s, size_t len)
00131 {
00132     dbg_return_if (s == NULL, ~0);
00133     dbg_return_if (len > s->data_len, ~0);
00134 
00135     if (len < s->data_len)
00136     {
00137         s->data_len = len;
00138         s->data[len] = '\0';
00139     }
00140 
00141     /* if (len == s->data_len) do nothing */ 
00142 
00143     return 0;
00144 }
00145 
00155 inline size_t u_string_len (u_string_t *s)
00156 {
00157     dbg_return_if (s == NULL, 0);
00158 
00159     return s->data_len;
00160 }
00161 
00172 inline const char *u_string_c (u_string_t *s)
00173 {
00174     dbg_return_if (s == NULL, NULL);
00175 
00176     return s->data;
00177 }
00178 
00191 inline int u_string_copy (u_string_t *dst, u_string_t *src)
00192 {
00193     dbg_return_if (dst == NULL, ~0);
00194     dbg_return_if (src == NULL, ~0);
00195 
00196     (void) u_string_clear(dst);
00197 
00198     return u_string_append(dst, src->data, src->data_len);
00199 }
00200 
00211 int u_string_clear (u_string_t *s)
00212 {
00213     dbg_return_if (s == NULL, ~0);
00214 
00215     /* clear the string but do not free the buffer */
00216     if (s->data_sz)
00217     {
00218         s->data[0] = '\0';
00219         s->data_len = 0;
00220     }
00221 
00222     return 0;
00223 }
00224 
00240 int u_string_create (const char *buf, size_t len, u_string_t **ps)
00241 {
00242     u_string_t *s = NULL;
00243 
00244     dbg_return_if (ps == NULL, ~0);
00245 
00246     dbg_err_sif ((s = u_malloc(sizeof(u_string_t))) == NULL);
00247 
00248     s->data_sz = 0;
00249     s->data_len = 0;
00250     s->shift_cnt = 0;
00251     s->data = null;
00252 
00253     if (buf)
00254         dbg_err_if (u_string_append(s, buf, len));
00255 
00256     *ps = s;
00257 
00258     return 0;
00259 err:
00260     if (s)
00261         u_string_free(s);
00262     return ~0;
00263 }
00264 
00274 int u_string_free (u_string_t *s)
00275 {
00276     if (s)
00277     {
00278         if (s->data_sz)
00279             U_FREE(s->data);
00280         u_free(s);
00281     }
00282 
00283     return 0;
00284 }
00285 
00298 int u_string_set (u_string_t *s, const char *buf, size_t len)
00299 {
00300     dbg_return_if (s == NULL, ~0);
00301 
00302     (void) u_string_clear(s);
00303 
00304     return u_string_append(s, buf, len);
00305 }
00306 
00319 int u_string_reserve (u_string_t *s, size_t size)
00320 {
00321     char *nbuf = NULL;
00322 
00323     dbg_return_if (s == NULL, ~0);
00324     nop_return_if (size <= s->data_sz, 0);
00325    
00326     /* realloc requested size plus 1 char to store the terminating '\0' */
00327     nbuf = u_realloc(((s->data == null) ? NULL : s->data), size + 1);
00328     dbg_err_sif (nbuf == NULL);
00329 
00330     /* zero terminate it */
00331     nbuf[size] = '\0';
00332 
00333     s->data = (void *) nbuf;
00334     s->data_sz = size;
00335 
00336     return 0;
00337 err:
00338     return ~0;
00339 }
00340 
00355 int u_string_do_printf (u_string_t *s, int clear, const char *fmt, ...)
00356 {
00357     int rc;
00358     va_list ap;
00359 
00360     va_start(ap, fmt);
00361     rc = u_string_do_vprintf(s, clear, fmt, ap);
00362     va_end(ap);
00363 
00364     return rc;
00365 }
00366 
00379 int u_string_append (u_string_t *s, const char *buf, size_t len)
00380 {
00381     size_t nsz, min;
00382 
00383     dbg_return_if (s == NULL, ~0);
00384     dbg_return_if (buf == NULL, ~0);
00385     nop_return_if (len == 0, 0);    /* nothing to do */
00386 
00387     /* if there's not enough space on s->data alloc a bigger buffer */
00388     if (s->data_len + len + 1 > s->data_sz)
00389     {
00390         min = s->data_len + len + 1; /* min required buffer length */
00391         nsz = s->data_sz;
00392         while (nsz <= min)
00393             nsz += (BLOCK_SIZE << s->shift_cnt++);
00394 
00395         dbg_err_if (u_string_reserve(s, nsz));
00396     }
00397 
00398     /* append this chunk to the data buffer */
00399     strncpy(s->data + s->data_len, buf, len);
00400     s->data_len += len;
00401     s->data[s->data_len] = '\0';
00402     
00403     return 0;
00404 err:
00405     return ~0;
00406 }
00407 
00420 int u_string_sprintf (u_string_t *s, const char *fmt, ...)
00421 {
00422     int rc;
00423     va_list ap;
00424 
00425     va_start(ap, fmt);
00426     rc = u_string_do_vprintf(s, 1, fmt, ap);
00427     va_end(ap);
00428 
00429     return rc;
00430 }
00431 
00444 int u_string_aprintf (u_string_t *s, const char *fmt, ...)
00445 {
00446     int rc;
00447     va_list ap;
00448 
00449     va_start(ap, fmt);
00450     rc = u_string_do_vprintf(s, 0, fmt, ap);
00451     va_end(ap);
00452 
00453     return rc;
00454 }
00455 
00460 static int u_string_do_vprintf (u_string_t *s, int clear, const char *fmt, 
00461         va_list ap)
00462 {
00463     size_t sz, avail;
00464     va_list apcpy;
00465 
00466     dbg_return_if (s == NULL, ~0);
00467     dbg_return_if (fmt == NULL, ~0);
00468 
00469     if (clear)
00470         (void) u_string_clear(s);
00471 
00472 again:
00473     avail = s->data_sz - s->data_len; /* avail may be zero */
00474 
00475     /* copy ap to avoid using it twice when realloc'ing */
00476     u_va_copy(apcpy, ap); 
00477 
00478     /* write to the internal buffer of the string.
00479      * if the return value is greater than or equal to the size argument, 
00480      * the string was too short and some of the printed characters were 
00481      * discarded; in that case realloc a bigger buffer and retry */
00482     sz = vsnprintf(s->data + s->data_len, avail, fmt, apcpy);
00483 
00484     va_end(apcpy);
00485 
00486     if (sz >= avail)
00487     {
00488         dbg_err_if (u_string_reserve(s, s->data_sz + s->data_len + 2 * sz + 1));
00489 
00490         /* trunc the buffer again since vsnprintf could have overwritten '\0' */
00491         s->data[s->data_len] = '\0';
00492 
00493         goto again;
00494     }
00495 
00496     /* update string length */
00497     s->data_len += sz; 
00498 
00499     return 0;
00500 err:
00501     return ~0;
00502 }

←Products
© 2005-2012 - KoanLogic S.r.l. - All rights reserved