]>
git.saurik.com Git - redis.git/blob - deps/lua/src/strbuf.c
1 /* strbuf - string buffer routines
3 * Copyright (c) 2010-2011 Mark Pulford <mark@kyne.com.au>
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 void die(const char *fmt
, ...)
37 vfprintf(stderr
, fmt
, arg
);
39 fprintf(stderr
, "\n");
44 void strbuf_init(strbuf_t
*s
, int len
)
49 size
= STRBUF_DEFAULT_SIZE
;
51 size
= len
+ 1; /* \0 terminator */
56 s
->increment
= STRBUF_DEFAULT_INCREMENT
;
61 s
->buf
= malloc(size
);
65 strbuf_ensure_null(s
);
68 strbuf_t
*strbuf_new(int len
)
72 s
= malloc(sizeof(strbuf_t
));
78 /* Dynamic strbuf allocation / deallocation */
84 void strbuf_set_increment(strbuf_t
*s
, int increment
)
86 /* Increment > 0: Linear buffer growth rate
87 * Increment < -1: Exponential buffer growth rate */
88 if (increment
== 0 || increment
== -1)
89 die("BUG: Invalid string increment");
91 s
->increment
= increment
;
94 static inline void debug_stats(strbuf_t
*s
)
97 fprintf(stderr
, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
98 (long)s
, s
->reallocs
, s
->length
, s
->size
);
102 /* If strbuf_t has not been dynamically allocated, strbuf_free() can
103 * be called any number of times strbuf_init() */
104 void strbuf_free(strbuf_t
*s
)
116 char *strbuf_free_to_string(strbuf_t
*s
, int *len
)
122 strbuf_ensure_null(s
);
134 static int calculate_new_size(strbuf_t
*s
, int len
)
136 int reqsize
, newsize
;
139 die("BUG: Invalid strbuf length requested");
141 /* Ensure there is room for optional NULL termination */
144 /* If the user has requested to shrink the buffer, do it exactly */
145 if (s
->size
> reqsize
)
149 if (s
->increment
< 0) {
150 /* Exponential sizing */
151 while (newsize
< reqsize
)
152 newsize
*= -s
->increment
;
155 newsize
= ((newsize
+ s
->increment
- 1) / s
->increment
) * s
->increment
;
162 /* Ensure strbuf can handle a string length bytes long (ignoring NULL
163 * optional termination). */
164 void strbuf_resize(strbuf_t
*s
, int len
)
168 newsize
= calculate_new_size(s
, len
);
171 fprintf(stderr
, "strbuf(%lx) resize: %d => %d\n",
172 (long)s
, s
->size
, newsize
);
176 s
->buf
= realloc(s
->buf
, s
->size
);
178 die("Out of memory");
182 void strbuf_append_string(strbuf_t
*s
, const char *str
)
186 space
= strbuf_empty_length(s
);
188 for (i
= 0; str
[i
]; i
++) {
190 strbuf_resize(s
, s
->length
+ 1);
191 space
= strbuf_empty_length(s
);
194 s
->buf
[s
->length
] = str
[i
];
200 /* strbuf_append_fmt() should only be used when an upper bound
201 * is known for the output string. */
202 void strbuf_append_fmt(strbuf_t
*s
, int len
, const char *fmt
, ...)
207 strbuf_ensure_empty_length(s
, len
);
210 fmt_len
= vsnprintf(s
->buf
+ s
->length
, len
, fmt
, arg
);
214 die("BUG: Unable to convert number"); /* This should never happen.. */
216 s
->length
+= fmt_len
;
219 /* strbuf_append_fmt_retry() can be used when the there is no known
220 * upper bound for the output string. */
221 void strbuf_append_fmt_retry(strbuf_t
*s
, const char *fmt
, ...)
227 /* If the first attempt to append fails, resize the buffer appropriately
229 for (try = 0; ; try++) {
231 /* Append the new formatted string */
232 /* fmt_len is the length of the string required, excluding the
234 empty_len
= strbuf_empty_length(s
);
235 /* Add 1 since there is also space to store the terminating NULL. */
236 fmt_len
= vsnprintf(s
->buf
+ s
->length
, empty_len
+ 1, fmt
, arg
);
239 if (fmt_len
<= empty_len
)
242 die("BUG: length of formatted string changed");
244 strbuf_resize(s
, s
->length
+ fmt_len
);
247 s
->length
+= fmt_len
;
250 /* vi:ai et sw=4 ts=4: