Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / stdio / doprnt.c
1 /*
2  * doprnt.c - print formatted output
3  */
4 /* $Id: doprnt.c,v 1.11 1994/06/24 11:48:24 ceriel 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. */
13 static const char *
14 gnum(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 */
42 static char *
43 o_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
114 int
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 }