Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * pANS stdio -- vfprintf
3
 */
4
#include "iolib.h"
5
/*
6
 * Leading flags
7
 */
8
#define	SPACE	1		/* ' ' prepend space if no sign printed */
9
#define	ALT	2		/* '#' use alternate conversion */
10
#define	SIGN	4		/* '+' prepend sign, even if positive */
11
#define	LEFT	8		/* '-' left-justify */
12
#define	ZPAD	16		/* '0' zero-pad */
13
/*
14
 * Trailing flags
15
 */
16
#define	SHORT	32		/* 'h' convert a short integer */
17
#define	LONG	64		/* 'l' convert a long integer */
18
#define	LDBL	128		/* 'L' convert a long double */
19
#define	PTR	256		/*     convert a void * (%p) */
20
 
21
static int lflag[] = {	/* leading flags */
22
0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
23
0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
24
0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
25
0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
26
SPACE,	0,	0,	ALT,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
27
0,	0,	0,	SIGN,	0,	LEFT,	0,	0,	/*  (  )  *  +  ,  -  .  / */
28
ZPAD,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
29
0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
30
0,	0,	0,	0,	0,	0,	0,	0,	/*  @  A  B  C  D  E  F  G */
31
0,	0,	0,	0,	0,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
32
0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
33
0,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
34
0,	0,	0,	0,	0,	0,	0,	0,	/*  `  a  b  c  d  e  f  g */
35
0,	0,	0,	0,	0,	0,	0,	0,	/*  h  i  j  k  l  m  n  o */
36
0,	0,	0,	0,	0,	0,	0,	0,	/*  p  q  r  s  t  u  v  w */
37
0,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
38
 
39
0,	0,	0,	0,	0,	0,	0,	0,
40
0,	0,	0,	0,	0,	0,	0,	0,
41
0,	0,	0,	0,	0,	0,	0,	0,
42
0,	0,	0,	0,	0,	0,	0,	0,
43
0,	0,	0,	0,	0,	0,	0,	0,
44
0,	0,	0,	0,	0,	0,	0,	0,
45
0,	0,	0,	0,	0,	0,	0,	0,
46
0,	0,	0,	0,	0,	0,	0,	0,
47
0,	0,	0,	0,	0,	0,	0,	0,
48
0,	0,	0,	0,	0,	0,	0,	0,
49
0,	0,	0,	0,	0,	0,	0,	0,
50
0,	0,	0,	0,	0,	0,	0,	0,
51
0,	0,	0,	0,	0,	0,	0,	0,
52
0,	0,	0,	0,	0,	0,	0,	0,
53
0,	0,	0,	0,	0,	0,	0,	0,
54
0,	0,	0,	0,	0,	0,	0,	0,
55
};
56
 
57
static int tflag[] = {	/* trailing flags */
58
0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
59
0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
60
0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
61
0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
62
0,	0,	0,	0,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
63
0,	0,	0,	0,	0,	0,	0,	0,	/*  (  )  *  +  ,  -  .  / */
64
0,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
65
0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
66
0,	0,	0,	0,	0,	0,	0,	0,	/*  @  A  B  C  D  E  F  G */
67
0,	0,	0,	0,	LDBL,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
68
0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
69
0,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
70
0,	0,	0,	0,	0,	0,	0,	0,	/*  `  a  b  c  d  e  f  g */
71
SHORT,	0,	0,	0,	LONG,	0,	0,	0,	/*  h  i  j  k  l  m  n  o */
72
0,	0,	0,	0,	0,	0,	0,	0,	/*  p  q  r  s  t  u  v  w */
73
0,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
74
 
75
0,	0,	0,	0,	0,	0,	0,	0,
76
0,	0,	0,	0,	0,	0,	0,	0,
77
0,	0,	0,	0,	0,	0,	0,	0,
78
0,	0,	0,	0,	0,	0,	0,	0,
79
0,	0,	0,	0,	0,	0,	0,	0,
80
0,	0,	0,	0,	0,	0,	0,	0,
81
0,	0,	0,	0,	0,	0,	0,	0,
82
0,	0,	0,	0,	0,	0,	0,	0,
83
0,	0,	0,	0,	0,	0,	0,	0,
84
0,	0,	0,	0,	0,	0,	0,	0,
85
0,	0,	0,	0,	0,	0,	0,	0,
86
0,	0,	0,	0,	0,	0,	0,	0,
87
0,	0,	0,	0,	0,	0,	0,	0,
88
0,	0,	0,	0,	0,	0,	0,	0,
89
0,	0,	0,	0,	0,	0,	0,	0,
90
0,	0,	0,	0,	0,	0,	0,	0,
91
};
92
 
