POK(kernelpart)
/home/jaouen/pok_official/pok/trunk/kernel/libc/printf.c
Go to the documentation of this file.
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 #if defined (POK_NEEDS_DEBUG) || defined (POK_NEEDS_INSTRUMENTATION) || defined (POK_NEEDS_COVERAGE_INFOS)
00019 
00020 #include <types.h>
00021 #include <libc.h>
00022 #include <stdarg.h>
00023 #include <bsp.h>
00024 
00025 static const char digits[] = "0123456789abcdef";
00026 
00027 #define INT_UNSIGNED    1
00028 #define INT_SIGNED      2
00029 
00030 #define BASE_HEX        16
00031 #define BASE_OCT        8
00032 
00033 #define MY_BUF_SIZE     8192
00034 
00035 /*
00036  * some types
00037  */
00038 
00039 struct          s_file
00040 {
00041    char         buff[MY_BUF_SIZE];
00042    size_t       pos;
00043 };
00044 
00045 union           u_arg
00046 {
00047    unsigned long        value;
00048    unsigned int uint;
00049    int            sint;
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_cons_write (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 
00084    if (file->pos == MY_BUF_SIZE)
00085    {
00086       my_fflush(file);
00087    }
00088 }
00089 
00090 static void     close_buffered_output(struct s_file *file)
00091 {
00092    my_fflush(file);
00093 }
00094 
00095 /*
00096  * formatting functions
00097  */
00098 
00099 static int      conv(unsigned int n, int base, int dig[])
00100 {
00101    int i;
00102 
00103    i = 0;
00104 
00105    while (n)
00106    {
00107       dig[i] = n % base;
00108       ++i;
00109       n /= base;
00110    }
00111    return i - 1;
00112 }
00113 
00114 static int      my_printnbr_base (unsigned int   n,
00115                               const char     base[],
00116                               int            card,
00117                               struct s_file  *file)
00118 {
00119    int   digits[96];
00120    int   i;
00121    int   count;
00122 
00123    if (n == 0)
00124    {
00125       my_putc ('0', file);
00126       return 1;
00127    }
00128 
00129    count = i = conv (n, card, digits);
00130 
00131    for (; i >= 0; --i)
00132    {
00133       my_putc(base[digits[i]], file);
00134    }
00135 
00136    return count;
00137 }
00138 
00139 static int      print_int (union u_arg* value,
00140                        struct s_file* file,
00141                        int flags)
00142 {
00143    int sh;
00144 
00145    sh = 0;
00146 
00147    if (value->sint == 0)
00148    {
00149       my_putc('0', file);
00150       return 1;
00151    }
00152 
00153    if (flags == INT_SIGNED)
00154    {
00155       if (value->sint < 0)
00156       {
00157          my_putc('-', file);
00158          value->uint = -value->sint;
00159          sh = 1;
00160       }
00161       else
00162       {
00163          value->uint = value->sint;
00164       }
00165    }
00166 
00167    return my_printnbr_base (value->uint, digits, 10, file) + sh;
00168 }
00169 
00170 static int      print_str (union u_arg* value, struct s_file* file, int flags)
00171 {
00172    int   count;
00173    char*        s;
00174 
00175    count = 0;
00176    s     = value->ptr;
00177 
00178    flags = flags;
00179 
00180    for (; *s; ++count, ++s)
00181    {
00182       my_putc(*s, file);
00183    }
00184 
00185    return count;
00186 }
00187 
00188 static int      print_char(union u_arg* value, struct s_file* file, int flags)
00189 {
00190    char c;
00191 
00192    flags = flags;
00193    c     = value->sint;
00194 
00195    my_putc (c, file);
00196 
00197    return 1;
00198 }
00199 
00200 static int      print_base(union u_arg* value, struct s_file* file, int flags)
00201 {
00202    return my_printnbr_base (value->uint, digits, flags, file);
00203 }
00204 
00205 static const struct s_format formats[] =
00206 {
00207    { 'd', print_int, INT_SIGNED },
00208    { 'i', print_int, INT_SIGNED },
00209    { 'u', print_int, INT_UNSIGNED },
00210    { 's', print_str, 0 },
00211    { 'c', print_char, 0 },
00212    { 'o', print_base, BASE_OCT },
00213    { 'x', print_base, BASE_HEX },
00214    { 0, NULL, 0 }
00215 };
00216 
00217 static int special_char (char fmt,
00218                          union u_arg* value,
00219                          struct s_file* file)
00220 {
00221    int i;
00222 
00223    for (i = 0; formats[i].fun; ++i)
00224    {
00225       if (formats[i].ch == fmt)
00226       {
00227          break;
00228       }
00229    }
00230 
00231    if (formats[i].fun)
00232    {
00233       return formats[i].fun(value, file, formats[i].flags);
00234    }
00235    else
00236    {
00237       if (fmt != '%')
00238       {
00239          my_putc('%', file);
00240       }
00241 
00242       my_putc(fmt, file);
00243 
00244       return 1 + (fmt != '%');
00245    }
00246 }
00247 
00248 /*
00249  * finally, printf
00250  */
00251 
00252 int vprintf (const char* format, va_list args)
00253 {
00254    struct s_file* file;
00255    union u_arg     arg;
00256    int            count;
00257 
00258    count = 0;
00259 
00260    for (file = init_buffered_output();
00261          *format;
00262          format += (*format == '%' ? 2 : 1))
00263    {
00264       if (*format == '%')
00265       {
00266          if (!*(format + 1))
00267          {
00268             break;
00269          }
00270 
00271          if (*(format + 1) != '%')
00272          {
00273             arg.value = va_arg(args, unsigned long);
00274          }
00275 
00276          count += special_char(*(format + 1), &arg, file);
00277       }
00278       else
00279       {
00280          my_putc(*format, file);
00281          ++count;
00282       }
00283    }
00284 
00285    close_buffered_output(file);
00286    return count;
00287 }
00288 
00289 int printf (const char *format, ...)
00290 {
00291    int      res;
00292    va_list  args;
00293 
00294    va_start (args, format);
00295    res = vprintf (format, args);
00296    va_end (args);
00297 
00298    return res;
00299 }
00300 
00301 #endif