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