1 /* $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <prop/prop_string.h> 33 #include "prop_object_impl.h" 34 35 struct _prop_string { 36 struct _prop_object ps_obj; 37 union { 38 char * psu_mutable; 39 const char * psu_immutable; 40 } ps_un; 41 #define ps_mutable ps_un.psu_mutable 42 #define ps_immutable ps_un.psu_immutable 43 size_t ps_size; /* not including \0 */ 44 int ps_flags; 45 }; 46 47 #define PS_F_NOCOPY 0x01 48 49 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng") 50 51 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string", 52 "property string container object") 53 54 static _prop_object_free_rv_t 55 _prop_string_free(prop_stack_t, prop_object_t *); 56 static bool _prop_string_externalize( 57 struct _prop_object_externalize_context *, 58 void *); 59 static _prop_object_equals_rv_t 60 _prop_string_equals(prop_object_t, prop_object_t, 61 void **, void **, 62 prop_object_t *, prop_object_t *); 63 64 static const struct _prop_object_type _prop_object_type_string = { 65 .pot_type = PROP_TYPE_STRING, 66 .pot_free = _prop_string_free, 67 .pot_extern = _prop_string_externalize, 68 .pot_equals = _prop_string_equals, 69 }; 70 71 #define prop_object_is_string(x) \ 72 ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string) 73 #define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "") 74 75 /* ARGSUSED */ 76 static _prop_object_free_rv_t 77 _prop_string_free(prop_stack_t stack, prop_object_t *obj) 78 { 79 prop_string_t ps = *obj; 80 81 if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL) 82 _PROP_FREE(ps->ps_mutable, M_PROP_STRING); 83 _PROP_POOL_PUT(_prop_string_pool, ps); 84 85 return (_PROP_OBJECT_FREE_DONE); 86 } 87 88 static bool 89 _prop_string_externalize(struct _prop_object_externalize_context *ctx, 90 void *v) 91 { 92 prop_string_t ps = v; 93 94 if (ps->ps_size == 0) 95 return (_prop_object_externalize_empty_tag(ctx, "string")); 96 97 if (_prop_object_externalize_start_tag(ctx, "string") == false || 98 _prop_object_externalize_append_encoded_cstring(ctx, 99 ps->ps_immutable) == false || 100 _prop_object_externalize_end_tag(ctx, "string") == false) 101 return (false); 102 103 return (true); 104 } 105 106 /* ARGSUSED */ 107 static _prop_object_equals_rv_t 108 _prop_string_equals(prop_object_t v1, prop_object_t v2, 109 void **stored_pointer1, void **stored_pointer2, 110 prop_object_t *next_obj1, prop_object_t *next_obj2) 111 { 112 prop_string_t str1 = v1; 113 prop_string_t str2 = v2; 114 115 if (str1 == str2) 116 return (_PROP_OBJECT_EQUALS_TRUE); 117 if (str1->ps_size != str2->ps_size) 118 return (_PROP_OBJECT_EQUALS_FALSE); 119 if (strcmp(prop_string_contents(str1), prop_string_contents(str2))) 120 return (_PROP_OBJECT_EQUALS_FALSE); 121 else 122 return (_PROP_OBJECT_EQUALS_TRUE); 123 } 124 125 static prop_string_t 126 _prop_string_alloc(void) 127 { 128 prop_string_t ps; 129 130 ps = _PROP_POOL_GET(_prop_string_pool); 131 if (ps != NULL) { 132 _prop_object_init(&ps->ps_obj, &_prop_object_type_string); 133 134 ps->ps_mutable = NULL; 135 ps->ps_size = 0; 136 ps->ps_flags = 0; 137 } 138 139 return (ps); 140 } 141 142 /* 143 * prop_string_create -- 144 * Create an empty mutable string. 145 */ 146 prop_string_t 147 prop_string_create(void) 148 { 149 150 return (_prop_string_alloc()); 151 } 152 153 /* 154 * prop_string_create_cstring -- 155 * Create a string that contains a copy of the provided C string. 156 */ 157 prop_string_t 158 prop_string_create_cstring(const char *str) 159 { 160 prop_string_t ps; 161 char *cp; 162 size_t len; 163 164 ps = _prop_string_alloc(); 165 if (ps != NULL) { 166 len = strlen(str); 167 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 168 if (cp == NULL) { 169 prop_object_release(ps); 170 return (NULL); 171 } 172 strcpy(cp, str); 173 ps->ps_mutable = cp; 174 ps->ps_size = len; 175 } 176 return (ps); 177 } 178 179 /* 180 * prop_string_create_cstring_nocopy -- 181 * Create an immutable string that contains a refrence to the 182 * provided C string. 183 */ 184 prop_string_t 185 prop_string_create_cstring_nocopy(const char *str) 186 { 187 prop_string_t ps; 188 189 ps = _prop_string_alloc(); 190 if (ps != NULL) { 191 ps->ps_immutable = str; 192 ps->ps_size = strlen(str); 193 ps->ps_flags |= PS_F_NOCOPY; 194 } 195 return (ps); 196 } 197 198 /* 199 * prop_string_copy -- 200 * Copy a string. If the original string is immutable, then the 201 * copy is also immutable and references the same external data. 202 */ 203 prop_string_t 204 prop_string_copy(prop_string_t ops) 205 { 206 prop_string_t ps; 207 208 if (! prop_object_is_string(ops)) 209 return (NULL); 210 211 ps = _prop_string_alloc(); 212 if (ps != NULL) { 213 ps->ps_size = ops->ps_size; 214 ps->ps_flags = ops->ps_flags; 215 if (ops->ps_flags & PS_F_NOCOPY) 216 ps->ps_immutable = ops->ps_immutable; 217 else { 218 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 219 if (cp == NULL) { 220 prop_object_release(ps); 221 return (NULL); 222 } 223 strcpy(cp, prop_string_contents(ops)); 224 ps->ps_mutable = cp; 225 } 226 } 227 return (ps); 228 } 229 230 /* 231 * prop_string_copy_mutable -- 232 * Copy a string, always returning a mutable copy. 233 */ 234 prop_string_t 235 prop_string_copy_mutable(prop_string_t ops) 236 { 237 prop_string_t ps; 238 char *cp; 239 240 if (! prop_object_is_string(ops)) 241 return (NULL); 242 243 ps = _prop_string_alloc(); 244 if (ps != NULL) { 245 ps->ps_size = ops->ps_size; 246 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 247 if (cp == NULL) { 248 prop_object_release(ps); 249 return (NULL); 250 } 251 strcpy(cp, prop_string_contents(ops)); 252 ps->ps_mutable = cp; 253 } 254 return (ps); 255 } 256 257 /* 258 * prop_string_size -- 259 * Return the size of the string, not including the terminating NUL. 260 */ 261 size_t 262 prop_string_size(prop_string_t ps) 263 { 264 265 if (! prop_object_is_string(ps)) 266 return (0); 267 268 return (ps->ps_size); 269 } 270 271 /* 272 * prop_string_mutable -- 273 * Return true if the string is a mutable string. 274 */ 275 bool 276 prop_string_mutable(prop_string_t ps) 277 { 278 279 if (! prop_object_is_string(ps)) 280 return (false); 281 282 return ((ps->ps_flags & PS_F_NOCOPY) == 0); 283 } 284 285 /* 286 * prop_string_cstring -- 287 * Return a copy of the contents of the string as a C string. 288 * The string is allocated with the M_TEMP malloc type. 289 */ 290 char * 291 prop_string_cstring(prop_string_t ps) 292 { 293 char *cp; 294 295 if (! prop_object_is_string(ps)) 296 return (NULL); 297 298 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP); 299 if (cp != NULL) 300 strcpy(cp, prop_string_contents(ps)); 301 302 return (cp); 303 } 304 305 /* 306 * prop_string_cstring_nocopy -- 307 * Return an immutable reference to the contents of the string 308 * as a C string. 309 */ 310 const char * 311 prop_string_cstring_nocopy(prop_string_t ps) 312 { 313 314 if (! prop_object_is_string(ps)) 315 return (NULL); 316 317 return (prop_string_contents(ps)); 318 } 319 320 /* 321 * prop_string_append -- 322 * Append the contents of one string to another. Returns true 323 * upon success. The destination string must be mutable. 324 */ 325 bool 326 prop_string_append(prop_string_t dst, prop_string_t src) 327 { 328 char *ocp, *cp; 329 size_t len; 330 331 if (! (prop_object_is_string(dst) && 332 prop_object_is_string(src))) 333 return (false); 334 335 if (dst->ps_flags & PS_F_NOCOPY) 336 return (false); 337 338 len = dst->ps_size + src->ps_size; 339 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 340 if (cp == NULL) 341 return (false); 342 sprintf(cp, "%s%s", prop_string_contents(dst), 343 prop_string_contents(src)); 344 ocp = dst->ps_mutable; 345 dst->ps_mutable = cp; 346 dst->ps_size = len; 347 if (ocp != NULL) 348 _PROP_FREE(ocp, M_PROP_STRING); 349 350 return (true); 351 } 352 353 /* 354 * prop_string_append_cstring -- 355 * Append a C string to a string. Returns true upon success. 356 * The destination string must be mutable. 357 */ 358 bool 359 prop_string_append_cstring(prop_string_t dst, const char *src) 360 { 361 char *ocp, *cp; 362 size_t len; 363 364 if (! prop_object_is_string(dst)) 365 return (false); 366 367 _PROP_ASSERT(src != NULL); 368 369 if (dst->ps_flags & PS_F_NOCOPY) 370 return (false); 371 372 len = dst->ps_size + strlen(src); 373 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 374 if (cp == NULL) 375 return (false); 376 sprintf(cp, "%s%s", prop_string_contents(dst), src); 377 ocp = dst->ps_mutable; 378 dst->ps_mutable = cp; 379 dst->ps_size = len; 380 if (ocp != NULL) 381 _PROP_FREE(ocp, M_PROP_STRING); 382 383 return (true); 384 } 385 386 /* 387 * prop_string_equals -- 388 * Return true if two strings are equivalent. 389 */ 390 bool 391 prop_string_equals(prop_string_t str1, prop_string_t str2) 392 { 393 if (!prop_object_is_string(str1) || !prop_object_is_string(str2)) 394 return (false); 395 396 return prop_object_equals(str1, str2); 397 } 398 399 /* 400 * prop_string_equals_cstring -- 401 * Return true if the string is equivalent to the specified 402 * C string. 403 */ 404 bool 405 prop_string_equals_cstring(prop_string_t ps, const char *cp) 406 { 407 408 if (! prop_object_is_string(ps)) 409 return (false); 410 411 return (strcmp(prop_string_contents(ps), cp) == 0); 412 } 413 414 /* 415 * _prop_string_internalize -- 416 * Parse a <string>...</string> and return the object created from the 417 * external representation. 418 */ 419 /* ARGSUSED */ 420 bool 421 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj, 422 struct _prop_object_internalize_context *ctx) 423 { 424 prop_string_t string; 425 char *str; 426 size_t len, alen; 427 428 if (ctx->poic_is_empty_element) { 429 *obj = prop_string_create(); 430 return (true); 431 } 432 433 /* No attributes recognized here. */ 434 if (ctx->poic_tagattr != NULL) 435 return (true); 436 437 /* Compute the length of the result. */ 438 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len, 439 NULL) == false) 440 return (true); 441 442 str = _PROP_MALLOC(len + 1, M_PROP_STRING); 443 if (str == NULL) 444 return (true); 445 446 if (_prop_object_internalize_decode_string(ctx, str, len, &alen, 447 &ctx->poic_cp) == false || 448 alen != len) { 449 _PROP_FREE(str, M_PROP_STRING); 450 return (true); 451 } 452 str[len] = '\0'; 453 454 if (_prop_object_internalize_find_tag(ctx, "string", 455 _PROP_TAG_TYPE_END) == false) { 456 _PROP_FREE(str, M_PROP_STRING); 457 return (true); 458 } 459 460 string = _prop_string_alloc(); 461 if (string == NULL) { 462 _PROP_FREE(str, M_PROP_STRING); 463 return (true); 464 } 465 466 string->ps_mutable = str; 467 string->ps_size = len; 468 *obj = string; 469 470 return (true); 471 } 472