summaryrefslogtreecommitdiff
path: root/src/upb_string.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2011-02-13 12:59:54 -0800
committerJoshua Haberman <joshua@reverberate.org>2011-02-13 12:59:54 -0800
commit6bdbb45e88e7b88b294dfb6e4cb493cbc3c8cf74 (patch)
tree0e00246fb124ebdf6a2210c816704c1d840e2138 /src/upb_string.c
parentee84a7da167d2211066c4a663d41febdf9544438 (diff)
Merged core/ and stream/ -> src/. The split wasn't worth it.
Diffstat (limited to 'src/upb_string.c')
-rw-r--r--src/upb_string.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/upb_string.c b/src/upb_string.c
new file mode 100644
index 0000000..30ed88f
--- /dev/null
+++ b/src/upb_string.c
@@ -0,0 +1,143 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2010 Joshua Haberman. See LICENSE for details.
+ */
+
+#include "upb_string.h"
+
+#include <stdlib.h>
+#ifdef __GLIBC__
+#include <malloc.h>
+#elif defined(__APPLE__)
+#include <malloc/malloc.h>
+#endif
+
+static uint32_t upb_round_up_pow2(uint32_t v) {
+ // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return v;
+}
+
+upb_string *upb_string_new() {
+ upb_string *str = malloc(sizeof(*str));
+ str->ptr = NULL;
+ str->cached_mem = NULL;
+ str->len = 0;
+#ifndef UPB_HAVE_MSIZE
+ str->size = 0;
+#endif
+ str->src = NULL;
+ upb_atomic_refcount_init(&str->refcount, 1);
+ return str;
+}
+
+uint32_t upb_string_size(upb_string *str) {
+#ifdef __GLIBC__
+ return malloc_usable_size(str->cached_mem);
+#elif defined(__APPLE__)
+ return malloc_size(str->cached_mem);
+#else
+ return str->size;
+#endif
+}
+
+void _upb_string_free(upb_string *str) {
+ free(str->cached_mem);
+ _upb_string_release(str);
+ free(str);
+}
+
+char *upb_string_getrwbuf(upb_string *str, upb_strlen_t len) {
+ // assert(str->ptr == NULL);
+ upb_strlen_t size = upb_string_size(str);
+ if (size < len) {
+ size = upb_round_up_pow2(len);
+ str->cached_mem = realloc(str->cached_mem, size);
+#ifndef UPB_HAVE_MSIZE
+ str->size = size;
+#endif
+ }
+ str->len = len;
+ str->ptr = str->cached_mem;
+ return str->cached_mem;
+}
+
+void upb_string_substr(upb_string *str, upb_string *target_str,
+ upb_strlen_t start, upb_strlen_t len) {
+ if(str->ptr) *(char*)0 = 0;
+ assert(str->ptr == NULL);
+ str->src = upb_string_getref(target_str);
+ str->ptr = upb_string_getrobuf(target_str) + start;
+ str->len = len;
+}
+
+void upb_string_vprintf(upb_string *str, const char *format, va_list args) {
+ // Try once without reallocating. We have to va_copy because we might have
+ // to call vsnprintf again.
+ uint32_t size = UPB_MAX(upb_string_size(str), 16);
+ char *buf = upb_string_getrwbuf(str, size);
+ va_list args_copy;
+ va_copy(args_copy, args);
+ uint32_t true_size = vsnprintf(buf, size, format, args_copy);
+ va_end(args_copy);
+
+ if (true_size >= size) {
+ // Need to reallocate. We reallocate even if the sizes were equal,
+ // because snprintf excludes the terminating NULL from its count.
+ // We don't care about the terminating NULL, but snprintf might
+ // bail out of printing even other characters if it doesn't have
+ // enough space to write the NULL also.
+ upb_string_recycle(&str);
+ buf = upb_string_getrwbuf(str, true_size + 1);
+ vsnprintf(buf, true_size + 1, format, args);
+ }
+ str->len = true_size;
+}
+
+upb_string *upb_string_asprintf(const char *format, ...) {
+ upb_string *str = upb_string_new();
+ va_list args;
+ va_start(args, format);
+ upb_string_vprintf(str, format, args);
+ va_end(args);
+ return str;
+}
+
+upb_string *upb_strdup(upb_string *s) {
+ upb_string *str = upb_string_new();
+ upb_strcpy(str, s);
+ return str;
+}
+
+void upb_strcat(upb_string *s, upb_string *append) {
+ uint32_t old_size = upb_string_len(s);
+ uint32_t append_size = upb_string_len(append);
+ uint32_t new_size = old_size + append_size;
+ char *buf = upb_string_getrwbuf(s, new_size);
+ memcpy(buf + old_size, upb_string_getrobuf(append), append_size);
+}
+
+upb_string *upb_strreadfile(const char *filename) {
+ FILE *f = fopen(filename, "rb");
+ if(!f) return NULL;
+ if(fseek(f, 0, SEEK_END) != 0) goto error;
+ long size = ftell(f);
+ if(size < 0) goto error;
+ if(fseek(f, 0, SEEK_SET) != 0) goto error;
+ upb_string *s = upb_string_new();
+ char *buf = upb_string_getrwbuf(s, size);
+ if(fread(buf, size, 1, f) != 1) goto error;
+ fclose(f);
+ return s;
+
+error:
+ fclose(f);
+ return NULL;
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback