__vcscan.c 8.6 KB

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