1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #include "sfhdr.h"
23
24 /* The main engine for reading formatted data
25 **
26 ** Written by Kiem-Phong Vo.
27 */
28
29 #define MAXWIDTH (int)(((uint)~0)>>1) /* max amount to scan */
30
31 /*
32 * pull in a private strtold()
33 */
34
35 #include "sfstrtof.h"
36
37 /* refresh stream buffer - taking care of unseekable/share streams too */
38 #if __STD_C
_sfbuf(Sfio_t * f,int * peek)39 static void _sfbuf(Sfio_t* f, int* peek)
40 #else
41 static void _sfbuf(f, peek)
42 Sfio_t* f;
43 int* peek;
44 #endif
45 {
46 if(f->next >= f->endb)
47 { if(*peek) /* try peeking for a share stream if possible */
48 { f->mode |= SF_RV;
49 if(SFFILBUF(f,-1) > 0)
50 { f->mode |= SF_PEEK;
51 return;
52 }
53 *peek = 0; /* can't peek, back to normal reads */
54 }
55 (void)SFFILBUF(f,-1);
56 }
57 }
58
59 /* buffer used during scanning of a double value or a multi-byte
60 character. the fields mirror certain local variables in sfvscanf. */
61 typedef struct _scan_s
62 { int error; /* get set by _sfdscan if no value specified */
63 int inp; /* last input character read */
64 int width; /* field width */
65 Sfio_t *f; /* stream being scanned */
66 uchar *d, *endd, *data; /* local buffering system */
67 int peek; /* != 0 if unseekable/share stream */
68 int n_input;/* number of input bytes processed */
69 } Scan_t;
70
71 /* ds != 0 for scanning double values */
72 #define SCinit(sc,ds) ((sc)->inp = (sc)->error = -1, (sc)->f = f, \
73 ((sc)->width = (ds) ? width : -1), \
74 (sc)->d = d, (sc)->endd = endd, (sc)->data = data, \
75 (sc)->peek = peek, (sc)->n_input = n_input)
76 #define SCend(sc,ds) (inp = (sc)->inp, f = (sc)->f, \
77 (width = (ds) ? (sc)->width : width), \
78 d = (sc)->d, endd = (sc)->endd, data = (sc)->data, \
79 peek = (sc)->peek, n_input = (sc)->n_input)
80
81 #if __STD_C
_scgetc(void * arg,int flag)82 static int _scgetc(void* arg, int flag)
83 #else
84 static int _scgetc(arg, flag)
85 void* arg;
86 int flag;
87 #endif
88 {
89 Scan_t *sc = (Scan_t*)arg;
90
91 if (flag)
92 { sc->error = flag;
93 return 0;
94 }
95
96 /* if width >= 0, do not allow to exceed width number of bytes */
97 if(sc->width == 0)
98 { sc->inp = -1;
99 return 0;
100 }
101
102 if(sc->d >= sc->endd) /* refresh local buffer */
103 { sc->n_input += sc->d - sc->data;
104 if(sc->peek)
105 SFREAD(sc->f, sc->data, sc->d - sc->data);
106 else sc->f->next = sc->d;
107
108 _sfbuf(sc->f, &sc->peek);
109 sc->data = sc->d = sc->f->next;
110 sc->endd = sc->f->endb;
111
112 if(sc->d >= sc->endd)
113 { sc->inp = -1;
114 return 0;
115 }
116 }
117
118 if((sc->width -= 1) >= 0) /* from _sfdscan */
119 return (sc->inp = (int)(*sc->d++));
120 else return ((int)(*sc->d++));
121 }
122
123 /* structure to match characters in a character class */
124 typedef struct _accept_s
125 { char ok[SF_MAXCHAR+1];
126 int yes;
127 char *form, *endf;
128 #if _has_multibyte
129 wchar_t wc;
130 #endif
131 } Accept_t;
132
133 #if __STD_C
_sfsetclass(const char * form,Accept_t * ac,int flags)134 static char* _sfsetclass(const char* form, Accept_t* ac, int flags)
135 #else
136 static char* _sfsetclass(form, ac, flags)
137 char* form; /* format string */
138 Accept_t* ac; /* values of accepted characters */
139 int flags; /* SFFMT_LONG for wchar_t */
140 #endif
141 {
142 int c, endc, n;
143 #if _has_multibyte
144 SFMBDCL(mbs)
145 #endif
146
147 if(*form == '^') /* complementing this set */
148 { ac->yes = 0;
149 form += 1;
150 }
151 else ac->yes = 1;
152
153 for(c = 0; c <= SF_MAXCHAR; ++c)
154 ac->ok[c] = !ac->yes;
155
156 if(*form == ']' || *form == '-') /* special first char */
157 { ac->ok[*form] = ac->yes;
158 form += 1;
159 }
160 ac->form = (char*)form;
161
162 if(flags&SFFMT_LONG)
163 SFMBCLR(&mbs);
164 for(n = 1; *form != ']'; form += n)
165 { if((c = *((uchar*)form)) == 0)
166 return NIL(char*);
167
168 if(*(form+1) == '-')
169 { endc = *((uchar*)(form+2));
170 #if _has_multibyte
171 if(c >= 128 || endc >= 128 ) /* range must be ascii */
172 goto one_char;
173 #endif
174 for(; c <= endc; ++c)
175 ac->ok[c] = ac->yes;
176 n = 3;
177 }
178 else
179 { one_char:
180 #if _has_multibyte /* true multi-byte chars must be checked differently */
181 if((flags&SFFMT_LONG) && (n = (int)SFMBLEN(form,&mbs)) <= 0)
182 return NIL(char*);
183 if(n == 1)
184 #endif
185 ac->ok[c] = ac->yes;
186 }
187 }
188
189 ac->endf = (char*)form;
190 return (char*)(form+1);
191 }
192
193 #if _has_multibyte
194 #if __STD_C
_sfwaccept(wchar_t wc,Accept_t * ac)195 static int _sfwaccept(wchar_t wc, Accept_t* ac)
196 #else
197 static int _sfwaccept(wc, ac)
198 wchar_t wc;
199 Accept_t* ac;
200 #endif
201 {
202 int endc, c, n;
203 wchar_t fwc;
204 char *form = ac->form;
205 SFMBDCL(mbs)
206
207 SFMBCLR(&mbs);
208 for(n = 1; *form != ']'; form += n)
209 { if((c = *((uchar*)form)) == 0)
210 return 0;
211
212 if(*(form+1) == '-')
213 { endc = *((uchar*)(form+2));
214 if(c >= 128 || endc >= 128 ) /* range must be ascii */
215 goto one_char;
216 n = 3;
217 }
218 else
219 { one_char:
220 if((n = mbrtowc(&fwc, form, ac->endf-form, &mbs)) > 1 &&
221 wc == fwc )
222 return ac->yes;
223 }
224 }
225
226 return !ac->yes;
227 }
228
229 #if _has_multibyte == 1
230 #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,(Void_t*)(mbs))
231 #else
232 #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,NIL(Void_t*))
233 #endif
234
235 #if __STD_C
_sfgetwc(Scan_t * sc,wchar_t * wc,int fmt,Accept_t * ac,Void_t * mbs)236 static int _sfgetwc(Scan_t* sc, wchar_t* wc, int fmt, Accept_t* ac, Void_t *mbs)
237 #else
238 static int _sfgetwc(sc, wc, fmt, ac, mbs)
239 Scan_t* sc; /* the scanning handle */
240 wchar_t* wc; /* to return a scanned wchar_t */
241 int fmt; /* %s, %c, %[ */
242 Accept_t* ac; /* accept handle for %[ */
243 Void_t* mbs; /* multibyte parsing state */
244 #endif
245 {
246 int n, v;
247 char b[16]; /* assuming that SFMBMAX <= 16! */
248
249 /* shift left data so that there will be more room to back up on error.
250 this won't help streams with small buffers - c'est la vie! */
251 if(sc->d > sc->f->data && (n = sc->endd - sc->d) > 0 && n < SFMBMAX)
252 { memcpy(sc->f->data, sc->d, n);
253 if(sc->f->endr == sc->f->endb)
254 sc->f->endr = sc->f->data+n;
255 if(sc->f->endw == sc->f->endb)
256 sc->f->endw = sc->f->data+n;
257 sc->f->endb = sc->f->data+n;
258 sc->d = sc->data = sc->f->data;
259 sc->endd = sc->f->endb;
260 if(!mbs) sc->f->endb = sc->endd; /* stop cc's "unused mbs" warning */
261 }
262
263 for(n = 0; n < SFMBMAX; )
264 { if((v = _scgetc((Void_t*)sc, 0)) <= 0)
265 goto no_match;
266 else b[n++] = v;
267
268 if(mbrtowc(wc, b, n, (mbstate_t*)mbs) == (size_t)(-1))
269 goto no_match; /* malformed multi-byte char */
270 else
271 { /* multi-byte char converted successfully */
272 if(fmt == 'c')
273 return 1;
274 else if(fmt == 's')
275 { if(n > 1 || (n == 1 && !isspace(b[0]) ) )
276 return 1;
277 else goto no_match;
278 }
279 else if(fmt == '[')
280 { if((n == 1 && ac->ok[b[0]]) ||
281 (n > 1 && _sfwaccept(*wc,ac)) )
282 return 1;
283 else goto no_match;
284 }
285 else /* if(fmt == '1') match a single wchar_t */
286 { if(*wc == ac->wc)
287 return 1;
288 else goto no_match;
289 }
290 }
291 }
292
293 no_match: /* this unget is lossy on a stream with small buffer */
294 if((sc->d -= n) < sc->data)
295 sc->d = sc->data;
296 return 0;
297 }
298 #endif /*_has_multibyte*/
299
300
301 #if __STD_C
sfvscanf(Sfio_t * f,reg const char * form,va_list args)302 int sfvscanf(Sfio_t* f, reg const char* form, va_list args)
303 #else
304 int sfvscanf(f,form,args)
305 Sfio_t* f; /* file to be scanned */
306 reg char* form; /* scanning format */
307 va_list args;
308 #endif
309 {
310 reg int inp, shift, base, width;
311 ssize_t size;
312 int fmt, flags, dot, n_assign, v, n, n_input;
313 char *sp;
314
315 Accept_t acc;
316
317 Argv_t argv;
318 Sffmt_t *ft;
319 Fmt_t *fm, *fmstk;
320
321 Fmtpos_t* fp;
322 char *oform;
323 va_list oargs;
324 int argp, argn;
325
326 int decimal = 0, thousand = 0;
327
328 #if _has_multibyte
329 wchar_t wc;
330 SFMBDCL(fmbs)
331 SFMBDCL(mbs)
332 #endif
333
334 Void_t* value; /* location to assign scanned value */
335 char* t_str;
336 ssize_t n_str;
337
338 /* local buffering system */
339 Scan_t scd;
340 uchar *d, *endd, *data;
341 int peek;
342 #define SFbuf(f) (_sfbuf(f,&peek), (data = d = f->next), (endd = f->endb) )
343 #define SFlen(f) (d - data)
344 #define SFinit(f) ((peek = f->extent < 0 && (f->flags&SF_SHARE)), SFbuf(f) )
345 #define SFend(f) ((n_input += SFlen(f)), \
346 (peek ? SFREAD(f,(Void_t*)data,SFlen(f)) : ((f->next = d),0)) )
347 #define SFgetc(f,c) ((c) = (d < endd || (SFend(f), SFbuf(f), d < endd)) ? \
348 (int)(*d++) : -1 )
349 #define SFungetc(f,c) (d -= 1)
350
351 SFMTXDECL(f);
352
353 SFCVINIT(); /* initialize conversion tables */
354
355 SFMTXENTER(f,-1);
356
357 if(!form || f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
358 SFMTXRETURN(f, -1);
359 SFLOCK(f,0);
360
361 SFinit(f); /* initialize local buffering system */
362
363 n_assign = n_input = 0; inp = -1;
364
365 fmstk = NIL(Fmt_t*);
366 ft = NIL(Sffmt_t*);
367
368 fp = NIL(Fmtpos_t*);
369 argn = -1;
370 oform = (char*)form;
371 va_copy(oargs,args);
372
373 SFSETLOCALE(&decimal, &thousand);
374
375 loop_fmt:
376 SFMBCLR(&fmbs);
377 while((fmt = *form++))
378 { if(fmt != '%')
379 { if(isspace(fmt))
380 { if(fmt != '\n' || !(f->flags&SF_LINE))
381 fmt = -1;
382 for(;;)
383 { if(SFgetc(f,inp) < 0 || inp == fmt)
384 goto loop_fmt;
385 else if(!isspace(inp))
386 { SFungetc(f,inp);
387 goto loop_fmt;
388 }
389 }
390 }
391 else
392 { match_1:
393 #if _has_multibyte
394 if((n = (int)mbrtowc(&wc,form-1,SFMBMAX,&fmbs)) <= 0)
395 goto pop_fmt;
396 if(n > 1)
397 { acc.wc = wc;
398 SCinit(&scd,0); SFMBCLR(&mbs);
399 v = SFgetwc(&scd, &wc, '1', &acc, &mbs);
400 SCend(&scd,0);
401 if(v == 0)
402 goto pop_fmt;
403 form += n-1;
404 }
405 else
406 #endif
407 if(SFgetc(f,inp) != fmt)
408 { if(inp < 0)
409 goto done;
410 SFungetc(f,inp);
411 goto pop_fmt;
412 }
413 }
414 continue;
415 }
416
417 if(*form == '%')
418 { form += 1;
419 do SFgetc(f,inp); while(isspace(inp)); /* skip starting blanks */
420 SFungetc(f,inp);
421 goto match_1;
422 }
423
424 if(*form == '\0')
425 goto pop_fmt;
426
427 if(*form == '*')
428 { flags = SFFMT_SKIP;
429 form += 1;
430 }
431 else flags = 0;
432
433 /* matching some pattern */
434 base = 10; size = -1;
435 width = dot = 0;
436 t_str = NIL(char*); n_str = 0;
437 value = NIL(Void_t*);
438 argp = -1;
439
440 loop_flags: /* LOOP FOR FLAGS, WIDTH, BASE, TYPE */
441 switch((fmt = *form++) )
442 {
443 case LEFTP : /* get the type which is enclosed in balanced () */
444 t_str = (char*)form;
445 for(v = 1;;)
446 { switch(*form++)
447 {
448 case 0 : /* not balanceable, retract */
449 form = t_str;
450 t_str = NIL(char*);
451 n_str = 0;
452 goto loop_flags;
453 case LEFTP : /* increasing nested level */
454 v += 1;
455 continue;
456 case RIGHTP : /* decreasing nested level */
457 if((v -= 1) != 0)
458 continue;
459 if(*t_str != '*' )
460 n_str = (form-1) - t_str;
461 else
462 { t_str = (*_Sffmtintf)(t_str+1,&n);
463 if(*t_str == '$')
464 { if(!fp &&
465 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
466 goto pop_fmt;
467 n = FP_SET(n,argn);
468 }
469 else n = FP_SET(-1,argn);
470
471 if(fp)
472 { t_str = fp[n].argv.s;
473 n_str = fp[n].ft.size;
474 }
475 else if(ft && ft->extf )
476 { FMTSET(ft, form,args,
477 LEFTP, 0, 0, 0,0,0,
478 NIL(char*),0);
479 n = (*ft->extf)
480 (f,(Void_t*)&argv,ft);
481 if(n < 0)
482 goto pop_fmt;
483 if(!(ft->flags&SFFMT_VALUE) )
484 goto t_arg;
485 if((t_str = argv.s) &&
486 (n_str = (int)ft->size) < 0)
487 n_str = strlen(t_str);
488 }
489 else
490 { t_arg:
491 if((t_str = va_arg(args,char*)) )
492 n_str = strlen(t_str);
493 }
494 }
495 goto loop_flags;
496 }
497 }
498
499 case '#' : /* alternative format */
500 flags |= SFFMT_ALTER;
501 goto loop_flags;
502
503 case '.' : /* width & base */
504 dot += 1;
505 if(isdigit(*form))
506 { fmt = *form++;
507 goto dot_size;
508 }
509 else if(*form == '*')
510 { form = (*_Sffmtintf)(form+1,&n);
511 if(*form == '$')
512 { form += 1;
513 if(!fp &&
514 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
515 goto pop_fmt;
516 n = FP_SET(n,argn);
517 }
518 else n = FP_SET(-1,argn);
519
520 if(fp)
521 v = fp[n].argv.i;
522 else if(ft && ft->extf )
523 { FMTSET(ft, form,args, '.',dot, 0, 0,0,0,
524 NIL(char*), 0);
525 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0)
526 goto pop_fmt;
527 if(ft->flags&SFFMT_VALUE)
528 v = argv.i;
529 else v = (dot <= 2) ? va_arg(args,int) : 0;
530 }
531 else v = (dot <= 2) ? va_arg(args,int) : 0;
532 if(v < 0)
533 v = 0;
534 goto dot_set;
535 }
536 else goto loop_flags;
537
538 case '0' : case '1' : case '2' : case '3' : case '4' :
539 case '5' : case '6' : case '7' : case '8' : case '9' :
540 dot_size :
541 for(v = fmt-'0'; isdigit(*form); ++form)
542 v = v*10 + (*form - '0');
543
544 if(*form == '$')
545 { form += 1;
546 if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
547 goto pop_fmt;
548 argp = v-1;
549 goto loop_flags;
550 }
551
552 dot_set :
553 if(dot == 0 || dot == 1)
554 width = v;
555 else if(dot == 2)
556 base = v;
557 goto loop_flags;
558
559 case 'I' : /* object size */
560 size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG;
561 if(isdigit(*form))
562 { for(size = 0, n = *form; isdigit(n); n = *++form)
563 size = size*10 + (n - '0');
564 }
565 else if(*form == '*')
566 { form = (*_Sffmtintf)(form+1,&n);
567 if(*form == '$')
568 { form += 1;
569 if(!fp &&
570 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)))
571 goto pop_fmt;
572 n = FP_SET(n,argn);
573 }
574 else n = FP_SET(-1,argn);
575
576 if(fp) /* use position list */
577 size = fp[n].argv.i;
578 else if(ft && ft->extf )
579 { FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0,
580 NIL(char*), 0);
581 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0)
582 goto pop_fmt;
583 if(ft->flags&SFFMT_VALUE)
584 size = argv.i;
585 else size = va_arg(args,int);
586 }
587 else size = va_arg(args,int);
588 }
589 goto loop_flags;
590
591 case 'l' :
592 size = -1; flags &= ~SFFMT_TYPES;
593 if(*form == 'l')
594 { form += 1;
595 flags |= SFFMT_LLONG;
596 }
597 else flags |= SFFMT_LONG;
598 goto loop_flags;
599 case 'h' :
600 size = -1; flags &= ~SFFMT_TYPES;
601 if(*form == 'h')
602 { form += 1;
603 flags |= SFFMT_SSHORT;
604 }
605 else flags |= SFFMT_SHORT;
606 goto loop_flags;
607 case 'L' :
608 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_LDOUBLE;
609 goto loop_flags;
610 case 'j' :
611 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_JFLAG;
612 goto loop_flags;
613 case 'z' :
614 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG;
615 goto loop_flags;
616 case 't' :
617 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_TFLAG;
618 goto loop_flags;
619 case QUOTE :
620 if(thousand > 0)
621 flags |= SFFMT_THOUSAND;
622 goto loop_flags;
623 }
624
625 /* set object size for scalars */
626 if(flags & SFFMT_TYPES)
627 { if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n')
628 { if(flags&SFFMT_LONG)
629 size = sizeof(long);
630 else if(flags&SFFMT_SHORT)
631 size = sizeof(short);
632 else if(flags&SFFMT_SSHORT)
633 size = sizeof(char);
634 else if(flags&SFFMT_TFLAG)
635 size = sizeof(ptrdiff_t);
636 else if(flags&SFFMT_ZFLAG)
637 size = sizeof(size_t);
638 else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) )
639 size = sizeof(Sflong_t);
640 else if(flags&SFFMT_IFLAG)
641 { if(size <= 0 ||
642 size == sizeof(Sflong_t)*CHAR_BIT )
643 size = sizeof(Sflong_t);
644 }
645 else if(size < 0)
646 size = sizeof(int);
647 }
648 else if(_Sftype[fmt]&SFFMT_FLOAT)
649 { if(flags&(SFFMT_LONG|SFFMT_LLONG))
650 size = sizeof(double);
651 else if(flags&SFFMT_LDOUBLE)
652 size = sizeof(Sfdouble_t);
653 else if(flags&SFFMT_IFLAG)
654 { if(size <= 0)
655 size = sizeof(Sfdouble_t);
656 }
657 else if(size < 0)
658 size = sizeof(float);
659 }
660 else if(_Sftype[fmt]&SFFMT_CHAR)
661 {
662 #if _has_multibyte
663 if((flags&SFFMT_LONG) || fmt == 'C')
664 { size = sizeof(wchar_t) > sizeof(int) ?
665 sizeof(wchar_t) : sizeof(int);
666 } else
667 #endif
668 if(size < 0)
669 size = sizeof(int);
670 }
671 }
672
673 argp = FP_SET(argp,argn);
674 if(fp)
675 { if(!(fp[argp].ft.flags&SFFMT_SKIP) )
676 { n_assign += 1;
677 value = fp[argp].argv.vp;
678 size = fp[argp].ft.size;
679 if(ft && ft->extf && fp[argp].ft.fmt != fp[argp].fmt)
680 fmt = fp[argp].ft.fmt;
681 }
682 else flags |= SFFMT_SKIP;
683 }
684 else if(ft && ft->extf)
685 { FMTSET(ft, form,args, fmt, size,flags, width,0,base, t_str,n_str);
686 SFend(f); SFOPEN(f,0);
687 v = (*ft->extf)(f, (Void_t*)&argv, ft);
688 SFLOCK(f,0); SFbuf(f);
689
690 if(v < 0)
691 goto pop_fmt;
692 else if(v > 0) /* extf comsumed v input bytes */
693 { n_input += v;
694 if(!(ft->flags&SFFMT_SKIP) )
695 n_assign += 1;
696 continue;
697 }
698 else /* if(v == 0): extf did not use input stream */
699 { FMTGET(ft, form,args, fmt, size, flags, width,n,base);
700
701 if((ft->flags&SFFMT_VALUE) && !(ft->flags&SFFMT_SKIP) )
702 value = argv.vp;
703 }
704 }
705
706 if(_Sftype[fmt] == 0) /* unknown pattern */
707 goto pop_fmt;
708
709 if(fmt == '!')
710 { if(!fp)
711 fp = (*_Sffmtposf)(f,oform,oargs,ft,1);
712 else goto pop_fmt;
713
714 if(!(argv.ft = va_arg(args,Sffmt_t*)) )
715 continue;
716 if(!argv.ft->form && ft ) /* change extension functions */
717 { if(ft->eventf &&
718 (*ft->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0)
719 continue;
720 fmstk->ft = ft = argv.ft;
721 }
722 else /* stack a new environment */
723 { if(!(fm = (Fmt_t*)malloc(sizeof(Fmt_t))) )
724 goto done;
725
726 ft = fm->ft = argv.ft;
727 SFMBSET(ft->mbs, &fmbs);
728 if(ft->form)
729 { fm->form = (char*)form; SFMBCPY(&fm->mbs,&fmbs);
730 va_copy(fm->args,args);
731
732 fm->oform = oform;
733 va_copy(fm->oargs,oargs);
734 fm->argn = argn;
735 fm->fp = fp;
736
737 form = ft->form; SFMBCLR(ft->mbs);
738 va_copy(args,ft->args);
739 argn = -1;
740 fp = NIL(Fmtpos_t*);
741 oform = (char*)form;
742 va_copy(oargs,args);
743 }
744 else fm->form = NIL(char*);
745
746 fm->eventf = ft->eventf;
747 fm->next = fmstk;
748 fmstk = fm;
749 }
750 continue;
751 }
752
753 /* get the address to assign value */
754 if(!value && !(flags&SFFMT_SKIP) )
755 value = va_arg(args,Void_t*);
756
757 if(fmt == 'n') /* return length of consumed input */
758 {
759 #if !_ast_intmax_long
760 if(size == sizeof(Sflong_t) )
761 *((Sflong_t*)value) = (Sflong_t)(n_input+SFlen(f));
762 else
763 #endif
764 if(size == sizeof(long) )
765 *((long*)value) = (long)(n_input+SFlen(f));
766 else if(size == sizeof(short) )
767 *((short*)value) = (short)(n_input+SFlen(f));
768 else if(size == sizeof(uchar))
769 *((uchar*)value) = (uchar)(n_input+SFlen(f));
770 else *((int*)value) = (int)(n_input+SFlen(f));
771 continue;
772 }
773
774 /* if get here, start scanning input */
775 if(width == 0)
776 width = fmt == 'c' ? 1 : MAXWIDTH;
777
778 /* define the first input character */
779 if(fmt == 'c' || fmt == '[' || fmt == 'C' )
780 SFgetc(f,inp);
781 else
782 { do { SFgetc(f,inp); }
783 while(isspace(inp)); /* skip starting blanks */
784 }
785 if(inp < 0)
786 goto done;
787
788 if(_Sftype[fmt] == SFFMT_FLOAT)
789 { SFungetc(f,inp); SCinit(&scd,1);
790 argv.ld = _sfdscan((Void_t*)(&scd), _scgetc);
791 SCend(&scd,1);
792
793 if(scd.error >= 0)
794 { if(inp >= 0)
795 SFungetc(f, inp);
796 goto pop_fmt;
797 }
798
799 if(value)
800 {
801 #if !_ast_fltmax_double
802 if(size == sizeof(Sfdouble_t))
803 *((Sfdouble_t*)value) = argv.ld;
804 else
805 #endif
806 if(size == sizeof(double))
807 *((double*)value) = (double)argv.ld;
808 else *((float*)value) = (float)argv.ld;
809
810 n_assign += 1;
811 }
812 }
813 else if(_Sftype[fmt] == SFFMT_UINT || fmt == 'p')
814 { if(inp == '-')
815 { SFungetc(f,inp);
816 goto pop_fmt;
817 }
818 else goto int_cvt;
819 }
820 else if(_Sftype[fmt] == SFFMT_INT)
821 { int_cvt:
822 if(inp == '-' || inp == '+')
823 { if(inp == '-')
824 flags |= SFFMT_MINUS;
825 while(--width > 0 && SFgetc(f,inp) >= 0)
826 if(!isspace(inp))
827 break;
828 }
829 if(inp < 0)
830 goto done;
831
832 if(fmt == 'o')
833 base = 8;
834 else if(fmt == 'x' || fmt == 'X' || fmt == 'p')
835 base = 16;
836 else if(fmt == 'i' && inp == '0') /* self-described data */
837 { base = 8;
838 if(width > 1) /* peek to see if it's a base-16 */
839 { if(SFgetc(f,inp) >= 0)
840 { if(inp == 'x' || inp == 'X')
841 base = 16;
842 SFungetc(f,inp);
843 }
844 inp = '0';
845 }
846 }
847
848 /* now convert */
849 argv.lu = 0;
850 if(base == 16)
851 { sp = (char*)_Sfcv36;
852 shift = 4;
853 if(sp[inp] >= 16)
854 { SFungetc(f,inp);
855 goto pop_fmt;
856 }
857 if(inp == '0' && --width > 0)
858 { /* skip leading 0x or 0X */
859 if(SFgetc(f,inp) >= 0 &&
860 (inp == 'x' || inp == 'X') && --width > 0)
861 SFgetc(f,inp);
862 }
863 if(inp >= 0 && sp[inp] < 16)
864 goto base_shift;
865 }
866 else if(base == 10)
867 { for(n = v = 0;; )
868 { /* fast base 10 conversion */
869 #define TEN(x) (((x) << 3) + ((x) << 1) )
870 if (inp >= '0' && inp <= '9')
871 { argv.lu = TEN(argv.lu) + (inp-'0');
872 n += 1;
873 }
874 else if(inp == thousand)
875 { if((v && n != 3) || (!v && n > 3) )
876 break;
877 v = 1; n = 0;
878 }
879 else break;
880 if((width -= 1) <= 0 || SFgetc(f,inp) < 0)
881 break;
882 }
883 if (!n && !v)
884 { SFungetc(f,inp);
885 goto pop_fmt;
886 }
887
888 if(fmt == 'i' && inp == '#' && !(flags&SFFMT_ALTER) )
889 { base = (int)argv.lu;
890 if(base < 2 || base > SF_RADIX)
891 goto pop_fmt;
892 argv.lu = 0;
893 sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64);
894 if(--width > 0 &&
895 SFgetc(f,inp) >= 0 && sp[inp] < base)
896 goto base_conv;
897 }
898 }
899 else
900 { /* other bases */
901 sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64);
902 if(base < 2 || base > SF_RADIX || sp[inp] >= base)
903 { SFungetc(f,inp);
904 goto pop_fmt;
905 }
906
907 base_conv: /* check for power of 2 conversions */
908 if((base & ~(base-1)) == base)
909 { if(base < 8)
910 shift = base < 4 ? 1 : 2;
911 else if(base < 32)
912 shift = base < 16 ? 3 : 4;
913 else shift = base < 64 ? 5 : 6;
914
915 base_shift: do
916 { argv.lu = (argv.lu << shift) + sp[inp];
917 } while(--width > 0 &&
918 SFgetc(f,inp) >= 0 && sp[inp] < base);
919 }
920 else
921 { do
922 { argv.lu = (argv.lu * base) + sp[inp];
923 } while(--width > 0 &&
924 SFgetc(f,inp) >= 0 && sp[inp] < base);
925 }
926 }
927
928 if(flags&SFFMT_MINUS)
929 argv.ll = -argv.ll;
930
931 if(value)
932 { n_assign += 1;
933
934 if(fmt == 'p')
935 #if _more_void_int
936 *((Void_t**)value) = (Void_t*)((ulong)argv.lu);
937 #else
938 *((Void_t**)value) = (Void_t*)((uint)argv.lu);
939 #endif
940 #if !_ast_intmax_long
941 else if(size == sizeof(Sflong_t))
942 *((Sflong_t*)value) = argv.ll;
943 #endif
944 else if(size == sizeof(long))
945 { if(fmt == 'd' || fmt == 'i')
946 *((long*)value) = (long)argv.ll;
947 else *((ulong*)value) = (ulong)argv.lu;
948 }
949 else if(size == sizeof(short))
950 { if(fmt == 'd' || fmt == 'i')
951 *((short*)value) = (short)argv.ll;
952 else *((ushort*)value) = (ushort)argv.lu;
953 }
954 else if(size == sizeof(char) )
955 { if(fmt == 'd' || fmt == 'i')
956 *((char*)value) = (char)argv.ll;
957 else *((uchar*)value) = (uchar)argv.lu;
958 }
959 else
960 { if(fmt == 'd' || fmt == 'i')
961 *((int*)value) = (int)argv.ll;
962 else *((uint*)value) = (uint)argv.lu;
963 }
964 }
965 }
966 else if(fmt == 'C' || fmt == 'S')
967 { fmt = fmt == 'C' ? 'c' : 's';
968 flags = (flags & ~SFFMT_TYPES) | SFFMT_LONG;
969 goto do_string;
970 }
971 else if(fmt == 's' || fmt == 'c' || fmt == '[' )
972 { do_string:
973 if(value)
974 { if(size < 0)
975 size = MAXWIDTH;
976 if(fmt != 'c')
977 size -= 1;
978 #if _has_multibyte
979 if(flags&SFFMT_LONG)
980 argv.ws = (wchar_t*)value;
981 else
982 #endif
983 argv.s = (char*)value;
984 }
985 else size = 0;
986
987 if(fmt == '[' && !(form = _sfsetclass(form,&acc,flags)) )
988 { SFungetc(f,inp);
989 goto pop_fmt;
990 }
991
992 n = 0; /* count number of scanned characters */
993 #if _has_multibyte
994 if(flags&SFFMT_LONG)
995 { SFungetc(f,inp); SCinit(&scd,0); SFMBCLR(&mbs);
996 for(; width > 0; --width)
997 { if(SFgetwc(&scd,&wc,fmt,&acc,&mbs) == 0)
998 break;
999 if((n += 1) <= size)
1000 *argv.ws++ = wc;
1001 }
1002 SCend(&scd,0);
1003 }
1004 else
1005 #endif
1006
1007 if(fmt == 's')
1008 { do
1009 { if(isspace(inp))
1010 break;
1011 if((n += 1) <= size)
1012 *argv.s++ = inp;
1013 } while(--width > 0 && SFgetc(f,inp) >= 0);
1014 }
1015 else if(fmt == 'c')
1016 { do
1017 { if((n += 1) <= size)
1018 *argv.s++ = inp;
1019 } while(--width > 0 && SFgetc(f,inp) >= 0);
1020 }
1021 else /* if(fmt == '[') */
1022 { do
1023 { if(!acc.ok[inp])
1024 { if(n > 0 || (flags&SFFMT_ALTER) )
1025 break;
1026 else
1027 { SFungetc(f,inp);
1028 goto pop_fmt;
1029 }
1030 }
1031 if((n += 1) <= size)
1032 *argv.s++ = inp;
1033 } while(--width > 0 && SFgetc(f,inp) >= 0);
1034 }
1035
1036 if(value && (n > 0 || fmt == '[') )
1037 { n_assign += 1;
1038 if(fmt != 'c' && size >= 0)
1039 {
1040 #if _has_multibyte
1041 if(flags&SFFMT_LONG)
1042 *argv.ws = 0;
1043 else
1044 #endif
1045 *argv.s = 0;
1046 }
1047 }
1048 }
1049
1050 if(width > 0 && inp >= 0)
1051 SFungetc(f,inp);
1052 }
1053
1054 pop_fmt:
1055 if(fp)
1056 { free(fp);
1057 fp = NIL(Fmtpos_t*);
1058 }
1059 while((fm = fmstk) ) /* pop the format stack and continue */
1060 { if(fm->eventf)
1061 { if(!form || !form[0])
1062 (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),ft);
1063 else if((*fm->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0)
1064 goto loop_fmt;
1065 }
1066
1067 fmstk = fm->next;
1068 if((form = fm->form) )
1069 { SFMBCPY(&fmbs,&fm->mbs);
1070 va_copy(args, fm->args);
1071 oform = fm->oform;
1072 va_copy(oargs,fm->oargs);
1073 argn = fm->argn;
1074 fp = fm->fp;
1075 }
1076 ft = fm->ft;
1077 free(fm);
1078 if(form && form[0])
1079 goto loop_fmt;
1080 }
1081
1082 done:
1083 if(fp)
1084 free(fp);
1085 while((fm = fmstk) )
1086 { if(fm->eventf)
1087 (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),fm->ft);
1088 fmstk = fm->next;
1089 free(fm);
1090 }
1091
1092 SFend(f);
1093
1094 SFOPEN(f,0);
1095
1096 if(n_assign == 0 && inp < 0)
1097 n_assign = -1;
1098
1099 SFMTXRETURN(f,n_assign);
1100 }
1101