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