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