unix/fiss

lib/libfmt/dofmt.c in master
Repositories | Summary | Log | Files | LICENSE

dofmt.c (11644B) download


  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  */
 12int 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
 72void* __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 */
 89int __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
102int __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
115int __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
171int __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 */
213int __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 */
222int __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 */
230int 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 */
255int __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 */
263int 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 */
284int __runesfmt(Fmt* f) {
285	Rune* s;
286
287	s = va_arg(f->args, Rune*);
288	return fmtrunestrcpy(f, s);
289}
290
291/* fmt a % */
292int __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 */
301int __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
513int __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
533int __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 */
574int __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}