1 1.1 christos /* $NetBSD: string.c,v 1.2 2017/01/28 21:31:45 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 2010 Kungliga Tekniska Hgskolan 5 1.1 christos * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 christos * All rights reserved. 7 1.1 christos * 8 1.1 christos * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 1.1 christos * 10 1.1 christos * Redistribution and use in source and binary forms, with or without 11 1.1 christos * modification, are permitted provided that the following conditions 12 1.1 christos * are met: 13 1.1 christos * 14 1.1 christos * 1. Redistributions of source code must retain the above copyright 15 1.1 christos * notice, this list of conditions and the following disclaimer. 16 1.1 christos * 17 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 christos * notice, this list of conditions and the following disclaimer in the 19 1.1 christos * documentation and/or other materials provided with the distribution. 20 1.1 christos * 21 1.1 christos * 3. Neither the name of the Institute nor the names of its contributors 22 1.1 christos * may be used to endorse or promote products derived from this software 23 1.1 christos * without specific prior written permission. 24 1.1 christos * 25 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.1 christos * SUCH DAMAGE. 36 1.1 christos */ 37 1.1 christos 38 1.1 christos #include "baselocl.h" 39 1.1 christos #include <string.h> 40 1.1 christos 41 1.1 christos static void 42 1.1 christos string_dealloc(void *ptr) 43 1.1 christos { 44 1.1 christos heim_string_t s = ptr; 45 1.1 christos heim_string_free_f_t *deallocp; 46 1.1 christos heim_string_free_f_t dealloc; 47 1.1 christos 48 1.1 christos if (*(const char *)ptr != '\0') 49 1.1 christos return; 50 1.1 christos 51 1.1 christos /* Possible string ref */ 52 1.1 christos deallocp = _heim_get_isaextra(s, 0); 53 1.1 christos dealloc = *deallocp; 54 1.1 christos if (dealloc != NULL) { 55 1.1 christos char **strp = _heim_get_isaextra(s, 1); 56 1.1 christos dealloc(*strp); 57 1.1 christos } 58 1.1 christos } 59 1.1 christos 60 1.1 christos static int 61 1.1 christos string_cmp(void *a, void *b) 62 1.1 christos { 63 1.1 christos if (*(char *)a == '\0') { 64 1.1 christos char **strp = _heim_get_isaextra(a, 1); 65 1.1 christos 66 1.1 christos if (*strp != NULL) 67 1.1 christos a = *strp; /* a is a string ref */ 68 1.1 christos } 69 1.1 christos if (*(char *)b == '\0') { 70 1.1 christos char **strp = _heim_get_isaextra(b, 1); 71 1.1 christos 72 1.1 christos if (*strp != NULL) 73 1.1 christos b = *strp; /* b is a string ref */ 74 1.1 christos } 75 1.1 christos return strcmp(a, b); 76 1.1 christos } 77 1.1 christos 78 1.1 christos static unsigned long 79 1.1 christos string_hash(void *ptr) 80 1.1 christos { 81 1.1 christos const char *s = ptr; 82 1.1 christos unsigned long n; 83 1.1 christos 84 1.1 christos for (n = 0; *s; ++s) 85 1.1 christos n += *s; 86 1.1 christos return n; 87 1.1 christos } 88 1.1 christos 89 1.1 christos struct heim_type_data _heim_string_object = { 90 1.1 christos HEIM_TID_STRING, 91 1.1 christos "string-object", 92 1.1 christos NULL, 93 1.1 christos string_dealloc, 94 1.1 christos NULL, 95 1.1 christos string_cmp, 96 1.1 christos string_hash, 97 1.1 christos NULL 98 1.1 christos }; 99 1.1 christos 100 1.1 christos /** 101 1.1 christos * Create a string object 102 1.1 christos * 103 1.1 christos * @param string the string to create, must be an utf8 string 104 1.1 christos * 105 1.1 christos * @return string object 106 1.1 christos */ 107 1.1 christos 108 1.1 christos heim_string_t 109 1.1 christos heim_string_create(const char *string) 110 1.1 christos { 111 1.1 christos return heim_string_create_with_bytes(string, strlen(string)); 112 1.1 christos } 113 1.1 christos 114 1.1 christos /** 115 1.1 christos * Create a string object without copying the source. 116 1.1 christos * 117 1.1 christos * @param string the string to referenced, must be UTF-8 118 1.1 christos * @param dealloc the function to use to release the referece to the string 119 1.1 christos * 120 1.1 christos * @return string object 121 1.1 christos */ 122 1.1 christos 123 1.1 christos heim_string_t 124 1.1 christos heim_string_ref_create(const char *string, heim_string_free_f_t dealloc) 125 1.1 christos { 126 1.1 christos heim_string_t s; 127 1.1 christos heim_string_free_f_t *deallocp; 128 1.1 christos 129 1.1 christos s = _heim_alloc_object(&_heim_string_object, 1); 130 1.1 christos if (s) { 131 1.1 christos const char **strp; 132 1.1 christos 133 1.1 christos ((char *)s)[0] = '\0'; 134 1.1 christos deallocp = _heim_get_isaextra(s, 0); 135 1.1 christos *deallocp = dealloc; 136 1.1 christos strp = _heim_get_isaextra(s, 1); 137 1.1 christos *strp = string; 138 1.1 christos } 139 1.1 christos return s; 140 1.1 christos } 141 1.1 christos 142 1.1 christos /** 143 1.1 christos * Create a string object 144 1.1 christos * 145 1.1 christos * @param string the string to create, must be an utf8 string 146 1.1 christos * @param len the length of the string 147 1.1 christos * 148 1.1 christos * @return string object 149 1.1 christos */ 150 1.1 christos 151 1.1 christos heim_string_t 152 1.1 christos heim_string_create_with_bytes(const void *data, size_t len) 153 1.1 christos { 154 1.1 christos heim_string_t s; 155 1.1 christos 156 1.1 christos s = _heim_alloc_object(&_heim_string_object, len + 1); 157 1.1 christos if (s) { 158 1.1 christos memcpy(s, data, len); 159 1.1 christos ((char *)s)[len] = '\0'; 160 1.1 christos } 161 1.1 christos return s; 162 1.1 christos } 163 1.1 christos 164 1.1 christos /** 165 1.1 christos * Create a string object using a format string 166 1.1 christos * 167 1.1 christos * @param fmt format string 168 1.1 christos * @param ... 169 1.1 christos * 170 1.1 christos * @return string object 171 1.1 christos */ 172 1.1 christos 173 1.1 christos heim_string_t 174 1.1 christos heim_string_create_with_format(const char *fmt, ...) 175 1.1 christos { 176 1.1 christos heim_string_t s; 177 1.1 christos char *str = NULL; 178 1.1 christos va_list ap; 179 1.1 christos int ret; 180 1.1 christos 181 1.1 christos va_start(ap, fmt); 182 1.1 christos ret = vasprintf(&str, fmt, ap); 183 1.1 christos va_end(ap); 184 1.1 christos if (ret < 0 || str == NULL) 185 1.1 christos return NULL; 186 1.1 christos 187 1.1 christos s = heim_string_ref_create(str, string_dealloc); 188 1.1 christos if (s == NULL) 189 1.1 christos free(str); 190 1.1 christos return s; 191 1.1 christos } 192 1.1 christos 193 1.1 christos /** 194 1.1 christos * Return the type ID of string objects 195 1.1 christos * 196 1.1 christos * @return type id of string objects 197 1.1 christos */ 198 1.1 christos 199 1.1 christos heim_tid_t 200 1.1 christos heim_string_get_type_id(void) 201 1.1 christos { 202 1.1 christos return HEIM_TID_STRING; 203 1.1 christos } 204 1.1 christos 205 1.1 christos /** 206 1.1 christos * Get the string value of the content. 207 1.1 christos * 208 1.1 christos * @param string the string object to get the value from 209 1.1 christos * 210 1.1 christos * @return a utf8 string 211 1.1 christos */ 212 1.1 christos 213 1.1 christos const char * 214 1.1 christos heim_string_get_utf8(heim_string_t string) 215 1.1 christos { 216 1.1 christos if (*(const char *)string == '\0') { 217 1.1 christos const char **strp; 218 1.1 christos 219 1.1 christos /* String ref */ 220 1.1 christos strp = _heim_get_isaextra(string, 1); 221 1.1 christos if (*strp != NULL) 222 1.1 christos return *strp; 223 1.1 christos } 224 1.1 christos return (const char *)string; 225 1.1 christos } 226 1.1 christos 227 1.1 christos /* 228 1.1 christos * 229 1.1 christos */ 230 1.1 christos 231 1.1 christos static void 232 1.1 christos init_string(void *ptr) 233 1.1 christos { 234 1.1 christos heim_dict_t *dict = ptr; 235 1.1 christos *dict = heim_dict_create(101); 236 1.1 christos heim_assert(*dict != NULL, "__heim_string_constant"); 237 1.1 christos } 238 1.1 christos 239 1.1 christos heim_string_t 240 1.1 christos __heim_string_constant(const char *_str) 241 1.1 christos { 242 1.1 christos static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; 243 1.1 christos static heim_base_once_t once; 244 1.1 christos static heim_dict_t dict = NULL; 245 1.1 christos heim_string_t s, s2; 246 1.1 christos 247 1.1 christos heim_base_once_f(&once, &dict, init_string); 248 1.1 christos s = heim_string_create(_str); 249 1.1 christos 250 1.1 christos HEIMDAL_MUTEX_lock(&mutex); 251 1.1 christos s2 = heim_dict_get_value(dict, s); 252 1.1 christos if (s2) { 253 1.1 christos heim_release(s); 254 1.1 christos s = s2; 255 1.1 christos } else { 256 1.1 christos _heim_make_permanent(s); 257 1.1 christos heim_dict_set_value(dict, s, s); 258 1.1 christos } 259 1.1 christos HEIMDAL_MUTEX_unlock(&mutex); 260 1.1 christos 261 1.1 christos return s; 262 1.1 christos } 263