plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

dofmt.c (11229B)


      1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
      2 /* Copyright (c) 2004 Google Inc.; see LICENSE */
      3 
      4 #include <stdarg.h>
      5 #include <string.h>
      6 #include "plan9.h"
      7 #include "fmt.h"
      8 #include "fmtdef.h"
      9 
     10 /* format the output into f->to and return the number of characters fmted  */
     11 int
     12 dofmt(Fmt *f, char *fmt)
     13 {
     14 	Rune rune, *rt, *rs;
     15 	int r;
     16 	char *t, *s;
     17 	int n, nfmt;
     18 
     19 	nfmt = f->nfmt;
     20 	for(;;){
     21 		if(f->runes){
     22 			rt = (Rune*)f->to;
     23 			rs = (Rune*)f->stop;
     24 			while((r = *(uchar*)fmt) && r != '%'){
     25 				if(r < Runeself)
     26 					fmt++;
     27 				else{
     28 					fmt += chartorune(&rune, fmt);
     29 					r = rune;
     30 				}
     31 				FMTRCHAR(f, rt, rs, r);
     32 			}
     33 			fmt++;
     34 			f->nfmt += rt - (Rune *)f->to;
     35 			f->to = rt;
     36 			if(!r)
     37 				return f->nfmt - nfmt;
     38 			f->stop = rs;
     39 		}else{
     40 			t = (char*)f->to;
     41 			s = (char*)f->stop;
     42 			while((r = *(uchar*)fmt) && r != '%'){
     43 				if(r < Runeself){
     44 					FMTCHAR(f, t, s, r);
     45 					fmt++;
     46 				}else{
     47 					n = chartorune(&rune, fmt);
     48 					if(t + n > s){
     49 						t = (char*)__fmtflush(f, t, n);
     50 						if(t != nil)
     51 							s = (char*)f->stop;
     52 						else
     53 							return -1;
     54 					}
     55 					while(n--)
     56 						*t++ = *fmt++;
     57 				}
     58 			}
     59 			fmt++;
     60 			f->nfmt += t - (char *)f->to;
     61 			f->to = t;
     62 			if(!r)
     63 				return f->nfmt - nfmt;
     64 			f->stop = s;
     65 		}
     66 
     67 		fmt = (char*)__fmtdispatch(f, fmt, 0);
     68 		if(fmt == nil)
     69 			return -1;
     70 	}
     71 }
     72 
     73 void *
     74 __fmtflush(Fmt *f, void *t, int len)
     75 {
     76 	if(f->runes)
     77 		f->nfmt += (Rune*)t - (Rune*)f->to;
     78 	else
     79 		f->nfmt += (char*)t - (char *)f->to;
     80 	f->to = t;
     81 	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
     82 		f->stop = f->to;
     83 		return nil;
     84 	}
     85 	return f->to;
     86 }
     87 
     88 /*
     89  * put a formatted block of memory sz bytes long of n runes into the output buffer,
     90  * left/right justified in a field of at least f->width characters (if FmtWidth is set)
     91  */
     92 int
     93 __fmtpad(Fmt *f, int n)
     94 {
     95 	char *t, *s;
     96 	int i;
     97 
     98 	t = (char*)f->to;
     99 	s = (char*)f->stop;
    100 	for(i = 0; i < n; i++)
    101 		FMTCHAR(f, t, s, ' ');
    102 	f->nfmt += t - (char *)f->to;
    103 	f->to = t;
    104 	return 0;
    105 }
    106 
    107 int
    108 __rfmtpad(Fmt *f, int n)
    109 {
    110 	Rune *t, *s;
    111 	int i;
    112 
    113 	t = (Rune*)f->to;
    114 	s = (Rune*)f->stop;
    115 	for(i = 0; i < n; i++)
    116 		FMTRCHAR(f, t, s, ' ');
    117 	f->nfmt += t - (Rune *)f->to;
    118 	f->to = t;
    119 	return 0;
    120 }
    121 
    122 int
    123 __fmtcpy(Fmt *f, const void *vm, int n, int sz)
    124 {
    125 	Rune *rt, *rs, r;
    126 	char *t, *s, *m, *me;
    127 	ulong fl;
    128 	int nc, w;
    129 
    130 	m = (char*)vm;
    131 	me = m + sz;
    132 	fl = f->flags;
    133 	w = 0;
    134 	if(fl & FmtWidth)
    135 		w = f->width;
    136 	if((fl & FmtPrec) && n > f->prec)
    137 		n = f->prec;
    138 	if(f->runes){
    139 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
    140 			return -1;
    141 		rt = (Rune*)f->to;
    142 		rs = (Rune*)f->stop;
    143 		for(nc = n; nc > 0; nc--){
    144 			r = *(uchar*)m;
    145 			if(r < Runeself)
    146 				m++;
    147 			else if((me - m) >= UTFmax || fullrune(m, me-m))
    148 				m += chartorune(&r, m);
    149 			else
    150 				break;
    151 			FMTRCHAR(f, rt, rs, r);
    152 		}
    153 		f->nfmt += rt - (Rune *)f->to;
    154 		f->to = rt;
    155 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
    156 			return -1;
    157 	}else{
    158 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
    159 			return -1;
    160 		t = (char*)f->to;
    161 		s = (char*)f->stop;
    162 		for(nc = n; nc > 0; nc--){
    163 			r = *(uchar*)m;
    164 			if(r < Runeself)
    165 				m++;
    166 			else if((me - m) >= UTFmax || fullrune(m, me-m))
    167 				m += chartorune(&r, m);
    168 			else
    169 				break;
    170 			FMTRUNE(f, t, s, r);
    171 		}
    172 		f->nfmt += t - (char *)f->to;
    173 		f->to = t;
    174 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
    175 			return -1;
    176 	}
    177 	return 0;
    178 }
    179 
    180 int
    181 __fmtrcpy(Fmt *f, const void *vm, int n)
    182 {
    183 	Rune r, *m, *me, *rt, *rs;
    184 	char *t, *s;
    185 	ulong fl;
    186 	int w;
    187 
    188 	m = (Rune*)vm;
    189 	fl = f->flags;
    190 	w = 0;
    191 	if(fl & FmtWidth)
    192 		w = f->width;
    193 	if((fl & FmtPrec) && n > f->prec)
    194 		n = f->prec;
    195 	if(f->runes){
    196 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
    197 			return -1;
    198 		rt = (Rune*)f->to;
    199 		rs = (Rune*)f->stop;
    200 		for(me = m + n; m < me; m++)
    201 			FMTRCHAR(f, rt, rs, *m);
    202 		f->nfmt += rt - (Rune *)f->to;
    203 		f->to = rt;
    204 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
    205 			return -1;
    206 	}else{
    207 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
    208 			return -1;
    209 		t = (char*)f->to;
    210 		s = (char*)f->stop;
    211 		for(me = m + n; m < me; m++){
    212 			r = *m;
    213 			FMTRUNE(f, t, s, r);
    214 		}
    215 		f->nfmt += t - (char *)f->to;
    216 		f->to = t;
    217 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
    218 			return -1;
    219 	}
    220 	return 0;
    221 }
    222 
    223 /* fmt out one character */
    224 int
    225 __charfmt(Fmt *f)
    226 {
    227 	char x[1];
    228 
    229 	x[0] = va_arg(f->args, int);
    230 	f->prec = 1;
    231 	return __fmtcpy(f, (const char*)x, 1, 1);
    232 }
    233 
    234 /* fmt out one rune */
    235 int
    236 __runefmt(Fmt *f)
    237 {
    238 	Rune x[1];
    239 
    240 	x[0] = va_arg(f->args, int);
    241 	return __fmtrcpy(f, (const void*)x, 1);
    242 }
    243 
    244 /* public helper routine: fmt out a null terminated string already in hand */
    245 int
    246 fmtstrcpy(Fmt *f, char *s)
    247 {
    248 	int i, j;
    249 
    250 	if(!s)
    251 		return __fmtcpy(f, "<nil>", 5, 5);
    252 	/* if precision is specified, make sure we don't wander off the end */
    253 	if(f->flags & FmtPrec){
    254 #ifdef PLAN9PORT
    255 		Rune r;
    256 		i = 0;
    257 		for(j=0; j<f->prec && s[i]; j++)
    258 			i += chartorune(&r, s+i);
    259 #else
    260 		/* ANSI requires precision in bytes, not Runes */
    261 		for(i=0; i<f->prec; i++)
    262 			if(s[i] == 0)
    263 				break;
    264 		j = utfnlen(s, i);	/* won't print partial at end */
    265 #endif
    266 		return __fmtcpy(f, s, j, i);
    267 	}
    268 	return __fmtcpy(f, s, utflen(s), strlen(s));
    269 }
    270 
    271 /* fmt out a null terminated utf string */
    272 int
    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
    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
    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
    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
    327 __ifmt(Fmt *f)
    328 {
    329 	char buf[140], *p, *conv;
    330 	/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
    331 	uvlong vu;
    332 	ulong u;
    333 	int neg, base, i, n, fl, w, isv;
    334 	int ndig, len, excess, bytelen;
    335 	char *grouping;
    336 	char *thousands;
    337 
    338 	neg = 0;
    339 	fl = f->flags;
    340 	isv = 0;
    341 	vu = 0;
    342 	u = 0;
    343 #ifndef PLAN9PORT
    344 	/*
    345 	 * Unsigned verbs for ANSI C
    346 	 */
    347 	switch(f->r){
    348 	case 'o':
    349 	case 'p':
    350 	case 'u':
    351 	case 'x':
    352 	case 'X':
    353 		fl |= FmtUnsigned;
    354 		fl &= ~(FmtSign|FmtSpace);
    355 		break;
    356 	}
    357 #endif
    358 	if(f->r == 'p'){
    359 		u = (ulong)va_arg(f->args, void*);
    360 		f->r = 'x';
    361 		fl |= FmtUnsigned;
    362 	}else if(fl & FmtVLong){
    363 		isv = 1;
    364 		if(fl & FmtUnsigned)
    365 			vu = va_arg(f->args, uvlong);
    366 		else
    367 			vu = va_arg(f->args, vlong);
    368 	}else if(fl & FmtLong){
    369 		if(fl & FmtUnsigned)
    370 			u = va_arg(f->args, ulong);
    371 		else
    372 			u = va_arg(f->args, long);
    373 	}else if(fl & FmtByte){
    374 		if(fl & FmtUnsigned)
    375 			u = (uchar)va_arg(f->args, int);
    376 		else
    377 			u = (char)va_arg(f->args, int);
    378 	}else if(fl & FmtShort){
    379 		if(fl & FmtUnsigned)
    380 			u = (ushort)va_arg(f->args, int);
    381 		else
    382 			u = (short)va_arg(f->args, int);
    383 	}else{
    384 		if(fl & FmtUnsigned)
    385 			u = va_arg(f->args, uint);
    386 		else
    387 			u = va_arg(f->args, int);
    388 	}
    389 	conv = "0123456789abcdef";
    390 	grouping = "\4";	/* for hex, octal etc. (undefined by spec but nice) */
    391 	thousands = f->thousands;
    392 	switch(f->r){
    393 	case 'd':
    394 	case 'i':
    395 	case 'u':
    396 		base = 10;
    397 		grouping = f->grouping;
    398 		break;
    399 	case 'X':
    400 		conv = "0123456789ABCDEF";
    401 		/* fall through */
    402 	case 'x':
    403 		base = 16;
    404 		thousands = ":";
    405 		break;
    406 	case 'b':
    407 		base = 2;
    408 		thousands = ":";
    409 		break;
    410 	case 'o':
    411 		base = 8;
    412 		break;
    413 	default:
    414 		return -1;
    415 	}
    416 	if(!(fl & FmtUnsigned)){
    417 		if(isv && (vlong)vu < 0){
    418 			vu = -(vlong)vu;
    419 			neg = 1;
    420 		}else if(!isv && (long)u < 0){
    421 			u = -(long)u;
    422 			neg = 1;
    423 		}
    424 	}
    425 	p = buf + sizeof buf - 1;
    426 	n = 0;	/* in runes */
    427 	excess = 0;	/* number of bytes > number runes */
    428 	ndig = 0;
    429 	len = utflen(thousands);
    430 	bytelen = strlen(thousands);
    431 	if(isv){
    432 		while(vu){
    433 			i = vu % base;
    434 			vu /= base;
    435 			if((fl & FmtComma) && n % 4 == 3){
    436 				*p-- = ',';
    437 				n++;
    438 			}
    439 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    440 				n += len;
    441 				excess += bytelen - len;
    442 				p -= bytelen;
    443 				memmove(p+1, thousands, bytelen);
    444 			}
    445 			*p-- = conv[i];
    446 			n++;
    447 		}
    448 	}else{
    449 		while(u){
    450 			i = u % base;
    451 			u /= base;
    452 			if((fl & FmtComma) && n % 4 == 3){
    453 				*p-- = ',';
    454 				n++;
    455 			}
    456 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    457 				n += len;
    458 				excess += bytelen - len;
    459 				p -= bytelen;
    460 				memmove(p+1, thousands, bytelen);
    461 			}
    462 			*p-- = conv[i];
    463 			n++;
    464 		}
    465 	}
    466 	if(n == 0){
    467 		/*
    468 		 * "The result of converting a zero value with
    469 		 * a precision of zero is no characters."  - ANSI
    470 		 *
    471 		 * "For o conversion, # increases the precision, if and only if
    472 		 * necessary, to force the first digit of the result to be a zero
    473 		 * (if the value and precision are both 0, a single 0 is printed)." - ANSI
    474 		 */
    475 		if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
    476 			*p-- = '0';
    477 			n = 1;
    478 			if(fl & FmtApost)
    479 				__needsep(&ndig, &grouping);
    480 		}
    481 
    482 		/*
    483 		 * Zero values don't get 0x.
    484 		 */
    485 		if(f->r == 'x' || f->r == 'X')
    486 			fl &= ~FmtSharp;
    487 	}
    488 	for(w = f->prec; n < w && p > buf+3; n++){
    489 		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    490 			n += len;
    491 			excess += bytelen - len;
    492 			p -= bytelen;
    493 			memmove(p+1, thousands, bytelen);
    494 		}
    495 		*p-- = '0';
    496 	}
    497 	if(neg || (fl & (FmtSign|FmtSpace)))
    498 		n++;
    499 	if(fl & FmtSharp){
    500 		if(base == 16)
    501 			n += 2;
    502 		else if(base == 8){
    503 			if(p[1] == '0')
    504 				fl &= ~FmtSharp;
    505 			else
    506 				n++;
    507 		}
    508 	}
    509 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
    510 		w = 0;
    511 		if(fl & FmtWidth)
    512 			w = f->width;
    513 		for(; n < w && p > buf+3; n++){
    514 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    515 				n += len;
    516 				excess += bytelen - len;
    517 				p -= bytelen;
    518 				memmove(p+1, thousands, bytelen);
    519 			}
    520 			*p-- = '0';
    521 		}
    522 		f->flags &= ~FmtWidth;
    523 	}
    524 	if(fl & FmtSharp){
    525 		if(base == 16)
    526 			*p-- = f->r;
    527 		if(base == 16 || base == 8)
    528 			*p-- = '0';
    529 	}
    530 	if(neg)
    531 		*p-- = '-';
    532 	else if(fl & FmtSign)
    533 		*p-- = '+';
    534 	else if(fl & FmtSpace)
    535 		*p-- = ' ';
    536 	f->flags &= ~FmtPrec;
    537 	return __fmtcpy(f, p + 1, n, n + excess);
    538 }
    539 
    540 int
    541 __countfmt(Fmt *f)
    542 {
    543 	void *p;
    544 	ulong fl;
    545 
    546 	fl = f->flags;
    547 	p = va_arg(f->args, void*);
    548 	if(fl & FmtVLong){
    549 		*(vlong*)p = f->nfmt;
    550 	}else if(fl & FmtLong){
    551 		*(long*)p = f->nfmt;
    552 	}else if(fl & FmtByte){
    553 		*(char*)p = f->nfmt;
    554 	}else if(fl & FmtShort){
    555 		*(short*)p = f->nfmt;
    556 	}else{
    557 		*(int*)p = f->nfmt;
    558 	}
    559 	return 0;
    560 }
    561 
    562 int
    563 __flagfmt(Fmt *f)
    564 {
    565 	switch(f->r){
    566 	case ',':
    567 		f->flags |= FmtComma;
    568 		break;
    569 	case '-':
    570 		f->flags |= FmtLeft;
    571 		break;
    572 	case '+':
    573 		f->flags |= FmtSign;
    574 		break;
    575 	case '#':
    576 		f->flags |= FmtSharp;
    577 		break;
    578 	case '\'':
    579 		f->flags |= FmtApost;
    580 		break;
    581 	case ' ':
    582 		f->flags |= FmtSpace;
    583 		break;
    584 	case 'u':
    585 		f->flags |= FmtUnsigned;
    586 		break;
    587 	case 'h':
    588 		if(f->flags & FmtShort)
    589 			f->flags |= FmtByte;
    590 		f->flags |= FmtShort;
    591 		break;
    592 	case 'L':
    593 		f->flags |= FmtLDouble;
    594 		break;
    595 	case 'l':
    596 		if(f->flags & FmtLong)
    597 			f->flags |= FmtVLong;
    598 		f->flags |= FmtLong;
    599 		break;
    600 	}
    601 	return 1;
    602 }
    603 
    604 /* default error format */
    605 int
    606 __badfmt(Fmt *f)
    607 {
    608 	char x[2+UTFmax];
    609 	int n;
    610 
    611 	x[0] = '%';
    612 	n = 1 + runetochar(x+1, &f->r);
    613 	x[n++] = '%';
    614 	f->prec = n;
    615 	__fmtcpy(f, (const void*)x, n, n);
    616 	return 0;
    617 }