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