File Coverage

bson/bson-string.c
Criterion Covered Total %
statement 0 190 0.0
branch 0 124 0.0
condition n/a
subroutine n/a
pod n/a
total 0 314 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright 2013 MongoDB, Inc.
3             *
4             * Licensed under the Apache License, Version 2.0 (the "License");
5             * you may not use this file except in compliance with the License.
6             * You may obtain a copy of the License at
7             *
8             * http://www.apache.org/licenses/LICENSE-2.0
9             *
10             * Unless required by applicable law or agreed to in writing, software
11             * distributed under the License is distributed on an "AS IS" BASIS,
12             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13             * See the License for the specific language governing permissions and
14             * limitations under the License.
15             */
16              
17              
18             #include
19             #include
20             #include
21              
22             #include "bson-compat.h"
23             #include "bson-config.h"
24             #include "bson-string.h"
25             #include "bson-memory.h"
26             #include "bson-utf8.h"
27              
28              
29             /*
30             *--------------------------------------------------------------------------
31             *
32             * bson_string_new --
33             *
34             * Create a new bson_string_t.
35             *
36             * bson_string_t is a power-of-2 allocation growing string. Every
37             * time data is appended the next power of two size is chosen for
38             * the allocation. Pretty standard stuff.
39             *
40             * It is UTF-8 aware through the use of bson_string_append_unichar().
41             * The proper UTF-8 character sequence will be used.
42             *
43             * Parameters:
44             * @str: a string to copy or NULL.
45             *
46             * Returns:
47             * A newly allocated bson_string_t that should be freed with
48             * bson_string_free().
49             *
50             * Side effects:
51             * None.
52             *
53             *--------------------------------------------------------------------------
54             */
55              
56             bson_string_t *
57 0           bson_string_new (const char *str) /* IN */
58             {
59             bson_string_t *ret;
60              
61 0           ret = bson_malloc0 (sizeof *ret);
62 0 0         ret->len = str ? (int)strlen (str) : 0;
63 0           ret->alloc = ret->len + 1;
64              
65 0 0         if (!bson_is_power_of_two (ret->alloc)) {
66 0           ret->alloc = (uint32_t)bson_next_power_of_two ((size_t)ret->alloc);
67             }
68              
69 0 0         BSON_ASSERT (ret->alloc >= 1);
70              
71 0           ret->str = bson_malloc (ret->alloc);
72              
73 0 0         if (str) {
74 0           memcpy (ret->str, str, ret->len);
75             }
76 0           ret->str [ret->len] = '\0';
77              
78 0           ret->str [ret->len] = '\0';
79              
80 0           return ret;
81             }
82              
83              
84             /*
85             *--------------------------------------------------------------------------
86             *
87             * bson_string_free --
88             *
89             * Free the bson_string_t @string and related allocations.
90             *
91             * If @free_segment is false, then the strings buffer will be
92             * returned and is not freed. Otherwise, NULL is returned.
93             *
94             * Returns:
95             * The string->str if free_segment is false.
96             * Otherwise NULL.
97             *
98             * Side effects:
99             * None.
100             *
101             *--------------------------------------------------------------------------
102             */
103              
104             char *
105 0           bson_string_free (bson_string_t *string, /* IN */
106             bool free_segment) /* IN */
107             {
108 0           char *ret = NULL;
109              
110 0 0         BSON_ASSERT (string);
111              
112 0 0         if (!free_segment) {
113 0           ret = string->str;
114             } else {
115 0           bson_free (string->str);
116             }
117              
118 0           bson_free (string);
119              
120 0           return ret;
121             }
122              
123              
124             /*
125             *--------------------------------------------------------------------------
126             *
127             * bson_string_append --
128             *
129             * Append the UTF-8 string @str to @string.
130             *
131             * Returns:
132             * None.
133             *
134             * Side effects:
135             * None.
136             *
137             *--------------------------------------------------------------------------
138             */
139              
140             void
141 0           bson_string_append (bson_string_t *string, /* IN */
142             const char *str) /* IN */
143             {
144             uint32_t len;
145              
146 0 0         BSON_ASSERT (string);
147 0 0         BSON_ASSERT (str);
148              
149 0           len = (uint32_t)strlen (str);
150              
151 0 0         if ((string->alloc - string->len - 1) < len) {
152 0           string->alloc += len;
153 0 0         if (!bson_is_power_of_two (string->alloc)) {
154 0           string->alloc = (uint32_t)bson_next_power_of_two ((size_t)string->alloc);
155             }
156 0           string->str = bson_realloc (string->str, string->alloc);
157             }
158              
159 0           memcpy (string->str + string->len, str, len);
160 0           string->len += len;
161 0           string->str [string->len] = '\0';
162 0           }
163              
164              
165             /*
166             *--------------------------------------------------------------------------
167             *
168             * bson_string_append_c --
169             *
170             * Append the ASCII character @c to @string.
171             *
172             * Do not use this if you are working with UTF-8 sequences,
173             * use bson_string_append_unichar().
174             *
175             * Returns:
176             * None.
177             *
178             * Side effects:
179             * None.
180             *
181             *--------------------------------------------------------------------------
182             */
183              
184             void
185 0           bson_string_append_c (bson_string_t *string, /* IN */
186             char c) /* IN */
187             {
188             char cc[2];
189              
190 0 0         BSON_ASSERT (string);
191              
192 0 0         if (BSON_UNLIKELY (string->alloc == (string->len + 1))) {
193 0           cc [0] = c;
194 0           cc [1] = '\0';
195 0           bson_string_append (string, cc);
196 0           return;
197             }
198              
199 0           string->str [string->len++] = c;
200 0           string->str [string->len] = '\0';
201             }
202              
203              
204             /*
205             *--------------------------------------------------------------------------
206             *
207             * bson_string_append_unichar --
208             *
209             * Append the bson_unichar_t @unichar to the string @string.
210             *
211             * Returns:
212             * None.
213             *
214             * Side effects:
215             * None.
216             *
217             *--------------------------------------------------------------------------
218             */
219              
220             void
221 0           bson_string_append_unichar (bson_string_t *string, /* IN */
222             bson_unichar_t unichar) /* IN */
223             {
224             uint32_t len;
225             char str [8];
226              
227 0 0         BSON_ASSERT (string);
228 0 0         BSON_ASSERT (unichar);
229              
230 0           bson_utf8_from_unichar (unichar, str, &len);
231              
232 0 0         if (len <= 6) {
233 0           str [len] = '\0';
234 0           bson_string_append (string, str);
235             }
236 0           }
237              
238              
239             /*
240             *--------------------------------------------------------------------------
241             *
242             * bson_string_append_printf --
243             *
244             * Format a string according to @format and append it to @string.
245             *
246             * Returns:
247             * None.
248             *
249             * Side effects:
250             * None.
251             *
252             *--------------------------------------------------------------------------
253             */
254              
255             void
256 0           bson_string_append_printf (bson_string_t *string,
257             const char *format,
258             ...)
259             {
260             va_list args;
261             char *ret;
262              
263 0 0         BSON_ASSERT (string);
264 0 0         BSON_ASSERT (format);
265              
266 0           va_start (args, format);
267 0           ret = bson_strdupv_printf (format, args);
268 0           va_end (args);
269 0           bson_string_append (string, ret);
270 0           bson_free (ret);
271 0           }
272              
273              
274             /*
275             *--------------------------------------------------------------------------
276             *
277             * bson_string_truncate --
278             *
279             * Truncate the string @string to @len bytes.
280             *
281             * The underlying memory will be released via realloc() down to
282             * the minimum required size specified by @len.
283             *
284             * Returns:
285             * None.
286             *
287             * Side effects:
288             * None.
289             *
290             *--------------------------------------------------------------------------
291             */
292              
293             void
294 0           bson_string_truncate (bson_string_t *string, /* IN */
295             uint32_t len) /* IN */
296             {
297             uint32_t alloc;
298              
299 0 0         BSON_ASSERT (string);
300 0 0         BSON_ASSERT (len < INT_MAX);
301              
302 0           alloc = len + 1;
303              
304 0 0         if (alloc < 16) {
305 0           alloc = 16;
306             }
307              
308 0 0         if (!bson_is_power_of_two (alloc)) {
309 0           alloc = (uint32_t)bson_next_power_of_two ((size_t)alloc);
310             }
311              
312 0           string->str = bson_realloc (string->str, alloc);
313 0           string->alloc = alloc;
314 0           string->len = len;
315              
316 0           string->str [string->len] = '\0';
317 0           }
318              
319              
320             /*
321             *--------------------------------------------------------------------------
322             *
323             * bson_strdup --
324             *
325             * Portable strdup().
326             *
327             * Returns:
328             * A newly allocated string that should be freed with bson_free().
329             *
330             * Side effects:
331             * None.
332             *
333             *--------------------------------------------------------------------------
334             */
335              
336             char *
337 0           bson_strdup (const char *str) /* IN */
338             {
339             long len;
340             char *out;
341              
342 0 0         if (!str) {
343 0           return NULL;
344             }
345              
346 0           len = (long)strlen (str);
347 0           out = bson_malloc (len + 1);
348              
349 0 0         if (!out) {
350 0           return NULL;
351             }
352              
353 0           memcpy (out, str, len + 1);
354              
355 0           return out;
356             }
357              
358              
359             /*
360             *--------------------------------------------------------------------------
361             *
362             * bson_strdupv_printf --
363             *
364             * Like bson_strdup_printf() but takes a va_list.
365             *
366             * Returns:
367             * A newly allocated string that should be freed with bson_free().
368             *
369             * Side effects:
370             * None.
371             *
372             *--------------------------------------------------------------------------
373             */
374              
375             char *
376 0           bson_strdupv_printf (const char *format, /* IN */
377             va_list args) /* IN */
378             {
379             va_list my_args;
380             char *buf;
381 0           int len = 32;
382             int n;
383              
384 0 0         BSON_ASSERT (format);
385              
386 0           buf = bson_malloc0 (len);
387              
388             while (true) {
389 0           va_copy (my_args, args);
390 0           n = bson_vsnprintf (buf, len, format, my_args);
391 0           va_end (my_args);
392              
393 0 0         if (n > -1 && n < len) {
    0          
394 0           return buf;
395             }
396              
397 0 0         if (n > -1) {
398 0           len = n + 1;
399             } else {
400 0           len *= 2;
401             }
402              
403 0           buf = bson_realloc (buf, len);
404 0           }
405             }
406              
407              
408             /*
409             *--------------------------------------------------------------------------
410             *
411             * bson_strdup_printf --
412             *
413             * Convenience function that formats a string according to @format
414             * and returns a copy of it.
415             *
416             * Returns:
417             * A newly created string that should be freed with bson_free().
418             *
419             * Side effects:
420             * None.
421             *
422             *--------------------------------------------------------------------------
423             */
424              
425             char *
426 0           bson_strdup_printf (const char *format, /* IN */
427             ...) /* IN */
428             {
429             va_list args;
430             char *ret;
431              
432 0 0         BSON_ASSERT (format);
433              
434 0           va_start (args, format);
435 0           ret = bson_strdupv_printf (format, args);
436 0           va_end (args);
437              
438 0           return ret;
439             }
440              
441              
442             /*
443             *--------------------------------------------------------------------------
444             *
445             * bson_strndup --
446             *
447             * A portable strndup().
448             *
449             * Returns:
450             * A newly allocated string that should be freed with bson_free().
451             *
452             * Side effects:
453             * None.
454             *
455             *--------------------------------------------------------------------------
456             */
457              
458             char *
459 0           bson_strndup (const char *str, /* IN */
460             size_t n_bytes) /* IN */
461             {
462             char *ret;
463              
464 0 0         BSON_ASSERT (str);
465              
466 0           ret = bson_malloc (n_bytes + 1);
467 0           memcpy (ret, str, n_bytes);
468 0           ret[n_bytes] = '\0';
469              
470 0           return ret;
471             }
472              
473              
474             /*
475             *--------------------------------------------------------------------------
476             *
477             * bson_strfreev --
478             *
479             * Frees each string in a NULL terminated array of strings.
480             * This also frees the underlying array.
481             *
482             * Returns:
483             * None.
484             *
485             * Side effects:
486             * None.
487             *
488             *--------------------------------------------------------------------------
489             */
490              
491             void
492 0           bson_strfreev (char **str) /* IN */
493             {
494             int i;
495              
496 0 0         if (str) {
497 0 0         for (i = 0; str [i]; i++)
498 0           bson_free (str [i]);
499 0           bson_free (str);
500             }
501 0           }
502              
503              
504             /*
505             *--------------------------------------------------------------------------
506             *
507             * bson_strnlen --
508             *
509             * A portable strnlen().
510             *
511             * Returns:
512             * The length of @s up to @maxlen.
513             *
514             * Side effects:
515             * None.
516             *
517             *--------------------------------------------------------------------------
518             */
519              
520             size_t
521 0           bson_strnlen (const char *s, /* IN */
522             size_t maxlen) /* IN */
523             {
524             #ifdef BSON_HAVE_STRNLEN
525 0           return strnlen (s, maxlen);
526             #else
527             size_t i;
528              
529             for (i = 0; i < maxlen; i++) {
530             if (s [i] == '\0') {
531             return i;
532             }
533             }
534              
535             return maxlen;
536             #endif
537             }
538              
539              
540             /*
541             *--------------------------------------------------------------------------
542             *
543             * bson_strncpy --
544             *
545             * A portable strncpy.
546             *
547             * Copies @src into @dst, which must be @size bytes or larger.
548             * The result is guaranteed to be \0 terminated.
549             *
550             * Returns:
551             * None.
552             *
553             * Side effects:
554             * None.
555             *
556             *--------------------------------------------------------------------------
557             */
558              
559             void
560 0           bson_strncpy (char *dst, /* IN */
561             const char *src, /* IN */
562             size_t size) /* IN */
563             {
564             #ifdef _MSC_VER
565             strncpy_s (dst, size, src, _TRUNCATE);
566             #else
567 0           strncpy (dst, src, size);
568 0           dst[size - 1] = '\0';
569             #endif
570 0           }
571              
572              
573             /*
574             *--------------------------------------------------------------------------
575             *
576             * bson_vsnprintf --
577             *
578             * A portable vsnprintf.
579             *
580             * If more than @size bytes are required (exluding the null byte),
581             * then @size bytes will be written to @string and the return value
582             * is the number of bytes required.
583             *
584             * This function will always return a NULL terminated string.
585             *
586             * Returns:
587             * The number of bytes required for @format excluding the null byte.
588             *
589             * Side effects:
590             * @str is initialized with the formatted string.
591             *
592             *--------------------------------------------------------------------------
593             */
594              
595             int
596 0           bson_vsnprintf (char *str, /* IN */
597             size_t size, /* IN */
598             const char *format, /* IN */
599             va_list ap) /* IN */
600             {
601             #ifdef BSON_OS_WIN32
602             int r = -1;
603              
604             BSON_ASSERT (str);
605              
606             if (size != 0) {
607             r = _vsnprintf_s (str, size, _TRUNCATE, format, ap);
608             }
609              
610             if (r == -1) {
611             r = _vscprintf (format, ap);
612             }
613              
614             str [size - 1] = '\0';
615              
616             return r;
617             #else
618             int r;
619              
620 0           r = vsnprintf (str, size, format, ap);
621 0           str [size - 1] = '\0';
622 0           return r;
623             #endif
624             }
625              
626              
627             /*
628             *--------------------------------------------------------------------------
629             *
630             * bson_snprintf --
631             *
632             * A portable snprintf.
633             *
634             * If @format requires more than @size bytes, then @size bytes are
635             * written and the result is the number of bytes required (excluding
636             * the null byte).
637             *
638             * This function will always return a NULL terminated string.
639             *
640             * Returns:
641             * The number of bytes required for @format.
642             *
643             * Side effects:
644             * @str is initialized.
645             *
646             *--------------------------------------------------------------------------
647             */
648              
649             int
650 0           bson_snprintf (char *str, /* IN */
651             size_t size, /* IN */
652             const char *format, /* IN */
653             ...)
654             {
655             int r;
656             va_list ap;
657              
658 0 0         BSON_ASSERT (str);
659              
660 0           va_start (ap, format);
661 0           r = bson_vsnprintf (str, size, format, ap);
662 0           va_end (ap);
663              
664 0           return r;
665             }
666              
667              
668             int64_t
669 0           bson_ascii_strtoll (const char *s,
670             char **e,
671             int base)
672             {
673 0           char *tok = (char *)s;
674             char c;
675 0           int64_t number = 0;
676 0           int64_t sign = 1;
677              
678 0 0         if (!s) {
679 0           errno = EINVAL;
680 0           return 0;
681             }
682              
683 0           c = *tok;
684              
685 0 0         while (isspace (c)) {
686 0           c = *++tok;
687             }
688              
689 0 0         if (!isdigit (c) && (c != '+') && (c != '-')) {
    0          
    0          
690 0           *e = tok - 1;
691 0           errno = EINVAL;
692 0           return 0;
693             }
694              
695 0 0         if (c == '-') {
696 0           sign = -1;
697 0           c = *++tok;
698             }
699              
700 0 0         if (c == '+') {
701 0           c = *++tok;
702             }
703              
704 0 0         if (c == '0' && tok[1] != '\0' &&
705 0 0         (isdigit (tok[1]) || tok[1] == 'x' || tok[1] == 'X')) {
    0          
706             /* Hex, octal or binary -- maybe. */
707              
708 0           c = *++tok;
709              
710 0 0         if (c == 'x' || c == 'X') { /* Hex */
    0          
711 0 0         if (base != 16) {
712 0           *e = (char *)(s);
713 0           errno = EINVAL;
714 0           return 0;
715             }
716              
717 0           c = *++tok;
718 0 0         if (!isxdigit (c)) {
719 0           *e = tok;
720 0           errno = EINVAL;
721 0           return 0;
722             }
723             do {
724 0           number = (number << 4) + (c - '0');
725 0           c = *(++tok);
726 0 0         } while (isxdigit (c));
727             }
728             else { /* Octal */
729 0 0         if (base != 8) {
730 0           *e = (char *)(s);
731 0           errno = EINVAL;
732 0           return 0;
733             }
734              
735 0 0         if (c < '0' || c >= '8') {
    0          
736 0           *e = tok;
737 0           errno = EINVAL;
738 0           return 0;
739             }
740             do {
741 0           number = (number << 3) + (c - '0');
742 0           c = *(++tok);
743 0 0         } while (('0' <= c) && (c < '8'));
    0          
744             }
745              
746 0 0         while (c == 'l' || c == 'L' || c == 'u' || c == 'U') {
    0          
    0          
    0          
747 0           c = *++tok;
748             }
749             }
750             else {
751             /* Decimal */
752 0 0         if (base != 10) {
753 0           *e = (char *)(s);
754 0           errno = EINVAL;
755 0           return 0;
756             }
757              
758             do {
759 0           number = (number * 10) + (c - '0');
760 0           c = *(++tok);
761 0 0         } while (isdigit (c));
762              
763 0 0         while (c == 'l' || c == 'L' || c == 'u' || c == 'U') {
    0          
    0          
    0          
764 0           c = *(++tok);
765             }
766             }
767              
768 0           *e = tok;
769 0           errno = 0;
770 0           return (sign * number);
771             }
772