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