summaryrefslogtreecommitdiffstats
path: root/membuffer.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2014-01-16 09:03:11 +0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2014-01-16 12:51:23 +0700
commit96a4fd1bb223d646bb3f3c8b9d4d0800ebe49e13 (patch)
treeccab6808c0f791790ad3662a836f451c90dad2c7 /membuffer.c
parent2e08f75618e6ff86e37de5e1ee0100a31cc8efb7 (diff)
downloadsubsurface-96a4fd1bb223d646bb3f3c8b9d4d0800ebe49e13.tar.gz
Save XML files into a memory buffer rather than directly into a file
This introduces a "struct membuffer" abstraction that you can write things into, and makes the XML saving code write to the memory buffer rather than a file. The UDDF export already really wanted this: it used to write to a file, only to then read that file back into memory, delete the file, and then *rewrite* the file after doing the magic xslt transform. But the longer-term reason for this is that I want to try to write other formats, and I want to try to share most helpers. And those other formats will need this memory buffer model. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'membuffer.c')
-rw-r--r--membuffer.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/membuffer.c b/membuffer.c
new file mode 100644
index 000000000..30ba05fdb
--- /dev/null
+++ b/membuffer.c
@@ -0,0 +1,160 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dive.h"
+#include "membuffer.h"
+
+void free_buffer(struct membuffer *b)
+{
+ free(b->buffer);
+ b->buffer = NULL;
+ b->used = 0;
+ b->size = 0;
+}
+
+void flush_buffer(struct membuffer *b, FILE *f)
+{
+ if (b->used) {
+ fwrite(b->buffer, 1, b->used, f);
+ free_buffer(b);
+ }
+}
+
+/*
+ * Running out of memory isn't really an issue these days.
+ * So rather than do insane error handling and making the
+ * interface very complex, we'll just die. It won't happen
+ * unless you're running on a potato.
+ */
+static void oom(void)
+{
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+}
+
+static void make_room(struct membuffer *b, unsigned int size)
+{
+ unsigned int needed = b->used + size;
+ if (needed > b->size) {
+ char *n;
+ /* round it up to not reallocate all the time.. */
+ needed = needed * 9 / 8 + 1024;
+ n = realloc(b->buffer, needed);
+ if (!n)
+ oom();
+ b->buffer = n;
+ b->size = needed;
+ }
+}
+
+void put_bytes(struct membuffer *b, const char *str, int len)
+{
+ make_room(b, len);
+ memcpy(b->buffer + b->used, str, len);
+ b->used += len;
+}
+
+void put_string(struct membuffer *b, const char *str)
+{
+ put_bytes(b, str, strlen(str));
+}
+
+void put_vformat(struct membuffer *b, const char *fmt, va_list args)
+{
+ /* Handle the common case on the stack */
+ char buffer[128], *p;
+ int len;
+
+ len = vsnprintf(buffer, sizeof(buffer), fmt, args);
+ if (len <= sizeof(buffer)) {
+ put_bytes(b, buffer, len);
+ return;
+ }
+
+ p = malloc(len);
+ len = vsnprintf(p, len, fmt, args);
+ put_bytes(b, p, len);
+ free(p);
+}
+
+void put_format(struct membuffer *b, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ put_vformat(b, fmt, args);
+ va_end(args);
+}
+
+void put_milli(struct membuffer *b, const char *pre, int value, const char *post)
+{
+ int i;
+ char buf[4];
+ const char *sign = "";
+ unsigned v;
+
+ v = value;
+ if (value < 0) {
+ sign = "-";
+ v = -value;
+ }
+ for (i = 2; i >= 0; i--) {
+ buf[i] = (v % 10) + '0';
+ v /= 10;
+ }
+ buf[3] = 0;
+ if (buf[2] == '0') {
+ buf[2] = 0;
+ if (buf[1] == '0')
+ buf[1] = 0;
+ }
+
+ put_format(b, "%s%s%u.%s%s", pre, sign, v, buf, post);
+}
+
+int put_temperature(struct membuffer *b, temperature_t temp, const char *pre, const char *post)
+{
+ if (!temp.mkelvin)
+ return 0;
+
+ put_milli(b, pre, temp.mkelvin - ZERO_C_IN_MKELVIN, post);
+ return 1;
+}
+
+int put_depth(struct membuffer *b, depth_t depth, const char *pre, const char *post)
+{
+ if (!depth.mm)
+ return 0;
+
+ put_milli(b, pre, depth.mm, post);
+ return 1;
+}
+
+int put_duration(struct membuffer *b, duration_t duration, const char *pre, const char *post)
+{
+ if (!duration.seconds)
+ return 0;
+
+ put_format(b, "%s%u:%02u%s", pre, FRACTION(duration.seconds, 60), post);
+ return 1;
+}
+
+int put_pressure(struct membuffer *b, pressure_t pressure, const char *pre, const char *post)
+{
+ if (!pressure.mbar)
+ return 0;
+
+ put_milli(b, pre, pressure.mbar, post);
+ return 1;
+}
+
+int put_salinity(struct membuffer *b, int salinity, const char *pre, const char *post)
+{
+ if (!salinity)
+ return 0;
+
+ put_format(b, "%s%d%s", pre, salinity / 10, post);
+ return 1;
+}