Add Apache License version 2.0.
[pbc.git] / misc / extend_printf.c
blobfa9bf2bb9c7597e0eb957ed85e7b59f276165f02
1 /*
2 * Behaves as gmp_printf with new conversion specifier %B for element_t types
3 */
5 #include <stdio.h>
6 #include <stdint.h> // for intptr_t
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <gmp.h>
11 #include "pbc_utils.h"
12 #include "pbc_field.h"
13 #include "pbc_memory.h"
15 struct sninfo_s {
16 char *s;
17 size_t size;
18 size_t left;
19 size_t result;
22 // TODO: remove repeated code for error handling
23 static int do_print(int(*strcb)(void *, char *s),
24 int (*fstrcb)(void *, char *s, void *),
25 int(*elcb)(void *, element_ptr e),
26 void *data,
27 const char *format, va_list ap) {
28 // A primitive front-end for printf()-family functions. Only handles types
29 // in specifiers, and assumes they all take void * arguments.
30 //
31 // I wish register_printf_specifier() were more widespread.
33 int count = 0, status;
34 char *copy, *c, *start, *next;
35 element_ptr e;
36 int found;
38 copy = pbc_strdup(format);
39 start = next = copy;
41 for(;;) {
42 for(;;) {
43 c = strchr(next, '%');
44 if (!c) {
45 status = strcb(data, start);
46 if (status < 0) {
47 count = -1;
48 } else count += status;
49 goto done;
51 if (!*(c + 1)) goto done;
52 if (*(c + 1) != '%') break;
53 next = c + 2;
55 *c = 0;
56 status = strcb(data, start);
57 if (status < 0) {
58 count = -1;
59 goto done;
60 } else count += status;
61 *c = '%';
62 start = c;
63 found = 0;
64 while(!found) {
65 c++;
66 switch (*c) {
67 case '\0':
68 goto done;
69 case 'B':
70 e = va_arg(ap, element_ptr);
71 status = elcb(data, e);
72 if (status < 0) {
73 count = -1;
74 goto done;
75 } else count += status;
76 found = 1;
77 break;
78 default:
79 if (strchr("diouxXeEfFgGaAcspnmZ", *c)) {
80 if (*c == 'Z') c++;
81 char ch = *(c+1);
82 *(c+1) = '\0';
83 status = fstrcb(data, start, va_arg(ap, void *));
84 if (status < 0) {
85 count = -1;
86 goto done;
87 } else count += status;
88 *(c+1) = ch;
89 found = 1;
91 break;
94 next = start = c + 1;
97 done:
98 pbc_free(copy);
100 return count;
103 static int string_cb(void *file, char *s) {
104 if (fputs(s, file) == EOF) return -1;
105 return (int)strlen(s);
108 static int format_cb(void *file, char *fstring, void *ptr) {
109 return gmp_fprintf(file, fstring, ptr);
112 static int element_cb(void *file, element_ptr e) {
113 return (int)element_out_str(file, 0, e);
116 int element_vfprintf(FILE *stream, const char *format, va_list ap) {
117 return do_print(string_cb, format_cb, element_cb, stream, format, ap);
120 int element_fprintf(FILE *stream, const char *format, ...) {
121 int status;
122 va_list ap;
124 va_start(ap, format);
125 status = element_vfprintf(stream, format, ap);
126 va_end(ap);
127 return status;
130 int element_printf(const char *format, ...) {
131 int status;
132 va_list ap;
134 va_start(ap, format);
135 status = element_vfprintf(stdout, format, ap);
136 va_end(ap);
137 return status;
140 static void next(struct sninfo_s *p, int status) {
141 p->result += status;
142 p->left = p->result >= p->size ? 0 : p->size - p->result;
145 static int string_cbv(void *data, char *s) {
146 struct sninfo_s *p = data;
147 int status = snprintf(p->s + p->result, p->left, "%s", s);
148 if (status < 0) return status;
149 next(data, status);
150 return status;
153 static int format_cbv(void *data, char *fstring, void *ptr) {
154 struct sninfo_s *p = data;
155 int status = gmp_snprintf(p->s + p->result, p->left, fstring, ptr);
156 if (status < 0) return status;
157 next(data, status);
158 return status;
161 static int element_cbv(void *data, element_ptr e) {
162 struct sninfo_s *p = data;
163 int status = element_snprint(p->s + p->result, p->left, e);
164 if (status < 0) return status;
165 next(data, status);
166 return status;
169 int element_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
170 struct sninfo_s info;
172 info.s = buf;
173 info.left = info.size = size;
174 info.result = 0;
176 do_print(string_cbv, format_cbv, element_cbv, &info, fmt, ap);
178 return (int)info.result;
181 int element_snprintf(char *buf, size_t size, const char *fmt, ...) {
182 int status;
183 va_list ap;
185 va_start(ap, fmt);
186 status = element_vsnprintf(buf, size, fmt, ap);
187 va_end(ap);
188 return status;