Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-string.c
4 : * Copyright (C) 2011-2012 Akira TAGOH
5 : *
6 : * Authors:
7 : * Akira TAGOH <akira@tagoh.org>
8 : *
9 : * You may distribute under the terms of either the GNU
10 : * Lesser General Public License or the Mozilla Public
11 : * License, as specified in the README file.
12 : */
13 : #ifdef HAVE_CONFIG_H
14 : #include "config.h"
15 : #endif
16 :
17 : #include <stdlib.h>
18 : #include <string.h>
19 : #include "lt-mem.h"
20 : #include "lt-messages.h"
21 : #include "lt-utils.h"
22 : #include "lt-string.h"
23 :
24 : #define LT_STRING_SIZE 128
25 :
26 : /**
27 : * SECTION: lt-string
28 : * @Short_Description: text buffers which grow automatically as text is added
29 : * @Title: Strings
30 : *
31 : * A #lt_string_t is an object that handles the memory management of a C
32 : * string.
33 : */
34 : struct _lt_string_t {
35 : lt_mem_t parent;
36 : char *string;
37 : size_t len;
38 : size_t allocated_len;
39 : };
40 :
41 : lt_bool_t _lt_string_expand(lt_string_t *string,
42 : size_t size);
43 :
44 : /*< private >*/
45 : lt_bool_t
46 0 : _lt_string_expand(lt_string_t *string,
47 : size_t size)
48 : {
49 0 : string->allocated_len += LT_ALIGNED_TO_POINTER (size + LT_STRING_SIZE);
50 0 : lt_mem_remove_ref(&string->parent, string->string);
51 0 : string->string = realloc(string->string, string->allocated_len);
52 0 : if (!string->string) {
53 0 : string->len = 0;
54 0 : string->allocated_len = 0;
55 :
56 0 : return FALSE;
57 : }
58 0 : lt_mem_add_ref(&string->parent, string->string, free);
59 :
60 0 : return TRUE;
61 : }
62 :
63 : /*< protected >*/
64 :
65 : /*< public >*/
66 :
67 : /**
68 : * lt_string_new:
69 : * @string: an initial string to set
70 : *
71 : * Creates an instance of #lt_string_t with @string.
72 : *
73 : * Returns: a new instance of #lt_string_t.
74 : */
75 : lt_string_t *
76 170 : lt_string_new(const char *string)
77 : {
78 170 : lt_string_t *retval = lt_mem_alloc_object(sizeof (lt_string_t));
79 :
80 170 : if (retval) {
81 170 : retval->len = string ? strlen(string) : 0;
82 170 : retval->allocated_len = LT_ALIGNED_TO_POINTER (retval->len + LT_STRING_SIZE);
83 170 : retval->string = malloc(retval->allocated_len);
84 170 : if (!retval->string) {
85 0 : lt_mem_unref(&retval->parent);
86 0 : return NULL;
87 : }
88 170 : if (string)
89 0 : strcpy(retval->string, string);
90 : else
91 170 : retval->string[retval->len] = 0;
92 170 : lt_mem_add_ref(&retval->parent, retval->string, free);
93 : }
94 :
95 170 : return retval;
96 : }
97 :
98 : /**
99 : * lt_string_ref:
100 : * @string: a #lt_string_t
101 : *
102 : * Increases the reference count of @string.
103 : *
104 : * Returns: (transfer none): the same @string object.
105 : */
106 : lt_string_t *
107 0 : lt_string_ref(lt_string_t *string)
108 : {
109 0 : lt_return_val_if_fail (string != NULL, NULL);
110 :
111 0 : return lt_mem_ref(&string->parent);
112 : }
113 :
114 : /**
115 : * lt_string_unref:
116 : * @string: a #lt_string_t
117 : *
118 : * Decreases the reference count of @string. when its reference count
119 : * drops to 0, the object is finalized (i.e. its memory is freed).
120 : */
121 : void
122 170 : lt_string_unref(lt_string_t *string)
123 : {
124 170 : if (string)
125 170 : lt_mem_unref(&string->parent);
126 170 : }
127 :
128 : /**
129 : * lt_string_free:
130 : * @string: a #lt_string_t
131 : * @free_segment: if %TRUE, the actual character data is freed as well
132 : *
133 : * Frees the memory allocated for the #lt_string_t.
134 : * If @free_segment is %TRUE it also frees the character data. If
135 : * it's %FALSE, the caller gains ownership of the buffer and must
136 : * free it after use with free().
137 : *
138 : * Returns: the character data of @string
139 : * (i.e. %NULL if @free_segment is %TRUE)
140 : */
141 : char *
142 60 : lt_string_free(lt_string_t *string,
143 : lt_bool_t free_segment)
144 : {
145 60 : char *retval = NULL;
146 :
147 60 : if (!free_segment) {
148 60 : lt_mem_remove_ref(&string->parent, string->string);
149 60 : retval = string->string;
150 : }
151 60 : lt_string_unref(string);
152 :
153 60 : return retval;
154 : }
155 :
156 : /**
157 : * lt_string_length:
158 : * @string: a #lt_string_t
159 : *
160 : * Returns the number of characters in buffer for @string.
161 : *
162 : * Returns: the number of characters
163 : */
164 : size_t
165 384 : lt_string_length(const lt_string_t *string)
166 : {
167 384 : lt_return_val_if_fail (string != NULL, 0);
168 :
169 384 : return string->len;
170 : }
171 :
172 : /**
173 : * lt_string_value:
174 : * @string: a #lt_string_t
175 : *
176 : * Returns the buffer in @string.
177 : *
178 : * Returns: a string which @string has.
179 : */
180 : const char *
181 66 : lt_string_value(const lt_string_t *string)
182 : {
183 66 : lt_return_val_if_fail (string != NULL, NULL);
184 :
185 66 : return string->string;
186 : }
187 :
188 : /**
189 : * lt_string_truncate:
190 : * @string: a #lt_string_t
191 : * @len: the number of characters to be truncated from the buffer.
192 : *
193 : * Truncates the characters in the buffer according to @len. if @len is
194 : * a negative, how many characters is truncated will be calculated from
195 : * current size. i.e. if the buffer contains "abc", and @len is -1,
196 : * the buffer will be "ab" after this call.
197 : *
198 : * Returns: (transfer none): the same @string object.
199 : */
200 : lt_string_t *
201 24 : lt_string_truncate(lt_string_t *string,
202 : ssize_t len)
203 : {
204 24 : lt_return_val_if_fail (string != NULL, NULL);
205 :
206 24 : if (len < 0)
207 0 : len = string->len + len;
208 24 : len = LT_MAX (len, 0);
209 24 : string->len = LT_MIN (len, string->len);
210 24 : string->string[string->len] = 0;
211 :
212 24 : return string;
213 : }
214 :
215 : /**
216 : * lt_string_clear:
217 : * @string: a #lt_string_t
218 : *
219 : * Clean up the buffer in @string.
220 : */
221 : void
222 24 : lt_string_clear(lt_string_t *string)
223 : {
224 24 : lt_string_truncate(string, 0);
225 24 : }
226 :
227 : /**
228 : * lt_string_append_c:
229 : * @string: a #lt_string_t
230 : * @c: the byte to append onto the end of @string
231 : *
232 : * Adds a byte onto the end of a #lt_string_t, expanding
233 : * it if necessary.
234 : *
235 : * Returns: (transfer none): the same @string object.
236 : */
237 : lt_string_t *
238 126 : lt_string_append_c(lt_string_t *string,
239 : char c)
240 : {
241 126 : lt_return_val_if_fail (string != NULL, NULL);
242 :
243 126 : if ((string->len + 2) >= string->allocated_len) {
244 0 : if (!_lt_string_expand(string, 1))
245 0 : return string;
246 : }
247 126 : string->string[string->len++] = c;
248 126 : string->string[string->len] = 0;
249 :
250 126 : return string;
251 : }
252 :
253 : /**
254 : * lt_string_append:
255 : * @string: a #lt_string_t
256 : * @str: the string to append onto the end of @string
257 : *
258 : * Adds a string onto the end of a #lt_string_t, expanding
259 : * it if necessary.
260 : *
261 : * Returns: (transfer none): the same @string object
262 : */
263 : lt_string_t *
264 410 : lt_string_append(lt_string_t *string,
265 : const char *str)
266 : {
267 : size_t len;
268 :
269 410 : lt_return_val_if_fail (string != NULL, NULL);
270 410 : lt_return_val_if_fail (str != NULL, string);
271 :
272 410 : len = strlen(str);
273 410 : if ((string->len + len + 1) >= string->allocated_len) {
274 0 : if (!_lt_string_expand(string, len))
275 0 : return string;
276 : }
277 410 : strncpy(&string->string[string->len], str, len);
278 410 : string->len += len;
279 410 : string->string[string->len] = 0;
280 :
281 410 : return string;
282 : }
283 :
284 : /**
285 : * lt_string_append_filename:
286 : * @string: a #lt_string_t
287 : * @path: the string to append onto the end of @string as a file path
288 : * @...: a %NULL-terminated list of strings to append onto the end of @string as a file path
289 : *
290 : * Adds a string onto the end of a #lt_string_t as a file path.
291 : *
292 : * Returns: (transfer none): the same @string object
293 : */
294 : lt_string_t *
295 52 : lt_string_append_filename(lt_string_t *string,
296 : const char *path,
297 : ...)
298 : {
299 : va_list ap;
300 : const char *p;
301 :
302 52 : lt_return_val_if_fail (string != NULL, NULL);
303 52 : lt_return_val_if_fail (path != NULL, string);
304 :
305 : #ifndef _WIN32
306 52 : if (lt_string_length(string) == 0 && path[0] != LT_DIR_SEPARATOR)
307 0 : lt_string_append(string, LT_DIR_SEPARATOR_S);
308 : #endif
309 :
310 52 : va_start(ap, path);
311 52 : p = path;
312 304 : while (p) {
313 200 : if (lt_string_length(string) > 0 && lt_string_at(string, -1) != LT_DIR_SEPARATOR)
314 148 : lt_string_append(string, LT_DIR_SEPARATOR_S);
315 200 : lt_string_append(string, p);
316 200 : p = (const char *)va_arg(ap, const char *);
317 : }
318 :
319 52 : return string;
320 : }
321 :
322 : /**
323 : * lt_string_append_printf:
324 : * @string: a #lt_string_t
325 : * @format: the string format. See the printf() documentation
326 : * @...: the parameters to insert into the format string
327 : *
328 : * Appends a formatted string onto the end of a #lt_string_t.
329 : * This is similar to the standard sprintf() function,
330 : * except that the text is appended to the #lt_string_t.
331 : */
332 : void
333 6 : lt_string_append_printf(lt_string_t *string,
334 : const char *format,
335 : ...)
336 : {
337 : va_list ap;
338 : char *str;
339 :
340 6 : lt_return_if_fail (string != NULL);
341 6 : lt_return_if_fail (format != NULL);
342 :
343 6 : va_start(ap, format);
344 6 : str = lt_strdup_vprintf(format, ap);
345 6 : lt_string_append(string, str);
346 6 : free(str);
347 :
348 6 : va_end(ap);
349 : }
350 :
351 : /**
352 : * lt_string_replace_c:
353 : * @string: a #lt_string_t
354 : * @pos: position in @string where replacement should happen
355 : * @c: the byte to replace
356 : *
357 : * Replaces a character in @string at @pos.
358 : *
359 : * Returns: (transfer none): the same @string object
360 : */
361 : lt_string_t *
362 0 : lt_string_replace_c(lt_string_t *string,
363 : size_t pos,
364 : char c)
365 : {
366 0 : lt_return_val_if_fail (string != NULL, NULL);
367 0 : lt_return_val_if_fail (pos < string->len, string);
368 0 : lt_return_val_if_fail (pos > 0, string);
369 :
370 0 : string->string[pos] = c;
371 :
372 0 : return string;
373 : }
374 :
375 : /**
376 : * lt_string_at:
377 : * @string: a #lt_string_t
378 : * @pos: position in @string where to obtain the byte
379 : *
380 : * Obtain a byte in a #lt_string_t at @pos. If @pos is a negative,
381 : * the position is calculated from current size. i.e. if the buffer
382 : * contains "abc", and @pos is -1, this will returns 'c' then.
383 : *
384 : * Returns: the byte in @string at @pos
385 : */
386 : char
387 148 : lt_string_at(lt_string_t *string,
388 : ssize_t pos)
389 : {
390 148 : lt_return_val_if_fail (string != NULL, 0);
391 :
392 148 : if (pos < 0)
393 148 : pos = string->len + pos;
394 148 : pos = LT_MAX (pos, 0);
395 148 : pos = LT_MIN (pos, string->len);
396 :
397 148 : return string->string[pos];
398 : }
|