xref: /plan9/sys/src/libc/fmt/dofmt.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
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 = 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 *
_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 = 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
_rfmtpad(Fmt * f,int n)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
_fmtcpy(Fmt * f,void * vm,int n,int sz)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
_fmtrcpy(Fmt * f,void * vm,int n)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
_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, 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, 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, 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
_ifmt(Fmt * f)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
_countfmt(Fmt * f)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
_flagfmt(Fmt * f)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
_badfmt(Fmt * f)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 }
529