ENH: make this work for older versions of OSX
[cmake.git] / Utilities / cmxmlrpc / xmlrpc_struct.c
blob50cc6dbd3e20b21dfffddb25fae20f2dde552692
1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 ** 1. Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** 2. Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** 3. The name of the author may not be used to endorse or promote products
12 ** derived from this software without specific prior written permission.
13 **
14 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 ** SUCH DAMAGE. */
26 #include "xmlrpc_config.h"
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "xmlrpc.h"
33 #include "xmlrpc_int.h"
35 #define KEY_ERROR_BUFFER_SZ (32)
38 void
39 xmlrpc_destroyStruct(xmlrpc_value * const structP) {
41 _struct_member * const members =
42 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
43 size_t const size =
44 XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
46 unsigned int i;
48 for (i = 0; i < size; ++i) {
49 xmlrpc_DECREF(members[i].key);
50 xmlrpc_DECREF(members[i].value);
52 XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block);
57 /*=========================================================================
58 ** xmlrpc_struct_new
59 **=========================================================================
60 ** Create a new <struct> value. The corresponding destructor code
61 ** currently lives in xmlrpc_DECREF.
63 ** We store the individual members in an array of _struct_member. This
64 ** contains a key, a hash code, and a value. We look up keys by doing
65 ** a linear search of the hash codes.
68 xmlrpc_value *
69 xmlrpc_struct_new(xmlrpc_env* env)
71 xmlrpc_value *strct;
72 int strct_valid;
74 XMLRPC_ASSERT_ENV_OK(env);
76 /* Set up error handling preconditions. */
77 strct_valid = 0;
79 /* Allocate and fill out an empty structure. */
80 strct = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
81 XMLRPC_FAIL_IF_NULL(strct, env, XMLRPC_INTERNAL_ERROR,
82 "Could not allocate memory for struct");
83 strct->_refcount = 1;
84 strct->_type = XMLRPC_TYPE_STRUCT;
85 XMLRPC_MEMBLOCK_INIT(_struct_member, env, &strct->_block, 0);
86 XMLRPC_FAIL_IF_FAULT(env);
87 strct_valid = 1;
89 cleanup:
90 if (env->fault_occurred) {
91 if (strct) {
92 if (strct_valid)
93 xmlrpc_DECREF(strct);
94 else
95 free(strct);
97 return NULL;
99 return strct;
104 /*=========================================================================
105 ** xmlrpc_struct_size
106 **=========================================================================
107 ** Return the number of key-value pairs contained in the struct. If the
108 ** value is not a struct, return -1 and set a fault.
111 int
112 xmlrpc_struct_size(xmlrpc_env* env, xmlrpc_value* strct)
114 int retval;
116 /* Suppress a compiler warning about uninitialized variables. */
117 retval = 0;
119 XMLRPC_ASSERT_ENV_OK(env);
120 XMLRPC_ASSERT_VALUE_OK(strct);
122 XMLRPC_TYPE_CHECK(env, strct, XMLRPC_TYPE_STRUCT);
123 retval = (int)XMLRPC_MEMBLOCK_SIZE(_struct_member, &strct->_block);
125 cleanup:
126 if (env->fault_occurred)
127 return -1;
128 return retval;
133 /*=========================================================================
134 ** get_hash
135 **=========================================================================
136 ** A mindlessly simple hash function. Please feel free to write something
137 ** more clever if this produces bad results.
140 static unsigned char
141 get_hash(const char * const key,
142 size_t const key_len) {
144 unsigned char retval;
145 size_t i;
147 XMLRPC_ASSERT(key != NULL);
149 retval = 0;
150 for (i = 0; i < key_len; i++)
151 retval += key[i];
152 return retval;
157 /*=========================================================================
158 ** find_member
159 **=========================================================================
160 ** Get the index of the member with the specified key, or -1 if no such
161 ** member exists.
164 static int
165 find_member(xmlrpc_value * const strctP,
166 const char * const key,
167 size_t const key_len) {
169 size_t size, i;
170 unsigned char hash;
171 _struct_member *contents;
172 xmlrpc_value *keyval;
173 char *keystr;
174 size_t keystr_size;
176 XMLRPC_ASSERT_VALUE_OK(strctP);
177 XMLRPC_ASSERT(key != NULL);
179 /* Look for our key. */
180 hash = get_hash(key, key_len);
181 size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strctP->_block);
182 contents = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
183 for (i = 0; i < size; i++) {
184 if (contents[i].key_hash == hash) {
185 keyval = contents[i].key;
186 keystr = XMLRPC_MEMBLOCK_CONTENTS(char, &keyval->_block);
187 keystr_size = XMLRPC_MEMBLOCK_SIZE(char, &keyval->_block)-1;
188 if (key_len == keystr_size && memcmp(key, keystr, key_len) == 0)
189 return (int)i;
192 return -1;
197 /*=========================================================================
198 ** xmlrpc_struct_has_key
199 **=========================================================================
202 int
203 xmlrpc_struct_has_key(xmlrpc_env * const envP,
204 xmlrpc_value * const strctP,
205 const char * const key) {
207 XMLRPC_ASSERT(key != NULL);
208 return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key));
213 int
214 xmlrpc_struct_has_key_n(xmlrpc_env * const envP,
215 xmlrpc_value * const strctP,
216 const char * const key,
217 size_t const key_len) {
218 int xmIndex;
220 /* Suppress a compiler warning about uninitialized variables. */
221 xmIndex = 0;
223 XMLRPC_ASSERT_ENV_OK(envP);
224 XMLRPC_ASSERT_VALUE_OK(strctP);
225 XMLRPC_ASSERT(key != NULL);
227 XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
228 xmIndex = find_member(strctP, key, key_len);
230 cleanup:
231 if (envP->fault_occurred)
232 return 0;
233 return (xmIndex >= 0);
238 /*=========================================================================
239 ** xmlrpc_struct_find_value...
240 **=========================================================================
241 ** These functions look up a specified key value in a specified struct.
242 ** If it exists, they return the value of the struct member. If not,
243 ** they return a NULL to indicate such.
246 /* It would be a nice extension to be able to look up a key that is
247 not a text string.
250 void
251 xmlrpc_struct_find_value(xmlrpc_env * const envP,
252 xmlrpc_value * const structP,
253 const char * const key,
254 xmlrpc_value ** const valuePP) {
255 /*----------------------------------------------------------------------------
256 Given a key, retrieve a value from the struct. If the key is not
257 present, return NULL as *valuePP.
258 -----------------------------------------------------------------------------*/
259 XMLRPC_ASSERT_ENV_OK(envP);
260 XMLRPC_ASSERT_VALUE_OK(structP);
261 XMLRPC_ASSERT_PTR_OK(key);
263 if (structP->_type != XMLRPC_TYPE_STRUCT)
264 xmlrpc_env_set_fault_formatted(
265 envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d",
266 structP->_type);
267 else {
268 int xmIndex;
270 /* Get our member index. */
271 xmIndex = find_member(structP, key, strlen(key));
272 if (xmIndex < 0)
273 *valuePP = NULL;
274 else {
275 _struct_member * const members =
276 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
277 *valuePP = members[xmIndex].value;
279 XMLRPC_ASSERT_VALUE_OK(*valuePP);
281 xmlrpc_INCREF(*valuePP);
288 void
289 xmlrpc_struct_find_value_v(xmlrpc_env * const envP,
290 xmlrpc_value * const structP,
291 xmlrpc_value * const keyP,
292 xmlrpc_value ** const valuePP) {
293 /*----------------------------------------------------------------------------
294 Given a key, retrieve a value from the struct. If the key is not
295 present, return NULL as *valuePP.
296 -----------------------------------------------------------------------------*/
297 XMLRPC_ASSERT_ENV_OK(envP);
298 XMLRPC_ASSERT_VALUE_OK(structP);
299 XMLRPC_ASSERT_VALUE_OK(keyP);
301 if (structP->_type != XMLRPC_TYPE_STRUCT)
302 xmlrpc_env_set_fault_formatted(
303 envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d",
304 structP->_type);
305 else {
306 if (keyP->_type != XMLRPC_TYPE_STRING)
307 xmlrpc_env_set_fault_formatted(
308 envP, XMLRPC_TYPE_ERROR, "Key value is not a string. "
309 "It is type #%d",
310 keyP->_type);
311 else {
312 int xmIndex;
314 /* Get our member index. */
315 xmIndex = find_member(structP,
316 XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block),
317 XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block)-1);
318 if (xmIndex < 0)
319 *valuePP = NULL;
320 else {
321 _struct_member * const members =
322 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
323 *valuePP = members[xmIndex].value;
325 XMLRPC_ASSERT_VALUE_OK(*valuePP);
327 xmlrpc_INCREF(*valuePP);
335 /*=========================================================================
336 ** xmlrpc_struct_read_value...
337 **=========================================================================
338 ** These fail if no member with the specified key exists.
339 ** Otherwise, they are the same as xmlrpc_struct_find_value...
342 void
343 xmlrpc_struct_read_value_v(xmlrpc_env * const envP,
344 xmlrpc_value * const structP,
345 xmlrpc_value * const keyP,
346 xmlrpc_value ** const valuePP) {
348 xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP);
350 if (!envP->fault_occurred) {
351 if (*valuePP == NULL) {
352 xmlrpc_env_set_fault_formatted(
353 envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'",
354 XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block),
355 XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block));
362 void
363 xmlrpc_struct_read_value(xmlrpc_env * const envP,
364 xmlrpc_value * const structP,
365 const char * const key,
366 xmlrpc_value ** const valuePP) {
368 xmlrpc_struct_find_value(envP, structP, key, valuePP);
370 if (!envP->fault_occurred) {
371 if (*valuePP == NULL) {
372 xmlrpc_env_set_fault_formatted(
373 envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%s'",
374 key);
375 /* We should fix the error message to format the key for display */
382 /*=========================================================================
383 ** xmlrpc_struct_get_value...
384 **=========================================================================
385 ** These are for backward compatibility. They used to be the only ones.
386 ** They're deprecated because they don't acquire a reference to the
387 ** value they return.
390 xmlrpc_value *
391 xmlrpc_struct_get_value_n(xmlrpc_env * const envP,
392 xmlrpc_value * const structP,
393 const char * const key,
394 size_t const keyLen) {
396 xmlrpc_value * retval;
397 xmlrpc_value * keyP;
399 keyP = xmlrpc_build_value(envP, "s#", key, keyLen);
400 if (!envP->fault_occurred) {
401 xmlrpc_struct_find_value_v(envP, structP, keyP, &retval);
403 if (!envP->fault_occurred) {
404 if (retval == NULL) {
405 xmlrpc_env_set_fault_formatted(
406 envP, XMLRPC_INDEX_ERROR,
407 "No member of struct has key '%.*s'",
408 keyLen, key);
409 /* We should fix the error message to format the key
410 for display */
411 } else
412 /* For backward compatibility. */
413 xmlrpc_DECREF(retval);
415 xmlrpc_DECREF(keyP);
417 return retval;
422 xmlrpc_value *
423 xmlrpc_struct_get_value(xmlrpc_env * const envP,
424 xmlrpc_value * const strctP,
425 const char * const key) {
427 XMLRPC_ASSERT(key != NULL);
428 return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key));
433 /*=========================================================================
434 ** xmlrpc_struct_set_value
435 **=========================================================================
438 void
439 xmlrpc_struct_set_value(xmlrpc_env * const envP,
440 xmlrpc_value * const strctP,
441 const char * const key,
442 xmlrpc_value * const valueP) {
444 XMLRPC_ASSERT(key != NULL);
445 xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP);
450 void
451 xmlrpc_struct_set_value_n(xmlrpc_env * const envP,
452 xmlrpc_value * const strctP,
453 const char * const key,
454 size_t const key_len,
455 xmlrpc_value * const valueP) {
457 xmlrpc_value *keyval;
459 XMLRPC_ASSERT_ENV_OK(envP);
460 XMLRPC_ASSERT(key != NULL);
462 /* Set up error handling preconditions. */
463 keyval = NULL;
465 XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
467 /* Build an xmlrpc_value from our string. */
468 keyval = xmlrpc_build_value(envP, "s#", key, key_len);
469 XMLRPC_FAIL_IF_FAULT(envP);
471 /* Do the actual work. */
472 xmlrpc_struct_set_value_v(envP, strctP, keyval, valueP);
474 cleanup:
475 if (keyval)
476 xmlrpc_DECREF(keyval);
481 void
482 xmlrpc_struct_set_value_v(xmlrpc_env * const envP,
483 xmlrpc_value * const strctP,
484 xmlrpc_value * const keyvalP,
485 xmlrpc_value * const valueP) {
487 char *key;
488 size_t key_len;
489 int xmIndex;
490 _struct_member *members, *member, new_member;
491 xmlrpc_value *old_value;
493 XMLRPC_ASSERT_ENV_OK(envP);
494 XMLRPC_ASSERT_VALUE_OK(strctP);
495 XMLRPC_ASSERT_VALUE_OK(keyvalP);
496 XMLRPC_ASSERT_VALUE_OK(valueP);
498 XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
499 XMLRPC_TYPE_CHECK(envP, keyvalP, XMLRPC_TYPE_STRING);
501 key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block);
502 key_len = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1;
503 xmIndex = find_member(strctP, key, key_len);
505 if (xmIndex >= 0) {
506 /* Change the value of an existing member. (But be careful--the
507 ** original and new values might be the same object, so watch
508 ** the order of INCREF and DECREF calls!) */
509 members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
510 member = &members[xmIndex];
512 /* Juggle our references. */
513 old_value = member->value;
514 member->value = valueP;
515 xmlrpc_INCREF(member->value);
516 xmlrpc_DECREF(old_value);
517 } else {
518 /* Add a new member. */
519 new_member.key_hash = get_hash(key, key_len);
520 new_member.key = keyvalP;
521 new_member.value = valueP;
522 XMLRPC_MEMBLOCK_APPEND(_struct_member, envP, &strctP->_block,
523 &new_member, 1);
524 XMLRPC_FAIL_IF_FAULT(envP);
525 xmlrpc_INCREF(keyvalP);
526 xmlrpc_INCREF(valueP);
529 cleanup:
530 return;
535 /* Note that the order of keys and values is undefined, and may change
536 when you modify the struct.
539 void
540 xmlrpc_struct_read_member(xmlrpc_env * const envP,
541 xmlrpc_value * const structP,
542 unsigned int const xmIndex,
543 xmlrpc_value ** const keyvalP,
544 xmlrpc_value ** const valueP) {
546 XMLRPC_ASSERT_ENV_OK(envP);
547 XMLRPC_ASSERT_VALUE_OK(structP);
548 XMLRPC_ASSERT_PTR_OK(keyvalP);
549 XMLRPC_ASSERT_PTR_OK(valueP);
551 if (structP->_type != XMLRPC_TYPE_STRUCT)
552 xmlrpc_env_set_fault_formatted(
553 envP, XMLRPC_TYPE_ERROR, "Attempt to read a struct member "
554 "of something that is not a struct");
555 else {
556 _struct_member * const members =
557 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
558 size_t const size =
559 XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
561 if (xmIndex >= size)
562 xmlrpc_env_set_fault_formatted(
563 envP, XMLRPC_INDEX_ERROR, "Index %u is beyond the end of "
564 "the %u-member structure", xmIndex, (unsigned int)size);
565 else {
566 _struct_member * const memberP = &members[xmIndex];
567 *keyvalP = memberP->key;
568 xmlrpc_INCREF(memberP->key);
569 *valueP = memberP->value;
570 xmlrpc_INCREF(memberP->value);
577 void
578 xmlrpc_struct_get_key_and_value(xmlrpc_env * const envP,
579 xmlrpc_value * const structP,
580 int const xmIndex,
581 xmlrpc_value ** const keyvalP,
582 xmlrpc_value ** const valueP) {
583 /*----------------------------------------------------------------------------
584 Same as xmlrpc_struct_read_member(), except doesn't take a reference
585 to the returned value.
587 This is obsolete.
588 -----------------------------------------------------------------------------*/
589 XMLRPC_ASSERT_ENV_OK(envP);
590 XMLRPC_ASSERT_VALUE_OK(structP);
591 XMLRPC_ASSERT_PTR_OK(keyvalP);
592 XMLRPC_ASSERT_PTR_OK(valueP);
594 if (xmIndex < 0)
595 xmlrpc_env_set_fault_formatted(
596 envP, XMLRPC_INDEX_ERROR, "Index %d is negative.");
597 else {
598 xmlrpc_struct_read_member(envP, structP, xmIndex, keyvalP, valueP);
599 if (!envP->fault_occurred) {
600 xmlrpc_DECREF(*keyvalP);
601 xmlrpc_DECREF(*valueP);
604 if (envP->fault_occurred) {
605 *keyvalP = NULL;
606 *valueP = NULL;