summaryrefslogtreecommitdiff
path: root/sys/src/libstdio/vfscanf.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libstdio/vfscanf.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libstdio/vfscanf.c')
-rwxr-xr-xsys/src/libstdio/vfscanf.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/sys/src/libstdio/vfscanf.c b/sys/src/libstdio/vfscanf.c
new file mode 100755
index 000000000..d17dcf2c4
--- /dev/null
+++ b/sys/src/libstdio/vfscanf.c
@@ -0,0 +1,364 @@
+/*
+ * pANS stdio -- vfscanf
+ */
+#include "iolib.h"
+#include <ctype.h>
+static int icvt_f(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_x(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_sq(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_c(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_d(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_i(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_n(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_o(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_p(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_s(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_u(FILE *f, va_list *args, int store, int width, int type);
+static int (*icvt[])(FILE *, va_list *, int, int, int)={
+0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
+0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
+0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
+0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
+0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
+0, 0, 0, 0, 0, icvt_f, 0, icvt_f, /* @ A B C D E F G */
+0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
+0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
+icvt_x, 0, 0, icvt_sq,0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
+0, 0, 0, icvt_c, icvt_d, icvt_f, icvt_f, icvt_f, /* ` a b c d e f g */
+0, icvt_i, 0, 0, 0, 0, icvt_n, icvt_o, /* h i j k l m n o */
+icvt_p, 0, 0, icvt_s, 0, icvt_u, 0, 0, /* p q r s t u v w */
+icvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
+
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+
+};
+#define ngetc(f) (nread++, getc(f))
+#define nungetc(c, f) (--nread, ungetc((c), f))
+#define wgetc(c, f, out) if(width--==0) goto out; (c)=ngetc(f)
+#define wungetc(c, f) (++width, nungetc(c, f))
+static int nread, ncvt;
+static const char *fmtp;
+
+int vfscanf(FILE *f, const char *s, va_list args){
+ int c, width, type, store;
+ nread=0;
+ ncvt=0;
+ fmtp=s;
+ for(;*fmtp;fmtp++) switch(*fmtp){
+ default:
+ if(isspace(*fmtp)){
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(c==EOF) return ncvt?ncvt:EOF;
+ nungetc(c, f);
+ break;
+ }
+ NonSpecial:
+ c=ngetc(f);
+ if(c==EOF) return ncvt?ncvt:EOF;
+ if(c!=*fmtp){
+ nungetc(c, f);
+ return ncvt;
+ }
+ break;
+ case '%':
+ fmtp++;
+ if(*fmtp!='*') store=1;
+ else{
+ store=0;
+ fmtp++;
+ }
+ if('0'<=*fmtp && *fmtp<='9'){
+ width=0;
+ while('0'<=*fmtp && *fmtp<='9') width=width*10 + *fmtp++ - '0';
+ }
+ else
+ width=-1;
+ type=*fmtp=='h' || *fmtp=='l' || *fmtp=='L'?*fmtp++:'n';
+ if(!icvt[*fmtp]) goto NonSpecial;
+ if(!(*icvt[*fmtp])(f, &args, store, width, type))
+ return ncvt?ncvt:EOF;
+ if(*fmtp=='\0') break;
+ if(store) ncvt++;
+ }
+ return ncvt;
+}
+static int icvt_n(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref f
+#pragma ref width
+ if(store){
+ --ncvt; /* this assignment doesn't count! */
+ switch(type){
+ case 'h': *va_arg(*args, short *)=nread; break;
+ case 'n': *va_arg(*args, int *)=nread; break;
+ case 'l':
+ case 'L': *va_arg(*args, long *)=nread; break;
+ }
+ }
+ return 1;
+}
+#define SIGNED 1
+#define UNSIGNED 2
+#define POINTER 3
+/*
+ * Generic fixed-point conversion
+ * f is the input FILE *;
+ * args is the va_list * into which to store the number;
+ * store is a flag to enable storing;
+ * width is the maximum field width;
+ * type is 'h' 'l' or 'L', the scanf type modifier;
+ * unsgned is SIGNED, UNSIGNED or POINTER, giving part of the type to store in;
+ * base is the number base -- if 0, C number syntax is used.
+ */
+static int icvt_fixed(FILE *f, va_list *args,
+ int store, int width, int type, int unsgned, int base){
+ unsigned long int num=0;
+ int sign=1, ndig=0, dig;
+ int c;
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ if(c=='+'){
+ wgetc(c, f, Done);
+ }
+ else if(c=='-'){
+ sign=-1;
+ wgetc(c, f, Done);
+ }
+ switch(base){
+ case 0:
+ if(c=='0'){
+ wgetc(c, f, Done);
+ if(c=='x' || c=='X'){
+ wgetc(c, f, Done);
+ base=16;
+ }
+ else{
+ ndig=1;
+ base=8;
+ }
+ }
+ else
+ base=10;
+ break;
+ case 16:
+ if(c=='0'){
+ wgetc(c, f, Done);
+ if(c=='x' || c=='X'){
+ wgetc(c, f, Done);
+ }
+ else ndig=1;
+ }
+ break;
+ }
+ while('0'<=c && c<='9' || 'a'<=c && c<='f' || 'A'<=c && c<='F'){
+ dig='0'<=c && c<='9'?c-'0':'a'<=c && c<='f'?c-'a'+10:c-'A'+10;
+ if(dig>=base) break;
+ ndig++;
+ num=num*base+dig;
+ wgetc(c, f, Done);
+ }
+ nungetc(c, f);
+Done:
+ if(ndig==0) return 0;
+ if(store){
+ switch(unsgned){
+ case SIGNED:
+ switch(type){
+ case 'h': *va_arg(*args, short *)=num*sign; break;
+ case 'n': *va_arg(*args, int *)=num*sign; break;
+ case 'l':
+ case 'L': *va_arg(*args, long *)=num*sign; break;
+ }
+ break;
+ case UNSIGNED:
+ switch(type){
+ case 'h': *va_arg(*args, unsigned short *)=num*sign; break;
+ case 'n': *va_arg(*args, unsigned int *)=num*sign; break;
+ case 'l':
+ case 'L': *va_arg(*args, unsigned long *)=num*sign; break;
+ }
+ break;
+ case POINTER:
+ *va_arg(*args, void **)=(void *)(num*sign); break;
+ }
+ }
+ return 1;
+}
+static int icvt_d(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, SIGNED, 10);
+}
+static int icvt_x(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 16);
+}
+static int icvt_o(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 8);
+}
+static int icvt_i(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, SIGNED, 0);
+}
+static int icvt_u(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 10);
+}
+static int icvt_p(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, POINTER, 16);
+}
+#define NBUF 509
+static int icvt_f(FILE *f, va_list *args, int store, int width, int type){
+ char buf[NBUF+1];
+ char *s=buf;
+ int c, ndig=0, ndpt=0, nexp=1;
+ if(width<0 || NBUF<width) width=NBUF; /* bug -- no limit specified in ansi */
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ if(c=='+' || c=='-'){
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ while('0'<=c && c<='9' || ndpt==0 && c=='.'){
+ if(c=='.') ndpt++;
+ else ndig++;
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ if(c=='e' || c=='E'){
+ *s++=c;
+ nexp=0;
+ wgetc(c, f, Done);
+ if(c=='+' || c=='-'){
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ while('0'<=c && c<='9'){
+ *s++=c;
+ nexp++;
+ wgetc(c, f, Done);
+ }
+ }
+ nungetc(c, f);
+Done:
+ if(ndig==0 || nexp==0) return 0;
+ *s='\0';
+ if(store) switch(type){
+ case 'h':
+ case 'n': *va_arg(*args, float *)=atof(buf); break;
+ case 'L': /* bug -- should store in a long double */
+ case 'l': *va_arg(*args, double *)=atof(buf); break;
+ }
+ return 1;
+}
+static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c, nn;
+ register char *s;
+ if(store) s=va_arg(*args, char *);
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ nn=0;
+ while(!isspace(c)){
+ if(c==EOF){
+ nread--;
+ if(nn==0) return 0;
+ else goto Done;
+ }
+ nn++;
+ if(store) *s++=c;
+ wgetc(c, f, Done);
+ }
+ nungetc(c, f);
+Done:
+ if(store) *s='\0';
+ return 1;
+}
+static int icvt_c(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c;
+ register char *s;
+ if(store) s=va_arg(*args, char *);
+ if(width<0) width=1;
+ for(;;){
+ wgetc(c, f, Done);
+ if(c==EOF) return 0;
+ if(store) *s++=c;
+ }
+Done:
+ return 1;
+}
+static int match(int c, const char *pat){
+ int ok=1;
+ if(*pat=='^'){
+ ok=!ok;
+ pat++;
+ }
+ while(pat!=fmtp){
+ if(pat+2<fmtp && pat[1]=='-'){
+ if(pat[0]<=c && c<=pat[2]
+ || pat[2]<=c && c<=pat[0])
+ return ok;
+ pat+=2;
+ }
+ else if(c==*pat) return ok;
+ pat++;
+ }
+ return !ok;
+}
+static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c, nn;
+ register char *s;
+ register const char *pat;
+ pat=++fmtp;
+ if(*fmtp=='^') fmtp++;
+ if(*fmtp!='\0') fmtp++;
+ while(*fmtp!='\0' && *fmtp!=']') fmtp++;
+ if(store) s=va_arg(*args, char *);
+ nn=0;
+ for(;;){
+ wgetc(c, f, Done);
+ if(c==EOF){
+ nread--;
+ if(nn==0) return 0;
+ else goto Done;
+ }
+ if(!match(c, pat)) break;
+ if(store) *s++=c;
+ nn++;
+ }
+ nungetc(c, f);
+Done:
+ if(store) *s='\0';
+ return 1;
+}