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