summaryrefslogtreecommitdiffstats
path: root/unit/atf-src/atf-c/detail/dynstr.c
diff options
context:
space:
mode:
Diffstat (limited to 'unit/atf-src/atf-c/detail/dynstr.c')
-rw-r--r--unit/atf-src/atf-c/detail/dynstr.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/unit/atf-src/atf-c/detail/dynstr.c b/unit/atf-src/atf-c/detail/dynstr.c
new file mode 100644
index 0000000..424a1c9
--- /dev/null
+++ b/unit/atf-src/atf-c/detail/dynstr.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include "atf-c/detail/dynstr.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "atf-c/detail/sanity.h"
+#include "atf-c/detail/text.h"
+#include "atf-c/error.h"
+
+/* ---------------------------------------------------------------------
+ * Auxiliary functions.
+ * --------------------------------------------------------------------- */
+
+static
+atf_error_t
+resize(atf_dynstr_t *ad, size_t newsize)
+{
+ char *newdata;
+ atf_error_t err;
+
+ PRE(newsize > ad->m_datasize);
+
+ newdata = (char *)malloc(newsize);
+ if (newdata == NULL) {
+ err = atf_no_memory_error();
+ } else {
+ strcpy(newdata, ad->m_data);
+ free(ad->m_data);
+ ad->m_data = newdata;
+ ad->m_datasize = newsize;
+ err = atf_no_error();
+ }
+
+ return err;
+}
+
+static
+atf_error_t
+prepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap,
+ bool prepend)
+{
+ char *aux;
+ atf_error_t err;
+ size_t newlen;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ err = atf_text_format_ap(&aux, fmt, ap2);
+ va_end(ap2);
+ if (atf_is_error(err))
+ goto out;
+ newlen = ad->m_length + strlen(aux);
+
+ if (newlen + sizeof(char) > ad->m_datasize) {
+ err = resize(ad, newlen + sizeof(char));
+ if (atf_is_error(err))
+ goto out_free;
+ }
+
+ if (prepend) {
+ memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1);
+ memcpy(ad->m_data, aux, strlen(aux));
+ } else
+ strcpy(ad->m_data + ad->m_length, aux);
+ ad->m_length = newlen;
+ err = atf_no_error();
+
+out_free:
+ free(aux);
+out:
+ return err;
+}
+
+/* ---------------------------------------------------------------------
+ * The "atf_dynstr" type.
+ * --------------------------------------------------------------------- */
+
+/*
+ * Constants.
+ */
+
+const size_t atf_dynstr_npos = SIZE_MAX;
+
+/*
+ * Constructors and destructors.
+ */
+
+atf_error_t
+atf_dynstr_init(atf_dynstr_t *ad)
+{
+ atf_error_t err;
+
+ ad->m_data = (char *)malloc(sizeof(char));
+ if (ad->m_data == NULL) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ ad->m_data[0] = '\0';
+ ad->m_datasize = 1;
+ ad->m_length = 0;
+ err = atf_no_error();
+
+out:
+ return err;
+}
+
+atf_error_t
+atf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
+{
+ atf_error_t err;
+
+ ad->m_datasize = strlen(fmt) + 1;
+ ad->m_length = 0;
+
+ do {
+ va_list ap2;
+ int ret;
+
+ ad->m_datasize *= 2;
+ ad->m_data = (char *)malloc(ad->m_datasize);
+ if (ad->m_data == NULL) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ va_copy(ap2, ap);
+ ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2);
+ va_end(ap2);
+ if (ret < 0) {
+ free(ad->m_data);
+ err = atf_libc_error(errno, "Cannot format string");
+ goto out;
+ }
+
+ INV(ret >= 0);
+ if ((size_t)ret >= ad->m_datasize) {
+ free(ad->m_data);
+ ad->m_data = NULL;
+ }
+ ad->m_length = ret;
+ } while (ad->m_length >= ad->m_datasize);
+
+ err = atf_no_error();
+out:
+ POST(atf_is_error(err) || ad->m_data != NULL);
+ return err;
+}
+
+atf_error_t
+atf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...)
+{
+ va_list ap;
+ atf_error_t err;
+
+ va_start(ap, fmt);
+ err = atf_dynstr_init_ap(ad, fmt, ap);
+ va_end(ap);
+
+ return err;
+}
+
+atf_error_t
+atf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen)
+{
+ atf_error_t err;
+
+ if (memlen >= SIZE_MAX - 1) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ ad->m_data = (char *)malloc(memlen + 1);
+ if (ad->m_data == NULL) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ ad->m_datasize = memlen + 1;
+ memcpy(ad->m_data, mem, memlen);
+ ad->m_data[memlen] = '\0';
+ ad->m_length = strlen(ad->m_data);
+ INV(ad->m_length <= memlen);
+ err = atf_no_error();
+
+out:
+ return err;
+}
+
+atf_error_t
+atf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch)
+{
+ atf_error_t err;
+
+ if (len == SIZE_MAX) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ ad->m_datasize = (len + 1) * sizeof(char);
+ ad->m_data = (char *)malloc(ad->m_datasize);
+ if (ad->m_data == NULL) {
+ err = atf_no_memory_error();
+ goto out;
+ }
+
+ memset(ad->m_data, ch, len);
+ ad->m_data[len] = '\0';
+ ad->m_length = len;
+ err = atf_no_error();
+
+out:
+ return err;
+}
+
+atf_error_t
+atf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src,
+ size_t beg, size_t end)
+{
+ if (beg > src->m_length)
+ beg = src->m_length;
+
+ if (end == atf_dynstr_npos || end > src->m_length)
+ end = src->m_length;
+
+ return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg);
+}
+
+atf_error_t
+atf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src)
+{
+ atf_error_t err;
+
+ dest->m_data = (char *)malloc(src->m_datasize);
+ if (dest->m_data == NULL)
+ err = atf_no_memory_error();
+ else {
+ memcpy(dest->m_data, src->m_data, src->m_datasize);
+ dest->m_datasize = src->m_datasize;
+ dest->m_length = src->m_length;
+ err = atf_no_error();
+ }
+
+ return err;
+}
+
+void
+atf_dynstr_fini(atf_dynstr_t *ad)
+{
+ INV(ad->m_data != NULL);
+ free(ad->m_data);
+}
+
+char *
+atf_dynstr_fini_disown(atf_dynstr_t *ad)
+{
+ INV(ad->m_data != NULL);
+ return ad->m_data;
+}
+
+/*
+ * Getters.
+ */
+
+const char *
+atf_dynstr_cstring(const atf_dynstr_t *ad)
+{
+ return ad->m_data;
+}
+
+size_t
+atf_dynstr_length(const atf_dynstr_t *ad)
+{
+ return ad->m_length;
+}
+
+size_t
+atf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch)
+{
+ size_t pos;
+
+ for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--)
+ ;
+
+ return pos == 0 ? atf_dynstr_npos : pos - 1;
+}
+
+/*
+ * Modifiers.
+ */
+
+atf_error_t
+atf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
+{
+ atf_error_t err;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ err = prepend_or_append(ad, fmt, ap2, false);
+ va_end(ap2);
+
+ return err;
+}
+
+atf_error_t
+atf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...)
+{
+ va_list ap;
+ atf_error_t err;
+
+ va_start(ap, fmt);
+ err = prepend_or_append(ad, fmt, ap, false);
+ va_end(ap);
+
+ return err;
+}
+
+void
+atf_dynstr_clear(atf_dynstr_t *ad)
+{
+ ad->m_data[0] = '\0';
+ ad->m_length = 0;
+}
+
+atf_error_t
+atf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
+{
+ atf_error_t err;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ err = prepend_or_append(ad, fmt, ap2, true);
+ va_end(ap2);
+
+ return err;
+}
+
+atf_error_t
+atf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...)
+{
+ va_list ap;
+ atf_error_t err;
+
+ va_start(ap, fmt);
+ err = prepend_or_append(ad, fmt, ap, true);
+ va_end(ap);
+
+ return err;
+}
+
+/*
+ * Operators.
+ */
+
+bool
+atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str)
+{
+ return strcmp(ad->m_data, str) == 0;
+}
+
+bool
+atf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2)
+{
+ return strcmp(s1->m_data, s2->m_data) == 0;
+}