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
#include "fmtdef.h"
4
 
5
/* format the output into f->to and return the number of characters fmted  */
6
int
7
dofmt(Fmt *f, char *fmt)
8
{
9
	Rune rune, *rt, *rs;
10
	int r;
11
	char *t, *s;
12
	int n, nfmt;
13
 
14
	nfmt = f->nfmt;
15
	for(;;){
16
		if(f->runes){
17
			rt = f->to;
18
			rs = f->stop;
19
			while((r = *(uchar*)fmt) && r != '%'){
20
				if(r < Runeself)
21
					fmt++;
22
				else{
23
					fmt += chartorune(&rune, fmt);
24
					r = rune;
25
				}
26
				FMTRCHAR(f, rt, rs, r);
27
			}
28
			fmt++;
29
			f->nfmt += rt - (Rune *)f->to;
30
			f->to = rt;
31
			if(!r)
32
				return f->nfmt - nfmt;
33
			f->stop = rs;
34
		}else{
35
			t = f->to;
36
			s = f->stop;
37
			while((r = *(uchar*)fmt) && r != '%'){
38
				if(r < Runeself){
39
					FMTCHAR(f, t, s, r);
40
					fmt++;
41
				}else{
42
					n = chartorune(&rune, fmt);
43
					if(t + n > s){
44
						t = _fmtflush(f, t, n);
45
						if(t != nil)
46
							s = f->stop;
47
						else
48
							return -1;
49
					}
50
					while(n--)
51
						*t++ = *fmt++;
52
				}
53
			}
54
			fmt++;
55
			f->nfmt += t - (char *)f->to;
56
			f->to = t;
57
			if(!r)
58
				return f->nfmt - nfmt;
59
			f->stop = s;
60
		}
61
 
62
		fmt = _fmtdispatch(f, fmt, 0);
63
		if(fmt == nil)
64
			return -1;
65
	}
66
}
67
 
68
void *
69
_fmtflush(Fmt *f, void *t, int len)
70
{
71
	if(f->runes)
72
		f->nfmt += (Rune*)t - (Rune*)f->to;
73
	else
74
		f->nfmt += (char*)t - (char *)f->to;
75
	f->to = t;
76
	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
77
		f->stop = f->to;
78
		return nil;
79
	}
80
	return f->to;
81
}
82
 
83
/*
84
 * put a formatted block of memory sz bytes long of n runes into the output buffer,
85
 * left/right justified in a field of at least f->width charactes
86
 */
87
int
88
_fmtpad(Fmt *f, int n)
89
{
90
	char *t, *s;
91
	int i;
92
 
93
	t = f->to;
94
	s = f->stop;
95
	for(i = 0; i < n; i++)
96
		FMTCHAR(f, t, s, ' ');
97
	f->nfmt += t - (char *)f->to;
98
	f->to = t;
99
	return 0;
100
}
101
 
102
int
103
_rfmtpad(Fmt *f, int n)
104
{
105
	Rune *t, *s;
106
	int i;
107
 
108
	t = f->to;
109
	s = f->stop;
110
	for(i = 0; i < n; i++)
111
		FMTRCHAR(f, t, s, ' ');
112
	f->nfmt += t - (Rune *)f->to;
113
	f->to = t;
114
	return 0;
115
}
116
 
117
int
118
_fmtcpy(Fmt *f, void *vm, int n, int sz)
119
{
120
	Rune *rt, *rs, r;
121
	char *t, *s, *m, *me;
122
	ulong fl;
123
	int nc, w;
124
 
125
	m = vm;
126
	me = m + sz;
127
	w = f->width;
128
	fl = f->flags;
129
	if((fl & FmtPrec) && n > f->prec)
130
		n = f->prec;
131
	if(f->runes){
132
		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
133
			return -1;
134
		rt = f->to;
135
		rs = f->stop;
136
		for(nc = n; nc > 0; nc--){
137
			r = *(uchar*)m;
138
			if(r < Runeself)
139
				m++;
140
			else if((me - m) >= UTFmax || fullrune(m, me-m))
141
				m += chartorune(&r, m);
142
			else
143
				break;
144
			FMTRCHAR(f, rt, rs, r);
145
		}
146
		f->nfmt += rt - (Rune *)f->to;
147
		f->to = rt;
148
		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
149
			return -1;
150
	}else{
151
		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
152
			return -1;
153
		t = f->to;
154
		s = f->stop;
155
		for(nc = n; nc > 0; nc--){
156
			r = *(uchar*)m;
157
			if(r < Runeself)
158
				m++;
159
			else if((me - m) >= UTFmax || fullrune(m, me-m))
160
				m += chartorune(&r, m);
161
			else
162
				break;
163
			FMTRUNE(f, t, s, r);
164
		}
165
		f->nfmt += t - (char *)f->to;
166
		f->to = t;
167
		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
168
			return -1;
169
	}
170
	return 0;
171
}
172
 
173
int
174
_fmtrcpy(Fmt *f, void *vm, int n)
175
{
176
	Rune r, *m, *me, *rt, *rs;
177
	char *t, *s;
178
	ulong fl;
179
	int w;
180
 
181
	m = vm;
182
	w = f->width;
183
	fl = f->flags;
184
	if((fl & FmtPrec) && n > f->prec)
185
		n = f->prec;
186
	if(f->runes){
187
		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
188
			return -1;
189
		rt = f->to;
190
		rs = f->stop;
191
		for(me = m + n; m < me; m++)
192
			FMTRCHAR(f, rt, rs, *m);
193
		f->nfmt += rt - (Rune *)f->to;
194
		f->to = rt;
195
		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
196
			return -1;
197
	}else{
198
		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
199
			return -1;
200
		t = f->to;
201
		s = f->stop;
202
		for(me = m + n; m < me; m++){
203
			r = *m;
204
			FMTRUNE(f, t, s, r);
205
		}
206
		f->nfmt += t - (char *)f->to;
207
		f->to = t;
208
		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
209
			return -1;
210
	}
211
	return 0;
212
}
213
 
214
/* fmt out one character */
215
int
216
_charfmt(Fmt *f)
217
{
218
	char x[1];
219
 
220
	x[0] = va_arg(f->args, int);
221
	f->prec = 1;
222
	return _fmtcpy(f, x, 1, 1);
223
}
224
 
225
/* fmt out one rune */
226
int
227
_runefmt(Fmt *f)
228
{
229
	Rune x[1];
230
 
231
	x[0] = va_arg(f->args, int);
232
	return _fmtrcpy(f, x, 1);
233
}
234
 
235
/* public helper routine: fmt out a null terminated string already in hand */
236
int
237
fmtstrcpy(Fmt *f, char *s)
238
{
239
	int i, j;
240
	Rune r;
241
 
242
	if(!s)
243
		return _fmtcpy(f, "<nil>", 5, 5);
244
	/* if precision is specified, make sure we don't wander off the end */
245
	if(f->flags & FmtPrec){
246
		i = 0;
247
		for(j=0; j<f->prec && s[i]; j++)
248
			i += chartorune(&r, s+i);
249
		return _fmtcpy(f, s, j, i);
250
	}
251
	return _fmtcpy(f, s, utflen(s), strlen(s));
252
}
253
 
254
/* fmt out a null terminated utf string */
255
int
256
_strfmt(Fmt *f)
257
{
258
	char *s;
259
 
260
	s = va_arg(f->args, char *);
261
	return fmtstrcpy(f, s);
262
}
263
 
264
/* public helper routine: fmt out a null terminated rune string already in hand */
265
int
266
fmtrunestrcpy(Fmt *f, Rune *s)
267
{
268
	Rune *e;
269
	int n, p;
270
 
271
	if(!s)
272
		return _fmtcpy(f, "<nil>", 5, 5);
273
	/* if precision is specified, make sure we don't wander off the end */
274
	if(f->flags & FmtPrec){
275
		p = f->prec;
276
		for(n = 0; n < p; n++)
277
			if(s[n] == 0)
278
				break;
279
	}else{
280
		for(e = s; *e; e++)
281
			;
282
		n = e - s;
283
	}
284
	return _fmtrcpy(f, s, n);
285
}
286
 
287
/* fmt out a null terminated rune string */
288
int
289
_runesfmt(Fmt *f)
290
{
291
	Rune *s;
292
 
293
	s = va_arg(f->args, Rune *);
294
	return fmtrunestrcpy(f, s);
295
}
296
 
297
/* fmt a % */
298
int
299
_percentfmt(Fmt *f)
300
{
301
	Rune x[1];
302
 
303
	x[0] = f->r;
304
	f->prec = 1;
305
	return _fmtrcpy(f, x, 1);
306
}
307
 
308
enum {
309
	/* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */
310
	Maxintwidth = 1 + 2 + 64 + 64/3,
311
};
312
 