93
static int ocvt_E(FILE *, va_list *, int, int, int);
94
static int ocvt_G(FILE *, va_list *, int, int, int);
95
static int ocvt_X(FILE *, va_list *, int, int, int);
96
static int ocvt_c(FILE *, va_list *, int, int, int);
97
static int ocvt_d(FILE *, va_list *, int, int, int);
98
static int ocvt_e(FILE *, va_list *, int, int, int);
99
static int ocvt_f(FILE *, va_list *, int, int, int);
100
static int ocvt_g(FILE *, va_list *, int, int, int);
101
static int ocvt_n(FILE *, va_list *, int, int, int);
102
static int ocvt_o(FILE *, va_list *, int, int, int);
103
static int ocvt_p(FILE *, va_list *, int, int, int);
104
static int ocvt_s(FILE *, va_list *, int, int, int);
105
static int ocvt_u(FILE *, va_list *, int, int, int);
106
static int ocvt_x(FILE *, va_list *, int, int, int);
107
 
108
static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
109
0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
110
0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
111
0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
112
0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
113
0,	0,	0,	0,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
114
0,	0,	0,	0,	0,	0,	0,	0,	/*  (  )  *  +  ,  -  .  / */
115
0,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
116
0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
117
0,	0,	0,	0,	0,	ocvt_E,	0,	ocvt_G,	/*  @  A  B  C  D  E  F  G */
118
0,	0,	0,	0,	0,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
119
0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
120
ocvt_X,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
121
0,	0,	0,	ocvt_c,	ocvt_d,	ocvt_e,	ocvt_f,	ocvt_g,	/*  `  a  b  c  d  e  f  g */
122
0,	ocvt_d,	0,	0,	0,	0,	ocvt_n,	ocvt_o,	/*  h  i  j  k  l  m  n  o */
123
ocvt_p,	0,	0,	ocvt_s,	0,	ocvt_u,	0,	0,	/*  p  q  r  s  t  u  v  w */
124
ocvt_x,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
125
 
126
0,	0,	0,	0,	0,	0,	0,	0,
127
0,	0,	0,	0,	0,	0,	0,	0,
128
0,	0,	0,	0,	0,	0,	0,	0,
129
0,	0,	0,	0,	0,	0,	0,	0,
130
0,	0,	0,	0,	0,	0,	0,	0,
131
0,	0,	0,	0,	0,	0,	0,	0,
132
0,	0,	0,	0,	0,	0,	0,	0,
133
0,	0,	0,	0,	0,	0,	0,	0,
134
0,	0,	0,	0,	0,	0,	0,	0,
135
0,	0,	0,	0,	0,	0,	0,	0,
136
0,	0,	0,	0,	0,	0,	0,	0,
137
0,	0,	0,	0,	0,	0,	0,	0,
138
0,	0,	0,	0,	0,	0,	0,	0,
139
0,	0,	0,	0,	0,	0,	0,	0,
140
0,	0,	0,	0,	0,	0,	0,	0,
141
0,	0,	0,	0,	0,	0,	0,	0,
142
};
143
 
144
static int nprint;
145
 
146
QLock _stdiolk;
147
 
148
int
149
vfprintf(FILE *f, const char *s, va_list args)
150
{
151
	int flags, width, precision;
152
 
153
	qlock(&_stdiolk);
154
 
155
	nprint = 0;
156
	while(*s){
157
		if(*s != '%'){
158
			putc(*s++, f);
159
			nprint++;
160
			continue;
161
		}
162
		s++;
163
		flags = 0;
164
		while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
165
		if(*s == '*'){
166
			width = va_arg(args, int);
167
			s++;
168
			if(width<0){
169
				flags |= LEFT;
170
				width = -width;
171
			}
172
		}
173
		else{
174
			width = 0;
175
			while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
176
		}
177
		if(*s == '.'){
178
			s++;
179
			if(*s == '*'){
180
				precision = va_arg(args, int);
181
				s++;
182
			}
183
			else{
184
				precision = 0;
185
				while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
186
			}
187
		}
188
		else
189
			precision = -1;
190
		while(tflag[*s&_IO_CHMASK]) flags |= tflag[*s++&_IO_CHMASK];
191
		if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
192
		else if(*s){
193
			putc(*s++, f);
194
			nprint++;
195
		}
196
	}
197
 
198
	qunlock(&_stdiolk);
199
 
200
	if(ferror(f)){
201
		if((f->flags&STRING) && f->wp==f->rp && f->wp>f->buf){
202
			*(f->wp-1) = '\0';
203
			return nprint;
204
		}
205
		return -1;
206
	}
207
	return nprint;
208
}
209
 
210
static int
211
ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
212
{
213
#pragma ref precision
214
	int i;
215
 
216
	if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
217
	putc((unsigned char)va_arg(*args, int), f);
218
	if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
219
	return width<1 ? 1 : width;
220
}
221
 
