vfscanf.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. nread=0;
  68. ncvt=0;
  69. fmtp=s;
  70. for(;*fmtp;fmtp++) switch(*fmtp){
  71. default:
  72. if(isspace(*fmtp)){
  73. do
  74. c=ngetc(f);
  75. while(isspace(c));
  76. if(c==EOF) return ncvt?ncvt:EOF;
  77. nungetc(c, f);
  78. break;
  79. }
  80. NonSpecial:
  81. c=ngetc(f);
  82. if(c==EOF) return ncvt?ncvt:EOF;
  83. if(c!=*fmtp){
  84. nungetc(c, f);
  85. return ncvt;
  86. }
  87. break;
  88. case '%':
  89. fmtp++;
  90. if(*fmtp!='*') store=1;
  91. else{
  92. store=0;
  93. fmtp++;
  94. }
  95. if('0'<=*fmtp && *fmtp<='9'){
  96. width=0;
  97. while('0'<=*fmtp && *fmtp<='9') width=width*10 + *fmtp++ - '0';
  98. }
  99. else
  100. width=-1;
  101. type=*fmtp=='h' || *fmtp=='l' || *fmtp=='L'?*fmtp++:'n';
  102. if(!icvt[*fmtp]) goto NonSpecial;
  103. if(!(*icvt[*fmtp])(f, &args, store, width, type))
  104. return ncvt?ncvt:EOF;
  105. if(*fmtp=='\0') break;
  106. if(store) ncvt++;
  107. }
  108. return ncvt;
  109. }
  110. static int icvt_n(FILE *f, va_list *args, int store, int width, int type){
  111. #pragma ref f
  112. #pragma ref width
  113. if(store){
  114. --ncvt; /* this assignment doesn't count! */
  115. switch(type){
  116. case 'h': *va_arg(*args, int16_t *)=nread; break;
  117. case 'n': *va_arg(*args, int *)=nread; break;
  118. case 'l':
  119. case 'L': *va_arg(*args, int32_t *)=nread; break;
  120. }
  121. }
  122. return 1;
  123. }
  124. #define SIGNED 1
  125. #define UNSIGNED 2
  126. #define POINTER 3
  127. /*
  128. * Generic fixed-point conversion
  129. * f is the input FILE *;
  130. * args is the va_list * into which to store the number;
  131. * store is a flag to enable storing;
  132. * width is the maximum field width;
  133. * type is 'h' 'l' or 'L', the scanf type modifier;
  134. * unsgned is SIGNED, UNSIGNED or POINTER, giving part of the type to store in;
  135. * base is the number base -- if 0, C number syntax is used.
  136. */
  137. static int icvt_fixed(FILE *f, va_list *args,
  138. int store, int width, int type, int unsgned, int base){
  139. unsigned long int num=0;
  140. int sign=1, ndig=0, dig;
  141. int c;
  142. do
  143. c=ngetc(f);
  144. while(isspace(c));
  145. if(width--==0){
  146. nungetc(c, f);
  147. goto Done;
  148. }
  149. if(c=='+'){
  150. wgetc(c, f, Done);
  151. }
  152. else if(c=='-'){
  153. sign=-1;
  154. wgetc(c, f, Done);
  155. }
  156. switch(base){
  157. case 0:
  158. if(c=='0'){
  159. wgetc(c, f, Done);
  160. if(c=='x' || c=='X'){
  161. wgetc(c, f, Done);
  162. base=16;
  163. }
  164. else{
  165. ndig=1;
  166. base=8;
  167. }
  168. }
  169. else
  170. base=10;
  171. break;
  172. case 16:
  173. if(c=='0'){
  174. wgetc(c, f, Done);
  175. if(c=='x' || c=='X'){
  176. wgetc(c, f, Done);
  177. }
  178. else ndig=1;
  179. }
  180. break;
  181. }
  182. while('0'<=c && c<='9' || 'a'<=c && c<='f' || 'A'<=c && c<='F'){
  183. dig='0'<=c && c<='9'?c-'0':'a'<=c && c<='f'?c-'a'+10:c-'A'+10;
  184. if(dig>=base) break;
  185. ndig++;
  186. num=num*base+dig;
  187. wgetc(c, f, Done);
  188. }
  189. nungetc(c, f);
  190. Done:
  191. if(ndig==0) return 0;
  192. if(store){
  193. switch(unsgned){
  194. case SIGNED:
  195. switch(type){
  196. case 'h': *va_arg(*args, int16_t *)=num*sign; break;
  197. case 'n': *va_arg(*args, int *)=num*sign; break;
  198. case 'l':
  199. case 'L': *va_arg(*args, int32_t *)=num*sign; break;
  200. }
  201. break;
  202. case UNSIGNED:
  203. switch(type){
  204. case 'h': *va_arg(*args, unsigned short *)=num*sign; break;
  205. case 'n': *va_arg(*args, unsigned int *)=num*sign; break;
  206. case 'l':
  207. case 'L': *va_arg(*args, unsigned long *)=num*sign; break;
  208. }
  209. break;
  210. case POINTER:
  211. *va_arg(*args, void **)=(void *)(num*sign); break;
  212. }
  213. }
  214. return 1;
  215. }
  216. static int icvt_d(FILE *f, va_list *args, int store, int width, int type){
  217. return icvt_fixed(f, args, store, width, type, SIGNED, 10);
  218. }
  219. static int icvt_x(FILE *f, va_list *args, int store, int width, int type){
  220. return icvt_fixed(f, args, store, width, type, UNSIGNED, 16);
  221. }
  222. static int icvt_o(FILE *f, va_list *args, int store, int width, int type){
  223. return icvt_fixed(f, args, store, width, type, UNSIGNED, 8);
  224. }
  225. static int icvt_i(FILE *f, va_list *args, int store, int width, int type){
  226. return icvt_fixed(f, args, store, width, type, SIGNED, 0);
  227. }
  228. static int icvt_u(FILE *f, va_list *args, int store, int width, int type){
  229. return icvt_fixed(f, args, store, width, type, UNSIGNED, 10);
  230. }
  231. static int icvt_p(FILE *f, va_list *args, int store, int width, int type){
  232. return icvt_fixed(f, args, store, width, type, POINTER, 16);
  233. }
  234. #define NBUF 509
  235. static int icvt_f(FILE *f, va_list *args, int store, int width, int type){
  236. char buf[NBUF+1];
  237. char *s=buf;
  238. int c, ndig=0, ndpt=0, nexp=1;
  239. if(width<0 || NBUF<width) width=NBUF; /* bug -- no limit specified in ansi */
  240. do
  241. c=ngetc(f);
  242. while(isspace(c));
  243. if(width--==0){
  244. nungetc(c, f);
  245. goto Done;
  246. }
  247. if(c=='+' || c=='-'){
  248. *s++=c;
  249. wgetc(c, f, Done);
  250. }
  251. while('0'<=c && c<='9' || ndpt==0 && c=='.'){
  252. if(c=='.') ndpt++;
  253. else ndig++;
  254. *s++=c;
  255. wgetc(c, f, Done);
  256. }
  257. if(c=='e' || c=='E'){
  258. *s++=c;
  259. nexp=0;
  260. wgetc(c, f, Done);
  261. if(c=='+' || c=='-'){
  262. *s++=c;
  263. wgetc(c, f, Done);
  264. }
  265. while('0'<=c && c<='9'){
  266. *s++=c;
  267. nexp++;
  268. wgetc(c, f, Done);
  269. }
  270. }
  271. nungetc(c, f);
  272. Done:
  273. if(ndig==0 || nexp==0) return 0;
  274. *s='\0';
  275. if(store) switch(type){
  276. case 'h':
  277. case 'n': *va_arg(*args, float *)=atof(buf); break;
  278. case 'L': /* bug -- should store in a long double */
  279. case 'l': *va_arg(*args, double *)=atof(buf); break;
  280. }
  281. return 1;
  282. }
  283. static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
  284. #pragma ref type
  285. int c, nn;
  286. register char *s;
  287. if(store) s=va_arg(*args, char *);
  288. do
  289. c=ngetc(f);
  290. while(isspace(c));
  291. if(width--==0){
  292. nungetc(c, f);
  293. goto Done;
  294. }
  295. nn=0;
  296. while(!isspace(c)){
  297. if(c==EOF){
  298. nread--;
  299. if(nn==0) return 0;
  300. else goto Done;
  301. }
  302. nn++;
  303. if(store) *s++=c;
  304. wgetc(c, f, Done);
  305. }
  306. nungetc(c, f);
  307. Done:
  308. if(store) *s='\0';
  309. return 1;
  310. }
  311. static int icvt_c(FILE *f, va_list *args, int store, int width, int type){
  312. #pragma ref type
  313. int c;
  314. register char *s;
  315. if(store) s=va_arg(*args, char *);
  316. if(width<0) width=1;
  317. for(;;){
  318. wgetc(c, f, Done);
  319. if(c==EOF) return 0;
  320. if(store) *s++=c;
  321. }
  322. Done:
  323. return 1;
  324. }
  325. static int match(int c, const char *pat){
  326. int ok=1;
  327. if(*pat=='^'){
  328. ok=!ok;
  329. pat++;
  330. }
  331. while(pat!=fmtp){
  332. if(pat+2<fmtp && pat[1]=='-'){
  333. if(pat[0]<=c && c<=pat[2]
  334. || pat[2]<=c && c<=pat[0])
  335. return ok;
  336. pat+=2;
  337. }
  338. else if(c==*pat) return ok;
  339. pat++;
  340. }
  341. return !ok;
  342. }
  343. static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
  344. #pragma ref type
  345. int c, nn;
  346. register char *s;
  347. register const char *pat;
  348. pat=++fmtp;
  349. if(*fmtp=='^') fmtp++;
  350. if(*fmtp!='\0') fmtp++;
  351. while(*fmtp!='\0' && *fmtp!=']') fmtp++;
  352. if(store) s=va_arg(*args, char *);
  353. nn=0;
  354. for(;;){
  355. wgetc(c, f, Done);
  356. if(c==EOF){
  357. nread--;
  358. if(nn==0) return 0;
  359. else goto Done;
  360. }
  361. if(!match(c, pat)) break;
  362. if(store) *s++=c;
  363. nn++;
  364. }
  365. nungetc(c, f);
  366. Done:
  367. if(store) *s='\0';
  368. return 1;
  369. }