1 /* $NetBSD: prop_string.c,v 1.10 2008/04/28 20:22:53 martin 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 int _prop_string_free(prop_stack_t, prop_object_t *); 55 static bool _prop_string_externalize( 56 struct _prop_object_externalize_context *, 57 void *); 58 static bool _prop_string_equals(prop_object_t, prop_object_t, 59 void **, void **, 60 prop_object_t *, prop_object_t *); 61 62 static const struct _prop_object_type _prop_object_type_string = { 63 .pot_type = PROP_TYPE_STRING, 64 .pot_free = _prop_string_free, 65 .pot_extern = _prop_string_externalize, 66 .pot_equals = _prop_string_equals, 67 }; 68 69 #define prop_object_is_string(x) \ 70 ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string) 71 #define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "") 72 73 /* ARGSUSED */ 74 static int 75 _prop_string_free(prop_stack_t stack, prop_object_t *obj) 76 { 77 prop_string_t ps = *obj; 78 79 if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL) 80 _PROP_FREE(ps->ps_mutable, M_PROP_STRING); 81 _PROP_POOL_PUT(_prop_string_pool, ps); 82 83 return (_PROP_OBJECT_FREE_DONE); 84 } 85 86 static bool 87 _prop_string_externalize(struct _prop_object_externalize_context *ctx, 88 void *v) 89 { 90 prop_string_t ps = v; 91 92 if (ps->ps_size == 0) 93 return (_prop_object_externalize_empty_tag(ctx, "string")); 94 95 if (_prop_object_externalize_start_tag(ctx, "string") == false || 96 _prop_object_externalize_append_encoded_cstring(ctx, 97 ps->ps_immutable) == false || 98 _prop_object_externalize_end_tag(ctx, "string") == false) 99 return (false); 100 101 return (true); 102 } 103 104 /* ARGSUSED */ 105 static bool 106 _prop_string_equals(prop_object_t v1, prop_object_t v2, 107 void **stored_pointer1, void **stored_pointer2, 108 prop_object_t *next_obj1, prop_object_t *next_obj2) 109 { 110 prop_string_t str1 = v1; 111 prop_string_t str2 = v2; 112 113 if (str1 == str2) 114 return (_PROP_OBJECT_EQUALS_TRUE); 115 if (str1->ps_size != str2->ps_size) 116 return (_PROP_OBJECT_EQUALS_FALSE); 117 if (strcmp(prop_string_contents(str1), prop_string_contents(str2))) 118 return (_PROP_OBJECT_EQUALS_FALSE); 119 else 120 return (_PROP_OBJECT_EQUALS_TRUE); 121 } 122 123 static prop_string_t 124 _prop_string_alloc(void) 125 { 126 prop_string_t ps; 127 128 ps = _PROP_POOL_GET(_prop_string_pool); 129 if (ps != NULL) { 130 _prop_object_init(&ps->ps_obj, &_prop_object_type_string); 131 132 ps->ps_mutable = NULL; 133 ps->ps_size = 0; 134 ps->ps_flags = 0; 135 } 136 137 return (ps); 138 } 139 140 /* 141 * prop_string_create -- 142 * Create an empty mutable string. 143 */ 144 prop_string_t 145 prop_string_create(void) 146 { 147 148 return (_prop_string_alloc()); 149 } 150 151 /* 152 * prop_string_create_cstring -- 153 * Create a string that contains a copy of the provided C string. 154 */ 155 prop_string_t 156 prop_string_create_cstring(const char *str) 157 { 158 prop_string_t ps; 159 char *cp; 160 size_t len; 161 162 ps = _prop_string_alloc(); 163 if (ps != NULL) { 164 len = strlen(str); 165 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 166 if (cp == NULL) { 167 prop_object_release(ps); 168 return (NULL); 169 } 170 strcpy(cp, str); 171 ps->ps_mutable = cp; 172 ps->ps_size = len; 173 } 174 return (ps); 175 } 176 177 /* 178 * prop_string_create_cstring_nocopy -- 179 * Create an immutable string that contains a refrence to the 180 * provided C string. 181 */ 182 prop_string_t 183 prop_string_create_cstring_nocopy(const char *str) 184 { 185 prop_string_t ps; 186 187 ps = _prop_string_alloc(); 188 if (ps != NULL) { 189 ps->ps_immutable = str; 190 ps->ps_size = strlen(str); 191 ps->ps_flags |= PS_F_NOCOPY; 192 } 193 return (ps); 194 } 195 196 /* 197 * prop_string_copy -- 198 * Copy a string. If the original string is immutable, then the 199 * copy is also immutable and references the same external data. 200 */ 201 prop_string_t 202 prop_string_copy(prop_string_t ops) 203 { 204 prop_string_t ps; 205 206 if (! prop_object_is_string(ops)) 207 return (NULL); 208 209 ps = _prop_string_alloc(); 210 if (ps != NULL) { 211 ps->ps_size = ops->ps_size; 212 ps->ps_flags = ops->ps_flags; 213 if (ops->ps_flags & PS_F_NOCOPY) 214 ps->ps_immutable = ops->ps_immutable; 215 else { 216 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 217 if (cp == NULL) { 218 prop_object_release(ps); 219 return (NULL); 220 } 221 strcpy(cp, prop_string_contents(ops)); 222 ps->ps_mutable = cp; 223 } 224 } 225 return (ps); 226 } 227 228 /* 229 * prop_string_copy_mutable -- 230 * Copy a string, always returning a mutable copy. 231 */ 232 prop_string_t 233 prop_string_copy_mutable(prop_string_t ops) 234 { 235 prop_string_t ps; 236 char *cp; 237 238 if (! prop_object_is_string(ops)) 239 return (NULL); 240 241 ps = _prop_string_alloc(); 242 if (ps != NULL) { 243 ps->ps_size = ops->ps_size; 244 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 245 if (cp == NULL) { 246 prop_object_release(ps); 247 return (NULL); 248 } 249 strcpy(cp, prop_string_contents(ops)); 250 ps->ps_mutable = cp; 251 } 252 return (ps); 253 } 254 255 /* 256 * prop_string_size -- 257 * Return the size of the string, not including the terminating NUL. 258 */ 259 size_t 260 prop_string_size(prop_string_t ps) 261 { 262 263 if (! prop_object_is_string(ps)) 264 return (0); 265 266 return (ps->ps_size); 267 } 268 269 /* 270 * prop_string_mutable -- 271 * Return true if the string is a mutable string. 272 */ 273 bool 274 prop_string_mutable(prop_string_t ps) 275 { 276 277 if (! prop_object_is_string(ps)) 278 return (false); 279 280 return ((ps->ps_flags & PS_F_NOCOPY) == 0); 281 } 282 283 /* 284 * prop_string_cstring -- 285 * Return a copy of the contents of the string as a C string. 286 * The string is allocated with the M_TEMP malloc type. 287 */ 288 char * 289 prop_string_cstring(prop_string_t ps) 290 { 291 char *cp; 292 293 if (! prop_object_is_string(ps)) 294 return (NULL); 295 296 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP); 297 if (cp != NULL) 298 strcpy(cp, prop_string_contents(ps)); 299 300 return (cp); 301 } 302 303 /* 304 * prop_string_cstring_nocopy -- 305 * Return an immutable reference to the contents of the string 306 * as a C string. 307 */ 308 const char * 309 prop_string_cstring_nocopy(prop_string_t ps) 310 { 311 312 if (! prop_object_is_string(ps)) 313 return (NULL); 314 315 return (prop_string_contents(ps)); 316 } 317 318 /* 319 * prop_string_append -- 320 * Append the contents of one string to another. Returns true 321 * upon success. The destination string must be mutable. 322 */ 323 bool 324 prop_string_append(prop_string_t dst, prop_string_t src) 325 { 326 char *ocp, *cp; 327 size_t len; 328 329 if (! (prop_object_is_string(dst) && 330 prop_object_is_string(src))) 331 return (false); 332 333 if (dst->ps_flags & PS_F_NOCOPY) 334 return (false); 335 336 len = dst->ps_size + src->ps_size; 337 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 338 if (cp == NULL) 339 return (false); 340 sprintf(cp, "%s%s", prop_string_contents(dst), 341 prop_string_contents(src)); 342 ocp = dst->ps_mutable; 343 dst->ps_mutable = cp; 344 dst->ps_size = len; 345 if (ocp != NULL) 346 _PROP_FREE(ocp, M_PROP_STRING); 347 348 return (true); 349 } 350 351 /* 352 * prop_string_append_cstring -- 353 * Append a C string to a string. Returns true upon success. 354 * The destination string must be mutable. 355 */ 356 bool 357 prop_string_append_cstring(prop_string_t dst, const char *src) 358 { 359 char *ocp, *cp; 360 size_t len; 361 362 if (! prop_object_is_string(dst)) 363 return (false); 364 365 _PROP_ASSERT(src != NULL); 366 367 if (dst->ps_flags & PS_F_NOCOPY) 368 return (false); 369 370 len = dst->ps_size + strlen(src); 371 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 372 if (cp == NULL) 373 return (false); 374 sprintf(cp, "%s%s", prop_string_contents(dst), src); 375 ocp = dst->ps_mutable; 376 dst->ps_mutable = cp; 377 dst->ps_size = len; 378 if (ocp != NULL) 379 _PROP_FREE(ocp, M_PROP_STRING); 380 381 return (true); 382 } 383 384 /* 385 * prop_string_equals -- 386 * Return true if two strings are equivalent. 387 */ 388 bool 389 prop_string_equals(prop_string_t str1, prop_string_t str2) 390 { 391 if (!prop_object_is_string(str1) || !prop_object_is_string(str2)) 392 return (false); 393 394 return prop_object_equals(str1, str2); 395 } 396 397 /* 398 * prop_string_equals_cstring -- 399 * Return true if the string is equivalent to the specified 400 * C string. 401 */ 402 bool 403 prop_string_equals_cstring(prop_string_t ps, const char *cp) 404 { 405 406 if (! prop_object_is_string(ps)) 407 return (false); 408 409 return (strcmp(prop_string_contents(ps), cp) == 0); 410 } 411 412 /* 413 * _prop_string_internalize -- 414 * Parse a <string>...</string> and return the object created from the 415 * external representation. 416 */ 417 /* ARGSUSED */ 418 bool 419 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj, 420 struct _prop_object_internalize_context *ctx) 421 { 422 prop_string_t string; 423 char *str; 424 size_t len, alen; 425 426 if (ctx->poic_is_empty_element) { 427 *obj = prop_string_create(); 428 return (true); 429 } 430 431 /* No attributes recognized here. */ 432 if (ctx->poic_tagattr != NULL) 433 return (true); 434 435 /* Compute the length of the result. */ 436 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len, 437 NULL) == false) 438 return (true); 439 440 str = _PROP_MALLOC(len + 1, M_PROP_STRING); 441 if (str == NULL) 442 return (true); 443 444 if (_prop_object_internalize_decode_string(ctx, str, len, &alen, 445 &ctx->poic_cp) == false || 446 alen != len) { 447 _PROP_FREE(str, M_PROP_STRING); 448 return (true); 449 } 450 str[len] = '\0'; 451 452 if (_prop_object_internalize_find_tag(ctx, "string", 453 _PROP_TAG_TYPE_END) == false) { 454 _PROP_FREE(str, M_PROP_STRING); 455 return (true); 456 } 457 458 string = _prop_string_alloc(); 459 if (string == NULL) { 460 _PROP_FREE(str, M_PROP_STRING); 461 return (true); 462 } 463 464 string->ps_mutable = str; 465 string->ps_size = len; 466 *obj = string; 467 468 return (true); 469 } 470