]> git.proxmox.com Git - mirror_frr.git/blame - lib/printf/printfcommon.h
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / printf / printfcommon.h
CommitLineData
ea0b6afe
DL
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
ea0b6afe
DL
48static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *);
49static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
50
51#define NIOV 8
52struct io_state {
5c25bd87
DL
53 struct fbuf *cb;
54 size_t avail;
ea0b6afe
DL
55};
56
57static inline void
5c25bd87 58io_init(struct io_state *iop, struct fbuf *cb)
ea0b6afe 59{
5c25bd87
DL
60 iop->cb = cb;
61 iop->avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
ea0b6afe
DL
62}
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 */
68static inline int
5c25bd87 69io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len)
ea0b6afe 70{
5c25bd87
DL
71 size_t copylen = len;
72
73 if (!iop->cb)
74 return 0;
75 if (iop->avail < copylen)
76 copylen = iop->avail;
ea0b6afe 77
5c25bd87
DL
78 memcpy(iop->cb->pos, ptr, copylen);
79 iop->avail -= copylen;
80 iop->cb->pos += copylen;
81 return 0;
ea0b6afe
DL
82}
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#define PADSIZE 16 /* pad chunk size */
90static const CHAR blanks[PADSIZE] =
91{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
92static 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 */
99static inline int
86bfbddf 100io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
ea0b6afe
DL
101{
102 int n;
103
104 while (howmany > 0) {
105 n = (howmany >= PADSIZE) ? PADSIZE : howmany;
86bfbddf 106 if (io_print(iop, with, n))
ea0b6afe
DL
107 return (-1);
108 howmany -= n;
109 }
110 return (0);
111}
112
113/*
114 * Print exactly len characters of the string spanning p to ep, truncating
115 * or padding with 'with' as necessary.
116 */
117static inline int
118io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
86bfbddf 119 int len, const CHAR * __restrict with)
ea0b6afe
DL
120{
121 int p_len;
122
123 p_len = ep - p;
124 if (p_len > len)
125 p_len = len;
126 if (p_len > 0) {
86bfbddf 127 if (io_print(iop, p, p_len))
ea0b6afe
DL
128 return (-1);
129 } else {
130 p_len = 0;
131 }
86bfbddf 132 return (io_pad(iop, len - p_len, with));
ea0b6afe
DL
133}
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 */
141static CHAR *
142__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
143{
144 CHAR *cp = endp;
145 long sval;
146
147 /*
148 * Handle the three cases separately, in the hope of getting
149 * better/faster code.
150 */
151 switch (base) {
152 case 10:
153 if (val < 10) { /* many numbers are 1 digit */
154 *--cp = to_char(val);
155 return (cp);
156 }
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 if (val > LONG_MAX) {
164 *--cp = to_char(val % 10);
165 sval = val / 10;
166 } else
167 sval = val;
168 do {
169 *--cp = to_char(sval % 10);
170 sval /= 10;
171 } while (sval != 0);
172 break;
173
174 case 8:
175 do {
176 *--cp = to_char(val & 7);
177 val >>= 3;
178 } while (val);
179 if (octzero && *cp != '0')
180 *--cp = '0';
181 break;
182
183 case 16:
184 do {
185 *--cp = xdigs[val & 15];
186 val >>= 4;
187 } while (val);
188 break;
189
190 default: /* oops */
191 abort();
192 }
193 return (cp);
194}
195
196/* Identical to __ultoa, but for intmax_t. */
197static CHAR *
198__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
199{
200 CHAR *cp = endp;
201 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 if (val <= ULONG_MAX)
206 return (__ultoa((u_long)val, endp, base, octzero, xdigs));
207 switch (base) {
208 case 10:
209 if (val < 10) {
210 *--cp = to_char(val % 10);
211 return (cp);
212 }
213 if (val > INTMAX_MAX) {
214 *--cp = to_char(val % 10);
215 sval = val / 10;
216 } else
217 sval = val;
218 do {
219 *--cp = to_char(sval % 10);
220 sval /= 10;
221 } while (sval != 0);
222 break;
223
224 case 8:
225 do {
226 *--cp = to_char(val & 7);
227 val >>= 3;
228 } while (val);
229 if (octzero && *cp != '0')
230 *--cp = '0';
231 break;
232
233 case 16:
234 do {
235 *--cp = xdigs[val & 15];
236 val >>= 4;
237 } while (val);
238 break;
239
240 default:
241 abort();
242 }
243 return (cp);
244}