1 /*
2  * Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <wchar.h>
24 #include <wctype.h>
25 #include <limits.h>
26 
27 #include "c99defs.h"
28 #include "dstr.h"
29 #include "darray.h"
30 #include "bmem.h"
31 #include "utf8.h"
32 #include "lexer.h"
33 #include "platform.h"
34 
35 static const char *astrblank = "";
36 static const wchar_t *wstrblank = L"";
37 
astrcmpi(const char * str1,const char * str2)38 int astrcmpi(const char *str1, const char *str2)
39 {
40 	if (!str1)
41 		str1 = astrblank;
42 	if (!str2)
43 		str2 = astrblank;
44 
45 	do {
46 		char ch1 = (char)toupper(*str1);
47 		char ch2 = (char)toupper(*str2);
48 
49 		if (ch1 < ch2)
50 			return -1;
51 		else if (ch1 > ch2)
52 			return 1;
53 	} while (*str1++ && *str2++);
54 
55 	return 0;
56 }
57 
wstrcmpi(const wchar_t * str1,const wchar_t * str2)58 int wstrcmpi(const wchar_t *str1, const wchar_t *str2)
59 {
60 	if (!str1)
61 		str1 = wstrblank;
62 	if (!str2)
63 		str2 = wstrblank;
64 
65 	do {
66 		wchar_t ch1 = (wchar_t)towupper(*str1);
67 		wchar_t ch2 = (wchar_t)towupper(*str2);
68 
69 		if (ch1 < ch2)
70 			return -1;
71 		else if (ch1 > ch2)
72 			return 1;
73 	} while (*str1++ && *str2++);
74 
75 	return 0;
76 }
77 
astrcmp_n(const char * str1,const char * str2,size_t n)78 int astrcmp_n(const char *str1, const char *str2, size_t n)
79 {
80 	if (!n)
81 		return 0;
82 	if (!str1)
83 		str1 = astrblank;
84 	if (!str2)
85 		str2 = astrblank;
86 
87 	do {
88 		char ch1 = *str1;
89 		char ch2 = *str2;
90 
91 		if (ch1 < ch2)
92 			return -1;
93 		else if (ch1 > ch2)
94 			return 1;
95 	} while (*str1++ && *str2++ && --n);
96 
97 	return 0;
98 }
99 
wstrcmp_n(const wchar_t * str1,const wchar_t * str2,size_t n)100 int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n)
101 {
102 	if (!n)
103 		return 0;
104 	if (!str1)
105 		str1 = wstrblank;
106 	if (!str2)
107 		str2 = wstrblank;
108 
109 	do {
110 		wchar_t ch1 = *str1;
111 		wchar_t ch2 = *str2;
112 
113 		if (ch1 < ch2)
114 			return -1;
115 		else if (ch1 > ch2)
116 			return 1;
117 	} while (*str1++ && *str2++ && --n);
118 
119 	return 0;
120 }
121 
astrcmpi_n(const char * str1,const char * str2,size_t n)122 int astrcmpi_n(const char *str1, const char *str2, size_t n)
123 {
124 	if (!n)
125 		return 0;
126 	if (!str1)
127 		str1 = astrblank;
128 	if (!str2)
129 		str2 = astrblank;
130 
131 	do {
132 		char ch1 = (char)toupper(*str1);
133 		char ch2 = (char)toupper(*str2);
134 
135 		if (ch1 < ch2)
136 			return -1;
137 		else if (ch1 > ch2)
138 			return 1;
139 	} while (*str1++ && *str2++ && --n);
140 
141 	return 0;
142 }
143 
wstrcmpi_n(const wchar_t * str1,const wchar_t * str2,size_t n)144 int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n)
145 {
146 	if (!n)
147 		return 0;
148 	if (!str1)
149 		str1 = wstrblank;
150 	if (!str2)
151 		str2 = wstrblank;
152 
153 	do {
154 		wchar_t ch1 = (wchar_t)towupper(*str1);
155 		wchar_t ch2 = (wchar_t)towupper(*str2);
156 
157 		if (ch1 < ch2)
158 			return -1;
159 		else if (ch1 > ch2)
160 			return 1;
161 	} while (*str1++ && *str2++ && --n);
162 
163 	return 0;
164 }
165 
astrstri(const char * str,const char * find)166 char *astrstri(const char *str, const char *find)
167 {
168 	size_t len;
169 
170 	if (!str || !find)
171 		return NULL;
172 
173 	len = strlen(find);
174 
175 	do {
176 		if (astrcmpi_n(str, find, len) == 0)
177 			return (char *)str;
178 	} while (*str++);
179 
180 	return NULL;
181 }
182 
wstrstri(const wchar_t * str,const wchar_t * find)183 wchar_t *wstrstri(const wchar_t *str, const wchar_t *find)
184 {
185 	size_t len;
186 
187 	if (!str || !find)
188 		return NULL;
189 
190 	len = wcslen(find);
191 
192 	do {
193 		if (wstrcmpi_n(str, find, len) == 0)
194 			return (wchar_t *)str;
195 	} while (*str++);
196 
197 	return NULL;
198 }
199 
is_padding(int ch)200 static inline bool is_padding(int ch)
201 {
202 	return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
203 }
204 
strdepad(char * str)205 char *strdepad(char *str)
206 {
207 	char *temp;
208 	size_t len;
209 
210 	if (!str)
211 		return str;
212 	if (!*str)
213 		return str;
214 
215 	temp = str;
216 
217 	/* remove preceding spaces/tabs */
218 	while (is_padding(*temp))
219 		++temp;
220 
221 	len = strlen(temp);
222 	if (temp != str)
223 		memmove(str, temp, len + 1);
224 
225 	if (len) {
226 		temp = str + (len - 1);
227 		while (is_padding(*temp))
228 			*(temp--) = 0;
229 	}
230 
231 	return str;
232 }
233 
wcsdepad(wchar_t * str)234 wchar_t *wcsdepad(wchar_t *str)
235 {
236 	wchar_t *temp;
237 	size_t len;
238 
239 	if (!str)
240 		return str;
241 	if (!*str)
242 		return str;
243 
244 	temp = str;
245 
246 	/* remove preceding spaces/tabs */
247 	while (is_padding(*temp))
248 		++temp;
249 
250 	len = wcslen(temp);
251 	if (temp != str)
252 		memmove(str, temp, (len + 1) * sizeof(wchar_t));
253 
254 	if (len) {
255 		temp = str + (len - 1);
256 		while (is_padding(*temp))
257 			*(temp--) = 0;
258 	}
259 
260 	return str;
261 }
262 
strlist_split(const char * str,char split_ch,bool include_empty)263 char **strlist_split(const char *str, char split_ch, bool include_empty)
264 {
265 	const char *cur_str = str;
266 	const char *next_str;
267 	char *out = NULL;
268 	size_t count = 0;
269 	size_t total_size = 0;
270 
271 	if (str) {
272 		char **table;
273 		char *offset;
274 		size_t cur_idx = 0;
275 		size_t cur_pos = 0;
276 
277 		next_str = strchr(str, split_ch);
278 
279 		while (next_str) {
280 			size_t size = next_str - cur_str;
281 
282 			if (size || include_empty) {
283 				++count;
284 				total_size += size + 1;
285 			}
286 
287 			cur_str = next_str + 1;
288 			next_str = strchr(cur_str, split_ch);
289 		}
290 
291 		if (*cur_str || include_empty) {
292 			++count;
293 			total_size += strlen(cur_str) + 1;
294 		}
295 
296 		/* ------------------ */
297 
298 		cur_pos = (count + 1) * sizeof(char *);
299 		total_size += cur_pos;
300 		out = bmalloc(total_size);
301 		offset = out + cur_pos;
302 		table = (char **)out;
303 
304 		/* ------------------ */
305 
306 		next_str = strchr(str, split_ch);
307 		cur_str = str;
308 
309 		while (next_str) {
310 			size_t size = next_str - cur_str;
311 
312 			if (size || include_empty) {
313 				table[cur_idx++] = offset;
314 				strncpy(offset, cur_str, size);
315 				offset[size] = 0;
316 				offset += size + 1;
317 			}
318 
319 			cur_str = next_str + 1;
320 			next_str = strchr(cur_str, split_ch);
321 		}
322 
323 		if (*cur_str || include_empty) {
324 			table[cur_idx++] = offset;
325 			strcpy(offset, cur_str);
326 		}
327 
328 		table[cur_idx] = NULL;
329 	}
330 
331 	return (char **)out;
332 }
333 
strlist_free(char ** strlist)334 void strlist_free(char **strlist)
335 {
336 	bfree(strlist);
337 }
338 
dstr_init_copy_strref(struct dstr * dst,const struct strref * src)339 void dstr_init_copy_strref(struct dstr *dst, const struct strref *src)
340 {
341 	dstr_init(dst);
342 	dstr_copy_strref(dst, src);
343 }
344 
dstr_copy(struct dstr * dst,const char * array)345 void dstr_copy(struct dstr *dst, const char *array)
346 {
347 	size_t len;
348 
349 	if (!array || !*array) {
350 		dstr_free(dst);
351 		return;
352 	}
353 
354 	len = strlen(array);
355 	dstr_ensure_capacity(dst, len + 1);
356 	memcpy(dst->array, array, len + 1);
357 	dst->len = len;
358 }
359 
dstr_copy_strref(struct dstr * dst,const struct strref * src)360 void dstr_copy_strref(struct dstr *dst, const struct strref *src)
361 {
362 	if (dst->array)
363 		dstr_free(dst);
364 
365 	dstr_ncopy(dst, src->array, src->len);
366 }
367 
size_min(size_t a,size_t b)368 static inline size_t size_min(size_t a, size_t b)
369 {
370 	return (a < b) ? a : b;
371 }
372 
dstr_ncopy(struct dstr * dst,const char * array,const size_t len)373 void dstr_ncopy(struct dstr *dst, const char *array, const size_t len)
374 {
375 	if (dst->array)
376 		dstr_free(dst);
377 
378 	if (!len)
379 		return;
380 
381 	dst->array = bmemdup(array, len + 1);
382 	dst->len = len;
383 	dst->capacity = len + 1;
384 
385 	dst->array[len] = 0;
386 }
387 
dstr_ncopy_dstr(struct dstr * dst,const struct dstr * str,const size_t len)388 void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
389 {
390 	size_t newlen;
391 
392 	if (dst->array)
393 		dstr_free(dst);
394 
395 	if (!len)
396 		return;
397 
398 	newlen = size_min(len, str->len);
399 	dst->array = bmemdup(str->array, newlen + 1);
400 	dst->len = newlen;
401 	dst->capacity = newlen + 1;
402 
403 	dst->array[newlen] = 0;
404 }
405 
dstr_cat_dstr(struct dstr * dst,const struct dstr * str)406 void dstr_cat_dstr(struct dstr *dst, const struct dstr *str)
407 {
408 	size_t new_len;
409 	if (!str->len)
410 		return;
411 
412 	new_len = dst->len + str->len;
413 
414 	dstr_ensure_capacity(dst, new_len + 1);
415 	memcpy(dst->array + dst->len, str->array, str->len + 1);
416 	dst->len = new_len;
417 }
418 
dstr_cat_strref(struct dstr * dst,const struct strref * str)419 void dstr_cat_strref(struct dstr *dst, const struct strref *str)
420 {
421 	dstr_ncat(dst, str->array, str->len);
422 }
423 
dstr_ncat(struct dstr * dst,const char * array,const size_t len)424 void dstr_ncat(struct dstr *dst, const char *array, const size_t len)
425 {
426 	size_t new_len;
427 	if (!array || !*array || !len)
428 		return;
429 
430 	new_len = dst->len + len;
431 
432 	dstr_ensure_capacity(dst, new_len + 1);
433 	memcpy(dst->array + dst->len, array, len);
434 
435 	dst->len = new_len;
436 	dst->array[new_len] = 0;
437 }
438 
dstr_ncat_dstr(struct dstr * dst,const struct dstr * str,const size_t len)439 void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
440 {
441 	size_t new_len, in_len;
442 	if (!str->array || !*str->array || !len)
443 		return;
444 
445 	in_len = size_min(len, str->len);
446 	new_len = dst->len + in_len;
447 
448 	dstr_ensure_capacity(dst, new_len + 1);
449 	memcpy(dst->array + dst->len, str->array, in_len);
450 
451 	dst->len = new_len;
452 	dst->array[new_len] = 0;
453 }
454 
dstr_insert(struct dstr * dst,const size_t idx,const char * array)455 void dstr_insert(struct dstr *dst, const size_t idx, const char *array)
456 {
457 	size_t new_len, len;
458 	if (!array || !*array)
459 		return;
460 	if (idx == dst->len) {
461 		dstr_cat(dst, array);
462 		return;
463 	}
464 
465 	len = strlen(array);
466 	new_len = dst->len + len;
467 
468 	dstr_ensure_capacity(dst, new_len + 1);
469 
470 	memmove(dst->array + idx + len, dst->array + idx, dst->len - idx + 1);
471 	memcpy(dst->array + idx, array, len);
472 
473 	dst->len = new_len;
474 }
475 
dstr_insert_dstr(struct dstr * dst,const size_t idx,const struct dstr * str)476 void dstr_insert_dstr(struct dstr *dst, const size_t idx,
477 		      const struct dstr *str)
478 {
479 	size_t new_len;
480 	if (!str->len)
481 		return;
482 	if (idx == dst->len) {
483 		dstr_cat_dstr(dst, str);
484 		return;
485 	}
486 
487 	new_len = dst->len + str->len;
488 
489 	dstr_ensure_capacity(dst, (new_len + 1));
490 
491 	memmove(dst->array + idx + str->len, dst->array + idx,
492 		dst->len - idx + 1);
493 	memcpy(dst->array + idx, str->array, str->len);
494 
495 	dst->len = new_len;
496 }
497 
dstr_insert_ch(struct dstr * dst,const size_t idx,const char ch)498 void dstr_insert_ch(struct dstr *dst, const size_t idx, const char ch)
499 {
500 	if (idx == dst->len) {
501 		dstr_cat_ch(dst, ch);
502 		return;
503 	}
504 
505 	dstr_ensure_capacity(dst, (++dst->len + 1));
506 	memmove(dst->array + idx + 1, dst->array + idx, dst->len - idx + 1);
507 	dst->array[idx] = ch;
508 }
509 
dstr_remove(struct dstr * dst,const size_t idx,const size_t count)510 void dstr_remove(struct dstr *dst, const size_t idx, const size_t count)
511 {
512 	size_t end;
513 	if (!count)
514 		return;
515 	if (count == dst->len) {
516 		dstr_free(dst);
517 		return;
518 	}
519 
520 	end = idx + count;
521 	if (end == dst->len)
522 		dst->array[idx] = 0;
523 	else
524 		memmove(dst->array + idx, dst->array + end, dst->len - end + 1);
525 
526 	dst->len -= count;
527 }
528 
dstr_printf(struct dstr * dst,const char * format,...)529 void dstr_printf(struct dstr *dst, const char *format, ...)
530 {
531 	va_list args;
532 	va_start(args, format);
533 	dstr_vprintf(dst, format, args);
534 	va_end(args);
535 }
536 
dstr_catf(struct dstr * dst,const char * format,...)537 void dstr_catf(struct dstr *dst, const char *format, ...)
538 {
539 	va_list args;
540 	va_start(args, format);
541 	dstr_vcatf(dst, format, args);
542 	va_end(args);
543 }
544 
dstr_vprintf(struct dstr * dst,const char * format,va_list args)545 void dstr_vprintf(struct dstr *dst, const char *format, va_list args)
546 {
547 	va_list args_cp;
548 	va_copy(args_cp, args);
549 
550 	int len = vsnprintf(NULL, 0, format, args_cp);
551 	va_end(args_cp);
552 
553 	if (len < 0)
554 		len = 4095;
555 
556 	dstr_ensure_capacity(dst, ((size_t)len) + 1);
557 	len = vsnprintf(dst->array, ((size_t)len) + 1, format, args);
558 
559 	if (!*dst->array) {
560 		dstr_free(dst);
561 		return;
562 	}
563 
564 	dst->len = len < 0 ? strlen(dst->array) : (size_t)len;
565 }
566 
dstr_vcatf(struct dstr * dst,const char * format,va_list args)567 void dstr_vcatf(struct dstr *dst, const char *format, va_list args)
568 {
569 	va_list args_cp;
570 	va_copy(args_cp, args);
571 
572 	int len = vsnprintf(NULL, 0, format, args_cp);
573 	va_end(args_cp);
574 
575 	if (len < 0)
576 		len = 4095;
577 
578 	dstr_ensure_capacity(dst, dst->len + ((size_t)len) + 1);
579 	len = vsnprintf(dst->array + dst->len, ((size_t)len) + 1, format, args);
580 
581 	if (!*dst->array) {
582 		dstr_free(dst);
583 		return;
584 	}
585 
586 	dst->len += len < 0 ? strlen(dst->array + dst->len) : (size_t)len;
587 }
588 
dstr_safe_printf(struct dstr * dst,const char * format,const char * val1,const char * val2,const char * val3,const char * val4)589 void dstr_safe_printf(struct dstr *dst, const char *format, const char *val1,
590 		      const char *val2, const char *val3, const char *val4)
591 {
592 	dstr_copy(dst, format);
593 	if (val1)
594 		dstr_replace(dst, "$1", val1);
595 	if (val2)
596 		dstr_replace(dst, "$2", val2);
597 	if (val3)
598 		dstr_replace(dst, "$3", val3);
599 	if (val4)
600 		dstr_replace(dst, "$4", val4);
601 }
602 
dstr_replace(struct dstr * str,const char * find,const char * replace)603 void dstr_replace(struct dstr *str, const char *find, const char *replace)
604 {
605 	size_t find_len, replace_len;
606 	char *temp;
607 
608 	if (dstr_is_empty(str))
609 		return;
610 
611 	if (!replace)
612 		replace = "";
613 
614 	find_len = strlen(find);
615 	replace_len = strlen(replace);
616 	temp = str->array;
617 
618 	if (replace_len < find_len) {
619 		unsigned long count = 0;
620 
621 		while ((temp = strstr(temp, find)) != NULL) {
622 			char *end = temp + find_len;
623 			size_t end_len = strlen(end);
624 
625 			if (end_len) {
626 				memmove(temp + replace_len, end, end_len + 1);
627 				if (replace_len)
628 					memcpy(temp, replace, replace_len);
629 			} else {
630 				strcpy(temp, replace);
631 			}
632 
633 			temp += replace_len;
634 			++count;
635 		}
636 
637 		if (count)
638 			str->len += (replace_len - find_len) * count;
639 
640 	} else if (replace_len > find_len) {
641 		unsigned long count = 0;
642 
643 		while ((temp = strstr(temp, find)) != NULL) {
644 			temp += find_len;
645 			++count;
646 		}
647 
648 		if (!count)
649 			return;
650 
651 		str->len += (replace_len - find_len) * count;
652 		dstr_ensure_capacity(str, str->len + 1);
653 		temp = str->array;
654 
655 		while ((temp = strstr(temp, find)) != NULL) {
656 			char *end = temp + find_len;
657 			size_t end_len = strlen(end);
658 
659 			if (end_len) {
660 				memmove(temp + replace_len, end, end_len + 1);
661 				memcpy(temp, replace, replace_len);
662 			} else {
663 				strcpy(temp, replace);
664 			}
665 
666 			temp += replace_len;
667 		}
668 
669 	} else {
670 		while ((temp = strstr(temp, find)) != NULL) {
671 			memcpy(temp, replace, replace_len);
672 			temp += replace_len;
673 		}
674 	}
675 }
676 
dstr_depad(struct dstr * str)677 void dstr_depad(struct dstr *str)
678 {
679 	if (str->array) {
680 		str->array = strdepad(str->array);
681 		if (*str->array)
682 			str->len = strlen(str->array);
683 		else
684 			dstr_free(str);
685 	}
686 }
687 
dstr_left(struct dstr * dst,const struct dstr * str,const size_t pos)688 void dstr_left(struct dstr *dst, const struct dstr *str, const size_t pos)
689 {
690 	dstr_resize(dst, pos);
691 	if (dst != str)
692 		memcpy(dst->array, str->array, pos);
693 }
694 
dstr_mid(struct dstr * dst,const struct dstr * str,const size_t start,const size_t count)695 void dstr_mid(struct dstr *dst, const struct dstr *str, const size_t start,
696 	      const size_t count)
697 {
698 	struct dstr temp;
699 	dstr_init(&temp);
700 	dstr_copy_dstr(&temp, str);
701 	dstr_ncopy(dst, temp.array + start, count);
702 	dstr_free(&temp);
703 }
704 
dstr_right(struct dstr * dst,const struct dstr * str,const size_t pos)705 void dstr_right(struct dstr *dst, const struct dstr *str, const size_t pos)
706 {
707 	struct dstr temp;
708 	dstr_init(&temp);
709 	dstr_ncopy(&temp, str->array + pos, str->len - pos);
710 	dstr_copy_dstr(dst, &temp);
711 	dstr_free(&temp);
712 }
713 
dstr_from_mbs(struct dstr * dst,const char * mbstr)714 void dstr_from_mbs(struct dstr *dst, const char *mbstr)
715 {
716 	dstr_free(dst);
717 	dst->len = os_mbs_to_utf8_ptr(mbstr, 0, &dst->array);
718 }
719 
dstr_to_mbs(const struct dstr * str)720 char *dstr_to_mbs(const struct dstr *str)
721 {
722 	char *dst;
723 	os_mbs_to_utf8_ptr(str->array, str->len, &dst);
724 	return dst;
725 }
726 
dstr_to_wcs(const struct dstr * str)727 wchar_t *dstr_to_wcs(const struct dstr *str)
728 {
729 	wchar_t *dst;
730 	os_utf8_to_wcs_ptr(str->array, str->len, &dst);
731 	return dst;
732 }
733 
dstr_from_wcs(struct dstr * dst,const wchar_t * wstr)734 void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr)
735 {
736 	size_t len = wchar_to_utf8(wstr, 0, NULL, 0, 0);
737 
738 	if (len) {
739 		dstr_resize(dst, len);
740 		wchar_to_utf8(wstr, 0, dst->array, len + 1, 0);
741 	} else {
742 		dstr_free(dst);
743 	}
744 }
745 
dstr_to_upper(struct dstr * str)746 void dstr_to_upper(struct dstr *str)
747 {
748 	wchar_t *wstr;
749 	wchar_t *temp;
750 
751 	if (dstr_is_empty(str))
752 		return;
753 
754 	wstr = dstr_to_wcs(str);
755 	temp = wstr;
756 
757 	if (!wstr)
758 		return;
759 
760 	while (*temp) {
761 		*temp = (wchar_t)towupper(*temp);
762 		temp++;
763 	}
764 
765 	dstr_from_wcs(str, wstr);
766 	bfree(wstr);
767 }
768 
dstr_to_lower(struct dstr * str)769 void dstr_to_lower(struct dstr *str)
770 {
771 	wchar_t *wstr;
772 	wchar_t *temp;
773 
774 	if (dstr_is_empty(str))
775 		return;
776 
777 	wstr = dstr_to_wcs(str);
778 	temp = wstr;
779 
780 	if (!wstr)
781 		return;
782 
783 	while (*temp) {
784 		*temp = (wchar_t)towlower(*temp);
785 		temp++;
786 	}
787 
788 	dstr_from_wcs(str, wstr);
789 	bfree(wstr);
790 }
791