313
/* fmt an integer */
314
int
315
_ifmt(Fmt *f)
316
{
317
	char buf[Maxintwidth + 1], *p, *conv;
318
	uvlong vu;
319
	ulong u;
320
	uintptr pu;
321
	int neg, base, i, n, fl, w, isv;
322
 
323
	neg = 0;
324
	fl = f->flags;
325
	isv = 0;
326
	vu = 0;
327
	u = 0;
328
	if(f->r == 'p'){
329
		pu = va_arg(f->args, uintptr);
330
		if(sizeof(uintptr) == sizeof(uvlong)){
331
			vu = pu;
332
			isv = 1;
333
		}else
334
			u = pu;
335
		f->r = 'x';
336
		fl |= FmtUnsigned;
337
	}else if(fl & FmtVLong){
338
		isv = 1;
339
		if(fl & FmtUnsigned)
340
			vu = va_arg(f->args, uvlong);
341
		else
342
			vu = va_arg(f->args, vlong);
343
	}else if(fl & FmtLong){
344
		if(fl & FmtUnsigned)
345
			u = va_arg(f->args, ulong);
346
		else
347
			u = va_arg(f->args, long);
348
	}else if(fl & FmtByte){
349
		if(fl & FmtUnsigned)
350
			u = (uchar)va_arg(f->args, int);
351
		else
352
			u = (char)va_arg(f->args, int);
353
	}else if(fl & FmtShort){
354
		if(fl & FmtUnsigned)
355
			u = (ushort)va_arg(f->args, int);
356
		else
357
			u = (short)va_arg(f->args, int);
358
	}else{
359
		if(fl & FmtUnsigned)
360
			u = va_arg(f->args, uint);
361
		else
362
			u = va_arg(f->args, int);
363
	}
364
	conv = "0123456789abcdef";
365
	switch(f->r){
366
	case 'd':
367
		base = 10;
368
		break;
369
	case 'x':
370
		base = 16;
371
		break;
372
	case 'X':
373
		base = 16;
374
		conv = "0123456789ABCDEF";
375
		break;
376
	case 'b':
377
		base = 2;
378
		break;
379
	case 'o':
380
		base = 8;
381
		break;
382
	default:
383
		return -1;
384
	}
385
	if(!(fl & FmtUnsigned)){
386
		if(isv && (vlong)vu < 0){
387
			vu = -(vlong)vu;
388
			neg = 1;
389
		}else if(!isv && (long)u < 0){
390
			u = -(long)u;
391
			neg = 1;
392
		}
393
	}
394
	p = buf + sizeof buf - 1;
395
	n = 0;
396
	if(isv){
397
		while(vu){
398
			i = vu % base;
399
			vu /= base;
400
			if((fl & FmtComma) && n % 4 == 3){
401
				*p-- = ',';
402
				n++;
403
			}
404
			*p-- = conv[i];
405
			n++;
406
		}
407
	}else{
408
		while(u){
409
			i = u % base;
410
			u /= base;
411
			if((fl & FmtComma) && n % 4 == 3){
412
				*p-- = ',';
413
				n++;
414
			}
415
			*p-- = conv[i];
416
			n++;
417
		}
418
	}
419
	if(n == 0){
420
		*p-- = '0';
421
		n = 1;
422
	}
423
	for(w = f->prec; n < w && p > buf+3; n++)
424
		*p-- = '0';
425
	if(neg || (fl & (FmtSign|FmtSpace)))
426
		n++;
427
	if(fl & FmtSharp){
428
		if(base == 16)
429
			n += 2;
430
		else if(base == 8){
431
			if(p[1] == '0')
432
				fl &= ~FmtSharp;
433
			else
434
				n++;
435
		}
436
	}
437
	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
438
		for(w = f->width; n < w && p > buf+3; n++)
439
			*p-- = '0';
440
		f->width = 0;
441
	}
442
	if(fl & FmtSharp){
443
		if(base == 16)
444
			*p-- = f->r;
445
		if(base == 16 || base == 8)
446
			*p-- = '0';
447
	}
448
	if(neg)
449
		*p-- = '-';
450
	else if(fl & FmtSign)
451
		*p-- = '+';
452
	else if(fl & FmtSpace)
453
		*p-- = ' ';
454
	f->flags &= ~FmtPrec;
455
	return _fmtcpy(f, p + 1, n, n);
456
}
457
 
458
int
459
_countfmt(Fmt *f)
460
{
461
	void *p;
462
	ulong fl;
463
 
464
	fl = f->flags;
465
	p = va_arg(f->args, void*);
466
	if(fl & FmtVLong){
467
		*(vlong*)p = f->nfmt;
468
	}else if(fl & FmtLong){
469
		*(long*)p = f->nfmt;
470
	}else if(fl & FmtByte){
471
		*(char*)p = f->nfmt;
472
	}else if(fl & FmtShort){
473
		*(short*)p = f->nfmt;
474
	}else{
475
		*(int*)p = f->nfmt;
476
	}
477
	return 0;
478
}
479
 
480
int
481
_flagfmt(Fmt *f)
482
{
483
	switch(f->r){
484
	case ',':
485
		f->flags |= FmtComma;
486
		break;
487
	case '-':
488
		f->flags |= FmtLeft;
489
		break;
490
	case '+':
491
		f->flags |= FmtSign;
492
		break;
493
	case '#':
494
		f->flags |= FmtSharp;
495
		break;
496
	case ' ':
497
		f->flags |= FmtSpace;
498
		break;
499
	case 'u':
500
		f->flags |= FmtUnsigned;
501
		break;
502
	case 'h':
503
		if(f->flags & FmtShort)
504
			f->flags |= FmtByte;
505
		f->flags |= FmtShort;
506
		break;
507
	case 'l':
508
		if(f->flags & FmtLong)
509
			f->flags |= FmtVLong;
510
		f->flags |= FmtLong;
511
		break;
512
	}
513
	return 1;
514
}
515
 
516
/* default error format */
517
int
518
_badfmt(Fmt *f)
519
{
520
	Rune x[3];
521
 
522
	x[0] = '%';
523
	x[1] = f->r;
524
	x[2] = '%';
525
	f->prec = 3;
526
	_fmtrcpy(f, x, 3);
527
	return 0;
528
}