]>
Commit | Line | Data |
---|---|---|
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 |
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 { | |
5c25bd87 DL |
53 | struct fbuf *cb; |
54 | size_t avail; | |
ea0b6afe DL |
55 | }; |
56 | ||
57 | static inline void | |
5c25bd87 | 58 | io_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 | */ | |
68 | static inline int | |
5c25bd87 | 69 | io_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 */ | |
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 | |
86bfbddf | 100 | io_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 | */ | |
117 | static inline int | |
118 | io_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 | */ | |
141 | static 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. */ | |
197 | static 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 | } |