summaryrefslogtreecommitdiffstats
path: root/src/raptor_stringbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/raptor_stringbuffer.c')
-rw-r--r--src/raptor_stringbuffer.c902
1 files changed, 902 insertions, 0 deletions
diff --git a/src/raptor_stringbuffer.c b/src/raptor_stringbuffer.c
new file mode 100644
index 0000000..03223c3
--- /dev/null
+++ b/src/raptor_stringbuffer.c
@@ -0,0 +1,902 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * raptor_stringbuffer.c - Stringbuffer class for growing strings
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-2004, University of Bristol, UK http://www.bristol.ac.uk/
+ *
+ * This package is Free Software and part of Redland http://librdf.org/
+ *
+ * It is licensed under the following three licenses as alternatives:
+ * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
+ * 2. GNU General Public License (GPL) V2 or any newer version
+ * 3. Apache License, V2.0 or any newer version
+ *
+ * You may not use this file except in compliance with at least one of
+ * the above three licenses.
+ *
+ * See LICENSE.html or LICENSE.txt at the top of this package for the
+ * complete terms and further detail along with the license texts for
+ * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
+ *
+ *
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <raptor_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* for abort() as used in errors */
+#endif
+
+/* Raptor includes */
+#include "raptor2.h"
+#include "raptor_internal.h"
+
+
+#ifndef STANDALONE
+
+struct raptor_stringbuffer_node_s
+{
+ struct raptor_stringbuffer_node_s* next;
+ unsigned char *string;
+ size_t length;
+};
+typedef struct raptor_stringbuffer_node_s raptor_stringbuffer_node;
+
+
+struct raptor_stringbuffer_s
+{
+ /* Pointing to the first item in the list of nodes */
+ raptor_stringbuffer_node* head;
+ /* and the last */
+ raptor_stringbuffer_node* tail;
+
+ /* total length of the string */
+ size_t length;
+
+ /* frozen string if already calculated, or NULL if not present */
+ unsigned char *string;
+};
+
+
+/* prototypes for local functions */
+static int raptor_stringbuffer_append_string_common(raptor_stringbuffer* stringbuffer, const unsigned char *string, size_t length, int do_copy);
+
+
+/* functions implementing the stringbuffer api */
+
+/**
+ * raptor_new_stringbuffer:
+ *
+ * Create a new stringbuffer.
+ *
+ * Return value: pointer to a raptor_stringbuffer object or NULL on failure
+ **/
+raptor_stringbuffer*
+raptor_new_stringbuffer(void)
+{
+ raptor_stringbuffer* sb;
+
+ sb = RAPTOR_CALLOC(raptor_stringbuffer*, 1, sizeof(*sb));
+ return sb;
+}
+
+
+/**
+ * raptor_free_stringbuffer:
+ * @stringbuffer: stringbuffer object to destroy.
+ *
+ * Destroy a stringbuffer.
+ *
+ **/
+void
+raptor_free_stringbuffer(raptor_stringbuffer *stringbuffer)
+{
+ if(!stringbuffer)
+ return;
+
+ if(stringbuffer->head) {
+ raptor_stringbuffer_node *node = stringbuffer->head;
+
+ while(node) {
+ raptor_stringbuffer_node *next = node->next;
+
+ if(node->string)
+ RAPTOR_FREE(char*, node->string);
+ RAPTOR_FREE(raptor_stringbuffer_node, node);
+ node = next;
+ }
+ }
+
+ if(stringbuffer->string)
+ RAPTOR_FREE(char*, stringbuffer->string);
+
+ RAPTOR_FREE(raptor_stringbuffer, stringbuffer);
+}
+
+
+
+/**
+ * raptor_stringbuffer_append_string_common:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @length: length of string
+ * @do_copy: non-0 to copy the string
+ *
+ * Add a string to the stringbuffer.
+ *
+ * INTERNAL
+ *
+ * If @string is NULL or @length is 0, no work is performed.
+ *
+ * If @do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_stringbuffer_append_string_common(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string,
+ size_t length,
+ int do_copy)
+{
+ raptor_stringbuffer_node *node;
+
+ if(!string || !length)
+ return 0;
+
+ node = RAPTOR_MALLOC(raptor_stringbuffer_node*, sizeof(*node));
+ if(!node) {
+ if(!do_copy)
+ RAPTOR_FREE(char*, string);
+ return 1;
+ }
+
+ if(do_copy) {
+ /* Note this copy does not include the \0 character - not needed */
+ node->string = RAPTOR_MALLOC(unsigned char*, length);
+ if(!node->string) {
+ RAPTOR_FREE(raptor_stringbuffer_node, node);
+ return 1;
+ }
+ memcpy(node->string, string, length);
+ } else
+ node->string = (unsigned char*)string;
+ node->length = length;
+
+
+ if(stringbuffer->tail) {
+ stringbuffer->tail->next = node;
+ stringbuffer->tail = node;
+ } else
+ stringbuffer->head = stringbuffer->tail = node;
+ node->next = NULL;
+
+ if(stringbuffer->string) {
+ RAPTOR_FREE(char*, stringbuffer->string);
+ stringbuffer->string = NULL;
+ }
+ stringbuffer->length += length;
+
+ return 0;
+}
+
+
+
+
+/**
+ * raptor_stringbuffer_append_counted_string:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @length: length of string
+ * @do_copy: non-0 to copy the string
+ *
+ * Add a counted string to the stringbuffer.
+ *
+ * If @string is NULL or @length is 0, no work is performed.
+ *
+ * If @do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_counted_string(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string, size_t length,
+ int do_copy)
+{
+ if(!string || !length)
+ return 0;
+
+ return raptor_stringbuffer_append_string_common(stringbuffer, string, length, do_copy);
+}
+
+
+/**
+ * raptor_stringbuffer_append_string:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @do_copy: non-0 to copy the string
+ *
+ * Add a string to the stringbuffer.
+ *
+ * If @string is NULL, no work is performed.
+ *
+ * If @do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_string(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string, int do_copy)
+{
+ if(!string)
+ return 0;
+
+ return raptor_stringbuffer_append_string_common(stringbuffer, string, strlen((const char*)string), do_copy);
+}
+
+
+/**
+ * raptor_stringbuffer_append_decimal:
+ * @stringbuffer: raptor stringbuffer
+ * @integer: integer to format as decimal and add
+ *
+ * Add an integer in decimal to the stringbuffer.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_decimal(raptor_stringbuffer* stringbuffer,
+ int integer)
+{
+ /* enough for 64 bit signed integer
+ * INT64_MAX is 9223372036854775807 (19 digits) + 1 for sign
+ */
+ unsigned char buf[20];
+ unsigned char *p;
+ int i = integer;
+ size_t length = 1;
+ if(integer < 0) {
+ length++;
+ i= -integer;
+ }
+ while(i /= 10)
+ length++;
+
+ p = buf+length-1;
+ i = integer;
+ if(i < 0)
+ i= -i;
+ do {
+ *p-- = RAPTOR_GOOD_CAST(unsigned char, '0'+(i %10));
+ i /= 10;
+ } while(i);
+ if(integer < 0)
+ *p= '-';
+
+ return raptor_stringbuffer_append_counted_string(stringbuffer, buf, length, 1);
+}
+
+
+/**
+ * raptor_stringbuffer_append_stringbuffer:
+ * @stringbuffer: #raptor_stringbuffer
+ * @append: #raptor_stringbuffer to append
+ *
+ * Add a stringbuffer to the stringbuffer.
+ *
+ * This function removes the content from the appending stringbuffer,
+ * making it empty and appends it to the supplied stringbuffer.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_stringbuffer(raptor_stringbuffer* stringbuffer,
+ raptor_stringbuffer* append)
+{
+ raptor_stringbuffer_node *node = append->head;
+
+ if(!node)
+ return 0;
+
+ /* move all append nodes to stringbuffer */
+ if(stringbuffer->tail) {
+ stringbuffer->tail->next = node;
+ } else
+ stringbuffer->head = node;
+
+ stringbuffer->tail = append->tail;
+
+ /* adjust our length */
+ stringbuffer->length += append->length;
+ if(stringbuffer->string) {
+ RAPTOR_FREE(char*, stringbuffer->string);
+ stringbuffer->string = NULL;
+ }
+
+ /* zap append content */
+ append->head = append->tail = NULL;
+ append->length = 0;
+ if(append->string) {
+ RAPTOR_FREE(char*, append->string);
+ append->string = NULL;
+ }
+
+ return 0;
+}
+
+
+
+
+/**
+ * raptor_stringbuffer_prepend_string_common:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @length: length of string
+ * @do_copy: non-0 to copy the string
+ *
+ * Add a string to the start of a stringbuffer.
+ *
+ * INTERNAL
+ *
+ * If do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_stringbuffer_prepend_string_common(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string, size_t length,
+ int do_copy)
+{
+ raptor_stringbuffer_node *node;
+
+ node = RAPTOR_MALLOC(raptor_stringbuffer_node*, sizeof(*node));
+ if(!node)
+ return 1;
+
+ if(do_copy) {
+ /* Note this copy does not include the \0 character - not needed */
+ node->string = RAPTOR_MALLOC(unsigned char*, length);
+ if(!node->string) {
+ RAPTOR_FREE(raptor_stringbuffer_node, node);
+ return 1;
+ }
+ memcpy(node->string, string, length);
+ } else
+ node->string = (unsigned char*)string;
+ node->length = length;
+
+
+ node->next = stringbuffer->head;
+ if(stringbuffer->head)
+ stringbuffer->head = node;
+ else
+ stringbuffer->head = stringbuffer->tail = node;
+
+ if(stringbuffer->string) {
+ RAPTOR_FREE(char*, stringbuffer->string);
+ stringbuffer->string = NULL;
+ }
+ stringbuffer->length += length;
+
+ return 0;
+}
+
+
+
+
+/**
+ * raptor_stringbuffer_prepend_counted_string:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @length: length of string
+ * @do_copy: non-0 to copy the string
+
+ * If do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Add a string to the start of the stringbuffer.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_prepend_counted_string(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string, size_t length,
+ int do_copy)
+{
+ return raptor_stringbuffer_prepend_string_common(stringbuffer, string, length, do_copy);
+}
+
+
+/**
+ * raptor_stringbuffer_prepend_string:
+ * @stringbuffer: raptor stringbuffer
+ * @string: string
+ * @do_copy: non-0 to copy the string
+ *
+ * Add a string to the start of the stringbuffer.
+ *
+ * If do_copy is non-0, the passed-in string is copied into new memory
+ * otherwise the stringbuffer becomes the owner of the string pointer
+ * and will free it when the stringbuffer is destroyed.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_prepend_string(raptor_stringbuffer* stringbuffer,
+ const unsigned char *string, int do_copy)
+{
+ return raptor_stringbuffer_prepend_string_common(stringbuffer, string, strlen((const char*)string), do_copy);
+}
+
+
+/**
+ * raptor_stringbuffer_length:
+ * @stringbuffer: raptor stringbuffer
+ *
+ * Return the stringbuffer length.
+ *
+ * Return value: size of stringbuffer
+ **/
+size_t
+raptor_stringbuffer_length(raptor_stringbuffer* stringbuffer)
+{
+ return stringbuffer->length;
+}
+
+
+
+/**
+ * raptor_stringbuffer_as_string:
+ * @stringbuffer: raptor stringbuffer
+ *
+ * Return the stringbuffer as a C string.
+ *
+ * Note: the return value is a to a shared string that the stringbuffer
+ * allocates and manages.
+ *
+ * Return value: NULL on failure or stringbuffer is empty, otherwise
+ * a pointer to a shared copy of the string.
+ **/
+unsigned char *
+raptor_stringbuffer_as_string(raptor_stringbuffer* stringbuffer)
+{
+ raptor_stringbuffer_node *node;
+ unsigned char *p;
+
+ if(!stringbuffer->length)
+ return NULL;
+ if(stringbuffer->string)
+ return stringbuffer->string;
+
+ stringbuffer->string = RAPTOR_MALLOC(unsigned char*, stringbuffer->length + 1);
+ if(!stringbuffer->string)
+ return NULL;
+
+ node = stringbuffer->head;
+ p = stringbuffer->string;
+ while(node) {
+ memcpy(p, node->string, node->length);
+ p+= node->length;
+ node = node->next;
+ }
+ *p='\0';
+ return stringbuffer->string;
+}
+
+
+/**
+ * raptor_stringbuffer_copy_to_string:
+ * @stringbuffer: raptor stringbuffer
+ * @string: output string
+ * @length: size of output string
+ *
+ * Copy the stringbuffer into a string.
+ *
+ * Copies the underlying string to a pre-allocated buffer. The
+ * output string is always '\0' terminated.
+ *
+ * Return value: non-0 on failure such as stringbuffer is empty, buffer is too small
+ **/
+int
+raptor_stringbuffer_copy_to_string(raptor_stringbuffer* stringbuffer,
+ unsigned char *string, size_t length)
+{
+ raptor_stringbuffer_node *node;
+ unsigned char *p;
+
+ if(!string || length < 1)
+ return 1;
+
+ if(!stringbuffer->length)
+ return 0;
+
+ p = string;
+ for(node = stringbuffer->head; node; node = node->next) {
+ if(node->length > length) {
+ p[-1]='\0';
+ return 1;
+ }
+ memcpy(p, node->string, node->length);
+ p+= node->length;
+ length-= node->length;
+ }
+ *p='\0';
+ return 0;
+}
+
+
+
+/**
+ * raptor_stringbuffer_append_hexadecimal:
+ * @stringbuffer: raptor stringbuffer
+ * @hex: integer to format
+ *
+ * Add an integer formatted in hexdecimal (base 16) to the stringbuffer.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_hexadecimal(raptor_stringbuffer* stringbuffer,
+ int hex)
+{
+ unsigned char buf[2];
+
+ if(hex < 0 || hex > 0xF)
+ return 1;
+
+ *buf = RAPTOR_GOOD_CAST(unsigned char, (hex < 10) ? ('0' + hex) : ('A' + hex - 10));
+ buf[1] = '\0';
+
+ return raptor_stringbuffer_append_counted_string(stringbuffer, buf, 1, 1);
+}
+
+
+/* RFC3986 Unreserved */
+#define IS_URI_UNRESERVED(c) ( (c >= 'A' && c <= 'F') || \
+ (c >= 'a' && c <= 'f') || \
+ (c >= '0' && c <= '9') || \
+ (c == '-' || c == '.' || c == '_' || c == '~') )
+#define IS_URI_SAFE(c) (IS_URI_UNRESERVED(c))
+
+
+/**
+ * raptor_stringbuffer_append_uri_escaped_counted_string:
+ * @sb: raptor stringbuffer
+ * @string: string
+ * @length: length of string
+ * @space_is_plus: if non-0, escape spaces as '+' otherwise percent-encode them
+ *
+ * Add a URI-escaped version of @string to the stringbuffer.
+ *
+ * If @string is NULL or @length is 0, no work is performed.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_stringbuffer_append_uri_escaped_counted_string(raptor_stringbuffer* sb,
+ const char* string,
+ size_t length,
+ int space_is_plus)
+{
+ unsigned int i;
+ unsigned char buf[2];
+ buf[1] = '\0';
+
+ if(!string || !length)
+ return 0;
+
+ for(i = 0; i < length; i++) {
+ char c = string[i];
+ if(!c)
+ break;
+
+ if(IS_URI_SAFE(c)) {
+ *buf = RAPTOR_GOOD_CAST(unsigned char, c);
+
+ if(raptor_stringbuffer_append_counted_string(sb, buf, 1, 1))
+ return 1;
+ } else if (c == ' ' && space_is_plus) {
+ *buf = '+';
+
+ if(raptor_stringbuffer_append_counted_string(sb, buf, 1, 1))
+ return 1;
+ } else {
+ *buf = '%';
+ if(raptor_stringbuffer_append_counted_string(sb, buf, 1, 1))
+ return 1;
+
+ if(raptor_stringbuffer_append_hexadecimal(sb, (c & 0xf0) >> 4))
+ return 1;
+
+ if(raptor_stringbuffer_append_hexadecimal(sb, (c & 0x0f)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = raptor_basename(argv[0]);
+#define TEST_ITEMS_COUNT 9
+ const char *items[TEST_ITEMS_COUNT] = { "the", "quick" ,"brown", "fox", "jumps", "over", "the", "lazy", "dog" };
+ const char *items_string = "thequickbrownfoxjumpsoverthelazydog";
+ const size_t items_len = 35;
+ const char *test_integer_string = "abcd";
+#define TEST_INTEGERS_COUNT 7
+ const int test_integers[TEST_INTEGERS_COUNT]={ 0, 1, -1, 11, 1234, 12345, -12345 };
+ const char *test_integer_results[TEST_INTEGERS_COUNT]={ "abcd0", "abcd1", "abcd-1", "abcd11", "abcd1234", "abcd12345", "abcd-12345" };
+ raptor_stringbuffer *sb;
+ unsigned char *str;
+ size_t len;
+ int i = 0;
+ raptor_stringbuffer *sb1, *sb2;
+#define TEST_APPEND_COUNT 2
+ const char *test_append_results[TEST_APPEND_COUNT]={ "thebrownjumpsthedog", "quickfoxoverlazy" };
+ const char *test_append_results_total="thebrownjumpsthedogquickfoxoverlazy";
+#define COPY_STRING_BUFFER_SIZE 100
+ unsigned char *copy_string;
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Creating string buffer\n", program);
+#endif
+
+ /* test appending */
+
+ sb = raptor_new_stringbuffer();
+ if(!sb) {
+ fprintf(stderr, "%s: Failed to create string buffer\n", program);
+ exit(1);
+ }
+
+ for(i = 0; i < TEST_ITEMS_COUNT; i++) {
+ int rc;
+ len = strlen(items[i]);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Adding string buffer item '%s'\n", program, items[i]);
+#endif
+
+ rc = raptor_stringbuffer_append_counted_string(sb, (unsigned char*)items[i], len, 1);
+ if(rc) {
+ fprintf(stderr, "%s: Adding string buffer item %d '%s' failed, returning error %d\n",
+ program, i, items[i], rc);
+ exit(1);
+ }
+ }
+
+ len = raptor_stringbuffer_length(sb);
+ if(len != items_len) {
+ fprintf(stderr, "%s: string buffer len is %d, expected %d\n", program,
+ (int)len, (int)items_len);
+ exit(1);
+ }
+
+ str = raptor_stringbuffer_as_string(sb);
+ if(strcmp((const char*)str, items_string)) {
+ fprintf(stderr, "%s: string buffer contains '%s', expected '%s'\n",
+ program, str, items_string);
+ exit(1);
+ }
+
+ raptor_free_stringbuffer(sb);
+
+
+ /* test prepending */
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Creating string buffer\n", program);
+#endif
+
+ sb = raptor_new_stringbuffer();
+ if(!sb) {
+ fprintf(stderr, "%s: Failed to create string buffer\n", program);
+ exit(1);
+ }
+
+ for(i = TEST_ITEMS_COUNT-1; i>=0 ; i--) {
+ int rc;
+ len = strlen(items[i]);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Prepending string buffer item '%s'\n", program, items[i]);
+#endif
+
+ rc = raptor_stringbuffer_prepend_counted_string(sb, (unsigned char*)items[i], len, 1);
+ if(rc) {
+ fprintf(stderr, "%s: Prepending string buffer item %d '%s' failed, returning error %d\n",
+ program, i, items[i], rc);
+ exit(1);
+ }
+ }
+
+ len = raptor_stringbuffer_length(sb);
+ if(len != items_len) {
+ fprintf(stderr, "%s: string buffer len is %d, expected %d\n", program,
+ (int)len, (int)items_len);
+ exit(1);
+ }
+
+ str = raptor_stringbuffer_as_string(sb);
+ if(strcmp((const char*)str, items_string)) {
+ fprintf(stderr, "%s: string buffer contains '%s', expected '%s'\n",
+ program, str, items_string);
+ exit(1);
+ }
+
+
+ /* test adding integers */
+
+ for(i = 0; i < TEST_INTEGERS_COUNT; i++) {
+ raptor_stringbuffer *isb = raptor_new_stringbuffer();
+ if(!isb) {
+ fprintf(stderr, "%s: Failed to create string buffer\n", program);
+ exit(1);
+ }
+
+ raptor_stringbuffer_append_string(isb,
+ (const unsigned char*)test_integer_string, 1);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Adding decimal integer %d to buffer\n", program, test_integers[i]);
+#endif
+
+ raptor_stringbuffer_append_decimal(isb, test_integers[i]);
+
+ str = raptor_stringbuffer_as_string(isb);
+ if(strcmp((const char*)str, test_integer_results[i])) {
+ fprintf(stderr, "%s: string buffer contains '%s', expected '%s'\n",
+ program, str, test_integer_results[i]);
+ exit(1);
+ }
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Freeing string buffer\n", program);
+#endif
+ raptor_free_stringbuffer(isb);
+ }
+
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Creating two stringbuffers to join\n", program);
+#endif
+
+ sb1 = raptor_new_stringbuffer();
+ if(!sb1) {
+ fprintf(stderr, "%s: Failed to create string buffer\n", program);
+ exit(1);
+ }
+ sb2 = raptor_new_stringbuffer();
+ if(!sb2) {
+ fprintf(stderr, "%s: Failed to create string buffer\n", program);
+ exit(1);
+ }
+
+ for(i = 0; i < TEST_ITEMS_COUNT; i++) {
+ raptor_stringbuffer *sbx;
+ int rc;
+ len = strlen(items[i]);
+
+ sbx = (i % 2) ? sb2 : sb1;
+ rc = raptor_stringbuffer_append_counted_string(sbx, (unsigned char*)items[i], len, 1);
+ if(rc) {
+ fprintf(stderr, "%s: Adding string buffer item %d '%s' failed, returning error %d\n",
+ program, i, items[i], rc);
+ exit(1);
+ }
+ }
+
+ if(1) {
+ int rc;
+
+ rc = raptor_stringbuffer_append_counted_string(sb1, (unsigned char*)"X", 0, 1);
+ if(rc) {
+ fprintf(stderr, "%s: Adding 0-length counted string failed, returning error %d\n",
+ program, rc);
+ exit(1);
+ }
+ rc = raptor_stringbuffer_append_string(sb1, NULL, 1);
+ if(rc) {
+ fprintf(stderr, "%s: Adding NULL string failed, returning error %d\n",
+ program, rc);
+ exit(1);
+ }
+ }
+
+ str = raptor_stringbuffer_as_string(sb1);
+ if(strcmp((const char*)str, test_append_results[0])) {
+ fprintf(stderr, "%s: string buffer sb1 contains '%s', expected '%s'\n",
+ program, str, test_append_results[0]);
+ exit(1);
+ }
+ str = raptor_stringbuffer_as_string(sb2);
+ if(strcmp((const char*)str, test_append_results[1])) {
+ fprintf(stderr, "%s: string buffer sb2 contains '%s', expected '%s'\n",
+ program, str, test_append_results[1]);
+ exit(1);
+ }
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Appended two stringbuffers\n", program);
+#endif
+
+ if(raptor_stringbuffer_append_stringbuffer(sb1, sb2)) {
+ fprintf(stderr, "%s: Failed to append string buffer\n", program);
+ exit(1);
+ }
+
+ str = raptor_stringbuffer_as_string(sb1);
+ if(strcmp((const char*)str, test_append_results_total)) {
+ fprintf(stderr, "%s: appended string buffer contains '%s', expected '%s'\n",
+ program, str, test_append_results_total);
+ exit(1);
+ }
+
+ len = raptor_stringbuffer_length(sb2);
+ if(len) {
+ fprintf(stderr, "%s: appended string buffer is length %d, not empty'\n",
+ program, (int)len);
+ exit(1);
+ }
+
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Copying string buffer to string\n", program);
+#endif
+
+ copy_string = (unsigned char*)malloc(COPY_STRING_BUFFER_SIZE);
+ if(raptor_stringbuffer_copy_to_string(sb1, copy_string, COPY_STRING_BUFFER_SIZE)) {
+ fprintf(stderr, "%s: copying string buffer to string failed\n",
+ program);
+ exit(1);
+ }
+ if(strcmp((const char*)copy_string, test_append_results_total)) {
+ fprintf(stderr, "%s: copied string buffer contains '%s', expected '%s'\n",
+ program, copy_string, test_append_results_total);
+ exit(1);
+ }
+ free(copy_string);
+
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: Freeing string buffers\n", program);
+#endif
+ raptor_free_stringbuffer(sb1);
+ raptor_free_stringbuffer(sb2);
+ raptor_free_stringbuffer(sb);
+
+ /* keep gcc -Wall happy */
+ return(0);
+}
+
+#endif