nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
stdarg.c
Go to the documentation of this file.
1 #include <stdint.h>
2 #include <stddef.h>
3 #include <sys/types.h>
4 #include <stdio.h>
5 #include <stdarg.h>
6 #include <ctype.h>
7 #include <string.h> /* strlen */
8 #include <errno.h>
9 
10 #include <object.h>
11 #include <list.h>
12 #include <pthread_mutex.h>
13 #include <thread.h>
14 #include <crt0.h>
15 
16 #define MAX_DIGIT_LEN 14
17 
18 struct info {
19  union {
21  struct {
22  char *ptr;
23  size_t sz;
24  int idx;
25  } buffer;
26  } out;
27 
28  enum {
29  STREAM = 0x00,
30  BUFFER = 0x01,
31  } type;
32 };
33 
34 static inline int hex_to_str(unsigned d, char *out)
35 {
36  const char *hex_table = "0123456789abcdef";
37  int ret;
38  char tmp[MAX_DIGIT_LEN];
39  int i;
40 
41  ret = 0;
42  while (d / 16) {
43  tmp[ret++] = hex_table[(d % 16)];
44  d /= 16;
45  }
46 
47  tmp[ret++] = hex_table[(d % 16)];
48 
49  i = ret;
50  while (i > 0) {
51  *out++ = tmp[--i];
52  }
53 
54  return ret;
55 }
56 
57 static inline int unsigned_to_str(unsigned d, char *out)
58 {
59  int ret;
60  char tmp[MAX_DIGIT_LEN];
61  int i;
62 
63  ret = 0;
64  while (d / 10) {
65  tmp[ret++] = (d % 10) + '0';
66  d /= 10;
67  }
68 
69  tmp[ret++] = (d % 10) + '0';
70 
71  i = ret;
72  while (i > 0) {
73  *out++ = tmp[--i];
74  }
75 
76  return ret;
77 }
78 
79 static inline int signed_to_str(int d, char *out)
80 {
81  int ret;
82  char tmp[MAX_DIGIT_LEN];
83  int i;
84  char *ptr;
85 
86  ptr = out;
87  if (d < 0) {
88  d = -d;
89  *ptr++ = '-';
90  }
91 
92  ret = 0;
93  while (d / 10) {
94  tmp[ret++] = (d % 10) + '0';
95  d /= 10;
96  }
97 
98  tmp[ret++] = (d % 10) + '0';
99 
100  i = ret;
101  while (i > 0) {
102  *ptr++ = tmp[--i];
103  }
104 
105  return (int)(ptr - out);
106 }
107 
108 static inline int fill_space(struct info *info, char ch, int len)
109 {
110  register int i;
111 
112  for (i = 0; i < len && info->out.buffer.idx < info->out.buffer.sz; i++) {
113  if (info->type == BUFFER) {
114  info->out.buffer.ptr[info->out.buffer.idx++] = ch;
115  } else {
116  fputc(ch, info->out.stream);
117  }
118  }
119 
120  return i;
121 }
122 
123 static inline int fmt_write(struct info *info, const char *ch, int len)
124 {
125  register int i;
126 
127  for (i = 0; i < len && info->out.buffer.idx < info->out.buffer.sz; i++) {
128  if (info->type == BUFFER) {
129  info->out.buffer.ptr[info->out.buffer.idx++] = *ch;
130  } else {
131  fputc(*ch, info->out.stream);
132  }
133 
134  ch++;
135  }
136 
137  return i;
138 }
139 
140 static inline int fmt_parser(struct info *info, const char *format, va_list ap)
141 {
142  int pntsz;
143  const char *fmt;
144  int len;
145  int ext_step;
146  int fill_zero;
147  char digit_buffer[MAX_DIGIT_LEN];
148  register int i;
149  char *buffer;
150  enum {
151  NORMAL,
152  ARG,
153  INFO,
154  OPT,
155  } state;
156 
157  pntsz = 0;
158  state = NORMAL;
159  for (fmt = format; *fmt; fmt++) {
160  switch (state) {
161  case ARG:
162  if (*fmt == '%') {
163  state = NORMAL;
164  buffer = (char *)fmt;
165  i = 1;
166  break;
167  }
168 
169  fill_zero = (*fmt == '.');
170  if (fill_zero) {
171  state = INFO;
172  } else if (isdigit(*fmt)) {
173  state = INFO;
174  fmt--;
175  } else {
176  state = OPT;
177  fmt--;
178  }
179 
180  continue;
181  case INFO:
182  if (isdigit(*fmt)) {
183  len = len * 10 + (*fmt - '0');
184  continue;
185  }
186 
187  state = OPT;
188  ext_step = 0;
189  fmt--;
190  continue;
191  case OPT:
192  buffer = digit_buffer;
193 
194  switch (*fmt) {
195  case 'f':
196  case 'F':
197  /* unsupported */
198  return -ENOSYS;
199  case 'l':
200  if (ext_step > 1) {
201  return -EINVAL;
202  }
203 
204  ext_step++;
205  continue;
206  case 'd':
207  case 'D':
208  i = signed_to_str(va_arg(ap, int), buffer);
209  break;
210  case 'x':
211  case 'X':
212  i = hex_to_str(va_arg(ap, int), buffer);
213  break;
214  case 'u':
215  case 'U':
216  i = unsigned_to_str(va_arg(ap, unsigned), buffer);
217  break;
218  case 'p':
219  case 'P':
220  buffer[0] = '0';
221  buffer[1] = 'x';
222  i = hex_to_str(va_arg(ap, unsigned), buffer + 2);
223  break;
224  case 's':
225  case 'S':
226  buffer = va_arg(ap, char *);
227  i = buffer ? strlen(buffer) : 0;
228  break;
229  case 'c':
230  case 'C':
231  buffer[0] = (char)va_arg(ap, int);
232  i = 1;
233  break;
234  default:
235  return -EINVAL;
236  }
237 
238  state = NORMAL;
239  pntsz += fill_space(info, (fill_zero ? '0' : ' '), len - i);
240  break;
241  case NORMAL:
242  default:
243  if (*fmt == '%') {
244  state = ARG;
245  len = 0;
246  continue;
247  }
248 
249  i = 1;
250  buffer = (char *)fmt;
251  break;
252  }
253 
254  pntsz += fmt_write(info, buffer, i);
255  }
256 
257  return pntsz;
258 }
259 
260 int vprintf(const char *format, va_list ap)
261 {
262  int ret;
263 
264  ret = vfprintf(stdout, format, ap);
265 
266  return ret;
267 }
268 
269 int vsprintf(char *str, const char *format, va_list ap)
270 {
271  int ret;
272 
273  ret = vsnprintf(str, 0x7FFFFFFF, format, ap);
274 
275  return ret;
276 }
277 
278 int vfprintf(FILE *stream, const char *format, va_list ap)
279 {
280  struct info info;
281 
282  info.out.stream = stream;
283  info.type = STREAM;
284 
285  return fmt_parser(&info, format, ap);
286 }
287 
288 int vsnprintf(char *outbuf, size_t size, const char *format, va_list ap)
289 {
290  struct info info;
291 
292  info.out.buffer.ptr = outbuf;
293  info.out.buffer.sz = size;
294  info.out.buffer.idx = 0;
295  info.type = BUFFER;
296 
297  return fmt_parser(&info, format, ap);
298 }
299 
300 /* End of a file */