]> git.saurik.com Git - apple/libc.git/blame - gen/simple_dprintf.c
Libc-391.5.21.tar.gz
[apple/libc.git] / gen / simple_dprintf.c
CommitLineData
3d9156a7
A
1/*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <string.h>
24#include <stdarg.h>
25#include <sys/types.h>
26#include <unistd.h>
27#include <errno.h>
28
29/* we use a small buffer to minimize stack usage constraints */
30#define MYBUFSIZE 32
31
32typedef struct {
33 char buf[MYBUFSIZE];
34 char *ptr;
35 char *end;
36 int fd;
37} BUF;
38
39/* flush the buffer and reset the pointer */
40static inline void
41flush(BUF *b)
42{
43 char *buf = b->buf;
44 int n = b->ptr - buf;
45 int w;
46
47 while(n > 0) {
48 w = write(b->fd, buf, n);
49 if(w < 0) {
50 if(errno == EINTR || errno == EAGAIN)
51 continue;
52 break;
53 }
54 n -= w;
55 buf += n;
56 }
57 b->ptr = b->buf;
58}
59
60/* output a single character */
61static inline void
62put_c(BUF *b, int c)
63{
64 if(b->ptr >= b->end)
65 flush(b);
66 *b->ptr++ = c;
67}
68
69/* output a null-terminated string */
70static inline void
71put_s(BUF *b, const char *str)
72{
73 while(*str)
74 put_c(b, *str++);
75}
76
77/* output a string of the specified size */
78static inline void
79put_n(BUF *b, const char *str, int n)
80{
81 while(n-- > 0)
82 put_c(b, *str++);
83}
84
85/*
86 * Output the signed decimal string representing the number in "in". "width" is
87 * the minimum field width, and "zero" is a boolean value, true for zero padding
88 * (otherwise blank padding).
89 */
90static void
91dec(BUF *b, long long in, int width, int zero)
92{
93 char buf[32];
94 char *cp = buf + sizeof(buf);
95 int pad;
96 int neg = 0;
97 unsigned long long n = (unsigned long long)in;
98
99 if(in < 0) {
100 neg++;
101 width--;
102 n = ~n + 1;
103 }
104 *--cp = 0;
105 if(n) {
106 while(n) {
107 *--cp = (n % 10) + '0';
108 n /= 10;
109 }
110 } else
111 *--cp = '0';
112 if(neg && zero) {
113 put_c(b, '-');
114 neg = 0;
115 }
116 pad = width - strlen(cp);
117 zero = zero ? '0' : ' ';
118 while(pad-- > 0)
119 put_c(b, zero);
120 if(neg)
121 put_c(b, '-');
122 put_s(b, cp);
123}
124
125/*
126 * Output the hex string representing the number in "i". "width" is the
127 * minimum field width, and "zero" is a boolean value, true for zero padding
128 * (otherwise blank padding). "upper" is a boolean value, true for upper
129 * case hex characters, lower case otherwise. "p" is a boolean value, true
130 * if 0x should be prepended (for %p), otherwise nothing.
131 */
132static char _h[] = "0123456789abcdef";
133static char _H[] = "0123456789ABCDEF";
134static char _0x[] = "0x";
135
136static void
137hex(BUF *b, unsigned long long n, int width, int zero, int upper, int p)
138{
139 char buf[32];
140 char *cp = buf + sizeof(buf);
141 char *h = upper ? _H : _h;
142
143 *--cp = 0;
144 if(n) {
145 while(n) {
146 *--cp = h[n & 0xf];
147 n >>= 4;
148 }
149 } else
150 *--cp = '0';
151 if(p) {
152 width -= 2;
153 if(zero) {
154 put_s(b, _0x);
155 p = 0;
156 }
157 }
158 width -= strlen(cp);
159 zero = zero ? '0' : ' ';
160 while(width-- > 0)
161 put_c(b, zero);
162 if(p)
163 put_s(b, _0x);
164 put_s(b, cp);
165}
166
167/*
168 * Output the unsigned decimal string representing the number in "in". "width"
169 * is the minimum field width, and "zero" is a boolean value, true for zero
170 * padding (otherwise blank padding).
171 */
172static void
173udec(BUF *b, unsigned long long n, int width, int zero)
174{
175 char buf[32];
176 char *cp = buf + sizeof(buf);
177 int pad;
178
179 *--cp = 0;
180 if(n) {
181 while(n) {
182 *--cp = (n % 10) + '0';
183 n /= 10;
184 }
185 } else
186 *--cp = '0';
187 pad = width - strlen(cp);
188 zero = zero ? '0' : ' ';
189 while(pad-- > 0)
190 put_c(b, zero);
191 put_s(b, cp);
192}
193
194/*
195 * A simplified vfprintf variant. The format string is interpreted with
196 * arguments for the va_list, and the results are written to the given
197 * file descriptor.
198 */
199void
200_simple_vdprintf(int fd, const char *fmt, va_list ap)
201{
202 BUF b;
203
204 b.fd = fd;
205 b.ptr = b.buf;
206 b.end = b.buf + MYBUFSIZE;
207 while(*fmt) {
208 int lflag, zero, width;
209 char *cp;
210 if(!(cp = strchr(fmt, '%'))) {
211 put_s(&b, fmt);
212 break;
213 }
214 put_n(&b, fmt, cp - fmt);
215 fmt = cp + 1;
216 if(*fmt == '%') {
217 put_c(&b, '%');
218 fmt++;
219 continue;
220 }
221 lflag = zero = width = 0;
222 for(;;) {
223 switch(*fmt) {
224 case '0':
225 zero++;
226 fmt++;
227 /* drop through */
228 case '1': case '2': case '3': case '4': case '5':
229 case '6': case '7': case '8': case '9':
230 while(*fmt >= '0' && *fmt <= '9')
231 width = 10 * width + (*fmt++ - '0');
232 continue;
233 case 'c':
234 zero = zero ? '0' : ' ';
235 width--;
236 while(width-- > 0)
237 put_c(&b, zero);
238 put_c(&b, va_arg(ap, int));
239 break;
240 case 'd': case 'i':
241 switch(lflag) {
242 case 0:
243 dec(&b, va_arg(ap, int), width, zero);
244 break;
245 case 1:
246 dec(&b, va_arg(ap, long), width, zero);
247 break;
248 default:
249 dec(&b, va_arg(ap, long long), width, zero);
250 break;
251 }
252 break;
253 case 'l':
254 lflag++;
255 fmt++;
256 continue;
257 case 'p':
258 hex(&b, (unsigned long)va_arg(ap, void *), width, zero, 0, 1);
259 break;
260 case 's':
261 cp = va_arg(ap, char *);
262 width -= strlen(cp);
263 zero = zero ? '0' : ' ';
264 while(width-- > 0)
265 put_c(&b, zero);
266 put_s(&b, cp);
267 break;
268 case 'u':
269 switch(lflag) {
270 case 0:
271 udec(&b, va_arg(ap, unsigned int), width, zero);
272 break;
273 case 1:
274 udec(&b, va_arg(ap, unsigned long), width, zero);
275 break;
276 default:
277 udec(&b, va_arg(ap, unsigned long long), width, zero);
278 break;
279 }
280 break;
281 case 'X': case 'x':
282 switch(lflag) {
283 case 0:
284 hex(&b, va_arg(ap, unsigned int), width, zero,
285 *fmt == 'X', 0);
286 break;
287 case 1:
288 hex(&b, va_arg(ap, unsigned long), width, zero,
289 *fmt == 'X', 0);
290 break;
291 default:
292 hex(&b, va_arg(ap, unsigned long long), width, zero,
293 *fmt == 'X', 0);
294 break;
295 }
296 break;
297 default:
298 put_c(&b, *fmt);
299 break;
300 }
301 break;
302 }
303 fmt++;
304 }
305 flush(&b);
306}
307
308/*
309 * A simplified fprintf variant. The format string is interpreted with
310 * arguments for the variable argument list, and the results are written
311 * to the given file descriptor.
312 */
313void
314_simple_dprintf(int fd, const char *format, ...)
315{
316 va_list ap;
317
318 va_start(ap, format);
319 _simple_vdprintf(fd, format, ap);
320 va_end(ap);
321}