xref: /plan9/sys/src/ape/lib/fmt/dofmt.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
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
dofmt(Fmt * f,char * fmt)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 *
__fmtflush(Fmt * f,void * t,int len)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
__fmtpad(Fmt * f,int n)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
__rfmtpad(Fmt * f,int n)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
__fmtcpy(Fmt * f,const void * vm,int n,int sz)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
__fmtrcpy(Fmt * f,const void * vm,int n)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
__charfmt(Fmt * f)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
__runefmt(Fmt * f)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
fmtstrcpy(Fmt * f,char * s)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
__strfmt(Fmt * f)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
fmtrunestrcpy(Fmt * f,Rune * s)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
__runesfmt(Fmt * f)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
__percentfmt(Fmt * f)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
__ifmt(Fmt * f)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
__countfmt(Fmt * f)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
__flagfmt(Fmt * f)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
__badfmt(Fmt * f)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 }
558