__vcscan.c 8.7 KB

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