github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/lib9/fmt/fmt.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  enum
    24  {
    25  	Maxfmt = 64
    26  };
    27  
    28  typedef struct Convfmt Convfmt;
    29  struct Convfmt
    30  {
    31  	int	c;
    32  	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
    33  };
    34  
    35  static struct
    36  {
    37  	/* lock by calling __fmtlock, __fmtunlock */
    38  	int	nfmt;
    39  	Convfmt	fmt[Maxfmt];
    40  } fmtalloc;
    41  
    42  static Convfmt knownfmt[] = {
    43  	' ',	__flagfmt,
    44  	'#',	__flagfmt,
    45  	'%',	__percentfmt,
    46  	'\'',	__flagfmt,
    47  	'+',	__flagfmt,
    48  	',',	__flagfmt,
    49  	'-',	__flagfmt,
    50  	'C',	__runefmt,	/* Plan 9 addition */
    51  	'E',	__efgfmt,
    52  #ifndef PLAN9PORT
    53  	'F',	__efgfmt,	/* ANSI only */
    54  #endif
    55  	'G',	__efgfmt,
    56  #ifndef PLAN9PORT
    57  	'L',	__flagfmt,	/* ANSI only */
    58  #endif
    59  	'S',	__runesfmt,	/* Plan 9 addition */
    60  	'X',	__ifmt,
    61  	'b',	__ifmt,		/* Plan 9 addition */
    62  	'c',	__charfmt,
    63  	'd',	__ifmt,
    64  	'e',	__efgfmt,
    65  	'f',	__efgfmt,
    66  	'g',	__efgfmt,
    67  	'h',	__flagfmt,
    68  #ifndef PLAN9PORT
    69  	'i',	__ifmt,		/* ANSI only */
    70  #endif
    71  	'l',	__flagfmt,
    72  	'n',	__countfmt,
    73  	'o',	__ifmt,
    74  	'p',	__ifmt,
    75  	'r',	__errfmt,
    76  	's',	__strfmt,
    77  #ifdef PLAN9PORT
    78  	'u',	__flagfmt,
    79  #else
    80  	'u',	__ifmt,
    81  #endif
    82  	'x',	__ifmt,
    83  	0,	nil,
    84  };
    85  
    86  
    87  int	(*fmtdoquote)(int);
    88  
    89  /*
    90   * __fmtlock() must be set
    91   */
    92  static int
    93  __fmtinstall(int c, Fmts f)
    94  {
    95  	Convfmt *p, *ep;
    96  
    97  	if(c<=0 || c>=65536)
    98  		return -1;
    99  	if(!f)
   100  		f = __badfmt;
   101  
   102  	ep = &fmtalloc.fmt[fmtalloc.nfmt];
   103  	for(p=fmtalloc.fmt; p<ep; p++)
   104  		if(p->c == c)
   105  			break;
   106  
   107  	if(p == &fmtalloc.fmt[Maxfmt])
   108  		return -1;
   109  
   110  	p->fmt = f;
   111  	if(p == ep){	/* installing a new format character */
   112  		fmtalloc.nfmt++;
   113  		p->c = c;
   114  	}
   115  
   116  	return 0;
   117  }
   118  
   119  int
   120  fmtinstall(int c, int (*f)(Fmt*))
   121  {
   122  	int ret;
   123  
   124  	__fmtlock();
   125  	ret = __fmtinstall(c, f);
   126  	__fmtunlock();
   127  	return ret;
   128  }
   129  
   130  static Fmts
   131  fmtfmt(int c)
   132  {
   133  	Convfmt *p, *ep;
   134  
   135  	ep = &fmtalloc.fmt[fmtalloc.nfmt];
   136  	for(p=fmtalloc.fmt; p<ep; p++)
   137  		if(p->c == c){
   138  			while(p->fmt == nil)	/* loop until value is updated */
   139  				;
   140  			return p->fmt;
   141  		}
   142  
   143  	/* is this a predefined format char? */
   144  	__fmtlock();
   145  	for(p=knownfmt; p->c; p++)
   146  		if(p->c == c){
   147  			__fmtinstall(p->c, p->fmt);
   148  			__fmtunlock();
   149  			return p->fmt;
   150  		}
   151  	__fmtunlock();
   152  
   153  	return __badfmt;
   154  }
   155  
   156  void*
   157  __fmtdispatch(Fmt *f, void *fmt, int isrunes)
   158  {
   159  	Rune rune, r;
   160  	int i, n;
   161  
   162  	f->flags = 0;
   163  	f->width = f->prec = 0;
   164  
   165  	for(;;){
   166  		if(isrunes){
   167  			r = *(Rune*)fmt;
   168  			fmt = (Rune*)fmt + 1;
   169  		}else{
   170  			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
   171  			r = rune;
   172  		}
   173  		f->r = r;
   174  		switch(r){
   175  		case '\0':
   176  			return nil;
   177  		case '.':
   178  			f->flags |= FmtWidth|FmtPrec;
   179  			continue;
   180  		case '0':
   181  			if(!(f->flags & FmtWidth)){
   182  				f->flags |= FmtZero;
   183  				continue;
   184  			}
   185  			/* fall through */
   186  		case '1': case '2': case '3': case '4':
   187  		case '5': case '6': case '7': case '8': case '9':
   188  			i = 0;
   189  			while(r >= '0' && r <= '9'){
   190  				i = i * 10 + (int)r - '0';
   191  				if(isrunes){
   192  					r = *(Rune*)fmt;
   193  					fmt = (Rune*)fmt + 1;
   194  				}else{
   195  					r = (Rune)*(char*)fmt;
   196  					fmt = (char*)fmt + 1;
   197  				}
   198  			}
   199  			if(isrunes)
   200  				fmt = (Rune*)fmt - 1;
   201  			else
   202  				fmt = (char*)fmt - 1;
   203  		numflag:
   204  			if(f->flags & FmtWidth){
   205  				f->flags |= FmtPrec;
   206  				f->prec = i;
   207  			}else{
   208  				f->flags |= FmtWidth;
   209  				f->width = i;
   210  			}
   211  			continue;
   212  		case '*':
   213  			i = va_arg(f->args, int);
   214  			if(i < 0){
   215  				/*
   216  				 * negative precision =>
   217  				 * ignore the precision.
   218  				 */
   219  				if(f->flags & FmtPrec){
   220  					f->flags &= ~(ulong)FmtPrec;
   221  					f->prec = 0;
   222  					continue;
   223  				}
   224  				i = -i;
   225  				f->flags |= FmtLeft;
   226  			}
   227  			goto numflag;
   228  		}
   229  		n = (*fmtfmt((int)r))(f);
   230  		if(n < 0)
   231  			return nil;
   232  		if(n == 0)
   233  			return fmt;
   234  	}
   235  }