POK
|
00001 /* 00002 * POK header 00003 * 00004 * The following file is a part of the POK project. Any modification should 00005 * made according to the POK licence. You CANNOT use this file or a part of 00006 * this file is this part of a file for your own project 00007 * 00008 * For more information on the POK licence, please see our LICENCE FILE 00009 * 00010 * Please follow the coding guidelines described in doc/CODING_GUIDELINES 00011 * 00012 * Copyright (c) 2007-2009 POK team 00013 * 00014 * Created by julien on Thu Jan 15 23:34:13 2009 00015 */ 00016 00017 00018 #include <types.h> 00019 #include <core/syscall.h> 00020 #include <libc/stdio.h> 00021 00022 static const char digits[] = "0123456789abcdef"; 00023 00024 #define INT_UNSIGNED 1 00025 #define INT_SIGNED 2 00026 #define FLOAT_SIGNED 3 00027 #define DOUBLE_PRECISION (6) 00028 00029 #define BASE_HEX 16 00030 #define BASE_OCT 8 00031 00032 #define MY_BUF_SIZE 128 00033 00034 /* 00035 * some types 00036 */ 00037 00038 struct s_file 00039 { 00040 char buff[MY_BUF_SIZE]; 00041 size_t pos; 00042 }; 00043 00044 union u_arg 00045 { 00046 uint32_t value; 00047 uint32_t uint; 00048 int sint; 00049 double vdouble; 00050 void *ptr; 00051 }; 00052 00053 typedef int (*t_fmtfun)(union u_arg *arg, struct s_file *file, int flags); 00054 00055 struct s_format 00056 { 00057 char ch; 00058 t_fmtfun fun; 00059 int flags; 00060 }; 00061 00062 /* 00063 * buffered I/O 00064 */ 00065 00066 static void my_fflush(struct s_file *file) 00067 { 00068 pok_syscall2 (POK_SYSCALL_CONSWRITE, (uint32_t)file->buff, file->pos); 00069 file->pos = 0; 00070 } 00071 00072 static struct s_file* init_buffered_output(void) 00073 { 00074 static struct s_file res; 00075 00076 res.pos = 0; 00077 return &res; 00078 } 00079 00080 static void my_putc(char c, struct s_file *file) 00081 { 00082 file->buff[file->pos++] = c; 00083 if (file->pos == MY_BUF_SIZE) 00084 my_fflush(file); 00085 } 00086 00087 static void close_buffered_output(struct s_file *file) 00088 { 00089 my_fflush(file); 00090 } 00091 00092 /* 00093 * formatting functions 00094 */ 00095 00096 static int conv (uint32_t n, int base, int dig[]) 00097 { 00098 int i = 0; 00099 00100 while (n) 00101 { 00102 dig[i] = n % base; 00103 ++i; 00104 n /= base; 00105 } 00106 return i - 1; 00107 } 00108 00109 static int my_printnbr_base (uint32_t n, 00110 const char base[], 00111 int card, 00112 struct s_file *file) 00113 { 00114 int digits[96]; 00115 int i; 00116 int count; 00117 00118 if (n == 0) 00119 { 00120 my_putc('0', file); 00121 return 1; 00122 } 00123 count = i = conv(n, card, digits); 00124 for (; i >= 0; --i) 00125 { 00126 my_putc(base[digits[i]], file); 00127 } 00128 return count; 00129 } 00130 00131 static int print_int (union u_arg* value, struct s_file* file, int flags) 00132 { 00133 int sh = 0; 00134 00135 if (value->sint == 0) 00136 { 00137 my_putc('0', file); 00138 return 1; 00139 } 00140 if (flags == INT_SIGNED) 00141 { 00142 if (value->sint < 0) 00143 { 00144 my_putc('-', file); 00145 value->uint = -value->sint; 00146 sh = 1; 00147 } 00148 else 00149 { 00150 value->uint = value->sint; 00151 } 00152 } 00153 return my_printnbr_base(value->uint, digits, 10, file) + sh; 00154 } 00155 00156 00157 static int print_float (union u_arg* value, struct s_file* file, int flags) 00158 { 00159 int floor = value->vdouble; 00160 uint32_t fractional = 0; 00161 int res = 0; 00162 int precision = 0; 00163 int decimal = 10; 00164 00165 res += my_printnbr_base(floor, digits, 10, file); 00166 my_putc('.', file); 00167 (void)flags; 00168 00169 while (precision < DOUBLE_PRECISION) 00170 { 00171 fractional = (value->vdouble - floor) * decimal; 00172 fractional %= 10; 00173 res += my_printnbr_base(fractional, digits, 10, file); 00174 decimal *= 10; 00175 ++precision; 00176 } 00177 00178 return res; 00179 } 00180 00181 00182 static int print_str (union u_arg* value, struct s_file* file, int flags) 00183 { 00184 int count = 0; 00185 char* s = value->ptr; 00186 00187 flags = flags; 00188 for (; *s; ++count, ++s) 00189 my_putc(*s, file); 00190 return count; 00191 } 00192 00193 static int print_char (union u_arg* value, struct s_file* file, int flags) 00194 { 00195 char c; 00196 00197 flags = flags; 00198 c = value->sint; 00199 my_putc(c, file); 00200 return 1; 00201 } 00202 00203 static int print_base(union u_arg* value, struct s_file* file, int flags) 00204 { 00205 return my_printnbr_base(value->uint, digits, flags, file); 00206 } 00207 00208 static const struct s_format formats[] = 00209 { 00210 { 'd', print_int, INT_SIGNED }, 00211 { 'f', print_float, FLOAT_SIGNED }, 00212 { 'i', print_int, INT_SIGNED }, 00213 { 'u', print_int, INT_UNSIGNED }, 00214 { 's', print_str, 0 }, 00215 { 'c', print_char, 0 }, 00216 { 'o', print_base, BASE_OCT }, 00217 { 'x', print_base, BASE_HEX }, 00218 { 0, NULL, 0 } 00219 }; 00220 00221 static int special_char(char fmt, union u_arg* value, struct s_file* file) 00222 { 00223 int i = 0; 00224 00225 for (i = 0; formats[i].fun; ++i) 00226 { 00227 if (formats[i].ch == fmt) 00228 break; 00229 } 00230 00231 if (formats[i].fun) 00232 { 00233 //printf("special_char: %i\n", value->vfloat); 00234 return formats[i].fun(value, file, formats[i].flags); 00235 } 00236 else 00237 { 00238 if (fmt != '%') 00239 { 00240 my_putc('%', file); 00241 } 00242 00243 my_putc(fmt, file); 00244 00245 return 1 + (fmt != '%'); 00246 } 00247 } 00248 00249 /* 00250 * finally, printf 00251 */ 00252 00253 int vprintf(const char* format, va_list args) 00254 { 00255 struct s_file* file; 00256 union u_arg arg; 00257 int count; 00258 00259 count = 0; 00260 arg.uint = 0; 00261 00262 for (file = init_buffered_output(); *format; format += (*format == '%' ? 2 : 1)) 00263 { 00264 if (*format == '%') 00265 { 00266 if (!*(format + 1)) 00267 { 00268 break; 00269 } 00270 if (*(format + 1) != '%') 00271 { 00272 switch (*(format + 1)) 00273 { 00274 case 'f': 00275 arg.vdouble = va_arg (args, double); 00276 break; 00277 00278 default: 00279 arg.value = va_arg (args, uint32_t); 00280 break; 00281 } 00282 } 00283 count += special_char(*(format + 1), &arg, file); 00284 } 00285 else 00286 { 00287 my_putc(*format, file); 00288 ++count; 00289 } 00290 } 00291 00292 close_buffered_output(file); 00293 return count; 00294 } 00295 00296 int printf(const char *format, ...) 00297 { 00298 int res; 00299 va_list args; 00300 00301 va_start(args, format); 00302 res = vprintf (format, args); 00303 va_end(args); 00304 return res; 00305 } 00306