vfscanf.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * pANS stdio -- vfscanf
  11. */
  12. #include "iolib.h"
  13. #include <ctype.h>
  14. static int icvt_f(FILE *f, va_list *args, int store, int width, int type);
  15. static int icvt_x(FILE *f, va_list *args, int store, int width, int type);
  16. static int icvt_sq(FILE *f, va_list *args, int store, int width, int type);
  17. static int icvt_c(FILE *f, va_list *args, int store, int width, int type);
  18. static int icvt_d(FILE *f, va_list *args, int store, int width, int type);
  19. static int icvt_i(FILE *f, va_list *args, int store, int width, int type);
  20. static int icvt_n(FILE *f, va_list *args, int store, int width, int type);
  21. static int icvt_o(FILE *f, va_list *args, int store, int width, int type);
  22. static int icvt_p(FILE *f, va_list *args, int store, int width, int type);
  23. static int icvt_s(FILE *f, va_list *args, int store, int width, int type);
  24. static int icvt_u(FILE *f, va_list *args, int store, int width, int type);
  25. static int (*icvt[])(FILE *, va_list *, int, int, int)={
  26. 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
  27. 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
  28. 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
  29. 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
  30. 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
  31. 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
  32. 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
  33. 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
  34. 0, 0, 0, 0, 0, icvt_f, 0, icvt_f, /* @ A B C D E F G */
  35. 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
  36. 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
  37. icvt_x, 0, 0, icvt_sq,0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
  38. 0, 0, 0, icvt_c, icvt_d, icvt_f, icvt_f, icvt_f, /* ` a b c d e f g */
  39. 0, icvt_i, 0, 0, 0, 0, icvt_n, icvt_o, /* h i j k l m n o */
  40. icvt_p, 0, 0, icvt_s, 0, icvt_u, 0, 0, /* p q r s t u v w */
  41. icvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
  42. 0, 0, 0, 0, 0, 0, 0, 0,
  43. 0, 0, 0, 0, 0, 0, 0, 0,
  44. 0, 0, 0, 0, 0, 0, 0, 0,
  45. 0, 0, 0, 0, 0, 0, 0, 0,
  46. 0, 0, 0, 0, 0, 0, 0, 0,
  47. 0, 0, 0, 0, 0, 0, 0, 0,
  48. 0, 0, 0, 0, 0, 0, 0, 0,
  49. 0, 0, 0, 0, 0, 0, 0, 0,
  50. 0, 0, 0, 0, 0, 0, 0, 0,
  51. 0, 0, 0, 0, 0, 0, 0, 0,
  52. 0, 0, 0, 0, 0, 0, 0, 0,
  53. 0, 0, 0, 0, 0, 0, 0, 0,
  54. 0, 0, 0, 0, 0, 0, 0, 0,
  55. 0, 0, 0, 0, 0, 0, 0, 0,
  56. 0, 0, 0, 0, 0, 0, 0, 0,
  57. 0, 0, 0, 0, 0, 0, 0, 0,
  58. };
  59. #define ngetc(f) (nread++, getc(f))
  60. #define nungetc(c, f) (--nread, ungetc((c), f))
  61. #define wgetc(c, f, out) if(width--==0) goto out; (c)=ngetc(f)
  62. #define wungetc(c, f) (++width, nungetc(c, f))
  63. static int nread, ncvt;
  64. static const char *fmtp;
  65. int vfscanf(FILE *f, const char *s, va_list args){
  66. int c, width, type, store;
  67. va_list arg;
  68. va_copy(arg, args);
  69. nread=0;
  70. ncvt=0;
  71. fmtp=s;
  72. for(;*fmtp;fmtp++) switch(*fmtp){
  73. default:
  74. if(isspace(*fmtp)){
  75. do
  76. c=ngetc(f);
  77. while(isspace(c));
  78. if(c==EOF) va_end(arg); return ncvt?ncvt:EOF;
  79. nungetc(c, f);
  80. break;
  81. }
  82. NonSpecial:
  83. c=ngetc(f);
  84. if(c==EOF) va_end(arg); return ncvt?ncvt:EOF;
  85. if(c!=*fmtp){
  86. nungetc(c, f);
  87. va_end(arg);
  88. return ncvt;
  89. }
  90. break;
  91. case '%':
  92. fmtp++;
  93. if(*fmtp!='*') store=1;
  94. else{
  95. store=0;
  96. fmtp++;
  97. }
  98. if('0'<=*fmtp && *fmtp<='9'){
  99. width=0;
  100. while('0'<=*fmtp && *fmtp<='9') width=width*10 + *fmtp++ - '0';
  101. }
  102. else
  103. width=-1;
  104. type=*fmtp=='h' || *fmtp=='l' || *fmtp=='L'?*fmtp++:'n';
  105. if(!icvt[(uint8_t)(*fmtp)]) goto NonSpecial;
  106. if(!(*icvt[(uint8_t)(*fmtp)])(f, &arg, store, width, type)){
  107. va_end(arg);
  108. return ncvt?ncvt:EOF;
  109. }
  110. if(*fmtp=='\0') break;
  111. if(store) ncvt++;
  112. }
  113. va_end(arg);
  114. return ncvt;
  115. }
  116. static int icvt_n(FILE *f, va_list *args, int store, int width, int type){
  117. //#pragma ref f
  118. //#pragma ref width
  119. if(store){
  120. --ncvt; /* this assignment doesn't count! */
  121. switch(type){
  122. case 'h': *va_arg(*args, int16_t *)=nread; break;
  123. case 'n': *va_arg(*args, int *)=nread; break;
  124. case 'l':
  125. case 'L': *va_arg(*args, int32_t *)=nread; break;
  126. }
  127. }
  128. return 1;
  129. }
  130. #define SIGNED 1
  131. #define UNSIGNED 2
  132. #define POINTER 3
  133. /*
  134. * Generic fixed-point conversion
  135. * f is the input FILE *;
  136. * args is the va_list * into which to store the number;
  137. * store is a flag to enable storing;
  138. * width is the maximum field width;
  139. * type is 'h' 'l' or 'L', the scanf type modifier;
  140. * unsgned is SIGNED, UNSIGNED or POINTER, giving part of the type to store in;
  141. * base is the number base -- if 0, C number syntax is used.
  142. */
  143. static int icvt_fixed(FILE *f, va_list *args,
  144. int store, int width, int type, int unsgned, int base){
  145. unsigned long int num=0;
  146. int sign=1, ndig=0, dig;
  147. int c;
  148. do
  149. c=ngetc(f);
  150. while(isspace(c));
  151. if(width--==0){
  152. nungetc(c, f);
  153. goto Done;
  154. }
  155. if(c=='+'){
  156. wgetc(c, f, Done);
  157. }
  158. else if(c=='-'){
  159. sign=-1;
  160. wgetc(c, f, Done);
  161. }
  162. switch(base){
  163. case 0:
  164. if(c=='0'){
  165. wgetc(c, f, Done);
  166. if(c=='x' || c=='X'){
  167. wgetc(c, f, Done);
  168. base=16;
  169. }
  170. else{
  171. ndig=1;
  172. base=8;
  173. }
  174. }
  175. else
  176. base=10;
  177. break;
  178. case 16:
  179. if(c=='0'){
  180. wgetc(c, f, Done);
  181. if(c=='x' || c=='X'){
  182. wgetc(c, f, Done);
  183. }
  184. else ndig=1;
  185. }
  186. break;
  187. }
  188. while(('0'<=c && c<='9') || ('a'<=c && c<='f') || ('A'<=c && c<='F')){
  189. dig='0'<=c && c<='9'?c-'0':'a'<=c && c<='f'?c-'a'+10:c-'A'+10;
  190. if(dig>=base) break;
  191. ndig++;
  192. num=num*base+dig;
  193. wgetc(c, f, Done);
  194. }
  195. nungetc(c, f);
  196. Done:
  197. if(ndig==0) return 0;
  198. if(store){
  199. switch(unsgned){
  200. case SIGNED:
  201. switch(type){
  202. case 'h': *va_arg(*args, int16_t *)=num*sign; break;
  203. case 'n': *va_arg(*args, int *)=num*sign; break;
  204. case 'l':
  205. case 'L': *va_arg(*args, int32_t *)=num*sign; break;
  206. }
  207. break;
  208. case UNSIGNED:
  209. switch(type){
  210. case 'h': *va_arg(*args, unsigned short *)=num*sign; break;
  211. case 'n': *va_arg(*args, unsigned int *)=num*sign; break;
  212. case 'l':
  213. case 'L': *va_arg(*args, unsigned long *)=num*sign; break;
  214. }
  215. break;
  216. case POINTER:
  217. *va_arg(*args, void **)=(void *)(num*sign); break;
  218. }
  219. }
  220. return 1;
  221. }
  222. static int icvt_d(FILE *f, va_list *args, int store, int width, int type){
  223. return icvt_fixed(f, args, store, width, type, SIGNED, 10);
  224. }
  225. static int icvt_x(FILE *f, va_list *args, int store, int width, int type){
  226. return icvt_fixed(f, args, store, width, type, UNSIGNED, 16);
  227. }
  228. static int icvt_o(FILE *f, va_list *args, int store, int width, int type){
  229. return icvt_fixed(f, args, store, width, type, UNSIGNED, 8);
  230. }
  231. static int icvt_i(FILE *f, va_list *args, int store, int width, int type){
  232. return icvt_fixed(f, args, store, width, type, SIGNED, 0);
  233. }
  234. static int icvt_u(FILE *f, va_list *args, int store, int width, int type){
  235. return icvt_fixed(f, args, store, width, type, UNSIGNED, 10);
  236. }
  237. static int icvt_p(FILE *f, va_list *args, int store, int width, int type){
  238. return icvt_fixed(f, args, store, width, type, POINTER, 16);
  239. }
  240. #define NBUF 509
  241. static int icvt_f(FILE *f, va_list *args, int store, int width, int type){
  242. char buf[NBUF+1];
  243. char *s=buf;
  244. int c, ndig=0, ndpt=0, nexp=1;
  245. if(width<0 || NBUF<width) width=NBUF; /* bug -- no limit specified in ansi */
  246. do
  247. c=ngetc(f);
  248. while(isspace(c));
  249. if(width--==0){
  250. nungetc(c, f);
  251. goto Done;
  252. }
  253. if(c=='+' || c=='-'){
  254. *s++=c;
  255. wgetc(c, f, Done);
  256. }
  257. while(('0'<=c && c<='9') || (ndpt==0 && c=='.')){
  258. if(c=='.') ndpt++;
  259. else ndig++;
  260. *s++=c;
  261. wgetc(c, f, Done);
  262. }
  263. if(c=='e' || c=='E'){
  264. *s++=c;
  265. nexp=0;
  266. wgetc(c, f, Done);
  267. if(c=='+' || c=='-'){
  268. *s++=c;
  269. wgetc(c, f, Done);
  270. }
  271. while('0'<=c && c<='9'){
  272. *s++=c;
  273. nexp++;
  274. wgetc(c, f, Done);
  275. }
  276. }
  277. nungetc(c, f);
  278. Done:
  279. if(ndig==0 || nexp==0) return 0;
  280. *s='\0';
  281. if(store) switch(type){
  282. case 'h':
  283. case 'n': *va_arg(*args, float *)=atof(buf); break;
  284. case 'L': /* bug -- should store in a long double */
  285. case 'l': *va_arg(*args, double *)=atof(buf); break;
  286. }
  287. return 1;
  288. }
  289. static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
  290. //#pragma ref type
  291. int c, nn;
  292. register char *s;
  293. if(store) s=va_arg(*args, char *);
  294. do
  295. c=ngetc(f);
  296. while(isspace(c));
  297. if(width--==0){
  298. nungetc(c, f);
  299. goto Done;
  300. }
  301. nn=0;
  302. while(!isspace(c)){
  303. if(c==EOF){
  304. nread--;
  305. if(nn==0) return 0;
  306. else goto Done;
  307. }
  308. nn++;
  309. if(store) *s++=c;
  310. wgetc(c, f, Done);
  311. }
  312. nungetc(c, f);
  313. Done:
  314. if(store) *s='\0';
  315. return 1;
  316. }
  317. static int icvt_c(FILE *f, va_list *args, int store, int width, int type){
  318. //#pragma ref type
  319. int c;
  320. register char *s;
  321. if(store) s=va_arg(*args, char *);
  322. if(width<0) width=1;
  323. for(;;){
  324. wgetc(c, f, Done);
  325. if(c==EOF) return 0;
  326. if(store) *s++=c;
  327. }
  328. Done:
  329. return 1;
  330. }
  331. static int match(int c, const char *pat){
  332. int ok=1;
  333. if(*pat=='^'){
  334. ok=!ok;
  335. pat++;
  336. }
  337. while(pat!=fmtp){
  338. if(pat+2<fmtp && pat[1]=='-'){
  339. if((pat[0]<=c && c<=pat[2])
  340. || (pat[2]<=c && c<=pat[0]))
  341. return ok;
  342. pat+=2;
  343. }
  344. else if(c==*pat) return ok;
  345. pat++;
  346. }
  347. return !ok;
  348. }
  349. static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
  350. //#pragma ref type
  351. int c, nn;
  352. register char *s;
  353. register const char *pat;
  354. pat=++fmtp;
  355. if(*fmtp=='^') fmtp++;
  356. if(*fmtp!='\0') fmtp++;
  357. while(*fmtp!='\0' && *fmtp!=']') fmtp++;
  358. if(store) s=va_arg(*args, char *);
  359. nn=0;
  360. for(;;){
  361. wgetc(c, f, Done);
  362. if(c==EOF){
  363. nread--;
  364. if(nn==0) return 0;
  365. else goto Done;
  366. }
  367. if(!match(c, pat)) break;
  368. if(store) *s++=c;
  369. nn++;
  370. }
  371. nungetc(c, f);
  372. Done:
  373. if(store) *s='\0';
  374. return 1;
  375. }