]> git.proxmox.com Git - mirror_frr.git/blob - lib/printf/glue.c
Merge pull request #4370 from pguibert6WIND/fix_interface_rtadv2
[mirror_frr.git] / lib / printf / glue.c
1 /*
2 * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <sys/types.h>
22 #include <string.h>
23 #include <wchar.h>
24
25 #include "printfrr.h"
26 #include "printflocal.h"
27
28 ssize_t bprintfrr(struct fbuf *out, const char *fmt, ...)
29 {
30 ssize_t ret;
31 va_list ap;
32
33 va_start(ap, fmt);
34 ret = vbprintfrr(out, fmt, ap);
35 va_end(ap);
36 return ret;
37 }
38
39 ssize_t vsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
40 {
41 struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
42 struct fbuf *fb = (out && outsz) ? &fbb : NULL;
43 ssize_t ret;
44
45 ret = vbprintfrr(fb, fmt, ap);
46 if (fb)
47 fb->pos[0] = '\0';
48 return ret;
49 }
50
51 ssize_t snprintfrr(char *out, size_t outsz, const char *fmt, ...)
52 {
53 struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
54 struct fbuf *fb = (out && outsz) ? &fbb : NULL;
55 ssize_t ret;
56 va_list ap;
57
58 va_start(ap, fmt);
59 ret = vbprintfrr(fb, fmt, ap);
60 va_end(ap);
61 if (fb)
62 fb->pos[0] = '\0';
63 return ret;
64 }
65
66 ssize_t vcsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
67 {
68 if (!out || !outsz)
69 return vbprintfrr(NULL, fmt, ap);
70
71 struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
72 ssize_t ret;
73 size_t pos;
74
75 pos = strnlen(out, outsz);
76 fbb.pos += pos;
77
78 ret = vbprintfrr(&fbb, fmt, ap);
79 fbb.pos[0] = '\0';
80 return ret >= 0 ? ret + (ssize_t)pos : ret;
81 }
82
83 ssize_t csnprintfrr(char *out, size_t outsz, const char *fmt, ...)
84 {
85 ssize_t ret;
86 va_list ap;
87
88 va_start(ap, fmt);
89 ret = vcsnprintfrr(out, outsz, fmt, ap);
90 va_end(ap);
91 return ret;
92 }
93
94 char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
95 va_list ap)
96 {
97 struct fbuf fb = { .buf = out, .pos = out, .len = outsz - 1, };
98 ssize_t len;
99 va_list ap2;
100 char *ret = out;
101
102 va_copy(ap2, ap);
103 len = vbprintfrr(&fb, fmt, ap);
104 if (len < 0)
105 /* error = malformed format string => try something useful */
106 return qstrdup(mt, fmt);
107
108 if ((size_t)len >= outsz - 1) {
109 ret = qmalloc(mt, len + 1);
110 fb.buf = fb.pos = ret;
111 fb.len = len;
112
113 vbprintfrr(&fb, fmt, ap2);
114 }
115 ret[len] = '\0';
116 return ret;
117 }
118
119 char *asnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
120 ...)
121 {
122 va_list ap;
123 char *ret;
124
125 va_start(ap, fmt);
126 ret = vasnprintfrr(mt, out, outsz, fmt, ap);
127 va_end(ap);
128 return ret;
129 }
130
131 char *vasprintfrr(struct memtype *mt, const char *fmt, va_list ap)
132 {
133 char buf[256];
134 char *ret;
135
136 ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
137
138 if (ret == buf)
139 ret = qstrdup(mt, ret);
140 return ret;
141 }
142
143 char *asprintfrr(struct memtype *mt, const char *fmt, ...)
144 {
145 char buf[256];
146 va_list ap;
147 char *ret;
148
149 va_start(ap, fmt);
150 ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
151 va_end(ap);
152
153 if (ret == buf)
154 ret = qstrdup(mt, ret);
155 return ret;
156 }
157
158 /* Q: WTF?
159 * A: since printf should be reasonably fast (think debugging logs), the idea
160 * here is to keep things close by each other in a cacheline. That's why
161 * ext_quick just has the first 2 characters of an extension, and we do a
162 * nice linear continuous sweep. Only if we find something, we go do more
163 * expensive things.
164 *
165 * Q: doesn't this need a mutex/lock?
166 * A: theoretically, yes, but that's quite expensive and I rather elide that
167 * necessity by putting down some usage rules. Just call this at startup
168 * while singlethreaded and all is fine. Ideally, just use constructors
169 * (and make sure dlopen() doesn't mess things up...)
170 */
171 #define MAXEXT 64
172
173 struct ext_quick {
174 char fmt[2];
175 };
176
177 static uint8_t ext_offsets[26] __attribute__((aligned(32)));
178 static struct ext_quick entries[MAXEXT] __attribute__((aligned(64)));
179 static const struct printfrr_ext *exts[MAXEXT] __attribute__((aligned(64)));
180
181 void printfrr_ext_reg(const struct printfrr_ext *ext)
182 {
183 uint8_t o;
184 ptrdiff_t i;
185
186 if (!printfrr_ext_char(ext->match[0]))
187 return;
188
189 o = ext->match[0] - 'A';
190 for (i = ext_offsets[o];
191 i < MAXEXT && entries[i].fmt[0] &&
192 memcmp(entries[i].fmt, ext->match, 2) < 0;
193 i++)
194 ;
195 if (i == MAXEXT)
196 return;
197 for (o++; o <= 'Z' - 'A'; o++)
198 ext_offsets[o]++;
199
200 memmove(entries + i + 1, entries + i,
201 (MAXEXT - i - 1) * sizeof(entries[0]));
202 memmove(exts + i + 1, exts + i,
203 (MAXEXT - i - 1) * sizeof(exts[0]));
204
205 memcpy(entries[i].fmt, ext->match, 2);
206 exts[i] = ext;
207 }
208
209 ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec,
210 const void *ptr)
211 {
212 const struct printfrr_ext *ext;
213 size_t i;
214
215 for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
216 if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
217 return 0;
218 if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
219 continue;
220 ext = exts[i];
221 if (!ext->print_ptr)
222 continue;
223 if (strncmp(ext->match, fmt, strlen(ext->match)))
224 continue;
225 return ext->print_ptr(buf, sz, fmt, prec, ptr);
226 }
227 return 0;
228 }
229
230 ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec,
231 uintmax_t num)
232 {
233 const struct printfrr_ext *ext;
234 size_t i;
235
236 for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
237 if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
238 return 0;
239 if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
240 continue;
241 ext = exts[i];
242 if (!ext->print_int)
243 continue;
244 if (strncmp(ext->match, fmt, strlen(ext->match)))
245 continue;
246 return ext->print_int(buf, sz, fmt, prec, num);
247 }
248 return 0;
249 }