github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/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 }