/src/frr/lib/printf/printfcommon.h
Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * Copyright (c) 1990, 1993 |
5 | | * The Regents of the University of California. All rights reserved. |
6 | | * |
7 | | * This code is derived from software contributed to Berkeley by |
8 | | * Chris Torek. |
9 | | * |
10 | | * Copyright (c) 2011 The FreeBSD Foundation |
11 | | * All rights reserved. |
12 | | * Portions of this software were developed by David Chisnall |
13 | | * under sponsorship from the FreeBSD Foundation. |
14 | | * |
15 | | * Redistribution and use in source and binary forms, with or without |
16 | | * modification, are permitted provided that the following conditions |
17 | | * are met: |
18 | | * 1. Redistributions of source code must retain the above copyright |
19 | | * notice, this list of conditions and the following disclaimer. |
20 | | * 2. Redistributions in binary form must reproduce the above copyright |
21 | | * notice, this list of conditions and the following disclaimer in the |
22 | | * documentation and/or other materials provided with the distribution. |
23 | | * 3. Neither the name of the University nor the names of its contributors |
24 | | * may be used to endorse or promote products derived from this software |
25 | | * without specific prior written permission. |
26 | | * |
27 | | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
28 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
29 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
30 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
31 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
32 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
33 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
34 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
35 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
36 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
37 | | * SUCH DAMAGE. |
38 | | * |
39 | | * $FreeBSD$ |
40 | | */ |
41 | | |
42 | | /* |
43 | | * This file defines common routines used by both printf and wprintf. |
44 | | * You must define CHAR to either char or wchar_t prior to including this. |
45 | | */ |
46 | | |
47 | | |
48 | | static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *); |
49 | | static CHAR *__ultoa(u_long, CHAR *, int, int, const char *); |
50 | | |
51 | | #define NIOV 8 |
52 | | struct io_state { |
53 | | struct fbuf *cb; |
54 | | size_t avail; |
55 | | }; |
56 | | |
57 | | static inline void |
58 | | io_init(struct io_state *iop, struct fbuf *cb) |
59 | 498k | { |
60 | 498k | iop->cb = cb; |
61 | 498k | iop->avail = cb ? cb->len - (cb->pos - cb->buf) : 0; |
62 | 498k | } |
63 | | |
64 | | /* |
65 | | * WARNING: The buffer passed to io_print() is not copied immediately; it must |
66 | | * remain valid until io_flush() is called. |
67 | | */ |
68 | | static inline int |
69 | | io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len) |
70 | 448k | { |
71 | 448k | size_t copylen = len; |
72 | | |
73 | 448k | if (!iop->cb) |
74 | 0 | return 0; |
75 | 448k | if (iop->avail < copylen) |
76 | 5 | copylen = iop->avail; |
77 | | |
78 | 448k | memcpy(iop->cb->pos, ptr, copylen); |
79 | 448k | iop->avail -= copylen; |
80 | 448k | iop->cb->pos += copylen; |
81 | 448k | return 0; |
82 | 448k | } |
83 | | |
84 | | /* |
85 | | * Choose PADSIZE to trade efficiency vs. size. If larger printf |
86 | | * fields occur frequently, increase PADSIZE and make the initialisers |
87 | | * below longer. |
88 | | */ |
89 | 52 | #define PADSIZE 16 /* pad chunk size */ |
90 | | static const CHAR blanks[PADSIZE] = |
91 | | {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; |
92 | | static const CHAR zeroes[PADSIZE] = |
93 | | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; |
94 | | |
95 | | /* |
96 | | * Pad with blanks or zeroes. 'with' should point to either the blanks array |
97 | | * or the zeroes array. |
98 | | */ |
99 | | static inline int |
100 | | io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) |
101 | 63.5k | { |
102 | 63.5k | int n; |
103 | | |
104 | 63.6k | while (howmany > 0) { |
105 | 52 | n = (howmany >= PADSIZE) ? PADSIZE : howmany; |
106 | 52 | if (io_print(iop, with, n)) |
107 | 0 | return (-1); |
108 | 52 | howmany -= n; |
109 | 52 | } |
110 | 63.5k | return (0); |
111 | 63.5k | } |
112 | | |
113 | | /* |
114 | | * Print exactly len characters of the string spanning p to ep, truncating |
115 | | * or padding with 'with' as necessary. |
116 | | */ |
117 | | static inline int |
118 | | io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, |
119 | | int len, const CHAR * __restrict with) |
120 | 0 | { |
121 | 0 | int p_len; |
122 | 0 |
|
123 | 0 | p_len = ep - p; |
124 | 0 | if (p_len > len) |
125 | 0 | p_len = len; |
126 | 0 | if (p_len > 0) { |
127 | 0 | if (io_print(iop, p, p_len)) |
128 | 0 | return (-1); |
129 | 0 | } else { |
130 | 0 | p_len = 0; |
131 | 0 | } |
132 | 0 | return (io_pad(iop, len - p_len, with)); |
133 | 0 | } |
134 | | |
135 | | /* |
136 | | * Convert an unsigned long to ASCII for printf purposes, returning |
137 | | * a pointer to the first character of the string representation. |
138 | | * Octal numbers can be forced to have a leading zero; hex numbers |
139 | | * use the given digits. |
140 | | */ |
141 | | static CHAR * |
142 | | __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) |
143 | 175 | { |
144 | 175 | CHAR *cp = endp; |
145 | 175 | long sval; |
146 | | |
147 | | /* |
148 | | * Handle the three cases separately, in the hope of getting |
149 | | * better/faster code. |
150 | | */ |
151 | 175 | switch (base) { |
152 | 175 | case 10: |
153 | 175 | if (val < 10) { /* many numbers are 1 digit */ |
154 | 77 | *--cp = to_char(val); |
155 | 77 | return (cp); |
156 | 77 | } |
157 | | /* |
158 | | * On many machines, unsigned arithmetic is harder than |
159 | | * signed arithmetic, so we do at most one unsigned mod and |
160 | | * divide; this is sufficient to reduce the range of |
161 | | * the incoming value to where signed arithmetic works. |
162 | | */ |
163 | 98 | if (val > LONG_MAX) { |
164 | 0 | *--cp = to_char(val % 10); |
165 | 0 | sval = val / 10; |
166 | 0 | } else |
167 | 98 | sval = val; |
168 | 483 | do { |
169 | 483 | *--cp = to_char(sval % 10); |
170 | 483 | sval /= 10; |
171 | 483 | } while (sval != 0); |
172 | 98 | break; |
173 | | |
174 | 0 | case 8: |
175 | 0 | do { |
176 | 0 | *--cp = to_char(val & 7); |
177 | 0 | val >>= 3; |
178 | 0 | } while (val); |
179 | 0 | if (octzero && *cp != '0') |
180 | 0 | *--cp = '0'; |
181 | 0 | break; |
182 | | |
183 | 0 | case 16: |
184 | 0 | do { |
185 | 0 | *--cp = xdigs[val & 15]; |
186 | 0 | val >>= 4; |
187 | 0 | } while (val); |
188 | 0 | break; |
189 | | |
190 | 0 | default: /* oops */ |
191 | 0 | abort(); |
192 | 175 | } |
193 | 98 | return (cp); |
194 | 175 | } |
195 | | |
196 | | /* Identical to __ultoa, but for intmax_t. */ |
197 | | static CHAR * |
198 | | __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) |
199 | 3 | { |
200 | 3 | CHAR *cp = endp; |
201 | 3 | intmax_t sval; |
202 | | |
203 | | /* quick test for small values; __ultoa is typically much faster */ |
204 | | /* (perhaps instead we should run until small, then call __ultoa?) */ |
205 | 3 | if (val <= ULONG_MAX) |
206 | 3 | return (__ultoa((u_long)val, endp, base, octzero, xdigs)); |
207 | 0 | switch (base) { |
208 | 0 | case 10: |
209 | 0 | if (val < 10) { |
210 | 0 | *--cp = to_char(val % 10); |
211 | 0 | return (cp); |
212 | 0 | } |
213 | 0 | if (val > INTMAX_MAX) { |
214 | 0 | *--cp = to_char(val % 10); |
215 | 0 | sval = val / 10; |
216 | 0 | } else |
217 | 0 | sval = val; |
218 | 0 | do { |
219 | 0 | *--cp = to_char(sval % 10); |
220 | 0 | sval /= 10; |
221 | 0 | } while (sval != 0); |
222 | 0 | break; |
223 | | |
224 | 0 | case 8: |
225 | 0 | do { |
226 | 0 | *--cp = to_char(val & 7); |
227 | 0 | val >>= 3; |
228 | 0 | } while (val); |
229 | 0 | if (octzero && *cp != '0') |
230 | 0 | *--cp = '0'; |
231 | 0 | break; |
232 | | |
233 | 0 | case 16: |
234 | 0 | do { |
235 | 0 | *--cp = xdigs[val & 15]; |
236 | 0 | val >>= 4; |
237 | 0 | } while (val); |
238 | 0 | break; |
239 | | |
240 | 0 | default: |
241 | 0 | abort(); |
242 | 0 | } |
243 | 0 | return (cp); |
244 | 0 | } |