The Go Programming Language

Text file src/lib9/fmt/dofmt.c

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.