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
dofmt(Fmt * f,char * fmt)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 = (Rune*)f->to;
18 			rs = (Rune*)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 = (char*)f->to;
36 			s = (char*)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 = (char*)__fmtflush(f, t, n);
45 						if(t != nil)
46 							s = (char*)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 = (char*)__fmtdispatch(f, fmt, 0);
63 		if(fmt == nil)
64 			return -1;
65 	}
66 }
67 
68 void *
__fmtflush(Fmt * f,void * t,int len)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
__fmtpad(Fmt * f,int n)88 __fmtpad(Fmt *f, int n)
89 {
90 	char *t, *s;
91 	int i;
92 
93 	t = (char*)f->to;
94 	s = (char*)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
__rfmtpad(Fmt * f,int n)103 __rfmtpad(Fmt *f, int n)
104 {
105 	Rune *t, *s;
106 	int i;
107 
108 	t = (Rune*)f->to;
109 	s = (Rune*)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
__fmtcpy(Fmt * f,const void * vm,int n,int sz)118 __fmtcpy(Fmt *f, const 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 = (char*)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 = (Rune*)f->to;
135 		rs = (Rune*)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 = (char*)f->to;
154 		s = (char*)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
__fmtrcpy(Fmt * f,const void * vm,int n)174 __fmtrcpy(Fmt *f, const 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 = (Rune*)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 = (Rune*)f->to;
190 		rs = (Rune*)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 = (char*)f->to;
201 		s = (char*)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
__charfmt(Fmt * f)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, (const char*)x, 1, 1);
223 }
224 
225 /* fmt out one rune */
226 int
__runefmt(Fmt * f)227 __runefmt(Fmt *f)
228 {
229 	Rune x[1];
230 
231 	x[0] = va_arg(f->args, int);
232 	return __fmtrcpy(f, (const void*)x, 1);
233 }
234 
235 /* public helper routine: fmt out a null terminated string already in hand */
236 int
fmtstrcpy(Fmt * f,char * s)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
__strfmt(Fmt * f)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
fmtrunestrcpy(Fmt * f,Rune * s)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
__runesfmt(Fmt * f)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
__percentfmt(Fmt * f)299 __percentfmt(Fmt *f)
300 {
301 	Rune x[1];
302 
303 	x[0] = f->r;
304 	f->prec = 1;
305 	return __fmtrcpy(f, (const void*)x, 1);
306 }
307 
308 /* fmt an integer */
309 int
__ifmt(Fmt * f)310 __ifmt(Fmt *f)
311 {
312 	char buf[70], *p, *conv;
313 	uvlong vu;
314 	ulong u;
315 	int neg, base, i, n, fl, w, isv;
316 
317 	neg = 0;
318 	fl = f->flags;
319 	isv = 0;
320 	vu = 0;
321 	u = 0;
322 	/*
323 	 * Unsigned verbs for ANSI C
324 	 */
325 	switch(f->r){
326 	case 'x':
327 	case 'X':
328 	case 'o':
329 	case 'u':
330 	case 'p':
331 		fl |= FmtUnsigned;
332 		fl &= ~(FmtSign|FmtSpace);
333 		break;
334 	}
335 	if(f->r == 'p'){
336 		if(sizeof(void*) == sizeof(uvlong)){
337 			isv = 1;
338 			vu = (uvlong)va_arg(f->args, uvlong);
339 		}else
340 			u = (ulong)va_arg(f->args, ulong);
341 		f->r = 'x';
342 		fl |= FmtUnsigned;
343 	}else if(fl & FmtVLong){
344 		isv = 1;
345 		if(fl & FmtUnsigned)
346 			vu = va_arg(f->args, uvlong);
347 		else
348 			vu = va_arg(f->args, vlong);
349 	}else if(fl & FmtLong){
350 		if(fl & FmtUnsigned)
351 			u = va_arg(f->args, ulong);
352 		else
353 			u = va_arg(f->args, long);
354 	}else if(fl & FmtByte){
355 		if(fl & FmtUnsigned)
356 			u = (uchar)va_arg(f->args, int);
357 		else
358 			u = (char)va_arg(f->args, int);
359 	}else if(fl & FmtShort){
360 		if(fl & FmtUnsigned)
361 			u = (ushort)va_arg(f->args, int);
362 		else
363 			u = (short)va_arg(f->args, int);
364 	}else{
365 		if(fl & FmtUnsigned)
366 			u = va_arg(f->args, uint);
367 		else
368 			u = va_arg(f->args, int);
369 	}
370 	conv = "0123456789abcdef";
371 	switch(f->r){
372 	case 'd':
373 	case 'i':
374 	case 'u':
375 		base = 10;
376 		break;
377 	case 'x':
378 		base = 16;
379 		break;
380 	case 'X':
381 		base = 16;
382 		conv = "0123456789ABCDEF";
383 		break;
384 	case 'b':
385 		base = 2;
386 		break;
387 	case 'o':
388 		base = 8;
389 		break;
390 	default:
391 		return -1;
392 	}
393 	if(!(fl & FmtUnsigned)){
394 		if(isv && (vlong)vu < 0){
395 			vu = -(vlong)vu;
396 			neg = 1;
397 		}else if(!isv && (long)u < 0){
398 			u = -(long)u;
399 			neg = 1;
400 		}
401 	}
402 	p = buf + sizeof buf - 1;
403 	n = 0;
404 	if(isv){
405 		while(vu){
406 			i = vu % base;
407 			vu /= base;
408 			if((fl & FmtComma) && n % 4 == 3){
409 				*p-- = ',';
410 				n++;
411 			}
412 			*p-- = conv[i];
413 			n++;
414 		}
415 	}else{
416 		while(u){
417 			i = u % base;
418 			u /= base;
419 			if((fl & FmtComma) && n % 4 == 3){
420 				*p-- = ',';
421 				n++;
422 			}
423 			*p-- = conv[i];
424 			n++;
425 		}
426 	}
427 	if(n == 0){
428 		*p-- = '0';
429 		n = 1;
430 	}
431 	for(w = f->prec; n < w && p > buf+3; n++)
432 		*p-- = '0';
433 	if(neg || (fl & (FmtSign|FmtSpace)))
434 		n++;
435 	if(fl & FmtSharp){
436 		if(base == 16)
437 			n += 2;
438 		else if(base == 8){
439 			if(p[1] == '0')
440 				fl &= ~FmtSharp;
441 			else
442 				n++;
443 		}
444 	}
445 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
446 		for(w = f->width; n < w && p > buf+3; n++)
447 			*p-- = '0';
448 		f->width = 0;
449 	}
450 	if(fl & FmtSharp){
451 		if(base == 16)
452 			*p-- = f->r;
453 		if(base == 16 || base == 8)
454 			*p-- = '0';
455 	}
456 	if(neg)
457 		*p-- = '-';
458 	else if(fl & FmtSign)
459 		*p-- = '+';
460 	else if(fl & FmtSpace)
461 		*p-- = ' ';
462 	f->flags &= ~FmtPrec;
463 	return __fmtcpy(f, p + 1, n, n);
464 }
465 
466 int
__countfmt(Fmt * f)467 __countfmt(Fmt *f)
468 {
469 	void *p;
470 	ulong fl;
471 
472 	fl = f->flags;
473 	p = va_arg(f->args, void*);
474 	if(fl & FmtVLong){
475 		*(vlong*)p = f->nfmt;
476 	}else if(fl & FmtLong){
477 		*(long*)p = f->nfmt;
478 	}else if(fl & FmtByte){
479 		*(char*)p = f->nfmt;
480 	}else if(fl & FmtShort){
481 		*(short*)p = f->nfmt;
482 	}else{
483 		*(int*)p = f->nfmt;
484 	}
485 	return 0;
486 }
487 
488 int
__flagfmt(Fmt * f)489 __flagfmt(Fmt *f)
490 {
491 	switch(f->r){
492 	case ',':
493 		f->flags |= FmtComma;
494 		break;
495 	case '-':
496 		f->flags |= FmtLeft;
497 		break;
498 	case '+':
499 		f->flags |= FmtSign;
500 		break;
501 	case '#':
502 		f->flags |= FmtSharp;
503 		break;
504 	case ' ':
505 		f->flags |= FmtSpace;
506 		break;
507 	case 'u':
508 		f->flags |= FmtUnsigned;
509 		break;
510 	case 'h':
511 		if(f->flags & FmtShort)
512 			f->flags |= FmtByte;
513 		f->flags |= FmtShort;
514 		break;
515 	case 'L':
516 		f->flags |= FmtLDouble;
517 		break;
518 	case 'l':
519 		if(f->flags & FmtLong)
520 			f->flags |= FmtVLong;
521 		f->flags |= FmtLong;
522 		break;
523 	}
524 	return 1;
525 }
526 
527 /* default error format */
528 int
__badfmt(Fmt * f)529 __badfmt(Fmt *f)
530 {
531 	char x[3];
532 
533 	x[0] = '%';
534 	x[1] = f->r;
535 	x[2] = '%';
536 	f->prec = 3;
537 	__fmtcpy(f, (const void*)x, 3, 3);
538 	return 0;
539 }
540