fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

dofmt.c (11644B)


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