kern

annotate src/klibc/stdio.c @ 80:4db99a52863e

fixed the "endianess" of the text messages in the ATA identify info block. this is the first time I've seen wrong byteorder in ascii text, the ATA committee should be commended.
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 Dec 2011 13:35:39 +0200
parents 86781ef20689
children
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@5 2 #include <string.h>
nuclear@5 3 #include <ctype.h>
nuclear@5 4
nuclear@5 5 static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
nuclear@5 6 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
nuclear@1 7
nuclear@1 8 /* putchar is defined in term.c */
nuclear@1 9
nuclear@1 10 int puts(const char *s)
nuclear@1 11 {
nuclear@1 12 while(*s) {
nuclear@1 13 putchar(*s++);
nuclear@1 14 }
nuclear@2 15 putchar('\n');
nuclear@1 16 return 0;
nuclear@1 17 }
nuclear@5 18
nuclear@5 19 /* -- printf and friends -- */
nuclear@5 20
nuclear@5 21 static char *convc = "dioxXucsfeEgGpn%";
nuclear@5 22
nuclear@5 23 #define IS_CONV(c) strchr(convc, c)
nuclear@5 24
nuclear@5 25 int printf(const char *fmt, ...)
nuclear@5 26 {
nuclear@5 27 int res;
nuclear@5 28 va_list ap;
nuclear@5 29
nuclear@5 30 va_start(ap, fmt);
nuclear@5 31 res = intern_printf(0, 0, fmt, ap);
nuclear@5 32 va_end(ap);
nuclear@5 33 return res;
nuclear@5 34 }
nuclear@5 35
nuclear@5 36 int vprintf(const char *fmt, va_list ap)
nuclear@5 37 {
nuclear@5 38 return intern_printf(0, 0, fmt, ap);
nuclear@5 39 }
nuclear@5 40
nuclear@5 41 int sprintf(char *buf, const char *fmt, ...)
nuclear@5 42 {
nuclear@5 43 int res;
nuclear@5 44 va_list ap;
nuclear@5 45
nuclear@5 46 va_start(ap, fmt);
nuclear@5 47 res = intern_printf(buf, 0, fmt, ap);
nuclear@5 48 va_end(ap);
nuclear@5 49 return res;
nuclear@5 50 }
nuclear@5 51
nuclear@5 52 int vsprintf(char *buf, const char *fmt, va_list ap)
nuclear@5 53 {
nuclear@5 54 return intern_printf(buf, 0, fmt, ap);
nuclear@5 55 }
nuclear@5 56
nuclear@5 57 int snprintf(char *buf, size_t sz, const char *fmt, ...)
nuclear@5 58 {
nuclear@5 59 int res;
nuclear@5 60 va_list ap;
nuclear@5 61
nuclear@5 62 va_start(ap, fmt);
nuclear@5 63 res = intern_printf(buf, sz, fmt, ap);
nuclear@5 64 va_end(ap);
nuclear@5 65 return res;
nuclear@5 66 }
nuclear@5 67
nuclear@5 68 int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
nuclear@5 69 {
nuclear@5 70 return intern_printf(buf, sz, fmt, ap);
nuclear@5 71 }
nuclear@5 72
nuclear@5 73
nuclear@5 74 /* intern_printf provides all the functionality needed by all the printf
nuclear@5 75 * variants.
nuclear@5 76 * - buf: optional buffer onto which the formatted results are written. If null
nuclear@5 77 * then the output goes to the terminal through putchar calls. This is used
nuclear@5 78 * by the (v)sprintf variants which write to an array of char.
nuclear@5 79 * - sz: optional maximum size of the output, 0 means unlimited. This is used
nuclear@5 80 * by the (v)snprintf variants to avoid buffer overflows.
nuclear@5 81 * The rest are obvious, format string and variable argument list.
nuclear@5 82 */
nuclear@5 83
nuclear@5 84 #define BUF(x) ((x) ? (x) + cnum : (x))
nuclear@5 85 #define SZ(x) ((x) ? (x) - cnum : (x))
nuclear@5 86
nuclear@5 87 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
nuclear@5 88 {
nuclear@5 89 char conv_buf[32];
nuclear@5 90 char *str;
nuclear@5 91 int i, slen;
nuclear@5 92 const char *fstart = 0;
nuclear@5 93
nuclear@5 94 /* state */
nuclear@5 95 int cnum = 0;
nuclear@5 96 int base = 10;
nuclear@5 97 int alt = 0;
nuclear@5 98 int fwidth = 0;
nuclear@5 99 int padc = ' ';
nuclear@5 100 int sign = 0;
nuclear@5 101 int left_align = 0; /* not implemented yet */
nuclear@5 102 int hex_caps = 0;
nuclear@5 103 int unsig = 0;
nuclear@5 104
nuclear@5 105 while(*fmt) {
nuclear@5 106 if(*fmt == '%') {
nuclear@5 107 fstart = fmt++;
nuclear@5 108 continue;
nuclear@5 109 }
nuclear@5 110
nuclear@5 111 if(fstart) {
nuclear@5 112 if(IS_CONV(*fmt)) {
nuclear@5 113 switch(*fmt) {
nuclear@5 114 case 'X':
nuclear@5 115 hex_caps = 1;
nuclear@5 116
nuclear@5 117 case 'x':
nuclear@5 118 case 'p':
nuclear@5 119 base = 16;
nuclear@5 120
nuclear@5 121 if(alt) {
nuclear@5 122 bwrite(BUF(buf), SZ(sz), "0x", 2);
nuclear@5 123 }
nuclear@5 124
nuclear@5 125 case 'u':
nuclear@5 126 unsig = 1;
nuclear@5 127
nuclear@5 128 if(0) {
nuclear@5 129 case 'o':
nuclear@5 130 base = 8;
nuclear@5 131
nuclear@5 132 if(alt) {
nuclear@5 133 bwrite(BUF(buf), SZ(sz), "0", 1);
nuclear@5 134 }
nuclear@5 135 }
nuclear@5 136
nuclear@5 137 case 'd':
nuclear@5 138 case 'i':
nuclear@5 139 if(unsig) {
nuclear@5 140 utoa(va_arg(ap, unsigned int), conv_buf, base);
nuclear@5 141 } else {
nuclear@5 142 itoa(va_arg(ap, int), conv_buf, base);
nuclear@5 143 }
nuclear@5 144 if(hex_caps) {
nuclear@5 145 for(i=0; conv_buf[i]; i++) {
nuclear@5 146 conv_buf[i] = toupper(conv_buf[i]);
nuclear@5 147 }
nuclear@5 148 }
nuclear@5 149
nuclear@5 150 slen = strlen(conv_buf);
nuclear@5 151 for(i=slen; i<fwidth; i++) {
nuclear@5 152 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
nuclear@5 153 cnum++;
nuclear@5 154 }
nuclear@5 155
nuclear@5 156 bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
nuclear@5 157 cnum += slen;
nuclear@5 158 break;
nuclear@5 159
nuclear@5 160 case 'c':
nuclear@5 161 {
nuclear@5 162 char c = va_arg(ap, int);
nuclear@5 163 bwrite(BUF(buf), SZ(sz), &c, 1);
nuclear@5 164 cnum++;
nuclear@5 165 }
nuclear@5 166 break;
nuclear@5 167
nuclear@5 168 case 's':
nuclear@5 169 str = va_arg(ap, char*);
nuclear@5 170 slen = strlen(str);
nuclear@5 171
nuclear@5 172 for(i=slen; i<fwidth; i++) {
nuclear@5 173 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
nuclear@5 174 cnum++;
nuclear@5 175 }
nuclear@5 176 bwrite(BUF(buf), SZ(sz), str, slen);
nuclear@5 177 cnum += slen;
nuclear@5 178 break;
nuclear@5 179
nuclear@5 180 case 'n':
nuclear@5 181 *va_arg(ap, int*) = cnum;
nuclear@5 182 break;
nuclear@5 183
nuclear@5 184 default:
nuclear@5 185 break;
nuclear@5 186 }
nuclear@5 187
nuclear@5 188 /* restore default conversion state */
nuclear@5 189 base = 10;
nuclear@5 190 alt = 0;
nuclear@5 191 fwidth = 0;
nuclear@5 192 padc = ' ';
nuclear@5 193 hex_caps = 0;
nuclear@5 194
nuclear@5 195 fstart = 0;
nuclear@5 196 fmt++;
nuclear@5 197 } else {
nuclear@5 198 switch(*fmt) {
nuclear@5 199 case '#':
nuclear@5 200 alt = 1;
nuclear@5 201 break;
nuclear@5 202
nuclear@5 203 case '+':
nuclear@5 204 sign = 1;
nuclear@5 205 break;
nuclear@5 206
nuclear@5 207 case '-':
nuclear@5 208 left_align = 1;
nuclear@5 209 break;
nuclear@5 210
nuclear@5 211 case 'l':
nuclear@5 212 case 'L':
nuclear@5 213 break;
nuclear@5 214
nuclear@5 215 case '0':
nuclear@5 216 padc = '0';
nuclear@5 217 break;
nuclear@5 218
nuclear@5 219 default:
nuclear@5 220 if(isdigit(*fmt)) {
nuclear@5 221 const char *fw = fmt;
nuclear@5 222 while(*fmt && isdigit(*fmt)) fmt++;
nuclear@5 223
nuclear@5 224 fwidth = atoi(fw);
nuclear@5 225 continue;
nuclear@5 226 }
nuclear@5 227 }
nuclear@5 228 fmt++;
nuclear@5 229 }
nuclear@5 230 } else {
nuclear@5 231 bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
nuclear@5 232 cnum++;
nuclear@5 233 }
nuclear@5 234 }
nuclear@5 235
nuclear@5 236 return 0;
nuclear@5 237 }
nuclear@5 238
nuclear@5 239
nuclear@5 240 /* bwrite is called by intern_printf to transparently handle writing into a
nuclear@5 241 * buffer (if buf is non-null) or to the terminal (if buf is null).
nuclear@5 242 */
nuclear@5 243 static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
nuclear@5 244 {
nuclear@5 245 if(buf) {
nuclear@5 246 if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
nuclear@5 247 memcpy(buf, str, sz);
nuclear@5 248
nuclear@5 249 buf[sz] = 0;
nuclear@5 250 } else {
nuclear@5 251 int i;
nuclear@5 252 for(i=0; i<sz; i++) {
nuclear@5 253 putchar(*str++);
nuclear@5 254 }
nuclear@5 255 }
nuclear@5 256 }
nuclear@5 257