Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include	<u.h>
2
#include	<libc.h>
3
 
4
enum
5
{
6
	SIZE	= 1024,
7
	IDIGIT	= 40,
8
	MAXCONV	= 40,
9
	FDIGIT	= 30,
10
	FDEFLT	= 6,
11
	NONE	= -1000,
12
	MAXFMT	= 512,
13
 
14
	FPLUS	= 1<<0,
15
	FMINUS	= 1<<1,
16
	FSHARP	= 1<<2,
17
	FLONG	= 1<<3,
18
	FSHORT	= 1<<4,
19
	FUNSIGN	= 1<<5,
20
	FVLONG	= 1<<6,
21
};
22
 
23
int	printcol;
24
 
25
static	int	convcount;
26
static	char	fmtindex[MAXFMT];
27
 
28
static	int	noconv(va_list*, Fconv*);
29
static	int	flags(va_list*, Fconv*);
30
 
31
static	int	cconv(va_list*, Fconv*);
32
static	int	rconv(va_list*, Fconv*);
33
static	int	sconv(va_list*, Fconv*);
34
static	int	percent(va_list*, Fconv*);
35
static	int	column(va_list*, Fconv*);
36
 
37
int	numbconv(va_list*, Fconv*);
38
 
39
static
40
int	(*fmtconv[MAXCONV])(va_list*, Fconv*) =
41
{
42
	noconv
43
};
44
 
45
static
46
void
47
initfmt(void)
48
{
49
	int cc;
50
 
51
	cc = 0;
52
	fmtconv[cc] = noconv;
53
	cc++;
54
 
55
	fmtconv[cc] = flags;
56
	fmtindex['+'] = cc;
57
	fmtindex['-'] = cc;
58
	fmtindex['#'] = cc;
59
	fmtindex['h'] = cc;
60
	fmtindex['l'] = cc;
61
	fmtindex['u'] = cc;
62
	cc++;
63
 
64
	fmtconv[cc] = numbconv;
65
	fmtindex['d'] = cc;
66
	fmtindex['o'] = cc;
67
	fmtindex['x'] = cc;
68
	fmtindex['X'] = cc;
69
	cc++;
70
 
71
	fmtconv[cc] = cconv;
72
	fmtindex['c'] = cc;
73
	fmtindex['C'] = cc;
74
	cc++;
75
 
76
	fmtconv[cc] = rconv;
77
	fmtindex['r'] = cc;
78
	cc++;
79
 
80
	fmtconv[cc] = sconv;
81
	fmtindex['s'] = cc;
82
	fmtindex['S'] = cc;
83
	cc++;
84
 
85
	fmtconv[cc] = percent;
86
	fmtindex['%'] = cc;
87
	cc++;
88
 
89
	fmtconv[cc] = column;
90
	fmtindex['|'] = cc;
91
	cc++;
92
 
93
	convcount = cc;
94
}
95
 
96
int
97
fmtinstall(int c, int (*f)(va_list*, Fconv*))
98
{
99
 
100
	if(convcount == 0)
101
		initfmt();
102
	if(c < 0 || c >= MAXFMT)
103
		return -1;
104
	if(convcount >= MAXCONV)
105
		return -1;
106
	fmtconv[convcount] = f;
107
	fmtindex[c] = convcount;
108
	convcount++;
109
	return 0;
110
}
111
 
