1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include "wzd_all.h"
28
29 #ifndef WZD_USE_PCH
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #include <ctype.h> /* isspace */
35
36 #include "libwzd-base/list.h"
37
38 #include "wzd_string.h"
39
40 #include "wzd_structs.h"
41 #include "wzd_log.h"
42 #include "wzd_misc.h" /* ascii_lower */
43
44 #ifdef HAVE_UTF8
45 # include "wzd_utf8.h"
46 #endif
47
48 #ifndef HAVE_STRTOK_R
49 # include "libwzd-base/wzd_strtok_r.h"
50 #endif
51
52 #include "wzd_debug.h"
53
54 #endif /* WZD_USE_PCH */
55
56 struct wzd_string_t {
57 char * buffer;
58 size_t length;
59 size_t allocated;
60 };
61
62 static inline void _str_set_min_size(wzd_string_t *str, size_t length);
63
64
65
str_allocate(void)66 wzd_string_t * str_allocate(void)
67 {
68 wzd_string_t * str;
69
70 str = wzd_malloc(sizeof(wzd_string_t));
71 str->buffer = NULL;
72 str->length = 0;
73 str->allocated = 0;
74
75 return str;
76 }
77
str_deallocate(wzd_string_t * st)78 void str_deallocate(wzd_string_t *st)
79 {
80 if (st) {
81 wzd_free(st->buffer);
82 #ifdef DEBUG
83 memset(st,0xab,sizeof(wzd_string_t));
84 #endif
85 wzd_free(st);
86 }
87 }
88
89 /** \brief Deallocates a NULL-terminated string list
90 */
str_deallocate_array(wzd_string_t ** array)91 void str_deallocate_array(wzd_string_t **array)
92 {
93 wzd_string_t ** iterator = array;
94
95 if (!iterator) return;
96
97 while ( (*iterator) ) {
98 str_deallocate(*iterator);
99 iterator++;
100 }
101 wzd_free(array);
102 }
103
str_fromchar(const char * str)104 wzd_string_t * str_fromchar(const char *str)
105 {
106 wzd_string_t * s;
107 size_t length;
108
109 s = str_allocate();
110
111 if (s && str) {
112 length = strlen(str);
113 _str_set_min_size(s,length+1);
114 memcpy(s->buffer,str,length);
115 s->buffer[length] = '\0';
116 s->length = length;
117 }
118
119 return s;
120 }
121
122 /** returns a pointer to a new string pointing to \a str
123 *
124 * \note \a str must not be freed, you must use str_deallocate() on the result
125 */
str_fromchar_raw(char * str)126 wzd_string_t * str_fromchar_raw(char *str)
127 {
128 wzd_string_t * s;
129
130 s = str_allocate();
131
132 if (s && str) {
133 s->buffer = str;
134 s->length = strlen(str);
135 s->allocated = s->length;
136 }
137
138 return s;
139 }
140
141 /* str_tochar
142 * returns a pointer to the data contained in the string str.
143 * These data must NOT be modified !
144 */
str_tochar(const wzd_string_t * str)145 const char * str_tochar(const wzd_string_t *str)
146 {
147 return (str)?str->buffer:NULL;
148 }
149
150 /** returns 1 if string exists and length is inside min and max (included)
151 */
str_checklength(const wzd_string_t * str,size_t min,size_t max)152 unsigned int str_checklength(const wzd_string_t *str, size_t min, size_t max)
153 {
154 if (!str || !str->buffer) return 0;
155 if (strlen(str->buffer) < min || strlen(str->buffer) > max) return 0;
156 return 1;
157 }
158
159 /** Get the length of the given string, or -1 if error
160 */
str_length(const wzd_string_t * str)161 size_t str_length(const wzd_string_t *str)
162 {
163 if (!str || !str->buffer) return -1;
164 return str->length;
165 }
166
str_store(wzd_string_t * str,const char * s)167 wzd_string_t * str_store(wzd_string_t * str, const char * s)
168 {
169 size_t length;
170
171 if (!str) return NULL;
172
173 length = strlen(s);
174 _str_set_min_size(str,length+1);
175
176 wzd_strncpy(str->buffer, s, length+1);
177 str->length = length;
178
179 return str;
180 }
181
str_dup(const wzd_string_t * src)182 wzd_string_t * str_dup(const wzd_string_t *src)
183 {
184 wzd_string_t * dst;
185
186 if (!src) return NULL;
187
188 #if DEBUG
189 if ( (src->length >= src->allocated) ||
190 (src->length != strlen(src->buffer)) )
191 {
192 out_err(LEVEL_CRITICAL,"invalid string (%s) at %s:%d\n",src->buffer,__FILE__,__LINE__);
193 return NULL;
194 }
195 #endif
196
197 dst = str_allocate();
198 _str_set_min_size(dst,src->allocated);
199 if (src->buffer) {
200 memcpy(dst->buffer,src->buffer,src->length);
201 dst->buffer[src->length] = '\0';
202 dst->length = src->length;
203 }
204
205 return dst;
206 }
207
str_copy(wzd_string_t * dst,const wzd_string_t * src)208 wzd_string_t * str_copy(wzd_string_t *dst, const wzd_string_t *src)
209 {
210 if (!src || !dst) return NULL;
211
212 #if DEBUG
213 if ( (src->length >= src->allocated) ||
214 (src->length != strlen(src->buffer)) )
215 {
216 out_err(LEVEL_CRITICAL,"invalid string (%s) at %s:%d\n",src->buffer,__FILE__,__LINE__);
217 return NULL;
218 }
219 if ( dst->buffer &&
220 ((dst->length >= dst->allocated) ||
221 (dst->length != strlen(dst->buffer))) )
222 {
223 out_err(LEVEL_CRITICAL,"invalid string (%s) at %s:%d\n",dst->buffer,__FILE__,__LINE__);
224 return NULL;
225 }
226 #endif
227
228 _str_set_min_size(dst,src->allocated);
229 if (src->buffer) {
230 memcpy(dst->buffer,src->buffer,src->length);
231 dst->buffer[src->length] = '\0';
232 dst->length = src->length;
233 }
234
235 return dst;
236 }
237
238 /** \brief append \a tail to string pointed to by \a str
239 */
str_append(wzd_string_t * str,const char * tail)240 wzd_string_t * str_append(wzd_string_t * str, const char *tail)
241 {
242 size_t length;
243
244 if (!str) return NULL;
245 if (!tail) return str;
246
247 length = strlen(tail);
248
249 _str_set_min_size(str,str->length + length + 1);
250 if (str->buffer) {
251 strlcat(str->buffer,tail,str->length+length+1);
252 str->length += length;
253 }
254
255 return str;
256 }
257
258 /** \brief append character \a c to string pointed to by str
259 */
str_append_c(wzd_string_t * str,const char c)260 wzd_string_t * str_append_c(wzd_string_t * str, const char c)
261 {
262 if (!str) return NULL;
263
264 _str_set_min_size(str,str->length + 2);
265 if (str->buffer) {
266 str->buffer[str->length] = c;
267 str->length ++;
268 str->buffer[str->length] = '\0';
269 }
270
271 return str;
272 }
273
274 /** \brief prepend 'head' to string pointed to by str
275 */
str_prepend(wzd_string_t * str,const char * head)276 wzd_string_t * str_prepend(wzd_string_t * str, const char *head)
277 {
278 size_t length;
279 char * buf;
280
281 if (!str) return NULL;
282 if (!head) return str;
283
284 length = strlen(head);
285
286 if (length + str->length >= str->allocated)
287 str->allocated = length + str->length + 1;
288 buf = wzd_malloc(str->allocated);
289 wzd_strncpy(buf, head, length);
290 if (str->buffer) {
291 memcpy(buf + length, str->buffer, str->length);
292 length += str->length;
293 wzd_free(str->buffer);
294 }
295 buf[length] = '\0';
296 str->buffer = buf;
297 str->length = length;
298
299 return str;
300 }
301
302
303 /** \brief remove all leading and trailing spaces from input string
304 */
str_trim(wzd_string_t * str)305 wzd_string_t * str_trim(wzd_string_t * str)
306 {
307 return str_trim_left(str_trim_right(str));
308 }
309
str_trim_left(wzd_string_t * str)310 wzd_string_t * str_trim_left(wzd_string_t *str)
311 {
312 unsigned int i=0;
313
314 if (!str || !str->buffer)
315 return NULL;
316
317 while (isspace(str->buffer[i])) {
318 ++i;
319 }
320
321 if (i!=0) {
322 unsigned int j=0;
323 for (;i!=str->length;i++)
324 {
325 str->buffer[j++] = str->buffer[i];
326 }
327 str->length = j;
328 str->buffer[j] = '\0';
329 }
330
331 return str;
332 }
333
str_trim_right(wzd_string_t * str)334 wzd_string_t * str_trim_right(wzd_string_t *str)
335 {
336 size_t len;
337
338 if (!str || !str->buffer)
339 return NULL;
340
341 if (str->length == 0) return str;
342
343 len = str->length;
344
345 while ((--len > 0) &&
346 (isspace(str->buffer[len]) ||
347 str->buffer[len] == '\n')) {
348 str->buffer[len] = '\0';
349 str->length--;
350 }
351 return str;
352 }
353
354 /** \brief Removes \a len characters from a wzd_string_t, starting at position \a pos.
355 *
356 * The rest of the wzd_string_t is shifted down to fill the gap.
357 */
str_erase(wzd_string_t * str,size_t pos,int len)358 wzd_string_t * str_erase(wzd_string_t * str, size_t pos, int len)
359 {
360 if (!str || !str->buffer) return NULL;
361 if (pos > str->length) return NULL;
362
363 if (len < 0)
364 len = str->length - pos;
365 else {
366 if (pos + len > str->length) return NULL;
367
368 if (pos + len < str->length)
369 wzd_memmove (str->buffer + pos, str->buffer + pos + len, str->length - (pos + len));
370 }
371
372 str->length -= len;
373
374 str->buffer[str->length] = 0;
375
376 return str;
377 }
378
379 /** \brief Convert string to lower case
380 * \note
381 * This function modifies its input string
382 */
str_tolower(wzd_string_t * str)383 wzd_string_t * str_tolower(wzd_string_t *str)
384 {
385 if (str && str->buffer)
386 ascii_lower(str->buffer, str->length);
387
388 return str;
389 }
390
391
392 /** \brief Extract token from string str
393 * \note
394 * This function modifies its input string
395 */
str_tok(wzd_string_t * str,const char * delim)396 wzd_string_t * str_tok(wzd_string_t *str, const char *delim)
397 {
398 wzd_string_t * token;
399 char *ptr, *t;
400 char * buffer;
401
402 #ifdef DEBUG
403 if (!str)
404 out_log(LEVEL_HIGH,"str_tok called with NULL argument !\n");
405 #endif
406
407 if (!str || !str->buffer || str->length == 0) return NULL;
408 if (!delim) return NULL;
409
410 buffer = wzd_strdup(str->buffer);
411 t = strtok_r(buffer, delim, &ptr);
412
413 token = STR(t);
414 if (t) {
415 if (ptr) {
416 str->length = strlen(ptr);
417 wzd_strncpy(str->buffer, ptr, str->length+1);
418 } else {
419 str->length = 0;
420 str->buffer[0] = '\0';
421 }
422 }
423 wzd_free(buffer);
424
425 return token;
426 }
427
428 /** \brief str_read next token
429 * \return a pointer to the next token, or NULL if not found, or if there is
430 * only whitespaces, or if quotes are unbalanced
431 *
432 * Read next token separated by a whitespace, except if string begins
433 * with a ' or ", in this case it searches the matching character.
434 * Note: input string is modified as a \\0 is written.
435 */
str_read_token(wzd_string_t * str)436 wzd_string_t * str_read_token(wzd_string_t *str)
437 {
438 char *tok, c;
439 char sep[2];
440 char *s;
441 char *ptr, *endptr;
442 wzd_string_t * str_ret=NULL;
443
444 if (!str || !str->buffer || str->length == 0) return NULL;
445
446 s = str->buffer;
447
448 if (s == NULL)
449 {
450 return NULL;
451 }
452
453 /* skip leading spaces */
454 while ( (c = *s) && isspace(c) ) s++;
455 if (*s == '\0') /* only whitespaces */
456 { return NULL; }
457
458 /* search for any whitespace or quote */
459 tok = strpbrk(s, " \t\r\n\"'");
460
461 if (!tok) {
462 str_ret = STR(str->buffer);
463 /* nothing, we return string */
464 str->length = 0;
465 str->buffer[0] = '\0';
466 return str_ret;
467 }
468
469 /* the first char is a quote ? */
470 if (*tok == '"' || *tok == '\'') {
471 sep[0] = *tok;
472 sep[1] = '\0';
473 if (!strchr(tok+1,*tok)) { /* unbalanced quotes */
474 return NULL;
475 }
476 /** \bug we can't have escaped characters */
477 ptr = strtok_r(tok, sep, &endptr);
478 str_ret = STR(ptr);
479 str->length = strlen(str->buffer);
480 return str_ret;
481 }
482
483 /* normal case, we search a whitespace */
484 return str_tok(str, " \t\r\n");
485 }
486
487
488
489 /** \brief Produce output according to \a format and variable number of arguments,
490 * and write output to \a str.
491 */
str_vsprintf(wzd_string_t * str,const char * format,va_list ap)492 int str_vsprintf(wzd_string_t *str, const char *format, va_list ap)
493 {
494 va_list ap2;
495 int result;
496
497 if (!str) return -1;
498 if (!format) return -1;
499
500 if (!str->buffer)
501 _str_set_min_size(str,strlen(format)+1);
502
503 /** vsnprintf modifies its last argument on some archs, we have to
504 * work on a copy of the va_list
505 */
506 #ifdef va_copy
507 va_copy(ap2,ap);
508 #else
509 memcpy (&ap2,&ap, sizeof(va_list));
510 #endif
511
512 result = vsnprintf(str->buffer, str->allocated, format, ap2);
513 #ifndef WIN32
514 if (result < 0) return result;
515 if ((unsigned int)result >= str->allocated)
516 {
517 _str_set_min_size(str, result+1);
518 va_end(ap2);
519 #ifdef va_copy
520 va_copy(ap2,ap);
521 #else
522 memcpy (&ap2,&ap, sizeof(va_list));
523 #endif
524 result = vsnprintf(str->buffer, str->allocated, format, ap2);
525 }
526 str->length = result;
527 #else /* WIN32 */
528 /* windows is crap, once again
529 * vsnprintf does not return the number that should be been allocated,
530 * it always return -1 if the buffer is not large enough
531 */
532 while (result < 0)
533 {
534 if (str->allocated >= 1024000) {
535 return -1;
536 }
537 _str_set_min_size(str,str->allocated + (str->allocated >> 2) + 20);
538 va_end(ap2);
539 #ifdef va_copy
540 va_copy(ap2,ap);
541 #else
542 memcpy (&ap2,&ap, sizeof(va_list));
543 #endif
544 result = vsnprintf(str->buffer, str->allocated-1, format, ap2);
545 }
546 str->length = result;
547 str->buffer[str->length] = '\0';
548 if ((u32_t)result == str->allocated) {
549 _str_set_min_size(str, result+1);
550 }
551 #endif
552
553 va_end (ap2);
554
555 return result;
556 }
557
558
559
560 /* str_sprintf
561 * Produce output according to format and variable number of arguments,
562 * and write output to str.
563 */
str_sprintf(wzd_string_t * str,const char * format,...)564 int str_sprintf(wzd_string_t *str, const char *format, ...)
565 {
566 va_list argptr;
567 int result;
568
569 if (!str) return -1;
570 if (!format) return -1;
571
572 va_start(argptr,format); /* note: ansi compatible version of va_start */
573
574 result = str_vsprintf(str, format, argptr);
575
576 va_end (argptr);
577
578 return result;
579 }
580
581 /** \brief Prepend formatted output to string
582 */
str_prepend_printf(wzd_string_t * str,const char * format,...)583 int str_prepend_printf(wzd_string_t *str, const char *format, ...)
584 {
585 va_list argptr;
586 int result;
587 char * buffer = NULL;
588 size_t length = 0;
589
590 if (!str) return -1;
591 if (!format) return -1;
592
593 if (!str->buffer)
594 _str_set_min_size(str,str->length + strlen(format)+1);
595
596 va_start(argptr,format); /* note: ansi compatible version of va_start */
597
598 #ifndef WIN32
599 result = vsnprintf(buffer, 0, format, argptr);
600 if (result < 0) return result;
601 result++;
602 if ((unsigned int)result >= length)
603 {
604 buffer = wzd_malloc( result + 1 );
605 va_end(argptr);
606 va_start(argptr,format); /* note: ansi compatible version of va_start */
607 result = vsnprintf(buffer, result, format, argptr);
608 }
609 length = result;
610 #else /* WIN32 */
611 /* windows is crap, once again
612 * vsnprintf does not return the number that should be been allocated,
613 * it always return -1 if the buffer is not large enough
614 */
615 length = strlen(format)+1;
616 buffer = wzd_malloc(length);
617 result = vsnprintf(buffer, length, format, argptr);
618 while (result < 0)
619 {
620 if (length >= 1024000) {
621 return -1;
622 }
623 wzd_free(buffer);
624 length = length + (length >> 2) + 20;
625 buffer = wzd_malloc(length);
626 va_end(argptr);
627 va_start(argptr,format); /* note: ansi compatible version of va_start */
628 result = vsnprintf(buffer, length-1, format, argptr);
629 }
630 length = result;
631 buffer[length] = '\0';
632 if ((u32_t)result == length) {
633 _str_set_min_size(str, result+1);
634 }
635 #endif
636
637 va_end (argptr);
638
639 str_prepend(str, buffer);
640 if (buffer) wzd_free(buffer);
641
642 return str->length;
643 }
644
645
646 /** \brief Append formatted output to string
647 */
str_append_printf(wzd_string_t * str,const char * format,...)648 int str_append_printf(wzd_string_t *str, const char *format, ...)
649 {
650 va_list argptr;
651 int result;
652 char * buffer = NULL;
653 size_t length = 0;
654
655 if (!str) return -1;
656 if (!format) return -1;
657
658 if (!str->buffer)
659 _str_set_min_size(str,str->length + strlen(format)+1);
660
661 va_start(argptr,format); /* note: ansi compatible version of va_start */
662
663 #ifndef WIN32
664 result = vsnprintf(buffer, 0, format, argptr);
665 if (result < 0) return result;
666 result++;
667 if ((unsigned int)result >= length)
668 {
669 buffer = wzd_malloc( result + 1 );
670 va_end(argptr);
671 va_start(argptr,format); /* note: ansi compatible version of va_start */
672 result = vsnprintf(buffer, result, format, argptr);
673 }
674 length = result;
675 #else /* WIN32 */
676 /* windows is crap, once again
677 * vsnprintf does not return the number that should be been allocated,
678 * it always return -1 if the buffer is not large enough
679 */
680 length = strlen(format)+1;
681 buffer = wzd_malloc(length);
682 result = vsnprintf(buffer, length, format, argptr);
683 while (result < 0)
684 {
685 if (length >= 1024000) {
686 return -1;
687 }
688 wzd_free(buffer);
689 length = length + (length >> 2) + 20;
690 buffer = wzd_malloc(length);
691 va_end(argptr);
692 va_start(argptr,format); /* note: ansi compatible version of va_start */
693 result = vsnprintf(buffer, length-1, format, argptr);
694 }
695 length = result;
696 buffer[length] = '\0';
697 if ((u32_t)result == length) {
698 _str_set_min_size(str, result+1);
699 }
700 #endif
701
702 va_end (argptr);
703
704 str_append(str, buffer);
705 if (buffer) wzd_free(buffer);
706
707 return str->length;
708 }
709
710 /** \brief Split \a str into a maximum of \a max_tokens pieces, separated by \a sep.
711 *
712 * If \a max_tokens is reached, the remainder of \a str is appended to the last token.
713 *
714 * \return a NULL-terminated string array, or NULL. The array must be freed using
715 * str_deallocate_array().
716 */
str_split(wzd_string_t * str,const char * sep,int max_tokens)717 wzd_string_t ** str_split(wzd_string_t * str, const char * sep, int max_tokens)
718 {
719 List string_list;
720 ListElmt * elmnt;
721 const char *remainder = NULL;
722 char * s;
723 wzd_string_t * token;
724 wzd_string_t ** str_array;
725 unsigned int i;
726
727 if (!str || !sep || sep[0]=='\0') return NULL;
728
729 if (max_tokens < 1) max_tokens = (unsigned int)-1;
730
731 list_init(&string_list,NULL);
732
733 remainder = str->buffer;
734 s = strstr(remainder, sep);
735 if (s) {
736 size_t len;
737 size_t delimiter_len = strlen(sep);
738
739 while (--max_tokens && s) {
740 len = s - remainder;
741 token = str_allocate();
742 _str_set_min_size(token, len + 1);
743 strncpy(token->buffer, remainder, len);
744 token->buffer[len] = '\0';
745 token->length = len;
746
747 list_ins_next(&string_list, list_tail(&string_list), token);
748
749 remainder = s + delimiter_len;
750
751 s = strstr(remainder, sep);
752 }
753 }
754
755 if (remainder && remainder[0] != '\0')
756 list_ins_next(&string_list, list_tail(&string_list), STR(remainder));
757
758 str_array = wzd_malloc( (list_size(&string_list)+1) * sizeof(wzd_string_t*) );
759 i = 0;
760 for (elmnt = list_head(&string_list); elmnt; elmnt = list_next(elmnt)) {
761 str_array[i++] = list_data(elmnt);
762 }
763 str_array[i] = NULL;
764
765 list_destroy(&string_list);
766
767 return str_array;
768 }
769
770 #ifdef HAVE_UTF8
771 /** \brief Convert utf8 string to other charset
772 * \note
773 * Require unicode support
774 */
str_utf8_to_local(wzd_string_t * str,const char * charset)775 int str_utf8_to_local(wzd_string_t *str, const char * charset)
776 {
777 char * utf_buf;
778 size_t length;
779
780 if (!utf8_valid(str->buffer, str->length)) {
781 return -1;
782 }
783
784 length = strlen(str->buffer) + 10; /* we allocate more, small security */
785 utf_buf = wzd_malloc(length);
786
787 if (utf8_to_local_charset(str->buffer, utf_buf, length, charset))
788 {
789 /* error during conversion */
790 wzd_free(utf_buf);
791 return -1;
792 }
793
794 wzd_free(str->buffer);
795 str->buffer = utf_buf;
796 str->allocated = length;
797 str->length = strlen(utf_buf);
798
799 return 0;
800 }
801
802 /** \brief Convert charset to utf8 string
803 * \note
804 * Require unicode support
805 */
str_local_to_utf8(wzd_string_t * str,const char * charset)806 int str_local_to_utf8(wzd_string_t *str, const char * charset)
807 {
808 char * utf_buf;
809 size_t length;
810
811 /** \bug testing if a strin to be converted to UTF-8 is already
812 valid UTF-8 is a bit stupid */
813 /* if (!utf8_valid(str->buffer, str->length)) {
814 return -1;
815 } */
816
817 length = strlen(str->buffer) + 10; /* we allocate more, small security */
818 utf_buf = wzd_malloc(length);
819
820 if (local_charset_to_utf8(str->buffer, utf_buf, length, charset))
821 {
822 /* error during conversion */
823 wzd_free(utf_buf);
824 return -1;
825 }
826
827 wzd_free(str->buffer);
828 str->buffer = utf_buf;
829 str->allocated = length;
830 str->length = strlen(utf_buf);
831
832 return 0;
833 }
834
835 /** \brief test if string is valid utf8
836 * \note
837 * require unicode support
838 */
str_is_valid_utf8(wzd_string_t * str)839 int str_is_valid_utf8(wzd_string_t *str)
840 {
841 return utf8_valid(str->buffer,str->length);
842 }
843
844 #else
str_utf8_to_local(wzd_string_t * str,const char * charset)845 int str_utf8_to_local(wzd_string_t *str, const char * charset)
846 {
847 return -1;
848 }
849
str_local_to_utf8(wzd_string_t * str,const char * charset)850 int str_local_to_utf8(wzd_string_t *str, const char * charset)
851 {
852 return -1;
853 }
854
str_is_valid_utf8(wzd_string_t * str)855 int str_is_valid_utf8(wzd_string_t *str)
856 {
857 return -1;
858 }
859
860 #endif /* HAVE_UTF8 */
861
862
863
864
865
_str_set_min_size(wzd_string_t * str,size_t length)866 static inline void _str_set_min_size(wzd_string_t *str, size_t length)
867 {
868 void * ptr;
869
870 if (str) {
871 if (length > str->allocated) {
872 /* allocate a bit more than requested */
873 if (length < 200) length += 20;
874 else length = (size_t)(length * 1.3);
875
876 if (!str->buffer) {
877 str->buffer = wzd_malloc(length);
878 str->buffer[0] = '\0';
879 } else {
880 if ( (ptr = wzd_realloc(str->buffer,length)) ) {
881 str->buffer = ptr;
882 str->buffer[str->length] = '\0';
883 } else {
884 ptr = wzd_malloc(length);
885 memcpy(ptr,str->buffer,str->length);
886 wzd_free(str->buffer);
887 str->buffer = ptr;
888 }
889 }
890 str->allocated = length;
891 }
892 }
893 }
894
895