aboutsummaryrefslogtreecommitdiffstats
path: root/moon-abe/pbc-0.5.14/misc/extend_printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'moon-abe/pbc-0.5.14/misc/extend_printf.c')
-rw-r--r--moon-abe/pbc-0.5.14/misc/extend_printf.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/moon-abe/pbc-0.5.14/misc/extend_printf.c b/moon-abe/pbc-0.5.14/misc/extend_printf.c
new file mode 100644
index 00000000..5e6537e2
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/misc/extend_printf.c
@@ -0,0 +1,188 @@
+/*
+ * Behaves as gmp_printf with new conversion specifier %B for element_t types
+ */
+
+#include <stdio.h>
+#include <stdint.h> // for intptr_t
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <gmp.h>
+#include "pbc_utils.h"
+#include "pbc_field.h"
+#include "pbc_memory.h"
+
+struct sninfo_s {
+ char *s;
+ size_t size;
+ size_t left;
+ size_t result;
+};
+
+// TODO: remove repeated code for error handling
+static int do_print(int (*strcb)(void *, char *s),
+ int (*fstrcb)(void *, char *s, void *),
+ int (*elcb)(void *, element_ptr e),
+ void *data,
+ const char *format, va_list ap) {
+ // A primitive front-end for printf()-family functions. Only handles types
+ // in specifiers, and assumes they all take void * arguments.
+ //
+ // I wish register_printf_specifier() were more widespread.
+ int count = 0, status;
+ char *copy, *c, *start, *next;
+ element_ptr e;
+ int found;
+
+ copy = pbc_strdup(format);
+ start = next = copy;
+
+ for(;;) {
+ for(;;) {
+ c = strchr(next, '%');
+ if (!c) {
+ status = strcb(data, start);
+ if (status < 0) {
+ count = -1;
+ } else count += status;
+ goto done;
+ }
+ if (!*(c + 1)) goto done;
+ if (*(c + 1) != '%') break;
+ next = c + 2;
+ }
+ *c = 0;
+ status = strcb(data, start);
+ if (status < 0) {
+ count = -1;
+ goto done;
+ } else count += status;
+ *c = '%';
+ start = c;
+ found = 0;
+ while(!found) {
+ c++;
+ switch (*c) {
+ case '\0':
+ goto done;
+ case 'B':
+ e = va_arg(ap, element_ptr);
+ status = elcb(data, e);
+ if (status < 0) {
+ count = -1;
+ goto done;
+ } else count += status;
+ found = 1;
+ break;
+ default:
+ if (strchr("diouxXeEfFgGaAcspnmZ", *c)) {
+ if (*c == 'Z') c++;
+ char ch = *(c+1);
+ *(c+1) = '\0';
+ status = fstrcb(data, start, va_arg(ap, void *));
+ if (status < 0) {
+ count = -1;
+ goto done;
+ } else count += status;
+ *(c+1) = ch;
+ found = 1;
+ }
+ break;
+ }
+ }
+ next = start = c + 1;
+ }
+
+done:
+ pbc_free(copy);
+
+ return count;
+}
+
+static int string_cb(void *file, char *s) {
+ if (fputs(s, file) == EOF) return -1;
+ return strlen(s);
+}
+
+static int format_cb(void *file, char *fstring, void *ptr) {
+ return gmp_fprintf(file, fstring, ptr);
+}
+
+static int element_cb(void *file, element_ptr e) {
+ return element_out_str(file, 0, e);
+}
+
+int element_vfprintf(FILE *stream, const char *format, va_list ap) {
+ return do_print(string_cb, format_cb, element_cb, stream, format, ap);
+}
+
+int element_fprintf(FILE *stream, const char *format, ...) {
+ int status;
+ va_list ap;
+
+ va_start(ap, format);
+ status = element_vfprintf(stream, format, ap);
+ va_end(ap);
+ return status;
+}
+
+int element_printf(const char *format, ...) {
+ int status;
+ va_list ap;
+
+ va_start(ap, format);
+ status = element_vfprintf(stdout, format, ap);
+ va_end(ap);
+ return status;
+}
+
+static void next(struct sninfo_s *p, int status) {
+ p->result += status;
+ p->left = p->result >= p->size ? 0 : p->size - p->result;
+}
+
+static int string_cbv(void *data, char *s) {
+ struct sninfo_s *p = data;
+ int status = snprintf(p->s + p->result, p->left, "%s", s);
+ if (status < 0) return status;
+ next(data, status);
+ return status;
+}
+
+static int format_cbv(void *data, char *fstring, void *ptr) {
+ struct sninfo_s *p = data;
+ int status = gmp_snprintf(p->s + p->result, p->left, fstring, ptr);
+ if (status < 0) return status;
+ next(data, status);
+ return status;
+}
+
+static int element_cbv(void *data, element_ptr e) {
+ struct sninfo_s *p = data;
+ int status = element_snprint(p->s + p->result, p->left, e);
+ if (status < 0) return status;
+ next(data, status);
+ return status;
+}
+
+int element_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
+ struct sninfo_s info;
+
+ info.s = buf;
+ info.left = info.size = size;
+ info.result = 0;
+
+ do_print(string_cbv, format_cbv, element_cbv, &info, fmt, ap);
+
+ return info.result;
+}
+
+int element_snprintf(char *buf, size_t size, const char *fmt, ...) {
+ int status;
+ va_list ap;
+
+ va_start(ap, fmt);
+ status = element_vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+ return status;
+}