wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

dofmt.c (11470B)


      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 <stdarg.h>
     15 #include <string.h>
     16 #include "plan9.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
     22 dofmt(Fmt *f, const 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 *
     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
    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
    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
    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 	fl = f->flags;
    143 	w = 0;
    144 	if(fl & FmtWidth)
    145 		w = f->width;
    146 	if((fl & FmtPrec) && n > f->prec)
    147 		n = f->prec;
    148 	if(f->runes){
    149 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
    150 			return -1;
    151 		rt = (Rune*)f->to;
    152 		rs = (Rune*)f->stop;
    153 		for(nc = n; nc > 0; nc--){
    154 			r = *(uchar*)m;
    155 			if(r < Runeself)
    156 				m++;
    157 			else if((me - m) >= UTFmax || fullrune(m, me-m))
    158 				m += chartorune(&r, m);
    159 			else
    160 				break;
    161 			FMTRCHAR(f, rt, rs, r);
    162 		}
    163 		f->nfmt += rt - (Rune *)f->to;
    164 		f->to = rt;
    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
    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 	fl = f->flags;
    200 	w = 0;
    201 	if(fl & FmtWidth)
    202 		w = f->width;
    203 	if((fl & FmtPrec) && n > f->prec)
    204 		n = f->prec;
    205 	if(f->runes){
    206 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
    207 			return -1;
    208 		rt = (Rune*)f->to;
    209 		rs = (Rune*)f->stop;
    210 		for(me = m + n; m < me; m++)
    211 			FMTRCHAR(f, rt, rs, *m);
    212 		f->nfmt += rt - (Rune *)f->to;
    213 		f->to = rt;
    214 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
    215 			return -1;
    216 	}else{
    217 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
    218 			return -1;
    219 		t = (char*)f->to;
    220 		s = (char*)f->stop;
    221 		for(me = m + n; m < me; m++){
    222 			r = *m;
    223 			FMTRUNE(f, t, s, r);
    224 		}
    225 		f->nfmt += t - (char *)f->to;
    226 		f->to = t;
    227 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
    228 			return -1;
    229 	}
    230 	return 0;
    231 }
    232 
    233 /* fmt out one character */
    234 int
    235 __charfmt(Fmt *f)
    236 {
    237 	char x[1];
    238 
    239 	x[0] = va_arg(f->args, int);
    240 	f->prec = 1;
    241 	return __fmtcpy(f, (const char*)x, 1, 1);
    242 }
    243 
    244 /* fmt out one rune */
    245 int
    246 __runefmt(Fmt *f)
    247 {
    248 	Rune x[1];
    249 
    250 	x[0] = va_arg(f->args, int);
    251 	return __fmtrcpy(f, (const void*)x, 1);
    252 }
    253 
    254 /* public helper routine: fmt out a null terminated string already in hand */
    255 int
    256 fmtstrcpy(Fmt *f, const char *s)
    257 {
    258 	int i, j;
    259 	Rune r;
    260 
    261 	if(!s)
    262 		return __fmtcpy(f, "<nil>", 5, 5);
    263 	/* if precision is specified, make sure we don't wander off the end */
    264 	if(f->flags & FmtPrec){
    265 		i = 0;
    266 		for(j=0; j<f->prec && s[i]; j++)
    267 			i += chartorune(&r, s+i);
    268 		return __fmtcpy(f, s, j, i);
    269 	}
    270 	return __fmtcpy(f, s, utflen(s), strlen(s));
    271 }
    272 
    273 /* fmt out a null terminated utf string */
    274 int
    275 __strfmt(Fmt *f)
    276 {
    277 	char *s;
    278 
    279 	s = va_arg(f->args, char *);
    280 	return fmtstrcpy(f, s);
    281 }
    282 
    283 /* public helper routine: fmt out a null terminated rune string already in hand */
    284 int
    285 fmtrunestrcpy(Fmt *f, Rune *s)
    286 {
    287 	Rune *e;
    288 	int n, p;
    289 
    290 	if(!s)
    291 		return __fmtcpy(f, "<nil>", 5, 5);
    292 	/* if precision is specified, make sure we don't wander off the end */
    293 	if(f->flags & FmtPrec){
    294 		p = f->prec;
    295 		for(n = 0; n < p; n++)
    296 			if(s[n] == 0)
    297 				break;
    298 	}else{
    299 		for(e = s; *e; e++)
    300 			;
    301 		n = e - s;
    302 	}
    303 	return __fmtrcpy(f, s, n);
    304 }
    305 
    306 /* fmt out a null terminated rune string */
    307 int
    308 __runesfmt(Fmt *f)
    309 {
    310 	Rune *s;
    311 
    312 	s = va_arg(f->args, Rune *);
    313 	return fmtrunestrcpy(f, s);
    314 }
    315 
    316 /* fmt a % */
    317 int
    318 __percentfmt(Fmt *f)
    319 {
    320 	Rune x[1];
    321 
    322 	x[0] = f->r;
    323 	f->prec = 1;
    324 	return __fmtrcpy(f, (const void*)x, 1);
    325 }
    326 
    327 /* fmt an integer */
    328 int
    329 __ifmt(Fmt *f)
    330 {
    331 	char buf[140], *p, *conv;
    332 	/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
    333 	uvlong vu;
    334 	ulong u;
    335 	int neg, base, i, n, fl, w, isv;
    336 	int ndig, len, excess, bytelen;
    337 	char *grouping;
    338 	char *thousands;
    339 
    340 	neg = 0;
    341 	fl = f->flags;
    342 	isv = 0;
    343 	vu = 0;
    344 	u = 0;
    345 	if(f->r == 'p'){
    346 		u = (ulong)va_arg(f->args, void*);
    347 		f->r = 'x';
    348 		fl |= FmtUnsigned;
    349 	}else if(fl & FmtVLong){
    350 		isv = 1;
    351 		if(fl & FmtUnsigned)
    352 			vu = va_arg(f->args, uvlong);
    353 		else
    354 			vu = va_arg(f->args, vlong);
    355 	}else if(fl & FmtLong){
    356 		if(fl & FmtUnsigned)
    357 			u = va_arg(f->args, ulong);
    358 		else
    359 			u = va_arg(f->args, long);
    360 	}else if(fl & FmtByte){
    361 		if(fl & FmtUnsigned)
    362 			u = (uchar)va_arg(f->args, int);
    363 		else
    364 			u = (char)va_arg(f->args, int);
    365 	}else if(fl & FmtShort){
    366 		if(fl & FmtUnsigned)
    367 			u = (ushort)va_arg(f->args, int);
    368 		else
    369 			u = (short)va_arg(f->args, int);
    370 	}else{
    371 		if(fl & FmtUnsigned)
    372 			u = va_arg(f->args, uint);
    373 		else
    374 			u = va_arg(f->args, int);
    375 	}
    376 	conv = "0123456789abcdef";
    377 	grouping = "\4";	/* for hex, octal etc. (undefined by spec but nice) */
    378 	thousands = f->thousands;
    379 	switch(f->r){
    380 	case 'd':
    381 	case 'i':
    382 	case 'u':
    383 		base = 10;
    384 		grouping = f->grouping;
    385 		break;
    386 	case 'X':
    387 		conv = "0123456789ABCDEF";
    388 		/* fall through */
    389 	case 'x':
    390 		base = 16;
    391 		thousands = ":";
    392 		break;
    393 	case 'b':
    394 		base = 2;
    395 		thousands = ":";
    396 		break;
    397 	case 'o':
    398 		base = 8;
    399 		break;
    400 	default:
    401 		return -1;
    402 	}
    403 	if(!(fl & FmtUnsigned)){
    404 		if(isv && (vlong)vu < 0){
    405 			vu = -(vlong)vu;
    406 			neg = 1;
    407 		}else if(!isv && (long)u < 0){
    408 			u = -(long)u;
    409 			neg = 1;
    410 		}
    411 	}
    412 	p = buf + sizeof buf - 1;
    413 	n = 0;	/* in runes */
    414 	excess = 0;	/* number of bytes > number runes */
    415 	ndig = 0;
    416 	len = utflen(thousands);
    417 	bytelen = strlen(thousands);
    418 	if(isv){
    419 		while(vu){
    420 			i = vu % base;
    421 			vu /= base;
    422 			if((fl & FmtComma) && n % 4 == 3){
    423 				*p-- = ',';
    424 				n++;
    425 			}
    426 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    427 				n += len;
    428 				excess += bytelen - len;
    429 				p -= bytelen;
    430 				memmove(p+1, thousands, bytelen);
    431 			}
    432 			*p-- = conv[i];
    433 			n++;
    434 		}
    435 	}else{
    436 		while(u){
    437 			i = u % base;
    438 			u /= base;
    439 			if((fl & FmtComma) && n % 4 == 3){
    440 				*p-- = ',';
    441 				n++;
    442 			}
    443 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    444 				n += len;
    445 				excess += bytelen - len;
    446 				p -= bytelen;
    447 				memmove(p+1, thousands, bytelen);
    448 			}
    449 			*p-- = conv[i];
    450 			n++;
    451 		}
    452 	}
    453 	if(n == 0){
    454 		/*
    455 		 * "The result of converting a zero value with
    456 		 * a precision of zero is no characters."  - ANSI
    457 		 *
    458 		 * "For o conversion, # increases the precision, if and only if
    459 		 * necessary, to force the first digit of the result to be a zero
    460 		 * (if the value and precision are both 0, a single 0 is printed)." - ANSI
    461 		 */
    462 		if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
    463 			*p-- = '0';
    464 			n = 1;
    465 			if(fl & FmtApost)
    466 				__needsep(&ndig, &grouping);
    467 		}
    468 		
    469 		/*
    470 		 * Zero values don't get 0x.
    471 		 */
    472 		if(f->r == 'x' || f->r == 'X')
    473 			fl &= ~FmtSharp;
    474 	}
    475 	for(w = f->prec; n < w && p > buf+3; n++){
    476 		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    477 			n += len;
    478 			excess += bytelen - len;
    479 			p -= bytelen;
    480 			memmove(p+1, thousands, bytelen);
    481 		}
    482 		*p-- = '0';
    483 	}
    484 	if(neg || (fl & (FmtSign|FmtSpace)))
    485 		n++;
    486 	if(fl & FmtSharp){
    487 		if(base == 16)
    488 			n += 2;
    489 		else if(base == 8){
    490 			if(p[1] == '0')
    491 				fl &= ~FmtSharp;
    492 			else
    493 				n++;
    494 		}
    495 	}
    496 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
    497 		w = 0;
    498 		if(fl & FmtWidth)
    499 			w = f->width;
    500 		for(; n < w && p > buf+3; n++){
    501 			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
    502 				n += len;
    503 				excess += bytelen - len;
    504 				p -= bytelen;
    505 				memmove(p+1, thousands, bytelen);
    506 			}
    507 			*p-- = '0';
    508 		}
    509 		f->flags &= ~FmtWidth;
    510 	}
    511 	if(fl & FmtSharp){
    512 		if(base == 16)
    513 			*p-- = f->r;
    514 		if(base == 16 || base == 8)
    515 			*p-- = '0';
    516 	}
    517 	if(neg)
    518 		*p-- = '-';
    519 	else if(fl & FmtSign)
    520 		*p-- = '+';
    521 	else if(fl & FmtSpace)
    522 		*p-- = ' ';
    523 	f->flags &= ~FmtPrec;
    524 	return __fmtcpy(f, p + 1, n, n + excess);
    525 }
    526 
    527 int
    528 __countfmt(Fmt *f)
    529 {
    530 	void *p;
    531 	ulong fl;
    532 
    533 	fl = f->flags;
    534 	p = va_arg(f->args, void*);
    535 	if(fl & FmtVLong){
    536 		*(vlong*)p = f->nfmt;
    537 	}else if(fl & FmtLong){
    538 		*(long*)p = f->nfmt;
    539 	}else if(fl & FmtByte){
    540 		*(char*)p = f->nfmt;
    541 	}else if(fl & FmtShort){
    542 		*(short*)p = f->nfmt;
    543 	}else{
    544 		*(int*)p = f->nfmt;
    545 	}
    546 	return 0;
    547 }
    548 
    549 int
    550 __flagfmt(Fmt *f)
    551 {
    552 	switch(f->r){
    553 	case ',':
    554 		f->flags |= FmtComma;
    555 		break;
    556 	case '-':
    557 		f->flags |= FmtLeft;
    558 		break;
    559 	case '+':
    560 		f->flags |= FmtSign;
    561 		break;
    562 	case '#':
    563 		f->flags |= FmtSharp;
    564 		break;
    565 	case '\'':
    566 		f->flags |= FmtApost;
    567 		break;
    568 	case ' ':
    569 		f->flags |= FmtSpace;
    570 		break;
    571 	case 'u':
    572 		f->flags |= FmtUnsigned;
    573 		break;
    574 	case 'h':
    575 		if(f->flags & FmtShort)
    576 			f->flags |= FmtByte;
    577 		f->flags |= FmtShort;
    578 		break;
    579 	case 'L':
    580 		f->flags |= FmtLDouble;
    581 		break;
    582 	case 'l':
    583 		if(f->flags & FmtLong)
    584 			f->flags |= FmtVLong;
    585 		f->flags |= FmtLong;
    586 		break;
    587 	}
    588 	return 1;
    589 }
    590 
    591 /* default error format */
    592 int
    593 __badfmt(Fmt *f)
    594 {
    595 	char x[2+UTFmax];
    596 	int n;
    597 
    598 	x[0] = '%';
    599 	n = 1 + runetochar(x+1, &f->r);
    600 	x[n++] = '%';
    601 	f->prec = n;
    602 	__fmtcpy(f, (const void*)x, n, n);
    603 	return 0;
    604 }