112
char*
113
doprint(char *s, char *es, char *fmt, va_list argp)
114
{
115
	int n, c;
116
	Rune rune;
117
	Fconv local;
118
 
119
	if(s >= es)
120
		return s;
121
	local.out = s;
122
	local.eout = es-UTFmax-1;
123
 
124
loop:
125
	c = *fmt & 0xff;
126
	if(c >= Runeself) {
127
		n = chartorune(&rune, fmt);
128
		fmt += n;
129
		c = rune;
130
	} else
131
		fmt++;
132
	switch(c) {
133
	case 0:
134
		*local.out = 0;
135
		return local.out;
136
 
137
	default:
138
		printcol++;
139
		goto common;
140
 
141
	case '\n':
142
		printcol = 0;
143
		goto common;
144
 
145
	case '\t':
146
		printcol = (printcol+8) & ~7;
147
		goto common;
148
 
149
	common:
150
		if(local.out < local.eout)
151
			if(c >= Runeself) {
152
				rune = c;
153
				n = runetochar(local.out, &rune);
154
				local.out += n;
155
			} else
156
				*local.out++ = c;
157
		goto loop;
158
 
159
	case '%':
160
		break;
161
	}
162
	local.f1 = NONE;
163
	local.f2 = NONE;
164
	local.f3 = 0;
165
 
166
	/*
167
	 * read one of the following
168
	 *	1. number, => f1, f2 in order.
169
	 *	2. '*' same as number (from args)
170
	 *	3. '.' ignored (separates numbers)
171
	 *	4. flag => f3
172
	 *	5. verb and terminate
173
	 */
174
l0:
175
	c = *fmt & 0xff;
176
	if(c >= Runeself) {
177
		n = chartorune(&rune, fmt);
178
		fmt += n;
179
		c = rune;
180
	} else
181
		fmt++;
182
 
183
l1:
184
	if(c == 0) {
185
		fmt--;
186
		goto loop;
187
	}
188
	if(c == '.') {
189
		if(local.f1 == NONE)
190
			local.f1 = 0;
191
		local.f2 = 0;
192
		goto l0;
193
	}
194
	if((c >= '1' && c <= '9') ||
195
	   (c == '0' && local.f1 != NONE)) {	/* '0' is a digit for f2 */
196
		n = 0;
197
		while(c >= '0' && c <= '9') {
198
			n = n*10 + c-'0';
199
			c = *fmt++;
200
		}
201
		if(local.f1 == NONE)
202
			local.f1 = n;
203
		else
204
			local.f2 = n;
205
		goto l1;
206
	}
207
	if(c == '*') {
208
		n = va_arg(argp, int);
209
		if(local.f1 == NONE)
210
			local.f1 = n;
211
		else
212
			local.f2 = n;
213
		goto l0;
214
	}
215
	n = 0;
216
	if(c >= 0 && c < MAXFMT)
217
		n = fmtindex[c];
218
	local.chr = c;
219
	n = (*fmtconv[n])(&argp, &local);
220
	if(n < 0) {
221
		local.f3 |= -n;
222
		goto l0;
223
	}
224
	goto loop;
225
}
226
 
227
int
228
numbconv(va_list *arg, Fconv *fp)
229
{
230
	char s[IDIGIT];
231
	int i, f, n, b, ucase;
232
	short h;
233
	long v;
234
	vlong vl;
235
 
236
	SET(v);
237
	SET(vl);
238
 
239
	ucase = 0;
240
	b = fp->chr;
241
	switch(fp->chr) {
242
	case 'u':
243
		fp->f3 |= FUNSIGN;
244
	case 'd':
245
		b = 10;
246
		break;
247
 
248
	case 'o':
249
		b = 8;
250
		break;
251
 
252
	case 'X':
253
		ucase = 1;
254
	case 'x':
255
		b = 16;
256
		break;
257
	}
258
 
259
	f = 0;
260
	switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
261
	case FVLONG|FLONG:
262
		vl = va_arg(*arg, vlong);
263
		break;
264
 
265
	case FUNSIGN|FVLONG|FLONG:
266
		vl = va_arg(*arg, uvlong);
267
		break;
268
 
269
	case FLONG:
270
		v = va_arg(*arg, long);
271
		break;
272
 
273
	case FUNSIGN|FLONG:
274
		v = va_arg(*arg, ulong);
275
		break;
276
 
277
	case FSHORT:
278
		h = va_arg(*arg, int);
279
		v = h;
280
		break;
281
 
282
	case FUNSIGN|FSHORT:
283
		h = va_arg(*arg, int);
284
		v = (ushort)h;
285
		break;
286
 
287
	default:
288
		v = va_arg(*arg, int);
289
		break;
290
 
291
	case FUNSIGN:
292
		v = va_arg(*arg, unsigned);
293
		break;
294
	}
295
	if(fp->f3 & FVLONG) {
296
		if(!(fp->f3 & FUNSIGN) && vl < 0) {
297
			vl = -vl;
298
			f = 1;
299
		}
300
	} else {
301
		if(!(fp->f3 & FUNSIGN) && v < 0) {
302
			v = -v;
303
			f = 1;
304
		}
305
	}
