POK
printf.c
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Thu Jan 15 23:34:13 2009
15  */
16 
17 
18 #include <types.h>
19 #include <core/syscall.h>
20 #include <libc/stdio.h>
21 
22 static const char digits[] = "0123456789abcdef";
23 
24 #define INT_UNSIGNED 1
25 #define INT_SIGNED 2
26 #define FLOAT_SIGNED 3
27 #define DOUBLE_PRECISION (6)
28 
29 #define BASE_HEX 16
30 #define BASE_OCT 8
31 
32 #define MY_BUF_SIZE 128
33 
34 /*
35  * some types
36  */
37 
38 struct s_file
39 {
40  char buff[MY_BUF_SIZE];
41  size_t pos;
42 };
43 
44 union u_arg
45 {
46  uint32_t value;
47  uint32_t uint;
48  int sint;
49  double vdouble;
50  void *ptr;
51 };
52 
53 typedef int (*t_fmtfun)(union u_arg *arg, struct s_file *file, int flags);
54 
55 struct s_format
56 {
57  char ch;
58  t_fmtfun fun;
59  int flags;
60 };
61 
62 /*
63  * buffered I/O
64  */
65 
66 static void my_fflush(struct s_file *file)
67 {
68  pok_syscall2 (POK_SYSCALL_CONSWRITE, (uint32_t)file->buff, file->pos);
69  file->pos = 0;
70 }
71 
72 static struct s_file* init_buffered_output(void)
73 {
74  static struct s_file res;
75 
76  res.pos = 0;
77  return &res;
78 }
79 
80 static void my_putc(char c, struct s_file *file)
81 {
82  file->buff[file->pos++] = c;
83  if (file->pos == MY_BUF_SIZE)
84  my_fflush(file);
85 }
86 
87 static void close_buffered_output(struct s_file *file)
88 {
89  my_fflush(file);
90 }
91 
92 /*
93  * formatting functions
94  */
95 
96 static int conv (uint32_t n, int base, int dig[])
97 {
98  int i = 0;
99 
100  while (n)
101  {
102  dig[i] = n % base;
103  ++i;
104  n /= base;
105  }
106  return i - 1;
107 }
108 
109 static int my_printnbr_base (uint32_t n,
110  const char base[],
111  int card,
112  struct s_file *file)
113 {
114  int digits[96];
115  int i;
116  int count;
117 
118  if (n == 0)
119  {
120  my_putc('0', file);
121  return 1;
122  }
123  count = i = conv(n, card, digits);
124  for (; i >= 0; --i)
125  {
126  my_putc(base[digits[i]], file);
127  }
128  return count;
129 }
130 
131 static int print_int (union u_arg* value, struct s_file* file, int flags)
132 {
133  int sh = 0;
134 
135  if (value->sint == 0)
136  {
137  my_putc('0', file);
138  return 1;
139  }
140  if (flags == INT_SIGNED)
141  {
142  if (value->sint < 0)
143  {
144  my_putc('-', file);
145  value->uint = -value->sint;
146  sh = 1;
147  }
148  else
149  {
150  value->uint = value->sint;
151  }
152  }
153  return my_printnbr_base(value->uint, digits, 10, file) + sh;
154 }
155 
156 
157 static int print_float (union u_arg* value, struct s_file* file, int flags)
158 {
159  int floor = value->vdouble;
160  uint32_t fractional = 0;
161  int res = 0;
162  int precision = 0;
163  int decimal = 10;
164 
165  res += my_printnbr_base(floor, digits, 10, file);
166  my_putc('.', file);
167  (void)flags;
168 
169  while (precision < DOUBLE_PRECISION)
170  {
171  fractional = (value->vdouble - floor) * decimal;
172  fractional %= 10;
173  res += my_printnbr_base(fractional, digits, 10, file);
174  decimal *= 10;
175  ++precision;
176  }
177 
178  return res;
179 }
180 
181 
182 static int print_str (union u_arg* value, struct s_file* file, int flags)
183 {
184  int count = 0;
185  char* s = value->ptr;
186 
187  flags = flags;
188  for (; *s; ++count, ++s)
189  my_putc(*s, file);
190  return count;
191 }
192 
193 static int print_char (union u_arg* value, struct s_file* file, int flags)
194 {
195  char c;
196 
197  flags = flags;
198  c = value->sint;
199  my_putc(c, file);
200  return 1;
201 }
202 
203 static int print_base(union u_arg* value, struct s_file* file, int flags)
204 {
205  return my_printnbr_base(value->uint, digits, flags, file);
206 }
207 
208 static const struct s_format formats[] =
209 {
210  { 'd', print_int, INT_SIGNED },
211  { 'f', print_float, FLOAT_SIGNED },
212  { 'i', print_int, INT_SIGNED },
213  { 'u', print_int, INT_UNSIGNED },
214  { 's', print_str, 0 },
215  { 'c', print_char, 0 },
216  { 'o', print_base, BASE_OCT },
217  { 'x', print_base, BASE_HEX },
218  { 0, NULL, 0 }
219 };
220 
221 static int special_char(char fmt, union u_arg* value, struct s_file* file)
222 {
223  int i = 0;
224 
225  for (i = 0; formats[i].fun; ++i)
226  {
227  if (formats[i].ch == fmt)
228  break;
229  }
230 
231  if (formats[i].fun)
232  {
233  //printf("special_char: %i\n", value->vfloat);
234  return formats[i].fun(value, file, formats[i].flags);
235  }
236  else
237  {
238  if (fmt != '%')
239  {
240  my_putc('%', file);
241  }
242 
243  my_putc(fmt, file);
244 
245  return 1 + (fmt != '%');
246  }
247 }
248 
249 /*
250  * finally, printf
251  */
252 
253 int vprintf(const char* format, va_list args)
254 {
255  struct s_file* file;
256  union u_arg arg;
257  int count;
258 
259  count = 0;
260  arg.uint = 0;
261 
262  for (file = init_buffered_output(); *format; format += (*format == '%' ? 2 : 1))
263  {
264  if (*format == '%')
265  {
266  if (!*(format + 1))
267  {
268  break;
269  }
270  if (*(format + 1) != '%')
271  {
272  switch (*(format + 1))
273  {
274  case 'f':
275  arg.vdouble = va_arg (args, double);
276  break;
277 
278  default:
279  arg.value = va_arg (args, uint32_t);
280  break;
281  }
282  }
283  count += special_char(*(format + 1), &arg, file);
284  }
285  else
286  {
287  my_putc(*format, file);
288  ++count;
289  }
290  }
291 
292  close_buffered_output(file);
293  return count;
294 }
295 
296 int printf(const char *format, ...)
297 {
298  int res;
299  va_list args;
300 
301  va_start(args, format);
302  res = vprintf (format, args);
303  va_end(args);
304  return res;
305 }
306