uc-sdk
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xscanf.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <limits.h>
5 #include <ctype.h>
6 #include <math.h>
7 
8 /* some macros to cut this short
9  * NEXT(c); read next character
10  * PREV(c); ungetc a character
11  * VAL(a) leads to 1 if a is true and valid
12  */
13 #define NEXT(c) ((c)=xgetc(opaque),size++,incount++)
14 #define PREV(c) do{if((c)!=EOF)xungetc(opaque,(c));size--;incount--;}while(0)
15 #define VAL(a) ((a)&&size<=width)
16 
17 #ifdef NOFLOATINGPOINT
18 #undef FULL_SPECIFIERS
19 #else
20 #define FULL_SPECIFIERS
21 #endif
22 
23 extern unsigned char *__decimalpoint;
24 
25 #ifdef FULL_SPECIFIERS
26 static const unsigned char undef[3][sizeof(double)]= /* Undefined numeric values, IEEE */
27 { { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
28  { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
29  { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 } /* NaN */
30 };
31 #endif
32 
33 int vxscanf(int (*xgetc)(void *),void (*xungetc)(void*,int),void *opaque,const char *format,va_list args)
34 {
35  size_t blocks=0,incount=0;
36  int c=0;
37 
38  while(*format)
39  {
40  size_t size=0;
41 
42  if(*format=='%')
43  {
44  size_t width=ULONG_MAX;
45  char type,subtype='i',ignore=0;
46  const unsigned char *ptr=(const unsigned char *)format+1;
47  size_t i;
48 
49  if(isdigit(*ptr))
50  { width=0;
51  while(isdigit(*ptr))
52  width=width*10+(*ptr++-'0'); }
53 
54  while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*')
55  { if(*ptr=='*')
56  ignore=1;
57  else
58  subtype=*ptr;
59  ptr++;
60  }
61 
62  type=*ptr++;
63 
64  if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[')
65  { do /* ignore leading whitespace characters */
66  NEXT(c);
67  while(isspace(c));
68  size=1; } /* The first non-whitespace character is already read */
69 
70  switch(type)
71  { case 'c':
72  { unsigned char *bp;
73 
74  if(width==ULONG_MAX) /* Default */
75  width=1;
76 
77  if(!ignore)
78  bp=va_arg(args,unsigned char *);
79  else
80  bp=NULL; /* Just to get the compiler happy */
81 
82  NEXT(c); /* 'c' did not skip whitespace */
83  while(VAL(c!=EOF))
84  { if(!ignore)
85  *bp++=c;
86  NEXT(c);
87  }
88  PREV(c);
89 
90  if(!ignore&&size)
91  blocks++;
92  break;
93  }
94  case '[':
95  { unsigned char *bp;
96  unsigned char tab[32],a,b;
97  char circflag=0;
98 
99  if(*ptr=='^')
100  { circflag=1;
101  ptr++; }
102  for(i=0;i<sizeof(tab);i++)
103  tab[i]=circflag?255:0;
104  for(;;)
105  { if(!*ptr)
106  break;
107  a=b=*ptr++;
108  if(*ptr=='-'&&ptr[1]&&ptr[1]!=']')
109  { ptr++;
110  b=*ptr++; }
111  for(i=a;i<=b;i++)
112  if(circflag)
113  tab[i/8]&=~(1<<(i&7));
114  else
115  tab[i/8]|=1<<(i&7);
116  if(*ptr==']')
117  { ptr++;
118  break; }
119  }
120 
121  if(!ignore)
122  bp=va_arg(args,unsigned char *);
123  else
124  bp=NULL; /* Just to get the compiler happy */
125 
126  NEXT(c);
127  while(VAL(c!=EOF&&tab[c/8]&(1<<(c&7))))
128  { if(!ignore)
129  *bp++=c;
130  NEXT(c);
131  }
132  PREV(c);
133 
134  if(!ignore&&size)
135  { *bp++='\0';
136  blocks++; }
137  break;
138  }
139  case 's':
140  { unsigned char *bp;
141 
142  if(!ignore)
143  bp=va_arg(args,unsigned char *);
144  else
145  bp=NULL; /* Just to get the compiler happy */
146 
147  while(VAL(c!=EOF&&!isspace(c)))
148  { if(!ignore)
149  *bp++=c;
150  NEXT(c);
151  }
152  PREV(c);
153 
154  if(!ignore&&size)
155  { *bp++='\0';
156  blocks++; }
157  break;
158  }
159 #ifdef FULL_SPECIFIERS
160  case 'e':
161  case 'f':
162  case 'g':
163  { double v;
164  int ex=0;
165  int min=0,mine=0; /* This is a workaround for gcc 2.3.3: should be char */
166 
167  do /* This is there just to be able to break out */
168  {
169  if(VAL(c=='-'||c=='+'))
170  { min=c;
171  NEXT(c); }
172 
173  if(VAL(tolower(c)=='i')) /* +- inf */
174  { int d;
175  NEXT(d);
176  if(VAL(tolower(d)=='n'))
177  { int e;
178  NEXT(e);
179  if(VAL(tolower(e)=='f'))
180  { v=*(double *)&undef[min=='-'];
181  break; } /* break out */
182  PREV(e);
183  }
184  PREV(d);
185  }
186  else if(VAL(toupper(c)=='N')) /* NaN */
187  { int d;
188  NEXT(d);
189  if(VAL(tolower(d)=='a'))
190  { int e;
191  NEXT(e);
192  if(VAL(toupper(e)=='N'))
193  { v=*(double *)&undef[2];
194  break; }
195  PREV(e);
196  }
197  PREV(d);
198  }
199 
200  v=0.0;
201  while(VAL(isdigit(c)))
202  { v=v*10.0+(c-'0');
203  NEXT(c);
204  }
205 
206  if(VAL(c==__decimalpoint[0]))
207  { double dp=0.1;
208  NEXT(c);
209  while(VAL(isdigit(c)))
210  { v=v+dp*(c-'0');
211  dp=dp/10.0;
212  NEXT(c); }
213  if(size==2+(min!=0)) /* No number read till now -> malformatted */
214  { PREV(c);
215  c=__decimalpoint[0]; }
216  }
217 
218  if(min&&size==2) /* No number read till now -> malformatted */
219  { PREV(c);
220  c=min; }
221  if(size==1)
222  break;
223 
224  if(VAL(tolower(c)=='e'))
225  { int d;
226  NEXT(d);
227  if(VAL(d=='-'||d=='+'))
228  { mine=d;
229  NEXT(d); }
230 
231  if(VAL(isdigit(d)))
232  { do
233  { ex=ex*10+(d-'0');
234  NEXT(d);
235  }while(VAL(isdigit(d)&&ex<100));
236  c=d;
237  }else
238  { PREV(d);
239  if(mine)
240  PREV(mine);
241  }
242  }
243  PREV(c);
244 
245  if(mine=='-')
246  v=v/pow(10.0,ex);
247  else
248  v=v*pow(10.0,ex);
249 
250  if(min=='-')
251  v=-v;
252 
253  }while(0);
254 
255  if(!ignore&&size)
256  { switch(subtype)
257  { case 'l':
258  case 'L':
259  *va_arg(args,double *)=v;
260  break;
261  case 'i':
262  *va_arg(args,float *)=v;
263  break;
264  }
265  blocks++;
266  }
267  break;
268  }
269 #endif
270  case '%':
271  NEXT(c);
272  if(c!='%')
273  PREV(c); /* unget non-'%' character */
274  break;
275  case 'n':
276  if(!ignore)
277  *va_arg(args,int *)=incount;
278  size=1; /* fake a valid argument */
279  blocks++;
280  break;
281  default:
282  { unsigned long v=0;
283  int base;
284  int min=0;
285 
286  if(!type)
287  ptr--; /* unparse NUL character */
288 
289  if(type=='p')
290  { subtype='l'; /* This is the same as %lx */
291  type='x'; }
292 
293  if(VAL((c=='-'&&type!='u')||c=='+'))
294  { min=c;
295  NEXT(c); }
296 
297  if(type=='i') /* which one to use ? */
298  { if(VAL(c=='0')) /* Could be octal or sedecimal */
299  { int d;
300  NEXT(d); /* Get a look at next character */
301  if(VAL(tolower(d)=='x'))
302  { int e;
303  NEXT(e); /* And the next */
304  if(VAL(isxdigit(c)))
305  type='x'; /* Is a valid x number with '0x?' */
306  PREV(e);
307  }else
308  type='o';
309  PREV(d);
310  }else if(VAL(!isdigit(c)&&isxdigit(c)))
311  type='x'; /* Is a valid x number without '0x' */
312  }
313 
314  while(type=='x'&&VAL(c=='0')) /* sedecimal */
315  { int d;
316  NEXT(d);
317  if(VAL(tolower(d)=='x'))
318  { int e;
319  NEXT(e);
320  if(VAL(isxdigit(e)))
321  { c=e;
322  break; } /* Used while just to do this ;-) */
323  PREV(e);
324  }
325  PREV(d);
326  break; /* Need no loop */
327  }
328 
329  base=type=='x'||type=='X'?16:(type=='o'?8:10);
330  while(VAL(isxdigit(c)&&(base!=10||isdigit(c))&&(base!=8||c<='7')))
331  { v=v*base+(isdigit(c)?c-'0':0)+(isupper(c)?c-'A'+10:0)+(islower(c)?c-'a'+10:0);
332  NEXT(c);
333  }
334 
335  if(min&&size==2) /* If there is no valid character after sign, unget last */
336  { PREV(c);
337  c=min; }
338 
339  PREV(c);
340 
341  if(ignore||!size)
342  break;
343 
344  if(type=='u')
345  switch(subtype)
346  { case 'l':
347  case 'L':
348  *va_arg(args,unsigned long *)=v;
349  break;
350  case 'i':
351  *va_arg(args,unsigned int *)=v;
352  break;
353  case 'h':
354  *va_arg(args,unsigned short *)=v;
355  break;
356  }
357  else
358  { signed long v2;
359  if(min=='-')
360  v2=-v;
361  else
362  v2=v;
363  switch(subtype)
364  { case 'l':
365  case 'L':
366  *va_arg(args,signed long *)=v2;
367  break;
368  case 'i':
369  *va_arg(args,signed int *)=v2;
370  break;
371  case 'h':
372  *va_arg(args,signed short *)=v2;
373  break;
374  }
375  }
376  blocks++;
377  break;
378  }
379  }
380  format=(const char *)ptr;
381  }else
382  { if(isspace(*format))
383  { do
384  NEXT(c);
385  while(isspace(c));
386  PREV(c);
387  size=1; }
388  else
389  { NEXT(c);
390  if(c!=*format)
391  PREV(c); }
392  format++;
393  }
394  if(!size)
395  break;
396  }
397 
398  if(c==EOF&&!blocks)
399  return c;
400  else
401  return blocks;
402 }