306
	s[IDIGIT-1] = 0;
307
	for(i = IDIGIT-2;; i--) {
308
		if(fp->f3 & FVLONG)
309
			n = (uvlong)vl % b;
310
		else
311
			n = (ulong)v % b;
312
		n += '0';
313
		if(n > '9') {
314
			n += 'a' - ('9'+1);
315
			if(ucase)
316
				n += 'A'-'a';
317
		}
318
		s[i] = n;
319
		if(i < 2)
320
			break;
321
		if(fp->f3 & FVLONG)
322
			vl = (uvlong)vl / b;
323
		else
324
			v = (ulong)v / b;
325
		if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
326
			continue;
327
		if(fp->f3 & FVLONG) {
328
			if(vl <= 0)
329
				break;
330
			continue;
331
		}
332
		if(v <= 0)
333
			break;
334
	}
335
 
336
	if(fp->f3 & FSHARP) {
337
		if(b == 8 && s[i] != '0')
338
			s[--i] = '0';
339
		if(b == 16) {
340
			if(ucase)
341
				s[--i] = 'X';
342
			else
343
				s[--i] = 'x';
344
			s[--i] = '0';
345
		}
346
	}
347
	if(f)
348
		s[--i] = '-';
349
	fp->f2 = NONE;
350
	strconv(s+i, fp);
351
	return 0;
352
}
353
 
354
void
355
Strconv(Rune *s, Fconv *fp)
356
{
357
	int n, c, i;
358
	Rune rune;
359
 
360
	if(fp->f3 & FMINUS)
361
		fp->f1 = -fp->f1;
362
	n = 0;
363
	if(fp->f1 != NONE && fp->f1 >= 0) {
364
		for(; s[n]; n++)
365
			;
366
		while(n < fp->f1) {
367
			if(fp->out < fp->eout)
368
				*fp->out++ = ' ';
369
			printcol++;
370
			n++;
371
		}
372
	}
373
	for(;;) {
374
		c = *s++;
375
		if(c == 0)
376
			break;
377
		n++;
378
		if(fp->f2 == NONE || fp->f2 > 0) {
379
			if(fp->out < fp->eout)
380
				if(c >= Runeself) {
381
					rune = c;
382
					i = runetochar(fp->out, &rune);
383
					fp->out += i;
384
				} else
385
					*fp->out++ = c;
386
			if(fp->f2 != NONE)
387
				fp->f2--;
388
			switch(c) {
389
			default:
390
				printcol++;
391
				break;
392
			case '\n':
393
				printcol = 0;
394
				break;
395
			case '\t':
396
				printcol = (printcol+8) & ~7;
397
				break;
398
			}
399
		}
400
	}
401
	if(fp->f1 != NONE && fp->f1 < 0) {
402
		fp->f1 = -fp->f1;
403
		while(n < fp->f1) {
404
			if(fp->out < fp->eout)
405
				*fp->out++ = ' ';
406
			printcol++;
407
			n++;
408
		}
409
	}
410
}
411
 
412
void
413
strconv(char *s, Fconv *fp)
414
{
415
	int n, c, i;
416
	Rune rune;
417
 
418
	if(fp->f3 & FMINUS)
419
		fp->f1 = -fp->f1;
420
	n = 0;
421
	if(fp->f1 != NONE && fp->f1 >= 0) {
422
		n = utflen(s);
423
		while(n < fp->f1) {
424
			if(fp->out < fp->eout)
425
				*fp->out++ = ' ';
426
			printcol++;
427
			n++;
428
		}
429
	}
430
	for(;;) {
431
		c = *s & 0xff;
432
		if(c >= Runeself) {
433
			i = chartorune(&rune, s);
434
			s += i;
435
			c = rune;
436
		} else
437
			s++;
438
		if(c == 0)
439
			break;
440
		n++;
441
		if(fp->f2 == NONE || fp->f2 > 0) {
442
			if(fp->out < fp->eout)
443
				if(c >= Runeself) {
444
					rune = c;
445
					i = runetochar(fp->out, &rune);
446
					fp->out += i;
447
				} else
448
					*fp->out++ = c;
449
			if(fp->f2 != NONE)
450
				fp->f2--;
451
			switch(c) {
452
			default:
453
				printcol++;
454
				break;
455
			case '\n':
456
				printcol = 0;
457
				break;
458
			case '\t':
459
				printcol = (printcol+8) & ~7;
460
				break;
461
			}
462
		}
463
	}
464
	if(fp->f1 != NONE && fp->f1 < 0) {
465
		fp->f1 = -fp->f1;
466
		while(n < fp->f1) {
467
			if(fp->out < fp->eout)
468
				*fp->out++ = ' ';
469
			printcol++;
470
			n++;
471
		}
472
	}
473
}
474
 
