github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/lib9/fmt/fltfmt.c (about)

     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  /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
    20  #include <u.h>
    21  #include <errno.h>
    22  #include <libc.h>
    23  #include "fmtdef.h"
    24  
    25  enum
    26  {
    27  	FDIGIT	= 30,
    28  	FDEFLT	= 6,
    29  	NSIGNIF	= 17
    30  };
    31  
    32  /*
    33   * first few powers of 10, enough for about 1/2 of the
    34   * total space for doubles.
    35   */
    36  static double pows10[] =
    37  {
    38  	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,
    39  	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,
    40  	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,
    41  	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,
    42  	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,
    43  	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,
    44  	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,
    45  	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,
    46  	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,
    47  	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,
    48  	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
    49  	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
    50  	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
    51  	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
    52  	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
    53  	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
    54  };
    55  
    56  #undef	pow10
    57  #define	npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
    58  #define	pow10(x)  fmtpow10(x)
    59  
    60  static double
    61  pow10(int n)
    62  {
    63  	double d;
    64  	int neg;
    65  
    66  	neg = 0;
    67  	if(n < 0){
    68  		neg = 1;
    69  		n = -n;
    70  	}
    71  
    72  	if(n < npows10)
    73  		d = pows10[n];
    74  	else{
    75  		d = pows10[npows10-1];
    76  		for(;;){
    77  			n -= npows10 - 1;
    78  			if(n < npows10){
    79  				d *= pows10[n];
    80  				break;
    81  			}
    82  			d *= pows10[npows10 - 1];
    83  		}
    84  	}
    85  	if(neg)
    86  		return 1./d;
    87  	return d;
    88  }
    89  
    90  /*
    91   * add 1 to the decimal integer string a of length n.
    92   * if 99999 overflows into 10000, return 1 to tell caller
    93   * to move the virtual decimal point.
    94   */
    95  static int
    96  xadd1(char *a, int n)
    97  {
    98  	char *b;
    99  	int c;
   100  
   101  	if(n < 0 || n > NSIGNIF)
   102  		return 0;
   103  	for(b = a+n-1; b >= a; b--) {
   104  		c = *b + 1;
   105  		if(c <= '9') {
   106  			*b = (char)c;
   107  			return 0;
   108  		}
   109  		*b = '0';
   110  	}
   111  	/*
   112  	 * need to overflow adding digit.
   113  	 * shift number down and insert 1 at beginning.
   114  	 * decimal is known to be 0s or we wouldn't
   115  	 * have gotten this far.  (e.g., 99999+1 => 00000)
   116  	 */
   117  	a[0] = '1';
   118  	return 1;
   119  }
   120  
   121  /*
   122   * subtract 1 from the decimal integer string a.
   123   * if 10000 underflows into 09999, make it 99999
   124   * and return 1 to tell caller to move the virtual
   125   * decimal point.  this way, xsub1 is inverse of xadd1.
   126   */
   127  static int
   128  xsub1(char *a, int n)
   129  {
   130  	char *b;
   131  	int c;
   132  
   133  	if(n < 0 || n > NSIGNIF)
   134  		return 0;
   135  	for(b = a+n-1; b >= a; b--) {
   136  		c = *b - 1;
   137  		if(c >= '0') {
   138  			if(c == '0' && b == a) {
   139  				/*
   140  				 * just zeroed the top digit; shift everyone up.
   141  				 * decimal is known to be 9s or we wouldn't
   142  				 * have gotten this far.  (e.g., 10000-1 => 09999)
   143  				 */
   144  				*b = '9';
   145  				return 1;
   146  			}
   147  			*b = (char)c;
   148  			return 0;
   149  		}
   150  		*b = '9';
   151  	}
   152  	/*
   153  	 * can't get here.  the number a is always normalized
   154  	 * so that it has a nonzero first digit.
   155  	 */
   156  	abort();
   157  }
   158  
   159  /*
   160   * format exponent like sprintf(p, "e%+02d", e)
   161   */
   162  static void
   163  xfmtexp(char *p, int e, int ucase)
   164  {
   165  	char se[9];
   166  	int i;
   167  
   168  	*p++ = ucase ? 'E' : 'e';
   169  	if(e < 0) {
   170  		*p++ = '-';
   171  		e = -e;
   172  	} else
   173  		*p++ = '+';
   174  	i = 0;
   175  	while(e) {
   176  		se[i++] = (char)(e % 10 + '0');
   177  		e /= 10;
   178  	}
   179  	while(i < 2)
   180  		se[i++] = '0';
   181  	while(i > 0)
   182  		*p++ = se[--i];
   183  	*p++ = '\0';
   184  }
   185  
   186  /*
   187   * compute decimal integer m, exp such that:
   188   *	f = m*10^exp
   189   *	m is as short as possible with losing exactness
   190   * assumes special cases (NaN, +Inf, -Inf) have been handled.
   191   */
   192  static void
   193  xdtoa(double f, char *s, int *exp, int *neg, int *ns)
   194  {
   195  	int d, e2, e, ee, i, ndigit, oerrno;
   196  	char c;
   197  	char tmp[NSIGNIF+10];
   198  	double g;
   199  
   200  	oerrno = errno; /* in case strtod smashes errno */
   201  
   202  	/*
   203  	 * make f non-negative.
   204  	 */
   205  	*neg = 0;
   206  	if(f < 0) {
   207  		f = -f;
   208  		*neg = 1;
   209  	}
   210  
   211  	/*
   212  	 * must handle zero specially.
   213  	 */
   214  	if(f == 0){
   215  		*exp = 0;
   216  		s[0] = '0';
   217  		s[1] = '\0';
   218  		*ns = 1;
   219  		return;
   220  	}
   221  
   222  	/*
   223  	 * find g,e such that f = g*10^e.
   224  	 * guess 10-exponent using 2-exponent, then fine tune.
   225  	 */
   226  	frexp(f, &e2);
   227  	e = (int)(e2 * .301029995664);
   228  	g = f * pow10(-e);
   229  	while(g < 1) {
   230  		e--;
   231  		g = f * pow10(-e);
   232  	}
   233  	while(g >= 10) {
   234  		e++;
   235  		g = f * pow10(-e);
   236  	}
   237  
   238  	/*
   239  	 * convert NSIGNIF digits as a first approximation.
   240  	 */
   241  	for(i=0; i<NSIGNIF; i++) {
   242  		d = (int)g;
   243  		s[i] = (char)(d+'0');
   244  		g = (g-d) * 10;
   245  	}
   246  	s[i] = 0;
   247  
   248  	/*
   249  	 * adjust e because s is 314159... not 3.14159...
   250  	 */
   251  	e -= NSIGNIF-1;
   252  	xfmtexp(s+NSIGNIF, e, 0);
   253  
   254  	/*
   255  	 * adjust conversion until strtod(s) == f exactly.
   256  	 */
   257  	for(i=0; i<10; i++) {
   258  		g = strtod(s, nil);
   259  		if(f > g) {
   260  			if(xadd1(s, NSIGNIF)) {
   261  				/* gained a digit */
   262  				e--;
   263  				xfmtexp(s+NSIGNIF, e, 0);
   264  			}
   265  			continue;
   266  		}
   267  		if(f < g) {
   268  			if(xsub1(s, NSIGNIF)) {
   269  				/* lost a digit */
   270  				e++;
   271  				xfmtexp(s+NSIGNIF, e, 0);
   272  			}
   273  			continue;
   274  		}
   275  		break;
   276  	}
   277  
   278  	/*
   279  	 * play with the decimal to try to simplify.
   280  	 */
   281  
   282  	/*
   283  	 * bump last few digits up to 9 if we can
   284  	 */
   285  	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   286  		c = s[i];
   287  		if(c != '9') {
   288  			s[i] = '9';
   289  			g = strtod(s, nil);
   290  			if(g != f) {
   291  				s[i] = c;
   292  				break;
   293  			}
   294  		}
   295  	}
   296  
   297  	/*
   298  	 * add 1 in hopes of turning 9s to 0s
   299  	 */
   300  	if(s[NSIGNIF-1] == '9') {
   301  		strcpy(tmp, s);
   302  		ee = e;
   303  		if(xadd1(tmp, NSIGNIF)) {
   304  			ee--;
   305  			xfmtexp(tmp+NSIGNIF, ee, 0);
   306  		}
   307  		g = strtod(tmp, nil);
   308  		if(g == f) {
   309  			strcpy(s, tmp);
   310  			e = ee;
   311  		}
   312  	}
   313  
   314  	/*
   315  	 * bump last few digits down to 0 as we can.
   316  	 */
   317  	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   318  		c = s[i];
   319  		if(c != '0') {
   320  			s[i] = '0';
   321  			g = strtod(s, nil);
   322  			if(g != f) {
   323  				s[i] = c;
   324  				break;
   325  			}
   326  		}
   327  	}
   328  
   329  	/*
   330  	 * remove trailing zeros.
   331  	 */
   332  	ndigit = NSIGNIF;
   333  	while(ndigit > 1 && s[ndigit-1] == '0'){
   334  		e++;
   335  		--ndigit;
   336  	}
   337  	s[ndigit] = 0;
   338  	*exp = e;
   339  	*ns = ndigit;
   340  	errno = oerrno;
   341  }
   342  
   343  #ifdef PLAN9PORT
   344  static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
   345  #else
   346  static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
   347  #endif
   348  
   349  int
   350  __efgfmt(Fmt *fmt)
   351  {
   352  	char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
   353  	double f;
   354  	int c, chr, dotwid, e, exp, ndigits, neg, newndigits;
   355  	int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
   356  	ulong fl;
   357  	Rune r, *rs, *rt;
   358  
   359  	if(fmt->flags&FmtLong)
   360  		f = (double)va_arg(fmt->args, long double);
   361  	else
   362  		f = va_arg(fmt->args, double);
   363  
   364  	/*
   365  	 * extract formatting flags
   366  	 */
   367  	fl = fmt->flags;
   368  	fmt->flags = 0;
   369  	prec = FDEFLT;
   370  	if(fl & FmtPrec)
   371  		prec = fmt->prec;
   372  	chr = (int)fmt->r;
   373  	ucase = 0;
   374  	switch(chr) {
   375  	case 'A':
   376  	case 'E':
   377  	case 'F':
   378  	case 'G':
   379  		chr += 'a'-'A';
   380  		ucase = 1;
   381  		break;
   382  	}
   383  
   384  	/*
   385  	 * pick off special numbers.
   386  	 */
   387  	if(__isNaN(f)) {
   388  		s = special[0+ucase];
   389  	special:
   390  		fmt->flags = fl & (FmtWidth|FmtLeft);
   391  		return __fmtcpy(fmt, s, (int)strlen(s), (int)strlen(s));
   392  	}
   393  	if(__isInf(f, 1)) {
   394  		s = special[2+ucase];
   395  		goto special;
   396  	}
   397  	if(__isInf(f, -1)) {
   398  		s = special[4+ucase];
   399  		goto special;
   400  	}
   401  
   402  	/*
   403  	 * get exact representation.
   404  	 */
   405  	digits = buf;
   406  	xdtoa(f, digits, &exp, &neg, &ndigits);
   407  
   408  	/*
   409  	 * get locale's decimal point.
   410  	 */
   411  	dot = fmt->decimal;
   412  	if(dot == nil)
   413  		dot = ".";
   414  	dotwid = utflen(dot);
   415  
   416  	/*
   417  	 * now the formatting fun begins.
   418  	 * compute parameters for actual fmt:
   419  	 *
   420  	 *	pad: number of spaces to insert before/after field.
   421  	 *	z1: number of zeros to insert before digits
   422  	 *	z2: number of zeros to insert after digits
   423  	 *	point: number of digits to print before decimal point
   424  	 *	ndigits: number of digits to use from digits[]
   425  	 *	suf: trailing suffix, like "e-5"
   426  	 */
   427  	realchr = chr;
   428  	switch(chr){
   429  	case 'g':
   430  		/*
   431  		 * convert to at most prec significant digits. (prec=0 means 1)
   432  		 */
   433  		if(prec == 0)
   434  			prec = 1;
   435  		if(ndigits > prec) {
   436  			if(digits[prec] >= '5' && xadd1(digits, prec))
   437  				exp++;
   438  			exp += ndigits-prec;
   439  			ndigits = prec;
   440  		}
   441  
   442  		/*
   443  		 * extra rules for %g (implemented below):
   444  		 *	trailing zeros removed after decimal unless FmtSharp.
   445  		 *	decimal point only if digit follows.
   446  		 */
   447  
   448  		/* fall through to %e */
   449  	default:
   450  	case 'e':
   451  		/*
   452  		 * one significant digit before decimal, no leading zeros.
   453  		 */
   454  		point = 1;
   455  		z1 = 0;
   456  
   457  		/*
   458  		 * decimal point is after ndigits digits right now.
   459  		 * slide to be after first.
   460  		 */
   461  		e  = exp + (ndigits-1);
   462  
   463  		/*
   464  		 * if this is %g, check exponent and convert prec
   465  		 */
   466  		if(realchr == 'g') {
   467  			if(-4 <= e && e < prec)
   468  				goto casef;
   469  			prec--;	/* one digit before decimal; rest after */
   470  		}
   471  
   472  		/*
   473  		 * compute trailing zero padding or truncate digits.
   474  		 */
   475  		if(1+prec >= ndigits)
   476  			z2 = 1+prec - ndigits;
   477  		else {
   478  			/*
   479  			 * truncate digits
   480  			 */
   481  			assert(realchr != 'g');
   482  			newndigits = 1+prec;
   483  			if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   484  				/*
   485  				 * had 999e4, now have 100e5
   486  				 */
   487  				e++;
   488  			}
   489  			ndigits = newndigits;
   490  			z2 = 0;
   491  		}
   492  		xfmtexp(suf, e, ucase);
   493  		sufwid = (int)strlen(suf);
   494  		break;
   495  
   496  	casef:
   497  	case 'f':
   498  		/*
   499  		 * determine where digits go with respect to decimal point
   500  		 */
   501  		if(ndigits+exp > 0) {
   502  			point = ndigits+exp;
   503  			z1 = 0;
   504  		} else {
   505  			point = 1;
   506  			z1 = 1 + -(ndigits+exp);
   507  		}
   508  
   509  		/*
   510  		 * %g specifies prec = number of significant digits
   511  		 * convert to number of digits after decimal point
   512  		 */
   513  		if(realchr == 'g')
   514  			prec += z1 - point;
   515  
   516  		/*
   517  		 * compute trailing zero padding or truncate digits.
   518  		 */
   519  		if(point+prec >= z1+ndigits)
   520  			z2 = point+prec - (z1+ndigits);
   521  		else {
   522  			/*
   523  			 * truncate digits
   524  			 */
   525  			assert(realchr != 'g');
   526  			newndigits = point+prec - z1;
   527  			if(newndigits < 0) {
   528  				z1 += newndigits;
   529  				newndigits = 0;
   530  			} else if(newndigits == 0) {
   531  				/* perhaps round up */
   532  				if(digits[0] >= '5'){
   533  					digits[0] = '1';
   534  					newndigits = 1;
   535  					goto newdigit;
   536  				}
   537  			} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   538  				/*
   539  				 * digits was 999, is now 100; make it 1000
   540  				 */
   541  				digits[newndigits++] = '0';
   542  			newdigit:
   543  				/*
   544  				 * account for new digit
   545  				 */
   546  				if(z1)	/* 0.099 => 0.100 or 0.99 => 1.00*/
   547  					z1--;
   548  				else	/* 9.99 => 10.00 */
   549  					point++;
   550  			}
   551  			z2 = 0;
   552  			ndigits = newndigits;
   553  		}
   554  		sufwid = 0;
   555  		break;
   556  	}
   557  
   558  	/*
   559  	 * if %g is given without FmtSharp, remove trailing zeros.
   560  	 * must do after truncation, so that e.g. print %.3g 1.001
   561  	 * produces 1, not 1.00.  sorry, but them's the rules.
   562  	 */
   563  	if(realchr == 'g' && !(fl & FmtSharp)) {
   564  		if(z1+ndigits+z2 >= point) {
   565  			if(z1+ndigits < point)
   566  				z2 = point - (z1+ndigits);
   567  			else{
   568  				z2 = 0;
   569  				while(z1+ndigits > point && digits[ndigits-1] == '0')
   570  					ndigits--;
   571  			}
   572  		}
   573  	}
   574  
   575  	/*
   576  	 * compute width of all digits and decimal point and suffix if any
   577  	 */
   578  	wid = z1+ndigits+z2;
   579  	if(wid > point)
   580  		wid += dotwid;
   581  	else if(wid == point){
   582  		if(fl & FmtSharp)
   583  			wid += dotwid;
   584  		else
   585  			point++;	/* do not print any decimal point */
   586  	}
   587  	wid += sufwid;
   588  
   589  	/*
   590  	 * determine sign
   591  	 */
   592  	sign = 0;
   593  	if(neg)
   594  		sign = '-';
   595  	else if(fl & FmtSign)
   596  		sign = '+';
   597  	else if(fl & FmtSpace)
   598  		sign = ' ';
   599  	if(sign)
   600  		wid++;
   601  
   602  	/*
   603  	 * compute padding
   604  	 */
   605  	pad = 0;
   606  	if((fl & FmtWidth) && fmt->width > wid)
   607  		pad = fmt->width - wid;
   608  	if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
   609  		z1 += pad;
   610  		point += pad;
   611  		pad = 0;
   612  	}
   613  
   614  	/*
   615  	 * format the actual field.  too bad about doing this twice.
   616  	 */
   617  	if(fmt->runes){
   618  		if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   619  			return -1;
   620  		rt = (Rune*)fmt->to;
   621  		rs = (Rune*)fmt->stop;
   622  		if(sign)
   623  			FMTRCHAR(fmt, rt, rs, sign);
   624  		while(z1>0 || ndigits>0 || z2>0) {
   625  			if(z1 > 0){
   626  				z1--;
   627  				c = '0';
   628  			}else if(ndigits > 0){
   629  				ndigits--;
   630  				c = *digits++;
   631  			}else{
   632  				z2--;
   633  				c = '0';
   634  			}
   635  			FMTRCHAR(fmt, rt, rs, c);
   636  			if(--point == 0) {
   637  				for(p = dot; *p; ){
   638  					p += chartorune(&r, p);
   639  					FMTRCHAR(fmt, rt, rs, r);
   640  				}
   641  			}
   642  		}
   643  		fmt->nfmt += (int)(rt - (Rune*)fmt->to);
   644  		fmt->to = rt;
   645  		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   646  			return -1;
   647  		if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   648  			return -1;
   649  	}else{
   650  		if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   651  			return -1;
   652  		t = (char*)fmt->to;
   653  		s = (char*)fmt->stop;
   654  		if(sign)
   655  			FMTCHAR(fmt, t, s, sign);
   656  		while(z1>0 || ndigits>0 || z2>0) {
   657  			if(z1 > 0){
   658  				z1--;
   659  				c = '0';
   660  			}else if(ndigits > 0){
   661  				ndigits--;
   662  				c = *digits++;
   663  			}else{
   664  				z2--;
   665  				c = '0';
   666  			}
   667  			FMTCHAR(fmt, t, s, c);
   668  			if(--point == 0)
   669  				for(p=dot; *p; p++)
   670  					FMTCHAR(fmt, t, s, *p);
   671  		}
   672  		fmt->nfmt += (int)(t - (char*)fmt->to);
   673  		fmt->to = t;
   674  		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   675  			return -1;
   676  		if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   677  			return -1;
   678  	}
   679  	return 0;
   680  }
   681