vfscanf.c 9.5 KB

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