475
static
476
int
477
noconv(va_list *arg, Fconv *fp)
478
{
479
	int n;
480
	char s[10];
481
 
482
	if(convcount == 0) {
483
		initfmt();
484
		n = 0;
485
		if(fp->chr >= 0 && fp->chr < MAXFMT)
486
			n = fmtindex[fp->chr];
487
		return (*fmtconv[n])(arg, fp);
488
	}
489
	s[0] = '*';
490
	s[1] = fp->chr;
491
	s[2] = '*';
492
	s[3] = 0;
493
	fp->f1 = 0;
494
	fp->f2 = NONE;
495
	fp->f3 = 0;
496
	strconv(s, fp);
497
	return 0;
498
}
499
 
500
static
501
int
502
rconv(va_list*, Fconv *fp)
503
{
504
	char s[ERRLEN];
505
 
506
	s[0] = 0;
507
	errstr(s);
508
	fp->f2 = NONE;
509
	strconv(s, fp);
510
	return 0;
511
}
512
 
513
static
514
int
515
cconv(va_list *arg, Fconv *fp)
516
{
517
	char s[10];
518
	Rune rune;
519
 
520
	rune = va_arg(*arg, int);
521
	if(fp->chr == 'c')
522
		rune &= 0xff;
523
	s[runetochar(s, &rune)] = 0;
524
 
525
	fp->f2 = NONE;
526
	strconv(s, fp);
527
	return 0;
528
}
529
 
530
static
531
int
532
sconv(va_list *arg, Fconv *fp)
533
{
534
	char *s;
535
	Rune *r;
536
 
537
	if(fp->chr == 's') {
538
		s = va_arg(*arg, char*);
539
		if(s == 0)
540
			s = "<null>";
541
		strconv(s, fp);
542
	} else {
543
		r = va_arg(*arg, Rune*);
544
		if(r == 0)
545
			r = L"<null>";
546
		Strconv(r, fp);
547
	}
548
	return 0;
549
}
550
 
551
static
552
int
553
percent(va_list*, Fconv *fp)
554
{
555
 
556
	if(fp->out < fp->eout)
557
		*fp->out++ = '%';
558
	printcol++;
559
	return 0;
560
}
561
 
562
static
563
int
564
column(va_list *arg, Fconv *fp)
565
{
566
	int col, pc;
567
 
568
	col = va_arg(*arg, int);
569
	while(fp->out < fp->eout && printcol < col) {
570
		pc = (printcol+8) & ~7;
571
		if(pc <= col) {
572
			*fp->out++ = '\t';
573
			printcol = pc;
574
		} else {
575
			*fp->out++ = ' ';
576
			printcol++;
577
		}
578
	}
579
	return 0;
580
}
581
 
582
static
583
int
584
flags(va_list*, Fconv *fp)
585
{
586
	int f;
587
 
588
	f = 0;
589
	switch(fp->chr) {
590
	case '+':
591
		f = FPLUS;
592
		break;
593
 
594
	case '-':
595
		f = FMINUS;
596
		break;
597
 
598
	case '#':
599
		f = FSHARP;
600
		break;
601
 
602
	case 'h':
603
		f = FSHORT;
604
		break;
605
 
606
	case 'l':
607
		f = FLONG;
608
		if(fp->f3 & FLONG)
609
			f = FVLONG;
610
		break;
611
 
612
	case 'u':
613
		f = FUNSIGN;
614
		break;
615
	}
616
	return -f;
617
}