]>
git.proxmox.com Git - mirror_frr.git/blob - lib/printf/glue.c
1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
10 #include <sys/types.h>
15 #include "printflocal.h"
17 ssize_t
bprintfrr(struct fbuf
*out
, const char *fmt
, ...)
23 ret
= vbprintfrr(out
, fmt
, ap
);
28 ssize_t
vsnprintfrr(char *out
, size_t outsz
, const char *fmt
, va_list ap
)
30 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
31 struct fbuf
*fb
= (out
&& outsz
) ? &fbb
: NULL
;
34 ret
= vbprintfrr(fb
, fmt
, ap
);
40 ssize_t
snprintfrr(char *out
, size_t outsz
, const char *fmt
, ...)
42 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
43 struct fbuf
*fb
= (out
&& outsz
) ? &fbb
: NULL
;
48 ret
= vbprintfrr(fb
, fmt
, ap
);
55 ssize_t
vcsnprintfrr(char *out
, size_t outsz
, const char *fmt
, va_list ap
)
58 return vbprintfrr(NULL
, fmt
, ap
);
60 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
64 pos
= strnlen(out
, outsz
);
67 ret
= vbprintfrr(&fbb
, fmt
, ap
);
69 return ret
>= 0 ? ret
+ (ssize_t
)pos
: ret
;
72 ssize_t
csnprintfrr(char *out
, size_t outsz
, const char *fmt
, ...)
78 ret
= vcsnprintfrr(out
, outsz
, fmt
, ap
);
83 char *vasnprintfrr(struct memtype
*mt
, char *out
, size_t outsz
, const char *fmt
,
86 struct fbuf fb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
92 len
= vbprintfrr(&fb
, fmt
, ap
);
95 /* error = malformed format string => try something useful */
96 return qstrdup(mt
, fmt
);
99 if ((size_t)len
>= outsz
- 1) {
100 ret
= qmalloc(mt
, len
+ 1);
101 fb
.buf
= fb
.pos
= ret
;
104 vbprintfrr(&fb
, fmt
, ap2
);
112 char *asnprintfrr(struct memtype
*mt
, char *out
, size_t outsz
, const char *fmt
,
119 ret
= vasnprintfrr(mt
, out
, outsz
, fmt
, ap
);
124 char *vasprintfrr(struct memtype
*mt
, const char *fmt
, va_list ap
)
129 ret
= vasnprintfrr(mt
, buf
, sizeof(buf
), fmt
, ap
);
132 ret
= qstrdup(mt
, ret
);
136 char *asprintfrr(struct memtype
*mt
, const char *fmt
, ...)
143 ret
= vasnprintfrr(mt
, buf
, sizeof(buf
), fmt
, ap
);
147 ret
= qstrdup(mt
, ret
);
152 * A: since printf should be reasonably fast (think debugging logs), the idea
153 * here is to keep things close by each other in a cacheline. That's why
154 * ext_quick just has the first 2 characters of an extension, and we do a
155 * nice linear continuous sweep. Only if we find something, we go do more
158 * Q: doesn't this need a mutex/lock?
159 * A: theoretically, yes, but that's quite expensive and I rather elide that
160 * necessity by putting down some usage rules. Just call this at startup
161 * while singlethreaded and all is fine. Ideally, just use constructors
162 * (and make sure dlopen() doesn't mess things up...)
170 static uint8_t ext_offsets
[26] __attribute__((aligned(32)));
171 static struct ext_quick entries
[MAXEXT
] __attribute__((aligned(64)));
172 static const struct printfrr_ext
*exts
[MAXEXT
] __attribute__((aligned(64)));
174 void printfrr_ext_reg(const struct printfrr_ext
*ext
)
179 if (!printfrr_ext_char(ext
->match
[0]))
182 o
= ext
->match
[0] - 'A';
183 for (i
= ext_offsets
[o
];
184 i
< MAXEXT
&& entries
[i
].fmt
[0] &&
185 memcmp(entries
[i
].fmt
, ext
->match
, 2) < 0;
190 for (o
++; o
<= 'Z' - 'A'; o
++)
193 memmove(entries
+ i
+ 1, entries
+ i
,
194 (MAXEXT
- i
- 1) * sizeof(entries
[0]));
195 memmove(exts
+ i
+ 1, exts
+ i
,
196 (MAXEXT
- i
- 1) * sizeof(exts
[0]));
198 memcpy(entries
[i
].fmt
, ext
->match
, 2);
202 ssize_t
printfrr_extp(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
205 const char *fmt
= ea
->fmt
;
206 const struct printfrr_ext
*ext
;
209 for (i
= ext_offsets
[fmt
[0] - 'A']; i
< MAXEXT
; i
++) {
210 if (!entries
[i
].fmt
[0] || entries
[i
].fmt
[0] > fmt
[0])
212 if (entries
[i
].fmt
[1] && entries
[i
].fmt
[1] != fmt
[1])
217 if (strncmp(ext
->match
, fmt
, strlen(ext
->match
)))
219 ea
->fmt
+= strlen(ext
->match
);
220 return ext
->print_ptr(buf
, ea
, ptr
);
225 ssize_t
printfrr_exti(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
228 const char *fmt
= ea
->fmt
;
229 const struct printfrr_ext
*ext
;
232 for (i
= ext_offsets
[fmt
[0] - 'A']; i
< MAXEXT
; i
++) {
233 if (!entries
[i
].fmt
[0] || entries
[i
].fmt
[0] > fmt
[0])
235 if (entries
[i
].fmt
[1] && entries
[i
].fmt
[1] != fmt
[1])
240 if (strncmp(ext
->match
, fmt
, strlen(ext
->match
)))
242 ea
->fmt
+= strlen(ext
->match
);
243 return ext
->print_int(buf
, ea
, num
);
248 printfrr_ext_autoreg_p("FB", printfrr_fb
);
249 static ssize_t
printfrr_fb(struct fbuf
*out
, struct printfrr_eargs
*ea
,
252 const struct fbuf
*in
= ptr
;
256 return bputs(out
, "NULL");
259 copy_len
= MIN(in
->pos
- in
->buf
,
260 out
->buf
+ out
->len
- out
->pos
);
262 memcpy(out
->pos
, in
->buf
, copy_len
);
263 out
->pos
+= copy_len
;
267 return in
->pos
- in
->buf
;
270 printfrr_ext_autoreg_p("VA", printfrr_va
);
271 static ssize_t
printfrr_va(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
274 const struct va_format
*vaf
= ptr
;
277 if (!vaf
|| !vaf
->fmt
|| !vaf
->va
)
278 return bputs(buf
, "NULL");
280 /* make sure we don't alter the data passed in - especially since
281 * bprintfrr (and thus this) might be called on the same format twice,
282 * when allocating a larger buffer in asnprintfrr()
284 va_copy(ap
, *vaf
->va
);
285 #pragma GCC diagnostic push
286 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
287 /* can't format check this */
288 return vbprintfrr(buf
, vaf
->fmt
, ap
);
289 #pragma GCC diagnostic pop