1 /* 2 * libc printf and friends 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Library General Public License version 2. 6 */ 7 8 #include "libcflat.h" 9 10 #define BUFSZ 2000 11 12 typedef struct pstream { 13 char *buffer; 14 int remain; 15 int added; 16 } pstream_t; 17 18 typedef struct strprops { 19 char pad; 20 int npad; 21 bool alternate; 22 } strprops_t; 23 24 static void addchar(pstream_t *p, char c) 25 { 26 if (p->remain) { 27 *p->buffer++ = c; 28 --p->remain; 29 } 30 ++p->added; 31 } 32 33 static void print_str(pstream_t *p, const char *s, strprops_t props) 34 { 35 const char *s_orig = s; 36 int npad = props.npad; 37 38 if (npad > 0) { 39 npad -= strlen(s_orig); 40 while (npad > 0) { 41 addchar(p, props.pad); 42 --npad; 43 } 44 } 45 46 while (*s) 47 addchar(p, *s++); 48 49 if (npad < 0) { 50 props.pad = ' '; /* ignore '0' flag with '-' flag */ 51 npad += strlen(s_orig); 52 while (npad < 0) { 53 addchar(p, props.pad); 54 ++npad; 55 } 56 } 57 } 58 59 static char digits[16] = "0123456789abcdef"; 60 61 static void print_int(pstream_t *ps, long long n, int base, strprops_t props) 62 { 63 char buf[sizeof(long) * 3 + 2], *p = buf; 64 int s = 0, i; 65 66 if (n < 0) { 67 n = -n; 68 s = 1; 69 } 70 71 while (n) { 72 *p++ = digits[n % base]; 73 n /= base; 74 } 75 76 if (s) 77 *p++ = '-'; 78 79 if (p == buf) 80 *p++ = '0'; 81 82 for (i = 0; i < (p - buf) / 2; ++i) { 83 char tmp; 84 85 tmp = buf[i]; 86 buf[i] = p[-1 - i]; 87 p[-1 - i] = tmp; 88 } 89 90 *p = 0; 91 92 print_str(ps, buf, props); 93 } 94 95 static void print_unsigned(pstream_t *ps, unsigned long long n, int base, 96 strprops_t props) 97 { 98 char buf[sizeof(long) * 3 + 3], *p = buf; 99 int i; 100 101 while (n) { 102 *p++ = digits[n % base]; 103 n /= base; 104 } 105 106 if (p == buf) 107 *p++ = '0'; 108 else if (props.alternate && base == 16) { 109 if (props.pad == '0') { 110 addchar(ps, '0'); 111 addchar(ps, 'x'); 112 113 if (props.npad > 0) 114 props.npad = MAX(props.npad - 2, 0); 115 } else { 116 *p++ = 'x'; 117 *p++ = '0'; 118 } 119 } 120 121 for (i = 0; i < (p - buf) / 2; ++i) { 122 char tmp; 123 124 tmp = buf[i]; 125 buf[i] = p[-1 - i]; 126 p[-1 - i] = tmp; 127 } 128 129 *p = 0; 130 131 print_str(ps, buf, props); 132 } 133 134 static int fmtnum(const char **fmt) 135 { 136 const char *f = *fmt; 137 int len = 0, num; 138 139 if (*f == '-') 140 ++f, ++len; 141 142 while (*f >= '0' && *f <= '9') 143 ++f, ++len; 144 145 num = atol(*fmt); 146 *fmt += len; 147 return num; 148 } 149 150 int vsnprintf(char *buf, int size, const char *fmt, va_list va) 151 { 152 pstream_t s; 153 154 s.buffer = buf; 155 s.remain = size - 1; 156 s.added = 0; 157 while (*fmt) { 158 char f = *fmt++; 159 int nlong = 0; 160 strprops_t props; 161 memset(&props, 0, sizeof(props)); 162 props.pad = ' '; 163 164 if (f != '%') { 165 addchar(&s, f); 166 continue; 167 } 168 morefmt: 169 f = *fmt++; 170 switch (f) { 171 case '%': 172 addchar(&s, '%'); 173 break; 174 case 'c': 175 addchar(&s, va_arg(va, int)); 176 break; 177 case '\0': 178 --fmt; 179 break; 180 case '#': 181 props.alternate = true; 182 goto morefmt; 183 case '0': 184 props.pad = '0'; 185 ++fmt; 186 /* fall through */ 187 case '1' ... '9': 188 case '-': 189 --fmt; 190 props.npad = fmtnum(&fmt); 191 goto morefmt; 192 case 'l': 193 ++nlong; 194 goto morefmt; 195 case 't': 196 case 'z': 197 /* Here we only care that sizeof(size_t) == sizeof(long). 198 * On a 32-bit platform it doesn't matter that size_t is 199 * typedef'ed to int or long; va_arg will work either way. 200 * Same for ptrdiff_t (%td). 201 */ 202 nlong = 1; 203 goto morefmt; 204 case 'd': 205 switch (nlong) { 206 case 0: 207 print_int(&s, va_arg(va, int), 10, props); 208 break; 209 case 1: 210 print_int(&s, va_arg(va, long), 10, props); 211 break; 212 default: 213 print_int(&s, va_arg(va, long long), 10, props); 214 break; 215 } 216 break; 217 case 'u': 218 switch (nlong) { 219 case 0: 220 print_unsigned(&s, va_arg(va, unsigned), 10, props); 221 break; 222 case 1: 223 print_unsigned(&s, va_arg(va, unsigned long), 10, props); 224 break; 225 default: 226 print_unsigned(&s, va_arg(va, unsigned long long), 10, props); 227 break; 228 } 229 break; 230 case 'x': 231 switch (nlong) { 232 case 0: 233 print_unsigned(&s, va_arg(va, unsigned), 16, props); 234 break; 235 case 1: 236 print_unsigned(&s, va_arg(va, unsigned long), 16, props); 237 break; 238 default: 239 print_unsigned(&s, va_arg(va, unsigned long long), 16, props); 240 break; 241 } 242 break; 243 case 'p': 244 props.alternate = true; 245 print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); 246 break; 247 case 's': 248 print_str(&s, va_arg(va, const char *), props); 249 break; 250 default: 251 addchar(&s, f); 252 break; 253 } 254 } 255 *s.buffer = 0; 256 return s.added; 257 } 258 259 int snprintf(char *buf, int size, const char *fmt, ...) 260 { 261 va_list va; 262 int r; 263 264 va_start(va, fmt); 265 r = vsnprintf(buf, size, fmt, va); 266 va_end(va); 267 return r; 268 } 269 270 int vprintf(const char *fmt, va_list va) 271 { 272 char buf[BUFSZ]; 273 int r; 274 275 r = vsnprintf(buf, sizeof(buf), fmt, va); 276 puts(buf); 277 return r; 278 } 279 280 int printf(const char *fmt, ...) 281 { 282 va_list va; 283 char buf[BUFSZ]; 284 int r; 285 286 va_start(va, fmt); 287 r = vsnprintf(buf, sizeof buf, fmt, va); 288 va_end(va); 289 puts(buf); 290 return r; 291 } 292 293 void binstr(unsigned long x, char out[BINSTR_SZ]) 294 { 295 int i; 296 char *c; 297 int n; 298 299 n = sizeof(unsigned long) * 8; 300 i = 0; 301 c = &out[0]; 302 for (;;) { 303 *c++ = (x & (1ul << (n - i - 1))) ? '1' : '0'; 304 i++; 305 306 if (i == n) { 307 *c = '\0'; 308 break; 309 } 310 if (i % 4 == 0) 311 *c++ = '\''; 312 } 313 assert(c + 1 - &out[0] == BINSTR_SZ); 314 } 315 316 void print_binstr(unsigned long x) 317 { 318 char out[BINSTR_SZ]; 319 binstr(x, out); 320 printf("%s", out); 321 } 322