222
static int
223
ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
224
{
225
	int i, n = 0;
226
	char *s;
227
 
228
	s = va_arg(*args, char *);
229
	if(!(flags&LEFT)){
230
		if(precision >= 0)
231
			for(i=0; i!=precision && s[i]; i++);
232
		else
233
			for(i=0; s[i]; i++);
234
		for(; i<width; i++){
235
			putc(' ', f);
236
			n++;
237
		}
238
	}
239
	if(precision >= 0){
240
		for(i=0; i!=precision && *s; i++){
241
			putc(*s++, f);
242
			n++;
243
		}
244
	} else{
245
		for(i=0;*s;i++){
246
			putc(*s++, f);
247
			n++;
248
		}
249
	}
250
	if(flags&LEFT){
251
		for(; i<width; i++){
252
			putc(' ', f);
253
			n++;
254
		}
255
	}
256
	return n;
257
}
258
 
259
static int
260
ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
261
{
262
#pragma ref f
263
#pragma ref width
264
#pragma ref precision
265
	if(flags&SHORT)
266
		*va_arg(*args, short *) = nprint;
267
	else if(flags&LONG)
268
		*va_arg(*args, long *) = nprint;
269
	else
270
		*va_arg(*args, int *) = nprint;
271
	return 0;
272
}
273
 
274
/*
275
 * Generic fixed-point conversion
276
 *	f is the output FILE *;
277
 *	args is the va_list * from which to get the number;
278
 *	flags, width and precision are the results of printf-cracking;
279
 *	radix is the number base to print in;
280
 *	alphabet is the set of digits to use;
281
 *	prefix is the prefix to print before non-zero numbers when
282
 *	using ``alternate form.''
283
 */
284
static int
285
ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
286
	int radix, int sgned, char alphabet[], char *prefix)
287
{
288
	char digits[128];	/* no reasonable machine will ever overflow this */
289
	char *sign;
290
	char *dp;
291
	long snum;
292
	unsigned long num;
293
	int nout, npad, nlzero;
294
 
295
	if(sgned){
296
		if(flags&PTR) snum = (long)va_arg(*args, void *);
297
		else if(flags&SHORT) snum = va_arg(*args, short);
298
		else if(flags&LONG) snum = va_arg(*args, long);
299
		else snum = va_arg(*args, int);
300
		if(snum < 0){
301
			sign = "-";
302
			num = -snum;
303
		} else{
304
			if(flags&SIGN) sign = "+";
305
			else if(flags&SPACE) sign = " ";
306
			else sign = "";
307
			num = snum;
308
		}
309
	} else {
310
		sign = "";
311
		if(flags&PTR) num = (long)va_arg(*args, void *);
312
		else if(flags&SHORT) num = va_arg(*args, unsigned short);
313
		else if(flags&LONG) num = va_arg(*args, unsigned long);
314
		else num = va_arg(*args, unsigned int);
315
	}
316
	if(num == 0) prefix = "";
317
	dp = digits;
318
	do{
319
		*dp++ = alphabet[num%radix];
320
		num /= radix;
321
	}while(num);
322
	if(precision==0 && dp-digits==1 && dp[-1]=='0')
323
		dp--;
324
	nlzero = precision-(dp-digits);
325
	if(nlzero < 0) nlzero = 0;
326
	if(flags&ALT){
327
		if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
328
	}
329
	else prefix = "";
330
	nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
331
	npad = width-nout;
332
	if(npad < 0) npad = 0;
333
	nout += npad;
334
	if(!(flags&LEFT)){
335
		if(flags&ZPAD && precision <= 0){
336
			fputs(sign, f);
337
			fputs(prefix, f);
338
			while(npad){
339
				putc('0', f);
340
				--npad;
341
			}
342
		} else{
343
			while(npad){
344
				putc(' ', f);
345
				--npad;
346
			}
347
			fputs(sign, f);
348
			fputs(prefix, f);
349
		}
350
		while(nlzero){
351
			putc('0', f);
352
			--nlzero;
353
		}
354
		while(dp!=digits) putc(*--dp, f);
355
	}
356
	else{
357
		fputs(sign, f);
358
		fputs(prefix, f);
359
		while(nlzero){
360
			putc('0', f);
361
			--nlzero;
362
		}
363
		while(dp != digits) putc(*--dp, f);
364
		while(npad){
365
			putc(' ', f);
366
			--npad;
367
		}
368
	}
369
	return nout;	
370
}
371
 
372
static int
373
ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
374
{
375
	return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
376
}
377
 
378
static int
379
ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
380
{
381
	return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
382
}
383
 
