github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/lib9/fmt/dofmt.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  #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  	Rune 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 = (Rune)*(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 += (int)(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 = (Rune)*(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 += (int)(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 += (int)((Rune*)t - (Rune*)f->to);
    91  	else
    92  		f->nfmt += (int)((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 += (int)(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 += (int)(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, (int)(me-m)))
   161  				m += chartorune(&r, m);
   162  			else
   163  				break;
   164  			FMTRCHAR(f, rt, rs, r);
   165  		}
   166  		f->nfmt += (int)(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, (int)(me-m)))
   180  				m += chartorune(&r, m);
   181  			else
   182  				break;
   183  			FMTRUNE(f, t, s, r);
   184  		}
   185  		f->nfmt += (int)(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 += (int)(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 += (int)(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] = (char)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] = (Rune)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), (int)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 = (int)(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 fl, u;
   346  	int neg, base, i, n, 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 = (uvlong)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 = (ulong)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 = (ulong)(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 = (ulong)(short)va_arg(f->args, int);
   396  	}else{
   397  		if(fl & FmtUnsigned)
   398  			u = va_arg(f->args, uint);
   399  		else
   400  			u = (ulong)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 = (uvlong)-(vlong)vu;
   432  			neg = 1;
   433  		}else if(!isv && (long)u < 0){
   434  			u = (ulong)-(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 = (int)strlen(thousands);
   444  	if(isv){
   445  		while(vu){
   446  			i = (int)(vu % (uvlong)base);
   447  			vu /= (uvlong)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, (size_t)bytelen);
   457  			}
   458  			*p-- = conv[i];
   459  			n++;
   460  		}
   461  	}else{
   462  		while(u){
   463  			i = (int)(u % (ulong)base);
   464  			u /= (ulong)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, (size_t)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  	for(w = f->prec; n < w && p > buf+3; n++){
   496  		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
   497  			n += len;
   498  			excess += bytelen - len;
   499  			p -= bytelen;
   500  			memmove(p+1, thousands, (size_t)bytelen);
   501  		}
   502  		*p-- = '0';
   503  	}
   504  	if(neg || (fl & (FmtSign|FmtSpace)))
   505  		n++;
   506  	if(fl & FmtSharp){
   507  		if(base == 16)
   508  			n += 2;
   509  		else if(base == 8){
   510  			if(p[1] == '0')
   511  				fl &= ~(ulong)FmtSharp;
   512  			else
   513  				n++;
   514  		}
   515  	}
   516  	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
   517  		w = 0;
   518  		if(fl & FmtWidth)
   519  			w = f->width;
   520  		for(; n < w && p > buf+3; n++){
   521  			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
   522  				n += len;
   523  				excess += bytelen - len;
   524  				p -= bytelen;
   525  				memmove(p+1, thousands, (size_t)bytelen);
   526  			}
   527  			*p-- = '0';
   528  		}
   529  		f->flags &= ~(ulong)FmtWidth;
   530  	}
   531  	if(fl & FmtSharp){
   532  		if(base == 16)
   533  			*p-- = (char)f->r;
   534  		if(base == 16 || base == 8)
   535  			*p-- = '0';
   536  	}
   537  	if(neg)
   538  		*p-- = '-';
   539  	else if(fl & FmtSign)
   540  		*p-- = '+';
   541  	else if(fl & FmtSpace)
   542  		*p-- = ' ';
   543  	f->flags &= ~(ulong)FmtPrec;
   544  	return __fmtcpy(f, p + 1, n, n + excess);
   545  }
   546  
   547  int
   548  __countfmt(Fmt *f)
   549  {
   550  	void *p;
   551  	ulong fl;
   552  
   553  	fl = f->flags;
   554  	p = va_arg(f->args, void*);
   555  	if(fl & FmtVLong){
   556  		*(vlong*)p = f->nfmt;
   557  	}else if(fl & FmtLong){
   558  		*(long*)p = f->nfmt;
   559  	}else if(fl & FmtByte){
   560  		*(char*)p = (char)f->nfmt;
   561  	}else if(fl & FmtShort){
   562  		*(short*)p = (short)f->nfmt;
   563  	}else{
   564  		*(int*)p = f->nfmt;
   565  	}
   566  	return 0;
   567  }
   568  
   569  int
   570  __flagfmt(Fmt *f)
   571  {
   572  	switch(f->r){
   573  	case ',':
   574  		f->flags |= FmtComma;
   575  		break;
   576  	case '-':
   577  		f->flags |= FmtLeft;
   578  		break;
   579  	case '+':
   580  		f->flags |= FmtSign;
   581  		break;
   582  	case '#':
   583  		f->flags |= FmtSharp;
   584  		break;
   585  	case '\'':
   586  		f->flags |= FmtApost;
   587  		break;
   588  	case ' ':
   589  		f->flags |= FmtSpace;
   590  		break;
   591  	case 'u':
   592  		f->flags |= FmtUnsigned;
   593  		break;
   594  	case 'h':
   595  		if(f->flags & FmtShort)
   596  			f->flags |= FmtByte;
   597  		f->flags |= FmtShort;
   598  		break;
   599  	case 'L':
   600  		f->flags |= FmtLDouble;
   601  		break;
   602  	case 'l':
   603  		if(f->flags & FmtLong)
   604  			f->flags |= FmtVLong;
   605  		f->flags |= FmtLong;
   606  		break;
   607  	}
   608  	return 1;
   609  }
   610  
   611  /* default error format */
   612  int
   613  __badfmt(Fmt *f)
   614  {
   615  	char x[2+UTFmax];
   616  	int n;
   617  
   618  	x[0] = '%';
   619  	n = 1 + runetochar(x+1, &f->r);
   620  	x[n++] = '%';
   621  	f->prec = n;
   622  	__fmtcpy(f, (const void*)x, n, n);
   623  	return 0;
   624  }