Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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