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