kern

annotate src/klibc/stdio.c @ 55:88a6c4e192f9

Fixed most important task switching bugs. Now it seems that I can switch in and out of user space reliably.
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 15 Aug 2011 04:03:39 +0300
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