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 'd': 180 switch (nlong) { 181 case 0: 182 print_int(&s, va_arg(va, int), 10, props); 183 break; 184 case 1: 185 print_int(&s, va_arg(va, long), 10, props); 186 break; 187 default: 188 print_int(&s, va_arg(va, long long), 10, props); 189 break; 190 } 191 break; 192 case 'u': 193 switch (nlong) { 194 case 0: 195 print_unsigned(&s, va_arg(va, unsigned), 10, props); 196 break; 197 case 1: 198 print_unsigned(&s, va_arg(va, unsigned long), 10, props); 199 break; 200 default: 201 print_unsigned(&s, va_arg(va, unsigned long long), 10, props); 202 break; 203 } 204 break; 205 case 'x': 206 switch (nlong) { 207 case 0: 208 print_unsigned(&s, va_arg(va, unsigned), 16, props); 209 break; 210 case 1: 211 print_unsigned(&s, va_arg(va, unsigned long), 16, props); 212 break; 213 default: 214 print_unsigned(&s, va_arg(va, unsigned long long), 16, props); 215 break; 216 } 217 break; 218 case 'p': 219 print_str(&s, "0x", props); 220 print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); 221 break; 222 case 's': 223 print_str(&s, va_arg(va, const char *), props); 224 break; 225 default: 226 addchar(&s, f); 227 break; 228 } 229 } 230 *s.buffer = 0; 231 ++s.added; 232 return s.added; 233 } 234 235 236 int snprintf(char *buf, int size, const char *fmt, ...) 237 { 238 va_list va; 239 int r; 240 241 va_start(va, fmt); 242 r = vsnprintf(buf, size, fmt, va); 243 va_end(va); 244 return r; 245 } 246 247 int vprintf(const char *fmt, va_list va) 248 { 249 char buf[BUFSZ]; 250 int r; 251 252 r = vsnprintf(buf, sizeof(buf), fmt, va); 253 puts(buf); 254 return r; 255 } 256 257 int printf(const char *fmt, ...) 258 { 259 va_list va; 260 char buf[BUFSZ]; 261 int r; 262 263 va_start(va, fmt); 264 r = vsnprintf(buf, sizeof buf, fmt, va); 265 va_end(va); 266 puts(buf); 267 return r; 268 } 269