]>
git.proxmox.com Git - mirror_frr.git/blob - lib/printf/glue.c
2 * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
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.
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.
21 #include <sys/types.h>
26 #include "printflocal.h"
28 ssize_t
bprintfrr(struct fbuf
*out
, const char *fmt
, ...)
34 ret
= vbprintfrr(out
, fmt
, ap
);
39 ssize_t
vsnprintfrr(char *out
, size_t outsz
, const char *fmt
, va_list ap
)
41 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
42 struct fbuf
*fb
= (out
&& outsz
) ? &fbb
: NULL
;
45 ret
= vbprintfrr(fb
, fmt
, ap
);
51 ssize_t
snprintfrr(char *out
, size_t outsz
, const char *fmt
, ...)
53 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
54 struct fbuf
*fb
= (out
&& outsz
) ? &fbb
: NULL
;
59 ret
= vbprintfrr(fb
, fmt
, ap
);
66 ssize_t
vcsnprintfrr(char *out
, size_t outsz
, const char *fmt
, va_list ap
)
69 return vbprintfrr(NULL
, fmt
, ap
);
71 struct fbuf fbb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
75 pos
= strnlen(out
, outsz
);
78 ret
= vbprintfrr(&fbb
, fmt
, ap
);
80 return ret
>= 0 ? ret
+ (ssize_t
)pos
: ret
;
83 ssize_t
csnprintfrr(char *out
, size_t outsz
, const char *fmt
, ...)
89 ret
= vcsnprintfrr(out
, outsz
, fmt
, ap
);
94 char *vasnprintfrr(struct memtype
*mt
, char *out
, size_t outsz
, const char *fmt
,
97 struct fbuf fb
= { .buf
= out
, .pos
= out
, .len
= outsz
- 1, };
103 len
= vbprintfrr(&fb
, fmt
, ap
);
106 /* error = malformed format string => try something useful */
107 return qstrdup(mt
, fmt
);
110 if ((size_t)len
>= outsz
- 1) {
111 ret
= qmalloc(mt
, len
+ 1);
112 fb
.buf
= fb
.pos
= ret
;
115 vbprintfrr(&fb
, fmt
, ap2
);
123 char *asnprintfrr(struct memtype
*mt
, char *out
, size_t outsz
, const char *fmt
,
130 ret
= vasnprintfrr(mt
, out
, outsz
, fmt
, ap
);
135 char *vasprintfrr(struct memtype
*mt
, const char *fmt
, va_list ap
)
140 ret
= vasnprintfrr(mt
, buf
, sizeof(buf
), fmt
, ap
);
143 ret
= qstrdup(mt
, ret
);
147 char *asprintfrr(struct memtype
*mt
, const char *fmt
, ...)
154 ret
= vasnprintfrr(mt
, buf
, sizeof(buf
), fmt
, ap
);
158 ret
= qstrdup(mt
, ret
);
163 * A: since printf should be reasonably fast (think debugging logs), the idea
164 * here is to keep things close by each other in a cacheline. That's why
165 * ext_quick just has the first 2 characters of an extension, and we do a
166 * nice linear continuous sweep. Only if we find something, we go do more
169 * Q: doesn't this need a mutex/lock?
170 * A: theoretically, yes, but that's quite expensive and I rather elide that
171 * necessity by putting down some usage rules. Just call this at startup
172 * while singlethreaded and all is fine. Ideally, just use constructors
173 * (and make sure dlopen() doesn't mess things up...)
181 static uint8_t ext_offsets
[26] __attribute__((aligned(32)));
182 static struct ext_quick entries
[MAXEXT
] __attribute__((aligned(64)));
183 static const struct printfrr_ext
*exts
[MAXEXT
] __attribute__((aligned(64)));
185 void printfrr_ext_reg(const struct printfrr_ext
*ext
)
190 if (!printfrr_ext_char(ext
->match
[0]))
193 o
= ext
->match
[0] - 'A';
194 for (i
= ext_offsets
[o
];
195 i
< MAXEXT
&& entries
[i
].fmt
[0] &&
196 memcmp(entries
[i
].fmt
, ext
->match
, 2) < 0;
201 for (o
++; o
<= 'Z' - 'A'; o
++)
204 memmove(entries
+ i
+ 1, entries
+ i
,
205 (MAXEXT
- i
- 1) * sizeof(entries
[0]));
206 memmove(exts
+ i
+ 1, exts
+ i
,
207 (MAXEXT
- i
- 1) * sizeof(exts
[0]));
209 memcpy(entries
[i
].fmt
, ext
->match
, 2);
213 ssize_t
printfrr_extp(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
216 const char *fmt
= ea
->fmt
;
217 const struct printfrr_ext
*ext
;
220 for (i
= ext_offsets
[fmt
[0] - 'A']; i
< MAXEXT
; i
++) {
221 if (!entries
[i
].fmt
[0] || entries
[i
].fmt
[0] > fmt
[0])
223 if (entries
[i
].fmt
[1] && entries
[i
].fmt
[1] != fmt
[1])
228 if (strncmp(ext
->match
, fmt
, strlen(ext
->match
)))
230 ea
->fmt
+= strlen(ext
->match
);
231 return ext
->print_ptr(buf
, ea
, ptr
);
236 ssize_t
printfrr_exti(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
239 const char *fmt
= ea
->fmt
;
240 const struct printfrr_ext
*ext
;
243 for (i
= ext_offsets
[fmt
[0] - 'A']; i
< MAXEXT
; i
++) {
244 if (!entries
[i
].fmt
[0] || entries
[i
].fmt
[0] > fmt
[0])
246 if (entries
[i
].fmt
[1] && entries
[i
].fmt
[1] != fmt
[1])
251 if (strncmp(ext
->match
, fmt
, strlen(ext
->match
)))
253 ea
->fmt
+= strlen(ext
->match
);
254 return ext
->print_int(buf
, ea
, num
);
259 printfrr_ext_autoreg_p("FB", printfrr_fb
)
260 static ssize_t
printfrr_fb(struct fbuf
*out
, struct printfrr_eargs
*ea
,
263 const struct fbuf
*in
= ptr
;
267 return bputs(out
, "NULL");
270 copy_len
= MIN(in
->pos
- in
->buf
,
271 out
->buf
+ out
->len
- out
->pos
);
273 memcpy(out
->pos
, in
->buf
, copy_len
);
274 out
->pos
+= copy_len
;
278 return in
->pos
- in
->buf
;
281 printfrr_ext_autoreg_p("VA", printfrr_va
)
282 static ssize_t
printfrr_va(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
285 const struct va_format
*vaf
= ptr
;
288 if (!vaf
|| !vaf
->fmt
|| !vaf
->va
)
289 return bputs(buf
, "NULL");
291 /* make sure we don't alter the data passed in - especially since
292 * bprintfrr (and thus this) might be called on the same format twice,
293 * when allocating a larger buffer in asnprintfrr()
295 va_copy(ap
, *vaf
->va
);
296 return vbprintfrr(buf
, vaf
->fmt
, ap
);