1 /* Copyright information is at end of file */
3 #include "xmlrpc_config.h"
12 #include "xmlrpc-c/base.h"
13 #include "xmlrpc-c/base_int.h"
14 #include "xmlrpc-c/string_int.h"
16 /* Borrowed from Python 1.5.2.
17 ** MPW pushes 'extended' for float and double types with varargs */
19 typedef extended va_double;
21 typedef double va_double;
24 /* Borrowed from Python 1.5.2.
25 ** Python copies its va_list objects before using them in certain
26 ** tricky fashions. We don't why Python does this, but since we're
27 ** abusing our va_list objects in a similar fashion, we'll copy them
30 #define VA_LIST_COPY(dest,src) memcpy((dest), (src), sizeof(va_list))
32 #define VA_LIST_COPY(dest,src) ((dest) = (src))
35 /*=========================================================================
36 ** Creating XML-RPC values.
37 **=========================================================================
38 ** Build new XML-RPC values from a format string. This code is heavily
39 ** inspired by Py_BuildValue from Python 1.5.2. In particular, our
40 ** particular abuse of the va_list data type is copied from the equivalent
41 ** Python code in modsupport.c. Since Python is portable, our code should
42 ** (in theory) also be portable.
47 getString(xmlrpc_env * const envP,
48 const char ** const formatP,
50 xmlrpc_value ** const valPP) {
55 str = (const char*) va_arg(*args, char*);
56 if (**formatP == '#') {
58 len = (size_t) va_arg(*args, size_t);
62 *valPP = xmlrpc_string_new_lp(envP, len, str);
67 #if HAVE_UNICODE_WCHAR
69 mkWideString(xmlrpc_env * const envP,
72 xmlrpc_value ** const valPP) {
76 wchar_t *wcs_contents;
78 xmlrpc_mem_block *utf8_block;
82 /* Error-handling preconditions. */
87 /* Initialize our XML-RPC value. */
88 valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
89 XMLRPC_FAIL_IF_NULL(valP, envP, XMLRPC_INTERNAL_ERROR,
90 "Could not allocate memory for wide string");
92 valP->_type = XMLRPC_TYPE_STRING;
94 /* More error-handling preconditions. */
95 valP->_wcs_block = NULL;
97 /* Build our wchar_t block first. */
99 XMLRPC_TYPED_MEM_BLOCK_NEW(wchar_t, envP, wcs_len + 1);
100 XMLRPC_FAIL_IF_FAULT(envP);
102 XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, valP->_wcs_block);
103 memcpy(wcs_contents, wcs, wcs_len * sizeof(wchar_t));
104 wcs_contents[wcs_len] = '\0';
106 /* Convert the wcs block to UTF-8. */
107 utf8_block = xmlrpc_wcs_to_utf8(envP, wcs_contents, wcs_len + 1);
108 XMLRPC_FAIL_IF_FAULT(envP);
109 utf8_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, utf8_block);
110 utf8_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, utf8_block);
112 /* XXX - We need an extra memcopy to initialize _block. */
113 XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &valP->_block, utf8_len);
114 XMLRPC_FAIL_IF_FAULT(envP);
116 contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
117 memcpy(contents, utf8_contents, utf8_len);
121 xmlrpc_mem_block_free(utf8_block);
122 if (envP->fault_occurred) {
124 if (valP->_wcs_block)
125 xmlrpc_mem_block_free(valP->_wcs_block);
127 xmlrpc_mem_block_clean(&valP->_block);
133 #endif /* HAVE_UNICODE_WCHAR */
138 getWideString(xmlrpc_env * const envP ATTR_UNUSED,
139 const char ** const formatP ATTR_UNUSED,
140 va_list * const args ATTR_UNUSED,
141 xmlrpc_value ** const valPP ATTR_UNUSED) {
143 #if HAVE_UNICODE_WCHAR
147 wcs = (wchar_t*) va_arg(*args, wchar_t*);
148 if (**formatP == '#') {
150 len = (size_t) va_arg(*args, size_t);
154 mkWideString(envP, wcs, len, valPP);
156 #endif /* HAVE_UNICODE_WCHAR */
162 getBase64(xmlrpc_env * const envP,
163 va_list * const args,
164 xmlrpc_value ** const valPP) {
166 unsigned char * value;
169 value = (unsigned char*) va_arg(*args, unsigned char*);
170 length = (size_t) va_arg(*args, size_t);
172 *valPP = xmlrpc_base64_new(envP, length, value);
178 getValue(xmlrpc_env * const envP,
179 const char** const format,
181 xmlrpc_value ** const valPP);
186 getArray(xmlrpc_env * const envP,
187 const char ** const formatP,
188 char const delimiter,
189 va_list * const args,
190 xmlrpc_value ** const arrayPP) {
192 xmlrpc_value * arrayP;
194 arrayP = xmlrpc_array_new(envP);
196 /* Add items to the array until we hit our delimiter. */
198 while (**formatP != delimiter && !envP->fault_occurred) {
200 xmlrpc_value * itemP;
202 if (**formatP == '\0')
203 xmlrpc_env_set_fault(
204 envP, XMLRPC_INTERNAL_ERROR,
205 "format string ended before closing ')'.");
207 getValue(envP, formatP, args, &itemP);
208 if (!envP->fault_occurred) {
209 xmlrpc_array_append_item(envP, arrayP, itemP);
210 xmlrpc_DECREF(itemP);
214 if (envP->fault_occurred)
215 xmlrpc_DECREF(arrayP);
223 getStructMember(xmlrpc_env * const envP,
224 const char ** const formatP,
225 va_list * const args,
226 xmlrpc_value ** const keyPP,
227 xmlrpc_value ** const valuePP) {
231 getValue(envP, formatP, args, keyPP);
232 if (!envP->fault_occurred) {
233 if (**formatP != ':')
234 xmlrpc_env_set_fault(
235 envP, XMLRPC_INTERNAL_ERROR,
236 "format string does not have ':' after a "
237 "structure member key.");
239 /* Skip over colon that separates key from value */
243 getValue(envP, formatP, args, valuePP);
245 if (envP->fault_occurred)
246 xmlrpc_DECREF(*keyPP);
253 getStruct(xmlrpc_env * const envP,
254 const char ** const formatP,
255 char const delimiter,
256 va_list * const args,
257 xmlrpc_value ** const structPP) {
259 xmlrpc_value * structP;
261 structP = xmlrpc_struct_new(envP);
262 if (!envP->fault_occurred) {
263 while (**formatP != delimiter && !envP->fault_occurred) {
265 xmlrpc_value * valueP;
267 getStructMember(envP, formatP, args, &keyP, &valueP);
269 if (!envP->fault_occurred) {
270 if (**formatP == ',')
271 (*formatP)++; /* Skip over the comma */
272 else if (**formatP == delimiter) {
273 /* End of the line */
275 xmlrpc_env_set_fault(
276 envP, XMLRPC_INTERNAL_ERROR,
277 "format string does not have ',' or ')' after "
278 "a structure member");
280 if (!envP->fault_occurred)
281 /* Add the new member to the struct. */
282 xmlrpc_struct_set_value_v(envP, structP, keyP, valueP);
284 xmlrpc_DECREF(valueP);
288 if (envP->fault_occurred)
289 xmlrpc_DECREF(structP);
297 mkArrayFromVal(xmlrpc_env * const envP,
298 xmlrpc_value * const value,
299 xmlrpc_value ** const valPP) {
301 if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY)
302 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
303 "Array format ('A'), non-array xmlrpc_value");
305 xmlrpc_INCREF(value);
313 mkStructFromVal(xmlrpc_env * const envP,
314 xmlrpc_value * const value,
315 xmlrpc_value ** const valPP) {
317 if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT)
318 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
319 "Struct format ('S'), non-struct xmlrpc_value");
321 xmlrpc_INCREF(value);
329 getValue(xmlrpc_env * const envP,
330 const char** const formatP,
331 va_list * const args,
332 xmlrpc_value ** const valPP) {
333 /*----------------------------------------------------------------------------
334 Get the next value from the list. *formatP points to the specifier
335 for the next value in the format string (i.e. to the type code
336 character) and we move *formatP past the whole specifier for the
337 next value. We read the required arguments from 'args'. We return
338 the value as *valPP with a reference to it.
340 For example, if *formatP points to the "i" in the string "sis",
341 we read one argument from 'args' and return as *valP an integer whose
342 value is the argument we read. We advance *formatP to point to the
343 last 's' and advance 'args' to point to the argument that belongs to
345 -----------------------------------------------------------------------------*/
346 char const formatChar = *(*formatP)++;
348 switch (formatChar) {
351 xmlrpc_int_new(envP, (xmlrpc_int32) va_arg(*args, xmlrpc_int32));
356 xmlrpc_bool_new(envP, (xmlrpc_bool) va_arg(*args, xmlrpc_bool));
361 xmlrpc_double_new(envP, (double) va_arg(*args, va_double));
365 getString(envP, formatP, args, valPP);
369 getWideString(envP, formatP, args, valPP);
372 /* The code 't' is reserved for a better, time_t based
373 implementation of dateTime conversion.
377 xmlrpc_datetime_new_str(envP, (char*) va_arg(*args, char*));
381 getBase64(envP, args, valPP);
386 xmlrpc_nil_new(envP);
390 /* We might someday want to use the code 'p!' to read in a
391 cleanup function for this pointer.
394 xmlrpc_cptr_new(envP, (void*) va_arg(*args, void*));
398 mkArrayFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
403 mkStructFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*),
408 *valPP = (xmlrpc_value*) va_arg(*args, xmlrpc_value*);
409 xmlrpc_INCREF(*valPP);
413 getArray(envP, formatP, ')', args, valPP);
414 if (!envP->fault_occurred) {
415 XMLRPC_ASSERT(**formatP == ')');
416 (*formatP)++; /* Skip over closing parenthesis */
421 getStruct(envP, formatP, '}', args, valPP);
422 if (!envP->fault_occurred) {
423 XMLRPC_ASSERT(**formatP == '}');
424 (*formatP)++; /* Skip over closing brace */
429 const char * const badCharacter = xmlrpc_makePrintableChar(formatChar);
430 xmlrpc_env_set_fault_formatted(
431 envP, XMLRPC_INTERNAL_ERROR,
432 "Unexpected character '%s' in format string", badCharacter);
433 xmlrpc_strfree(badCharacter);
441 xmlrpc_build_value_va(xmlrpc_env * const envP,
442 const char * const format,
444 xmlrpc_value ** const valPP,
445 const char ** const tailP) {
447 const char * formatCursor;
450 XMLRPC_ASSERT_ENV_OK(envP);
451 XMLRPC_ASSERT(format != NULL);
453 if (strlen(format) == 0)
454 xmlrpc_env_set_fault_formatted(
455 envP, XMLRPC_INTERNAL_ERROR, "Format string is empty.");
457 formatCursor = &format[0];
458 VA_LIST_COPY(args_copy, args);
459 getValue(envP, &formatCursor, &args_copy, valPP);
461 if (!envP->fault_occurred)
462 XMLRPC_ASSERT_VALUE_OK(*valPP);
464 *tailP = formatCursor;
471 xmlrpc_build_value(xmlrpc_env * const envP,
472 const char * const format,
476 xmlrpc_value* retval;
479 va_start(args, format);
480 xmlrpc_build_value_va(envP, format, args, &retval, &suffix);
483 if (!envP->fault_occurred) {
485 xmlrpc_env_set_fault_formatted(
486 envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
487 "specifier: '%s'. There must be exactly one arument.",
490 if (envP->fault_occurred)
491 xmlrpc_DECREF(retval);
500 /*=========================================================================
501 ** Parsing XML-RPC values.
502 **=========================================================================
503 ** Parse an XML-RPC value based on a format string. This code is heavily
504 ** inspired by Py_BuildValue from Python 1.5.2.
507 /* Prototype for recursive invocation: */
510 decomposeValue(xmlrpc_env * const env,
511 xmlrpc_value * const val,
512 const char ** const format,
514 xmlrpc_bool const oldstyleMemMgmt);
519 parsearray(xmlrpc_env * const env,
520 const xmlrpc_value * const array,
521 const char ** const format,
522 char const delimiter,
524 xmlrpc_bool const oldstyleMemMgmt) {
529 /* Fetch the array size. */
530 size = xmlrpc_array_size(env, array);
531 XMLRPC_FAIL_IF_FAULT(env);
533 /* Loop over the items in the array. */
534 for (i = 0; i < size; i++) {
535 /* Bail out if the caller didn't care about the rest of the items. */
539 item = xmlrpc_array_get_item(env, array, i);
540 XMLRPC_FAIL_IF_FAULT(env);
542 XMLRPC_ASSERT(**format != '\0');
543 if (**format == delimiter)
544 XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Too many items in array");
545 decomposeValue(env, item, format, args, oldstyleMemMgmt);
546 XMLRPC_FAIL_IF_FAULT(env);
550 if (**format != delimiter)
551 XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Not enough items in array");
560 parsestruct(xmlrpc_env * const env,
561 xmlrpc_value * const strct,
562 const char ** const format,
563 char const delimiter,
565 xmlrpc_bool const oldstyleMemMgmt) {
567 xmlrpc_value *key, *value;
571 /* Set up error handling preconditions. */
574 /* Build the members of our struct. */
575 while (**format != '*' && **format != delimiter && **format != '\0') {
577 /* Get our key, and skip over the ':' character. Notice the
578 ** sudden call to getValue--we're going in the opposite direction. */
579 getValue(env, format, args, &key);
580 XMLRPC_FAIL_IF_FAULT(env);
581 XMLRPC_ASSERT(**format == ':');
584 /* Look up the value for our key. */
585 xmlrpc_parse_value(env, key, "s#", &keystr, &keylen);
586 XMLRPC_FAIL_IF_FAULT(env);
587 value = xmlrpc_struct_get_value_n(env, strct, keystr, keylen);
588 XMLRPC_FAIL_IF_FAULT(env);
590 /* Get our value, and skip over the ',' character (if present). */
591 decomposeValue(env, value, format, args, oldstyleMemMgmt);
592 XMLRPC_FAIL_IF_FAULT(env);
593 XMLRPC_ASSERT(**format == ',' || **format == delimiter);
597 /* Release our reference, and restore our invariant. */
601 if (**format == '*') {
603 if (**format != delimiter && **format != '\0')
604 XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR,
605 "* can appear only at the end "
606 "of a structure format specifier");
608 /* Here we're supposed to fail if he didn't extract all the
609 members. But we don't know how to determine whether he
610 specified all the members, so we always fail.
612 XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "You must specify '*' as the "
613 "last member of a structure in a format specifier "
614 "used for parsing an xmlrpc_value");
616 XMLRPC_ASSERT(**format == delimiter || **format == '\0');
625 readString(xmlrpc_env * const envP,
626 const xmlrpc_value * const valueP,
627 const char ** const stringValueP,
628 xmlrpc_bool const oldstyleMemMgmt) {
630 if (oldstyleMemMgmt) {
631 xmlrpc_read_string_old(envP, valueP, stringValueP);
633 xmlrpc_read_string(envP, valueP, stringValueP);
639 readStringLp(xmlrpc_env * const envP,
640 const xmlrpc_value * const valueP,
641 size_t * const lengthP,
642 const char ** const stringValueP,
643 xmlrpc_bool const oldstyleMemMgmt) {
645 if (oldstyleMemMgmt) {
646 xmlrpc_read_string_lp_old(envP, valueP, lengthP, stringValueP);
648 xmlrpc_read_string_lp(envP, valueP, lengthP, stringValueP);
653 #if HAVE_UNICODE_WCHAR
655 readStringW(xmlrpc_env * const envP,
656 xmlrpc_value * const valueP,
657 const wchar_t ** const stringValueP,
658 xmlrpc_bool const oldstyleMemMgmt) {
660 if (oldstyleMemMgmt) {
661 xmlrpc_read_string_w_old(envP, valueP, stringValueP);
663 xmlrpc_read_string_w(envP, valueP, stringValueP);
669 readStringWLp(xmlrpc_env * const envP,
670 xmlrpc_value * const valueP,
671 size_t * const lengthP,
672 const wchar_t ** const stringValueP,
673 xmlrpc_bool const oldstyleMemMgmt) {
675 if (oldstyleMemMgmt) {
676 xmlrpc_read_string_w_lp_old(envP, valueP, lengthP, stringValueP);
678 xmlrpc_read_string_w_lp(envP, valueP, lengthP, stringValueP);
684 readDatetimeStr(xmlrpc_env * const envP,
685 const xmlrpc_value * const valueP,
686 const char ** const stringValueP,
687 xmlrpc_bool const oldstyleMemMgmt) {
690 xmlrpc_read_datetime_str_old(envP, valueP, stringValueP);
692 xmlrpc_read_datetime_str(envP, valueP, stringValueP);
698 readBase64(xmlrpc_env * const envP,
699 const xmlrpc_value * const valueP,
700 size_t * const lengthP,
701 const unsigned char ** const byteStringValueP,
702 xmlrpc_bool const oldstyleMemMgmt) {
705 xmlrpc_read_base64_old(envP, valueP, lengthP, byteStringValueP);
707 xmlrpc_read_base64(envP, valueP, lengthP, byteStringValueP);
713 decomposeValue(xmlrpc_env * const envP,
714 xmlrpc_value * const valueP,
715 const char ** const format,
717 xmlrpc_bool const oldstyleMemMgmt) {
721 formatSpecChar = *(*format)++;
723 switch (formatSpecChar) {
725 xmlrpc_int32 * const int32ptr =
726 (xmlrpc_int32*) va_arg(*args, xmlrpc_int32*);
727 xmlrpc_read_int(envP, valueP, int32ptr);
732 xmlrpc_bool * const boolptr =
733 (xmlrpc_bool*) va_arg(*args, xmlrpc_bool*);
734 xmlrpc_read_bool(envP, valueP, boolptr);
739 double * const doubleptr = (double*) va_arg(*args, double*);
740 xmlrpc_read_double(envP, valueP, doubleptr);
745 /* The code 't' is reserved for a better, time_t based
746 implementation of dateTime conversion.
748 const char ** const strptr = (const char**) va_arg(*args, char**);
749 readDatetimeStr(envP, valueP, strptr, oldstyleMemMgmt);
754 const char ** const strptr = (const char**) va_arg(*args, char**);
755 if (**format == '#') {
756 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
759 readStringLp(envP, valueP, sizeptr, strptr, oldstyleMemMgmt);
761 readString(envP, valueP, strptr, oldstyleMemMgmt);
766 #if HAVE_UNICODE_WCHAR
767 const wchar_t ** const wcsptr =
768 (const wchar_t**) va_arg(*args, wchar_t**);
769 if (**format == '#') {
770 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
772 readStringWLp(envP, valueP, sizeptr, wcsptr, oldstyleMemMgmt);
774 readStringW(envP, valueP, wcsptr, oldstyleMemMgmt);
776 xmlrpc_env_set_fault_formatted(
777 envP, XMLRPC_INTERNAL_ERROR,
778 "This XML-RPC For C/C++ library was built without Unicode "
779 "wide character capability. 'w' isn't available.");
780 #endif /* HAVE_UNICODE_WCHAR */
785 const unsigned char ** const binptr =
786 (const unsigned char**) va_arg(*args, unsigned char**);
787 size_t * const sizeptr = (size_t*) va_arg(*args, size_t**);
788 readBase64(envP, valueP, sizeptr, binptr, oldstyleMemMgmt);
793 xmlrpc_read_nil(envP, valueP);
798 void ** const voidptrptr = (void**) va_arg(*args, void**);
799 xmlrpc_read_cptr(envP, valueP, voidptrptr);
804 xmlrpc_value ** const valptr =
805 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
807 if (!oldstyleMemMgmt)
808 xmlrpc_INCREF(valueP);
813 if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY)
814 xmlrpc_env_set_fault_formatted(
815 envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for "
818 xmlrpc_value ** const valptr =
819 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
821 if (!oldstyleMemMgmt)
822 xmlrpc_INCREF(valueP);
827 if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT)
828 xmlrpc_env_set_fault_formatted(
829 envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for "
832 xmlrpc_value ** const valptr =
833 (xmlrpc_value**) va_arg(*args, xmlrpc_value**);
835 if (!oldstyleMemMgmt)
836 xmlrpc_INCREF(valueP);
841 if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY)
842 xmlrpc_env_set_fault_formatted(
843 envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for "
846 parsearray(envP, valueP, format, ')', args, oldstyleMemMgmt);
852 if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT)
853 xmlrpc_env_set_fault_formatted(
854 envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for "
857 parsestruct(envP, valueP, format, '}', args, oldstyleMemMgmt);
863 xmlrpc_env_set_fault_formatted(
864 envP, XMLRPC_INTERNAL_ERROR, "Invalid format character '%c'",
872 xmlrpc_decompose_value_va(xmlrpc_env * const envP,
873 xmlrpc_value * const value,
874 const char * const format,
877 const char *format_copy;
880 XMLRPC_ASSERT_ENV_OK(envP);
881 XMLRPC_ASSERT_VALUE_OK(value);
882 XMLRPC_ASSERT(format != NULL);
884 format_copy = format;
885 VA_LIST_COPY(args_copy, args);
886 decomposeValue(envP, value, &format_copy, &args_copy, false);
887 if (!envP->fault_occurred) {
888 XMLRPC_ASSERT(*format_copy == '\0');
895 xmlrpc_decompose_value(xmlrpc_env * const envP,
896 xmlrpc_value * const value,
897 const char * const format,
902 va_start(args, format);
903 xmlrpc_decompose_value_va(envP, value, format, args);
910 xmlrpc_parse_value_va(xmlrpc_env * const envP,
911 xmlrpc_value * const value,
912 const char * const format,
915 const char *format_copy;
918 XMLRPC_ASSERT_ENV_OK(envP);
919 XMLRPC_ASSERT_VALUE_OK(value);
920 XMLRPC_ASSERT(format != NULL);
922 format_copy = format;
923 VA_LIST_COPY(args_copy, args);
924 decomposeValue(envP, value, &format_copy, &args_copy, true);
925 if (!envP->fault_occurred) {
926 XMLRPC_ASSERT(*format_copy == '\0');
933 xmlrpc_parse_value(xmlrpc_env * const envP,
934 xmlrpc_value * const value,
935 const char * const format,
940 va_start(args, format);
941 xmlrpc_parse_value_va(envP, value, format, args);
947 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
948 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
950 ** Redistribution and use in source and binary forms, with or without
951 ** modification, are permitted provided that the following conditions
953 ** 1. Redistributions of source code must retain the above copyright
954 ** notice, this list of conditions and the following disclaimer.
955 ** 2. Redistributions in binary form must reproduce the above copyright
956 ** notice, this list of conditions and the following disclaimer in the
957 ** documentation and/or other materials provided with the distribution.
958 ** 3. The name of the author may not be used to endorse or promote products
959 ** derived from this software without specific prior written permission.
961 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
962 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
963 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
964 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
965 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
966 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
967 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
968 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
969 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
970 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF