1 #include "all.h" 2 3 #define PTR sizeof(char*) 4 #define SHORT sizeof(int) 5 #define INT sizeof(int) 6 #define LONG sizeof(long) 7 #define IDIGIT 30 8 #define MAXCON 30 9 10 static int convcount = { 10 }; 11 12 #define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c 13 14 static int noconv(Op*); 15 static int cconv(Op*); 16 static int dconv(Op*); 17 static int hconv(Op*); 18 static int lconv(Op*); 19 static int oconv(Op*); 20 static int sconv(Op*); 21 static int uconv(Op*); 22 static int xconv(Op*); 23 static int percent(Op*); 24 25 static 26 int (*fmtconv[MAXCON])(Op*) = 27 { 28 noconv, 29 cconv, dconv, hconv, lconv, 30 oconv, sconv, uconv, xconv, 31 percent, 32 }; 33 static 34 char fmtindex[128] = 35 { 36 ['c'] 1, 37 ['d'] 2, 38 ['h'] 3, 39 ['l'] 4, 40 ['o'] 5, 41 ['s'] 6, 42 ['u'] 7, 43 ['x'] 8, 44 ['%'] 9, 45 }; 46 47 int 48 fmtinstall(char c, int (*f)(Op*)) 49 { 50 51 c &= 0177; 52 if(fmtindex[c] == 0) { 53 if(convcount >= MAXCON) 54 return 1; 55 fmtindex[c] = convcount++; 56 } 57 fmtconv[fmtindex[c]] = f; 58 return 0; 59 } 60 61 char* 62 doprint(char *p, char *ep, char *fmt, void *argp) 63 { 64 int sf1, c; 65 Op o; 66 67 o.p = p; 68 o.ep = ep; 69 o.argp = argp; 70 71 loop: 72 c = *fmt++; 73 if(c != '%') { 74 if(c == 0) { 75 if(o.p < o.ep) 76 *o.p = 0; 77 return o.p; 78 } 79 PUT(&o, c); 80 goto loop; 81 } 82 o.f1 = 0; 83 o.f2 = -1; 84 o.f3 = 0; 85 c = *fmt++; 86 sf1 = 0; 87 if(c == '-') { 88 sf1 = 1; 89 c = *fmt++; 90 } 91 while(c >= '0' && c <= '9') { 92 o.f1 = o.f1*10 + c-'0'; 93 c = *fmt++; 94 } 95 if(sf1) 96 o.f1 = -o.f1; 97 if(c != '.') 98 goto l1; 99 c = *fmt++; 100 while(c >= '0' && c <= '9') { 101 if(o.f2 < 0) 102 o.f2 = 0; 103 o.f2 = o.f2*10 + c-'0'; 104 c = *fmt++; 105 } 106 l1: 107 if(c == 0) 108 fmt--; 109 c = (*fmtconv[fmtindex[c&0177]])(&o); 110 if(c < 0) { 111 o.f3 |= -c; 112 c = *fmt++; 113 goto l1; 114 } 115 o.argp = (char*)o.argp + c; 116 goto loop; 117 } 118 119 int 120 numbconv(Op *op, int base) 121 { 122 char b[IDIGIT]; 123 int i, f, n, r; 124 long v; 125 short h; 126 127 f = 0; 128 switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { 129 case FLONG: 130 v = *(long*)op->argp; 131 r = LONG; 132 break; 133 134 case FUNSIGN|FLONG: 135 v = *(ulong*)op->argp; 136 r = LONG; 137 break; 138 139 case FSHORT: 140 h = *(int*)op->argp; 141 v = h; 142 r = SHORT; 143 break; 144 145 case FUNSIGN|FSHORT: 146 h = *(int*)op->argp; 147 v = (ushort)h; 148 r = SHORT; 149 break; 150 151 default: 152 v = *(int*)op->argp; 153 r = INT; 154 break; 155 156 case FUNSIGN: 157 v = *(unsigned*)op->argp; 158 r = INT; 159 break; 160 } 161 if(!(op->f3 & FUNSIGN) && v < 0) { 162 v = -v; 163 f = 1; 164 } 165 b[IDIGIT-1] = 0; 166 for(i = IDIGIT-2;; i--) { 167 n = (ulong)v % base; 168 n += '0'; 169 if(n > '9') 170 n += 'a' - ('9'+1); 171 b[i] = n; 172 if(i < 2) 173 break; 174 v = (ulong)v / base; 175 if(op->f2 >= 0 && i >= IDIGIT-op->f2) 176 continue; 177 if(v <= 0) 178 break; 179 } 180 sout: 181 if(f) 182 b[--i] = '-'; 183 strconv(b+i, op, op->f1, -1); 184 return r; 185 } 186 187 void 188 strconv(char *o, Op *op, int f1, int f2) 189 { 190 int n, c; 191 char *p; 192 193 n = strlen(o); 194 if(f1 >= 0) 195 while(n < f1) { 196 PUT(op, ' '); 197 n++; 198 } 199 for(p=o; c = *p++;) 200 if(f2 != 0) { 201 PUT(op, c); 202 f2--; 203 } 204 if(f1 < 0) { 205 f1 = -f1; 206 while(n < f1) { 207 PUT(op, ' '); 208 n++; 209 } 210 } 211 } 212 213 static int 214 noconv(Op *op) 215 { 216 217 strconv("***", op, 0, -1); 218 return 0; 219 } 220 221 static int 222 cconv(Op *op) 223 { 224 char b[2]; 225 226 b[0] = *(int*)op->argp; 227 b[1] = 0; 228 strconv(b, op, op->f1, -1); 229 return INT; 230 } 231 232 static int 233 dconv(Op *op) 234 { 235 236 return numbconv(op, 10); 237 } 238 239 static int 240 hconv(Op *op) 241 { 242 USED(op); 243 return -FSHORT; 244 } 245 246 static int 247 lconv(Op *op) 248 { 249 USED(op); 250 return -FLONG; 251 } 252 253 static int 254 oconv(Op *op) 255 { 256 USED(op); 257 return numbconv(op, 8); 258 } 259 260 static int 261 sconv(Op *op) 262 { 263 264 strconv(*(char**)op->argp, op, op->f1, op->f2); 265 return PTR; 266 } 267 268 static int 269 uconv(Op *op) 270 { 271 USED(op); 272 return -FUNSIGN; 273 } 274 275 static int 276 xconv(Op *op) 277 { 278 279 return numbconv(op, 16); 280 } 281 282 static int 283 percent(Op *op) 284 { 285 286 PUT(op, '%'); 287 return 0; 288 } 289