source: trunk/minix/lib/stdio/doprnt.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 6.5 KB
Line 
1/*
2 * doprnt.c - print formatted output
3 */
4/* $Header: /cvsup/minix/src/lib/stdio/doprnt.c,v 1.1.1.1 2005/04/21 14:56:34 beng Exp $ */
5
6#include <ctype.h>
7#include <stdio.h>
8#include <stdarg.h>
9#include <string.h>
10#include "loc_incl.h"
11
12/* gnum() is used to get the width and precision fields of a format. */
13static const char *
14gnum(register const char *f, int *ip, va_list *app)
15{
16 register int i, c;
17
18 if (*f == '*') {
19 *ip = va_arg((*app), int);
20 f++;
21 } else {
22 i = 0;
23 while ((c = *f - '0') >= 0 && c <= 9) {
24 i = i*10 + c;
25 f++;
26 }
27 *ip = i;
28 }
29 return f;
30}
31
32#if _EM_WSIZE == _EM_PSIZE
33#define set_pointer(flags) /* nothing */
34#elif _EM_LSIZE == _EM_PSIZE
35#define set_pointer(flags) (flags |= FL_LONG)
36#else
37#error garbage pointer size
38#define set_pointer(flags) /* compilation might continue */
39#endif
40
41/* print an ordinal number */
42static char *
43o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed)
44{
45 long signed_val;
46 unsigned long unsigned_val;
47 char *old_s = s;
48 int base;
49
50 switch (flags & (FL_SHORT | FL_LONG)) {
51 case FL_SHORT:
52 if (is_signed) {
53 signed_val = (short) va_arg(*ap, int);
54 } else {
55 unsigned_val = (unsigned short) va_arg(*ap, unsigned);
56 }
57 break;
58 case FL_LONG:
59 if (is_signed) {
60 signed_val = va_arg(*ap, long);
61 } else {
62 unsigned_val = va_arg(*ap, unsigned long);
63 }
64 break;
65 default:
66 if (is_signed) {
67 signed_val = va_arg(*ap, int);
68 } else {
69 unsigned_val = va_arg(*ap, unsigned int);
70 }
71 break;
72 }
73
74 if (is_signed) {
75 if (signed_val < 0) {
76 *s++ = '-';
77 signed_val = -signed_val;
78 } else if (flags & FL_SIGN) *s++ = '+';
79 else if (flags & FL_SPACE) *s++ = ' ';
80 unsigned_val = signed_val;
81 }
82 if ((flags & FL_ALT) && (c == 'o')) *s++ = '0';
83 if (!unsigned_val) {
84 if (!precision)
85 return s;
86 } else if (((flags & FL_ALT) && (c == 'x' || c == 'X'))
87 || c == 'p') {
88 *s++ = '0';
89 *s++ = (c == 'X' ? 'X' : 'x');
90 }
91
92 switch (c) {
93 case 'b': base = 2; break;
94 case 'o': base = 8; break;
95 case 'd':
96 case 'i':
97 case 'u': base = 10; break;
98 case 'x':
99 case 'X':
100 case 'p': base = 16; break;
101 }
102
103 s = _i_compute(unsigned_val, base, s, precision);
104
105 if (c == 'X')
106 while (old_s != s) {
107 *old_s = toupper(*old_s);
108 old_s++;
109 }
110
111 return s;
112}
113
114int
115_doprnt(register const char *fmt, va_list ap, FILE *stream)
116{
117 register char *s;
118 register int j;
119 int i, c, width, precision, zfill, flags, between_fill;
120 int nrchars=0;
121 const char *oldfmt;
122 char *s1, buf[1025];
123
124 while (c = *fmt++) {
125 if (c != '%') {
126#ifdef CPM
127 if (c == '\n') {
128 if (putc('\r', stream) == EOF)
129 return nrchars ? -nrchars : -1;
130 nrchars++;
131 }
132#endif
133 if (putc(c, stream) == EOF)
134 return nrchars ? -nrchars : -1;
135 nrchars++;
136 continue;
137 }
138 flags = 0;
139 do {
140 switch(*fmt) {
141 case '-': flags |= FL_LJUST; break;
142 case '+': flags |= FL_SIGN; break;
143 case ' ': flags |= FL_SPACE; break;
144 case '#': flags |= FL_ALT; break;
145 case '0': flags |= FL_ZEROFILL; break;
146 default: flags |= FL_NOMORE; continue;
147 }
148 fmt++;
149 } while(!(flags & FL_NOMORE));
150
151 oldfmt = fmt;
152 fmt = gnum(fmt, &width, &ap);
153 if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
154
155 if (*fmt == '.') {
156 fmt++; oldfmt = fmt;
157 fmt = gnum(fmt, &precision, &ap);
158 if (precision >= 0) flags |= FL_PRECSPEC;
159 }
160
161 if ((flags & FL_WIDTHSPEC) && width < 0) {
162 width = -width;
163 flags |= FL_LJUST;
164 }
165 if (!(flags & FL_WIDTHSPEC)) width = 0;
166
167 if (flags & FL_SIGN) flags &= ~FL_SPACE;
168
169 if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
170
171
172 s = s1 = buf;
173
174 switch (*fmt) {
175 case 'h': flags |= FL_SHORT; fmt++; break;
176 case 'l': flags |= FL_LONG; fmt++; break;
177 case 'L': flags |= FL_LONGDOUBLE; fmt++; break;
178 }
179
180 switch (c = *fmt++) {
181 default:
182#ifdef CPM
183 if (c == '\n') {
184 if (putc('\r', stream) == EOF)
185 return nrchars ? -nrchars : -1;
186 nrchars++;
187 }
188#endif
189 if (putc(c, stream) == EOF)
190 return nrchars ? -nrchars : -1;
191 nrchars++;
192 continue;
193 case 'n':
194 if (flags & FL_SHORT)
195 *va_arg(ap, short *) = (short) nrchars;
196 else if (flags & FL_LONG)
197 *va_arg(ap, long *) = (long) nrchars;
198 else
199 *va_arg(ap, int *) = (int) nrchars;
200 continue;
201 case 's':
202 s1 = va_arg(ap, char *);
203 if (s1 == NULL)
204 s1 = "(null)";
205 s = s1;
206 while (precision || !(flags & FL_PRECSPEC)) {
207 if (*s == '\0')
208 break;
209 s++;
210 precision--;
211 }
212 break;
213 case 'p':
214 set_pointer(flags);
215 /* fallthrough */
216 case 'b':
217 case 'o':
218 case 'u':
219 case 'x':
220 case 'X':
221 if (!(flags & FL_PRECSPEC)) precision = 1;
222 else if (c != 'p') flags &= ~FL_ZEROFILL;
223 s = o_print(&ap, flags, s, c, precision, 0);
224 break;
225 case 'd':
226 case 'i':
227 flags |= FL_SIGNEDCONV;
228 if (!(flags & FL_PRECSPEC)) precision = 1;
229 else flags &= ~FL_ZEROFILL;
230 s = o_print(&ap, flags, s, c, precision, 1);
231 break;
232 case 'c':
233 *s++ = va_arg(ap, int);
234 break;
235#ifndef NOFLOAT
236 case 'G':
237 case 'g':
238 if ((flags & FL_PRECSPEC) && (precision == 0))
239 precision = 1;
240 case 'f':
241 case 'E':
242 case 'e':
243 if (!(flags & FL_PRECSPEC))
244 precision = 6;
245
246 if (precision >= sizeof(buf))
247 precision = sizeof(buf) - 1;
248
249 flags |= FL_SIGNEDCONV;
250 s = _f_print(&ap, flags, s, c, precision);
251 break;
252#endif /* NOFLOAT */
253 case 'r':
254 ap = va_arg(ap, va_list);
255 fmt = va_arg(ap, char *);
256 continue;
257 }
258 zfill = ' ';
259 if (flags & FL_ZEROFILL) zfill = '0';
260 j = s - s1;
261
262 /* between_fill is true under the following conditions:
263 * 1- the fill character is '0'
264 * and
265 * 2a- the number is of the form 0x... or 0X...
266 * or
267 * 2b- the number contains a sign or space
268 */
269 between_fill = 0;
270 if ((flags & FL_ZEROFILL)
271 && (((c == 'x' || c == 'X') && (flags & FL_ALT))
272 || (c == 'p')
273 || ((flags & FL_SIGNEDCONV)
274 && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
275 between_fill++;
276
277 if ((i = width - j) > 0)
278 if (!(flags & FL_LJUST)) { /* right justify */
279 nrchars += i;
280 if (between_fill) {
281 if (flags & FL_SIGNEDCONV) {
282 j--; nrchars++;
283 if (putc(*s1++, stream) == EOF)
284 return nrchars ? -nrchars : -1;
285 } else {
286 j -= 2; nrchars += 2;
287 if ((putc(*s1++, stream) == EOF)
288 || (putc(*s1++, stream) == EOF))
289 return nrchars ? -nrchars : -1;
290 }
291 }
292 do {
293 if (putc(zfill, stream) == EOF)
294 return nrchars ? -nrchars : -1;
295 } while (--i);
296 }
297
298 nrchars += j;
299 while (--j >= 0) {
300 if (putc(*s1++, stream) == EOF)
301 return nrchars ? -nrchars : -1;
302 }
303
304 if (i > 0) nrchars += i;
305 while (--i >= 0)
306 if (putc(zfill, stream) == EOF)
307 return nrchars ? -nrchars : -1;
308 }
309 return nrchars;
310}
Note: See TracBrowser for help on using the repository browser.