1
0

vfwscanf.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <ctype.h>
  5. #include <wchar.h>
  6. #include <wctype.h>
  7. #include <limits.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <math.h>
  11. #include <float.h>
  12. #include "stdio_impl.h"
  13. #include "shgetc.h"
  14. #include "intscan.h"
  15. #include "floatscan.h"
  16. #define SIZE_hh -2
  17. #define SIZE_h -1
  18. #define SIZE_def 0
  19. #define SIZE_l 1
  20. #define SIZE_L 2
  21. #define SIZE_ll 3
  22. static void store_int(void *dest, int size, unsigned long long i)
  23. {
  24. if (!dest) return;
  25. switch (size) {
  26. case SIZE_hh:
  27. *(char *)dest = i;
  28. break;
  29. case SIZE_h:
  30. *(short *)dest = i;
  31. break;
  32. case SIZE_def:
  33. *(int *)dest = i;
  34. break;
  35. case SIZE_l:
  36. *(long *)dest = i;
  37. break;
  38. case SIZE_ll:
  39. *(long long *)dest = i;
  40. break;
  41. }
  42. }
  43. static void *arg_n(va_list ap, unsigned int n)
  44. {
  45. void *p;
  46. unsigned int i;
  47. va_list ap2;
  48. va_copy(ap2, ap);
  49. for (i=n; i>1; i--) va_arg(ap2, void *);
  50. p = va_arg(ap2, void *);
  51. va_end(ap2);
  52. return p;
  53. }
  54. static int in_set(const wchar_t *set, int c)
  55. {
  56. int j;
  57. const wchar_t *p = set;
  58. if (*p == '-') {
  59. if (c=='-') return 1;
  60. p++;
  61. } else if (*p == ']') {
  62. if (c==']') return 1;
  63. p++;
  64. }
  65. for (; *p && *p != ']'; p++) {
  66. if (*p=='-' && p[1] && p[1] != ']')
  67. for (j=p++[-1]; j<*p; j++)
  68. if (c==j) return 1;
  69. if (c==*p) return 1;
  70. }
  71. return 0;
  72. }
  73. #if 1
  74. #undef getwc
  75. #define getwc(f) \
  76. ((f)->rpos < (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f))
  77. #undef ungetwc
  78. #define ungetwc(c,f) \
  79. ((f)->rend && (c)<128 ? *--(f)->rpos : ungetwc((c),(f)))
  80. #endif
  81. int vfwscanf(FILE *f, const wchar_t *fmt, va_list ap)
  82. {
  83. int width;
  84. int size;
  85. int alloc;
  86. const wchar_t *p;
  87. int c, t;
  88. char *s;
  89. wchar_t *wcs;
  90. void *dest=NULL;
  91. int invert;
  92. int matches=0;
  93. off_t pos = 0, cnt;
  94. static const char size_pfx[][3] = { "hh", "h", "", "l", "L", "ll" };
  95. char tmp[3*sizeof(int)+10];
  96. FLOCK(f);
  97. for (p=fmt; *p; p++) {
  98. if (iswspace(*p)) {
  99. while (iswspace(p[1])) p++;
  100. while (iswspace((c=getwc(f)))) pos++;
  101. ungetwc(c, f);
  102. continue;
  103. }
  104. if (*p != '%' || p[1] == '%') {
  105. p += *p=='%';
  106. c = getwc(f);
  107. if (c!=*p) {
  108. ungetwc(c, f);
  109. if (c<0) goto input_fail;
  110. goto match_fail;
  111. }
  112. pos++;
  113. continue;
  114. }
  115. p++;
  116. if (*p=='*') {
  117. dest = 0; p++;
  118. } else if (iswdigit(*p) && p[1]=='$') {
  119. dest = arg_n(ap, *p-'0'); p+=2;
  120. } else {
  121. dest = va_arg(ap, void *);
  122. }
  123. for (width=0; iswdigit(*p); p++) {
  124. width = 10*width + *p - '0';
  125. }
  126. if (*p=='m') {
  127. alloc = 1;
  128. p++;
  129. } else {
  130. alloc = 0;
  131. }
  132. size = SIZE_def;
  133. switch (*p++) {
  134. case 'h':
  135. if (*p == 'h') p++, size = SIZE_hh;
  136. else size = SIZE_h;
  137. break;
  138. case 'l':
  139. if (*p == 'l') p++, size = SIZE_ll;
  140. else size = SIZE_l;
  141. break;
  142. case 'j':
  143. size = SIZE_ll;
  144. break;
  145. case 'z':
  146. case 't':
  147. size = SIZE_l;
  148. break;
  149. case 'L':
  150. size = SIZE_L;
  151. break;
  152. case 'd': case 'i': case 'o': case 'u': case 'x':
  153. case 'a': case 'e': case 'f': case 'g':
  154. case 'A': case 'E': case 'F': case 'G': case 'X':
  155. case 's': case 'c': case '[':
  156. case 'S': case 'C':
  157. case 'p': case 'n':
  158. p--;
  159. break;
  160. default:
  161. goto fmt_fail;
  162. }
  163. t = *p;
  164. /* Transform ls,lc -> S,C */
  165. if (size==SIZE_l && (t&15)==3) t&=~32;
  166. if (t != 'n' && t != '[' && (t|32) != 'c') {
  167. while (iswspace((c=getwc(f)))) pos++;
  168. if (c < 0) goto input_fail;
  169. ungetwc(c, f);
  170. }
  171. switch (t) {
  172. case 'n':
  173. store_int(dest, size, pos);
  174. /* do not increment match count, etc! */
  175. continue;
  176. case 'c':
  177. if (width < 1) width = 1;
  178. s = dest;
  179. for (; width && (c=getwc(f)) >= 0; width--) {
  180. int l = wctomb(s?s:tmp, c);
  181. if (l<0) goto input_fail;
  182. if (s) s+=l;
  183. pos++;
  184. }
  185. if (width) goto match_fail;
  186. break;
  187. case 'C':
  188. if (width < 1) width = 1;
  189. wcs = dest;
  190. for (; width && (c=getwc(f)) >= 0; width--)
  191. pos++, wcs && (*wcs++ = c);
  192. if (width) goto match_fail;
  193. break;
  194. case 's':
  195. s = dest;
  196. while (!iswspace(c=getwc(f)) && c!=EOF) {
  197. int l = wctomb(s?s:tmp, c);
  198. if (l<0) goto input_fail;
  199. if (s) s+=l;
  200. pos++;
  201. }
  202. if (s) *s = 0;
  203. break;
  204. case 'S':
  205. wcs = dest;
  206. while (!iswspace(c=getwc(f)) && c!=EOF)
  207. pos++, *wcs++ = c;
  208. if (wcs) *wcs = 0;
  209. break;
  210. case '[':
  211. s = (size == SIZE_def) ? dest : 0;
  212. wcs = (size == SIZE_l) ? dest : 0;
  213. if (*++p == '^') p++, invert = 1;
  214. else invert = 0;
  215. int gotmatch = 0;
  216. for (;;) {
  217. if ((c=getwc(f))<0) break;
  218. if (in_set(p, c) == invert)
  219. break;
  220. if (wcs) {
  221. *wcs++ = c;
  222. } else if (size != SIZE_l) {
  223. int l = wctomb(s?s:tmp, c);
  224. if (l<0) goto input_fail;
  225. if (s) s+=l;
  226. }
  227. pos++;
  228. gotmatch=1;
  229. }
  230. ungetwc(c, f);
  231. if (!gotmatch) goto match_fail;
  232. if (*p==']') p++;
  233. while (*p!=']') {
  234. if (!*p) goto fmt_fail;
  235. p++;
  236. }
  237. if (wcs) *wcs++ = 0;
  238. if (s) *s++ = 0;
  239. break;
  240. case 'd': case 'i': case 'o': case 'u': case 'x':
  241. case 'a': case 'e': case 'f': case 'g':
  242. case 'A': case 'E': case 'F': case 'G': case 'X':
  243. case 'p':
  244. if (width < 1) width = 0;
  245. snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln",
  246. 1+!dest, "%*", width, size_pfx[size+2], t);
  247. cnt = 0;
  248. if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1)
  249. goto input_fail;
  250. else if (!cnt)
  251. goto match_fail;
  252. pos += cnt;
  253. break;
  254. default:
  255. goto fmt_fail;
  256. }
  257. if (dest) matches++;
  258. }
  259. if (0) {
  260. fmt_fail:
  261. input_fail:
  262. if (!matches) matches--;
  263. }
  264. match_fail:
  265. FUNLOCK(f);
  266. return matches;
  267. }