384
static int
385
ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
386
{
387
	return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
388
}
389
 
390
static int
391
ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
392
{
393
	return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
394
		"0123456789ABCDEF", "0X");
395
}
396
 
397
static int
398
ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
399
{
400
	return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
401
}
402
 
403
static int
404
ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
405
{
406
	return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
407
}
408
 
409
static int ocvt_flt(FILE *, va_list *, int, int, int, char);
410
 
411
static int
412
ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
413
{
414
	return ocvt_flt(f, args, flags, width, precision, 'E');
415
}
416
 
417
static int
418
ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
419
{
420
	return ocvt_flt(f, args, flags, width, precision, 'G');
421
}
422
 
423
static int
424
ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
425
{
426
	return ocvt_flt(f, args, flags, width, precision, 'e');
427
}
428
 
429
static int
430
ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
431
{
432
	return ocvt_flt(f, args, flags, width, precision, 'f');
433
}
434
 
435
static int
436
ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
437
{
438
	return ocvt_flt(f, args, flags, width, precision, 'g');
439
}
440
 
441
static int
442
ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
443
{
444
	int echr;
445
	char *digits, *edigits;
446
	int exponent;
447
	char fmt;
448
	int sign;
449
	int ndig;
450
	int nout, i;
451
	char ebuf[20];	/* no sensible machine will overflow this */
452
	char *eptr;
453
	double d;
454
 
455
	echr = 'e';
456
	fmt = afmt;
457
	d = va_arg(*args, double);
458
	if(precision < 0) precision = 6;
459
	switch(fmt){
460
	case 'f':
461
		digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
462
		break;
463
	case 'E':
464
		echr = 'E';
465
		fmt = 'e';
466
		/* fall through */
467
	case 'e':
468
		digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
469
		break;
470
	case 'G':
471
		echr = 'E';
472
		/* fall through */
473
	case 'g':
474
		if (precision > 0)
475
			digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
476
		else {
477
			digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
478
			precision = edigits - digits;
479
			if (exponent > precision && exponent <= precision + 4)
480
				precision = exponent;
481
			}
482
		if(exponent >= -3 && exponent <= precision){
483
			fmt = 'f';
484
			precision -= exponent;
485
		}else{
486
			fmt = 'e';
487
			--precision;
488
		}
489
		break;
490
	}
491
	if (exponent == 9999) {
492
		/* Infinity or Nan */
493
		precision = 0;
494
		exponent = edigits - digits;
495
		fmt = 'f';
496
	}
497
	ndig = edigits-digits;
498
	if((afmt=='g' || afmt=='G') && !(flags&ALT)){	/* knock off trailing zeros */
499
		if(fmt == 'f'){
500
			if(precision+exponent > ndig) {
501
				precision = ndig - exponent;
502
				if(precision < 0)
503
					precision = 0;
504
			}
505
		}
506
		else{
507
			if(precision > ndig-1) precision = ndig-1;
508
		}
509
	}
510
	nout = precision;				/* digits after decimal point */
511
	if(precision!=0 || flags&ALT) nout++;		/* decimal point */
512
	if(fmt=='f' && exponent>0) nout += exponent;	/* digits before decimal point */
513
	else nout++;					/* there's always at least one */
514
	if(sign || flags&(SPACE|SIGN)) nout++;		/* sign */
515
	if(fmt != 'f'){					/* exponent */
516
		eptr = ebuf;
517
		for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
518
			*eptr++ = '0' + i%10;
519
		while(eptr<ebuf+2) *eptr++ = '0';
520
		nout += eptr-ebuf+2;			/* e+99 */
521
	}
522
	if(!(flags&ZPAD) && !(flags&LEFT))
523
		while(nout < width){
524
			putc(' ', f);
525
			nout++;
526
		}
527
	if(sign) putc('-', f);
528
	else if(flags&SIGN) putc('+', f);
529
	else if(flags&SPACE) putc(' ', f);
530
	if(flags&ZPAD)
531
		while(nout < width){
532
			putc('0', f);
533
			nout++;
534
		}
535
	if(fmt == 'f'){
536
		for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
537
		if(i == 0) putc('0', f);
538
		if(precision>0 || flags&ALT) putc('.', f);
539
		for(i=0; i!=precision; i++)
540
			putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
541
	}
542
	else{
543
		putc(digits[0], f);
544
		if(precision>0 || flags&ALT) putc('.', f);
545
		for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
546
	}
547
	if(fmt != 'f'){
548
		putc(echr, f);
549
		putc(exponent<=0?'-':'+', f);
550
		while(eptr>ebuf) putc(*--eptr, f);
551
	}
552
	while(nout < width){
553
		putc(' ', f);
554
		nout++;
555
	}
556
	freedtoa(digits);
557
	return nout;
558
}