The Go Programming Language

Text file src/lib9/fmt/fmt.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	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 + r - '0';
   191					if(isrunes){
   192						r = *(Rune*)fmt;
   193						fmt = (Rune*)fmt + 1;
   194					}else{
   195						r = *(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 &= ~FmtPrec;
   221						f->prec = 0;
   222						continue;
   223					}
   224					i = -i;
   225					f->flags |= FmtLeft;
   226				}
   227				goto numflag;
   228			}
   229			n = (*fmtfmt(r))(f);
   230			if(n < 0)
   231				return nil;
   232			if(n == 0)
   233				return fmt;
   234		}
   235	}

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