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