Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | 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
#ifdef	CPM
132
			if (c == '\n') {
133
				if (putc('\r', stream) == EOF)
134
					return nrchars ? -nrchars : -1;
135
				nrchars++;
136
			}
137
#endif
138
			if (putc(c, stream) == EOF)
139
				return nrchars ? -nrchars : -1;
140
			nrchars++;
141
			continue;
142
		}
143
		flags = 0;
144
		do {
145
			switch(*fmt) {
146
			case '-':	flags |= FL_LJUST;	break;
147
			case '+':	flags |= FL_SIGN;	break;
148
			case ' ':	flags |= FL_SPACE;	break;
149
			case '#':	flags |= FL_ALT;	break;
150
			case '0':	flags |= FL_ZEROFILL;	break;
151
			default:	flags |= FL_NOMORE;	continue;
152
			}
153
			fmt++;
154
		} while(!(flags & FL_NOMORE));
155
 
156
		oldfmt = fmt;
157
		fmt = gnum(fmt, &width, &ap);
158
		if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
159
 
160
		if (*fmt == '.') {
161
			fmt++; oldfmt = fmt;
162
			fmt = gnum(fmt, &precision, &ap);
163
			if (precision >= 0) flags |= FL_PRECSPEC;
164
		}
165
 
166
		if ((flags & FL_WIDTHSPEC) && width < 0) {
167
			width = -width;
168
			flags |= FL_LJUST;
169
		}
170
		if (!(flags & FL_WIDTHSPEC)) width = 0;
171
 
172
		if (flags & FL_SIGN) flags &= ~FL_SPACE;
173
 
174
		if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
175
 
176
 
177
		s = s1 = buf;
178
 
179
		switch (*fmt) {
180
		case 'h':	flags |= FL_SHORT; fmt++; break;
181
		case 'l':	flags |= FL_LONG; fmt++; break;
182
		case 'L':	flags |= FL_LONGDOUBLE; fmt++; break;
183
		}
184
 
185
		switch (c = *fmt++) {
186
		default:
187
#ifdef	CPM
188
			if (c == '\n') {
189
				if (putc('\r', stream) == EOF)
190
					return nrchars ? -nrchars : -1;
191
				nrchars++;
192
			}
193
#endif
194
			if (putc(c, stream) == EOF)
195
				return nrchars ? -nrchars : -1;
196
			nrchars++;
197
			continue;
198
		case 'n':
199
			if (flags & FL_SHORT)
200
				*va_arg(ap, short *) = (short) nrchars;
201
			else if (flags & FL_LONG)
202
				*va_arg(ap, long *) = (long) nrchars;
203
			else
204
				*va_arg(ap, int *) = (int) nrchars;
205
			continue;
206
		case 's':
207
			s1 = va_arg(ap, char *);
208
			if (s1 == NULL)
209
				s1 = "(null)";
210
			s = s1;
211
			while (precision || !(flags & FL_PRECSPEC)) {
212
				if (*s == '\0')
213
					break;
214
				s++;
215
				precision--;
216
			}
217
			break;
218
		case 'p':
219
			set_pointer(flags);
220
			/* fallthrough */
221
		case 'b':
222
		case 'o':
223
		case 'u':
224
		case 'x':
225
		case 'X':
226
			if (!(flags & FL_PRECSPEC)) precision = 1;
227
			else if (c != 'p') flags &= ~FL_ZEROFILL;
228
			s = o_print(&ap, flags, s, c, precision, 0);
229
			break;
230
		case 'd':
231
		case 'i':
232
			flags |= FL_SIGNEDCONV;
233
			if (!(flags & FL_PRECSPEC)) precision = 1;
234
			else flags &= ~FL_ZEROFILL;
235
			s = o_print(&ap, flags, s, c, precision, 1);
236
			break;
237
		case 'c':
238
			*s++ = va_arg(ap, int);
239
			break;
240
#ifndef NOFLOAT
241
		case 'G':
242
		case 'g':
243
			if ((flags & FL_PRECSPEC) && (precision == 0))
244
				precision = 1;
245
		case 'f':
246
		case 'E':
247
		case 'e':
248
			if (!(flags & FL_PRECSPEC))
249
				precision = 6;
250
 
251
			if (precision >= sizeof(buf))
252
				precision = sizeof(buf) - 1;
253
 
254
			flags |= FL_SIGNEDCONV;
255
			s = _f_print(&ap, flags, s, c, precision);
256
			break;
257
#endif	/* NOFLOAT */
258
		case 'r':
259
			ap = va_arg(ap, va_list);
260
			fmt = va_arg(ap, char *);
261
			continue;
262
		}
263
		zfill = ' ';
264
		if (flags & FL_ZEROFILL) zfill = '0';
265
		j = s - s1;
266
 
267
		/* between_fill is true under the following conditions:
268
		 * 1- the fill character is '0'
269
		 * and
270
		 * 2a- the number is of the form 0x... or 0X...
271
		 * or
272
		 * 2b- the number contains a sign or space
273
		 */
274
		between_fill = 0;
275
		if ((flags & FL_ZEROFILL)
276
		    && (((c == 'x' || c == 'X') && (flags & FL_ALT) && j > 1)
277
			|| (c == 'p')
278
			|| ((flags & FL_SIGNEDCONV)
279
			    && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
280
			between_fill++;
281
 
282
		if ((i = width - j) > 0)
283
			if (!(flags & FL_LJUST)) {	/* right justify */
284
				nrchars += i;
285
				if (between_fill) {
286
				    if (flags & FL_SIGNEDCONV) {
287
					j--; nrchars++;
288
					if (putc(*s1++, stream) == EOF)
289
						return nrchars ? -nrchars : -1;
290
				    } else {
291
					j -= 2; nrchars += 2;
292
					if ((putc(*s1++, stream) == EOF)
293
					    || (putc(*s1++, stream) == EOF))
294
						return nrchars ? -nrchars : -1;
295
				    }
296
				}
297
				do {
298
					if (putc(zfill, stream) == EOF)
299
						return nrchars ? -nrchars : -1;
300
				} while (--i);
301
			}
302
 
303
		nrchars += j;
304
		while (--j >= 0) {
305
			if (putc(*s1++, stream) == EOF)
306
				return nrchars ? -nrchars : -1;
307
		}
308
 
309
		if (i > 0) nrchars += i;
310
		while (--i >= 0)
311
			if (putc(zfill, stream) == EOF)
312
				return nrchars ? -nrchars : -1;
313
	}
314
	return nrchars;
315
}