1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 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 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]; 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 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 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 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 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 SFCVINIT(); /* initialize conversion tables */ 352 353 SFMTXSTART(f,-1); 354 355 if(!form || f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0) 356 SFMTXRETURN(f, -1); 357 SFLOCK(f,0); 358 359 SFinit(f); /* initialize local buffering system */ 360 361 n_assign = n_input = 0; inp = -1; 362 363 fmstk = NIL(Fmt_t*); 364 ft = NIL(Sffmt_t*); 365 366 fp = NIL(Fmtpos_t*); 367 argn = -1; 368 oform = (char*)form; 369 va_copy(oargs,args); 370 371 SFSETLOCALE(&decimal, &thousand); 372 373 loop_fmt: 374 SFMBCLR(&fmbs); 375 while((fmt = *form++)) 376 { if(fmt != '%') 377 { if(isspace(fmt)) 378 { if(fmt != '\n' || !(f->flags&SF_LINE)) 379 fmt = -1; 380 for(;;) 381 { if(SFgetc(f,inp) < 0 || inp == fmt) 382 goto loop_fmt; 383 else if(!isspace(inp)) 384 { SFungetc(f,inp); 385 goto loop_fmt; 386 } 387 } 388 } 389 else 390 { match_1: 391 #if _has_multibyte 392 if((n = (int)mbrtowc(&wc,form-1,SFMBMAX,&fmbs)) <= 0) 393 goto pop_fmt; 394 if(n > 1) 395 { acc.wc = wc; 396 SCinit(&scd,0); SFMBCLR(&mbs); 397 v = SFgetwc(&scd, &wc, '1', &acc, &mbs); 398 SCend(&scd,0); 399 if(v == 0) 400 goto pop_fmt; 401 form += n-1; 402 } 403 else 404 #endif 405 if(SFgetc(f,inp) != fmt) 406 { if(inp < 0) 407 goto done; 408 SFungetc(f,inp); 409 goto pop_fmt; 410 } 411 } 412 continue; 413 } 414 415 if(*form == '%') 416 { form += 1; 417 goto match_1; 418 } 419 420 if(*form == '\0') 421 goto pop_fmt; 422 423 if(*form == '*') 424 { flags = SFFMT_SKIP; 425 form += 1; 426 } 427 else flags = 0; 428 429 /* matching some pattern */ 430 base = 10; size = -1; 431 width = dot = 0; 432 t_str = NIL(char*); n_str = 0; 433 value = NIL(Void_t*); 434 argp = -1; 435 436 loop_flags: /* LOOP FOR FLAGS, WIDTH, BASE, TYPE */ 437 switch((fmt = *form++) ) 438 { 439 case LEFTP : /* get the type which is enclosed in balanced () */ 440 t_str = (char*)form; 441 for(v = 1;;) 442 { switch(*form++) 443 { 444 case 0 : /* not balanceable, retract */ 445 form = t_str; 446 t_str = NIL(char*); 447 n_str = 0; 448 goto loop_flags; 449 case LEFTP : /* increasing nested level */ 450 v += 1; 451 continue; 452 case RIGHTP : /* decreasing nested level */ 453 if((v -= 1) != 0) 454 continue; 455 if(*t_str != '*' ) 456 n_str = (form-1) - t_str; 457 else 458 { t_str = (*_Sffmtintf)(t_str+1,&n); 459 if(*t_str == '$') 460 { if(!fp && 461 !(fp = (*_Sffmtposf) 462 (f,oform,oargs,ft,1)) ) 463 goto pop_fmt; 464 n = FP_SET(n,argn); 465 } 466 else n = FP_SET(-1,argn); 467 468 if(fp) 469 { t_str = fp[n].argv.s; 470 n_str = fp[n].ft.size; 471 } 472 else if(ft && ft->extf ) 473 { FMTSET(ft, form,args, 474 LEFTP, 0, 0, 0,0,0, 475 NIL(char*),0); 476 n = (*ft->extf) 477 (f,(Void_t*)&argv,ft); 478 if(n < 0) 479 goto pop_fmt; 480 if(!(ft->flags&SFFMT_VALUE) ) 481 goto t_arg; 482 if((t_str = argv.s) && 483 (n_str = (int)ft->size) < 0) 484 n_str = strlen(t_str); 485 } 486 else 487 { t_arg: 488 if((t_str = va_arg(args,char*)) ) 489 n_str = strlen(t_str); 490 } 491 } 492 goto loop_flags; 493 } 494 } 495 496 case '#' : /* alternative format */ 497 flags |= SFFMT_ALTER; 498 goto loop_flags; 499 500 case '.' : /* width & base */ 501 dot += 1; 502 if(isdigit(*form)) 503 { fmt = *form++; 504 goto dot_size; 505 } 506 else if(*form == '*') 507 { form = (*_Sffmtintf)(form+1,&n); 508 if(*form == '$') 509 { form += 1; 510 if(!fp && 511 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 512 goto pop_fmt; 513 n = FP_SET(n,argn); 514 } 515 else n = FP_SET(-1,argn); 516 517 if(fp) 518 v = fp[n].argv.i; 519 else if(ft && ft->extf ) 520 { FMTSET(ft, form,args, '.',dot, 0, 0,0,0, 521 NIL(char*), 0); 522 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 523 goto pop_fmt; 524 if(ft->flags&SFFMT_VALUE) 525 v = argv.i; 526 else v = (dot <= 2) ? va_arg(args,int) : 0; 527 } 528 else v = (dot <= 2) ? va_arg(args,int) : 0; 529 if(v < 0) 530 v = 0; 531 goto dot_set; 532 } 533 else goto loop_flags; 534 535 case '0' : case '1' : case '2' : case '3' : case '4' : 536 case '5' : case '6' : case '7' : case '8' : case '9' : 537 dot_size : 538 for(v = fmt-'0'; isdigit(*form); ++form) 539 v = v*10 + (*form - '0'); 540 541 if(*form == '$') 542 { form += 1; 543 if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 544 goto pop_fmt; 545 argp = v-1; 546 goto loop_flags; 547 } 548 549 dot_set : 550 if(dot == 0 || dot == 1) 551 width = v; 552 else if(dot == 2) 553 base = v; 554 goto loop_flags; 555 556 case 'I' : /* object size */ 557 size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG; 558 if(isdigit(*form)) 559 { for(size = 0, n = *form; isdigit(n); n = *++form) 560 size = size*10 + (n - '0'); 561 } 562 else if(*form == '*') 563 { form = (*_Sffmtintf)(form+1,&n); 564 if(*form == '$') 565 { form += 1; 566 if(!fp && 567 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1))) 568 goto pop_fmt; 569 n = FP_SET(n,argn); 570 } 571 else n = FP_SET(-1,argn); 572 573 if(fp) /* use position list */ 574 size = fp[n].argv.i; 575 else if(ft && ft->extf ) 576 { FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0, 577 NIL(char*), 0); 578 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 579 goto pop_fmt; 580 if(ft->flags&SFFMT_VALUE) 581 size = argv.i; 582 else size = va_arg(args,int); 583 } 584 else size = va_arg(args,int); 585 } 586 goto loop_flags; 587 588 case 'l' : 589 size = -1; flags &= ~SFFMT_TYPES; 590 if(*form == 'l') 591 { form += 1; 592 flags |= SFFMT_LLONG; 593 } 594 else flags |= SFFMT_LONG; 595 goto loop_flags; 596 case 'h' : 597 size = -1; flags &= ~SFFMT_TYPES; 598 if(*form == 'h') 599 { form += 1; 600 flags |= SFFMT_SSHORT; 601 } 602 else flags |= SFFMT_SHORT; 603 goto loop_flags; 604 case 'L' : 605 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_LDOUBLE; 606 goto loop_flags; 607 case 'j' : 608 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_JFLAG; 609 goto loop_flags; 610 case 'z' : 611 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG; 612 goto loop_flags; 613 case 't' : 614 size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_TFLAG; 615 goto loop_flags; 616 case QUOTE : 617 if(thousand > 0) 618 flags |= SFFMT_THOUSAND; 619 goto loop_flags; 620 } 621 622 /* set object size for scalars */ 623 if(flags & SFFMT_TYPES) 624 { if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n') 625 { if(flags&SFFMT_LONG) 626 size = sizeof(long); 627 else if(flags&SFFMT_SHORT) 628 size = sizeof(short); 629 else if(flags&SFFMT_SSHORT) 630 size = sizeof(char); 631 else if(flags&SFFMT_TFLAG) 632 size = sizeof(ptrdiff_t); 633 else if(flags&SFFMT_ZFLAG) 634 size = sizeof(size_t); 635 else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) ) 636 size = sizeof(Sflong_t); 637 else if(flags&SFFMT_IFLAG) 638 { if(size <= 0 || 639 size == sizeof(Sflong_t)*CHAR_BIT ) 640 size = sizeof(Sflong_t); 641 } 642 else if(size < 0) 643 size = sizeof(int); 644 } 645 else if(_Sftype[fmt]&SFFMT_FLOAT) 646 { if(flags&(SFFMT_LONG|SFFMT_LLONG)) 647 size = sizeof(double); 648 else if(flags&SFFMT_LDOUBLE) 649 size = sizeof(Sfdouble_t); 650 else if(flags&SFFMT_IFLAG) 651 { if(size <= 0) 652 size = sizeof(Sfdouble_t); 653 } 654 else if(size < 0) 655 size = sizeof(float); 656 } 657 else if(_Sftype[fmt]&SFFMT_CHAR) 658 { 659 #if _has_multibyte 660 if((flags&SFFMT_LONG) || fmt == 'C') 661 { size = sizeof(wchar_t) > sizeof(int) ? 662 sizeof(wchar_t) : sizeof(int); 663 } else 664 #endif 665 if(size < 0) 666 size = sizeof(int); 667 } 668 } 669 670 argp = FP_SET(argp,argn); 671 if(fp) 672 { if(!(fp[argp].ft.flags&SFFMT_SKIP) ) 673 { n_assign += 1; 674 value = fp[argp].argv.vp; 675 size = fp[argp].ft.size; 676 if(ft && ft->extf && fp[argp].ft.fmt != fp[argp].fmt) 677 fmt = fp[argp].ft.fmt; 678 } 679 else flags |= SFFMT_SKIP; 680 } 681 else if(ft && ft->extf) 682 { FMTSET(ft, form,args, fmt, size,flags, width,0,base, t_str,n_str); 683 SFend(f); SFOPEN(f,0); 684 v = (*ft->extf)(f, (Void_t*)&argv, ft); 685 SFLOCK(f,0); SFbuf(f); 686 687 if(v < 0) 688 goto pop_fmt; 689 else if(v > 0) /* extf comsumed v input bytes */ 690 { n_input += v; 691 if(!(ft->flags&SFFMT_SKIP) ) 692 n_assign += 1; 693 continue; 694 } 695 else /* if(v == 0): extf did not use input stream */ 696 { FMTGET(ft, form,args, fmt, size, flags, width,n,base); 697 698 if((ft->flags&SFFMT_VALUE) && !(ft->flags&SFFMT_SKIP) ) 699 value = argv.vp; 700 } 701 } 702 703 if(_Sftype[fmt] == 0) /* unknown pattern */ 704 goto pop_fmt; 705 706 if(fmt == '!') 707 { if(!fp) 708 fp = (*_Sffmtposf)(f,oform,oargs,ft,1); 709 else goto pop_fmt; 710 711 if(!(argv.ft = va_arg(args,Sffmt_t*)) ) 712 continue; 713 if(!argv.ft->form && ft ) /* change extension functions */ 714 { if(ft->eventf && 715 (*ft->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0) 716 continue; 717 fmstk->ft = ft = argv.ft; 718 } 719 else /* stack a new environment */ 720 { if(!(fm = (Fmt_t*)malloc(sizeof(Fmt_t))) ) 721 goto done; 722 723 ft = fm->ft = argv.ft; 724 SFMBSET(ft->mbs, &fmbs); 725 if(ft->form) 726 { fm->form = (char*)form; SFMBCPY(&fm->mbs,&fmbs); 727 va_copy(fm->args,args); 728 729 fm->oform = oform; 730 va_copy(fm->oargs,oargs); 731 fm->argn = argn; 732 fm->fp = fp; 733 734 form = ft->form; SFMBCLR(ft->mbs); 735 va_copy(args,ft->args); 736 argn = -1; 737 fp = NIL(Fmtpos_t*); 738 oform = (char*)form; 739 va_copy(oargs,args); 740 } 741 else fm->form = NIL(char*); 742 743 fm->eventf = ft->eventf; 744 fm->next = fmstk; 745 fmstk = fm; 746 } 747 continue; 748 } 749 750 /* get the address to assign value */ 751 if(!value && !(flags&SFFMT_SKIP) ) 752 value = va_arg(args,Void_t*); 753 754 if(fmt == 'n') /* return length of consumed input */ 755 { 756 #if !_ast_intmax_long 757 if(size == sizeof(Sflong_t) ) 758 *((Sflong_t*)value) = (Sflong_t)(n_input+SFlen(f)); 759 else 760 #endif 761 if(size == sizeof(long) ) 762 *((long*)value) = (long)(n_input+SFlen(f)); 763 else if(size == sizeof(short) ) 764 *((short*)value) = (short)(n_input+SFlen(f)); 765 else if(size == sizeof(uchar)) 766 *((uchar*)value) = (uchar)(n_input+SFlen(f)); 767 else *((int*)value) = (int)(n_input+SFlen(f)); 768 continue; 769 } 770 771 /* if get here, start scanning input */ 772 if(width == 0) 773 width = fmt == 'c' ? 1 : MAXWIDTH; 774 775 /* define the first input character */ 776 if(fmt == 'c' || fmt == '[' || fmt == 'C' ) 777 SFgetc(f,inp); 778 else 779 { do { SFgetc(f,inp); } 780 while(isspace(inp)); /* skip starting blanks */ 781 } 782 if(inp < 0) 783 goto done; 784 785 if(_Sftype[fmt] == SFFMT_FLOAT) 786 { SFungetc(f,inp); SCinit(&scd,1); 787 argv.ld = _sfdscan((Void_t*)(&scd), _scgetc); 788 SCend(&scd,1); 789 790 if(scd.error >= 0) 791 { if(inp >= 0) 792 SFungetc(f, inp); 793 goto pop_fmt; 794 } 795 796 if(value) 797 { 798 #if !_ast_fltmax_double 799 if(size == sizeof(Sfdouble_t)) 800 *((Sfdouble_t*)value) = argv.ld; 801 else 802 #endif 803 if(size == sizeof(double)) 804 *((double*)value) = (double)argv.ld; 805 else *((float*)value) = (float)argv.ld; 806 807 n_assign += 1; 808 } 809 } 810 else if(_Sftype[fmt] == SFFMT_UINT || fmt == 'p') 811 { if(inp == '-') 812 { SFungetc(f,inp); 813 goto pop_fmt; 814 } 815 else goto int_cvt; 816 } 817 else if(_Sftype[fmt] == SFFMT_INT) 818 { int_cvt: 819 if(inp == '-' || inp == '+') 820 { if(inp == '-') 821 flags |= SFFMT_MINUS; 822 while(--width > 0 && SFgetc(f,inp) >= 0) 823 if(!isspace(inp)) 824 break; 825 } 826 if(inp < 0) 827 goto done; 828 829 if(fmt == 'o') 830 base = 8; 831 else if(fmt == 'x' || fmt == 'X' || fmt == 'p') 832 base = 16; 833 else if(fmt == 'i' && inp == '0') /* self-described data */ 834 { base = 8; 835 if(width > 1) /* peek to see if it's a base-16 */ 836 { if(SFgetc(f,inp) >= 0) 837 { if(inp == 'x' || inp == 'X') 838 base = 16; 839 SFungetc(f,inp); 840 } 841 inp = '0'; 842 } 843 } 844 845 /* now convert */ 846 argv.lu = 0; 847 if(base == 16) 848 { sp = (char*)_Sfcv36; 849 shift = 4; 850 if(sp[inp] >= 16) 851 { SFungetc(f,inp); 852 goto pop_fmt; 853 } 854 if(inp == '0' && --width > 0) 855 { /* skip leading 0x or 0X */ 856 if(SFgetc(f,inp) >= 0 && 857 (inp == 'x' || inp == 'X') && --width > 0) 858 SFgetc(f,inp); 859 } 860 if(inp >= 0 && sp[inp] < 16) 861 goto base_shift; 862 } 863 else if(base == 10) 864 { for(n = v = 0;; ) 865 { /* fast base 10 conversion */ 866 #define TEN(x) (((x) << 3) + ((x) << 1) ) 867 if (inp >= '0' && inp <= '9') 868 { argv.lu = TEN(argv.lu) + (inp-'0'); 869 n += 1; 870 } 871 else if(inp == thousand) 872 { if((v && n != 3) || (!v && n > 3) ) 873 break; 874 v = 1; n = 0; 875 } 876 else break; 877 if((width -= 1) <= 0 || SFgetc(f,inp) < 0) 878 break; 879 } 880 if (!n && !v) 881 { SFungetc(f,inp); 882 goto pop_fmt; 883 } 884 885 if(fmt == 'i' && inp == '#' && !(flags&SFFMT_ALTER) ) 886 { base = (int)argv.lu; 887 if(base < 2 || base > SF_RADIX) 888 goto pop_fmt; 889 argv.lu = 0; 890 sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64); 891 if(--width > 0 && 892 SFgetc(f,inp) >= 0 && sp[inp] < base) 893 goto base_conv; 894 } 895 } 896 else 897 { /* other bases */ 898 sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64); 899 if(base < 2 || base > SF_RADIX || sp[inp] >= base) 900 { SFungetc(f,inp); 901 goto pop_fmt; 902 } 903 904 base_conv: /* check for power of 2 conversions */ 905 if((base & ~(base-1)) == base) 906 { if(base < 8) 907 shift = base < 4 ? 1 : 2; 908 else if(base < 32) 909 shift = base < 16 ? 3 : 4; 910 else shift = base < 64 ? 5 : 6; 911 912 base_shift: do 913 { argv.lu = (argv.lu << shift) + sp[inp]; 914 } while(--width > 0 && 915 SFgetc(f,inp) >= 0 && sp[inp] < base); 916 } 917 else 918 { do 919 { argv.lu = (argv.lu * base) + sp[inp]; 920 } while(--width > 0 && 921 SFgetc(f,inp) >= 0 && sp[inp] < base); 922 } 923 } 924 925 if(flags&SFFMT_MINUS) 926 argv.ll = -argv.ll; 927 928 if(value) 929 { n_assign += 1; 930 931 if(fmt == 'p') 932 #if _more_void_int 933 *((Void_t**)value) = (Void_t*)((ulong)argv.lu); 934 #else 935 *((Void_t**)value) = (Void_t*)((uint)argv.lu); 936 #endif 937 #if !_ast_intmax_long 938 else if(size == sizeof(Sflong_t)) 939 *((Sflong_t*)value) = argv.ll; 940 #endif 941 else if(size == sizeof(long)) 942 { if(fmt == 'd' || fmt == 'i') 943 *((long*)value) = (long)argv.ll; 944 else *((ulong*)value) = (ulong)argv.lu; 945 } 946 else if(size == sizeof(short)) 947 { if(fmt == 'd' || fmt == 'i') 948 *((short*)value) = (short)argv.ll; 949 else *((ushort*)value) = (ushort)argv.lu; 950 } 951 else if(size == sizeof(char) ) 952 { if(fmt == 'd' || fmt == 'i') 953 *((char*)value) = (char)argv.ll; 954 else *((uchar*)value) = (uchar)argv.lu; 955 } 956 else 957 { if(fmt == 'd' || fmt == 'i') 958 *((int*)value) = (int)argv.ll; 959 else *((uint*)value) = (uint)argv.lu; 960 } 961 } 962 } 963 else if(fmt == 'C' || fmt == 'S') 964 { fmt = fmt == 'C' ? 'c' : 's'; 965 flags = (flags & ~SFFMT_TYPES) | SFFMT_LONG; 966 goto do_string; 967 } 968 else if(fmt == 's' || fmt == 'c' || fmt == '[' ) 969 { do_string: 970 if(value) 971 { if(size < 0) 972 size = MAXWIDTH; 973 if(fmt != 'c') 974 size -= 1; 975 #if _has_multibyte 976 if(flags&SFFMT_LONG) 977 argv.ws = (wchar_t*)value; 978 else 979 #endif 980 argv.s = (char*)value; 981 } 982 else size = 0; 983 984 if(fmt == '[' && !(form = _sfsetclass(form,&acc,flags)) ) 985 { SFungetc(f,inp); 986 goto pop_fmt; 987 } 988 989 n = 0; /* count number of scanned characters */ 990 #if _has_multibyte 991 if(flags&SFFMT_LONG) 992 { SFungetc(f,inp); SCinit(&scd,0); SFMBCLR(&mbs); 993 for(; width > 0; --width) 994 { if(SFgetwc(&scd,&wc,fmt,&acc,&mbs) == 0) 995 break; 996 if((n += 1) <= size) 997 *argv.ws++ = wc; 998 } 999 SCend(&scd,0); 1000 } 1001 else 1002 #endif 1003 1004 if(fmt == 's') 1005 { do 1006 { if(isspace(inp)) 1007 break; 1008 if((n += 1) <= size) 1009 *argv.s++ = inp; 1010 } while(--width > 0 && SFgetc(f,inp) >= 0); 1011 } 1012 else if(fmt == 'c') 1013 { do 1014 { if((n += 1) <= size) 1015 *argv.s++ = inp; 1016 } while(--width > 0 && SFgetc(f,inp) >= 0); 1017 } 1018 else /* if(fmt == '[') */ 1019 { do 1020 { if(!acc.ok[inp]) 1021 { if(n > 0 || (flags&SFFMT_ALTER) ) 1022 break; 1023 else 1024 { SFungetc(f,inp); 1025 goto pop_fmt; 1026 } 1027 } 1028 if((n += 1) <= size) 1029 *argv.s++ = inp; 1030 } while(--width > 0 && SFgetc(f,inp) >= 0); 1031 } 1032 1033 if(value && (n > 0 || fmt == '[') ) 1034 { n_assign += 1; 1035 if(fmt != 'c' && size >= 0) 1036 { 1037 #if _has_multibyte 1038 if(flags&SFFMT_LONG) 1039 *argv.ws = 0; 1040 else 1041 #endif 1042 *argv.s = 0; 1043 } 1044 } 1045 } 1046 1047 if(width > 0 && inp >= 0) 1048 SFungetc(f,inp); 1049 } 1050 1051 pop_fmt: 1052 if(fp) 1053 { free(fp); 1054 fp = NIL(Fmtpos_t*); 1055 } 1056 while((fm = fmstk) ) /* pop the format stack and continue */ 1057 { if(fm->eventf) 1058 { if(!form || !form[0]) 1059 (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),ft); 1060 else if((*fm->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0) 1061 goto loop_fmt; 1062 } 1063 1064 fmstk = fm->next; 1065 if((form = fm->form) ) 1066 { SFMBCPY(&fmbs,&fm->mbs); 1067 va_copy(args, fm->args); 1068 oform = fm->oform; 1069 va_copy(oargs,fm->oargs); 1070 argn = fm->argn; 1071 fp = fm->fp; 1072 } 1073 ft = fm->ft; 1074 free(fm); 1075 if(form && form[0]) 1076 goto loop_fmt; 1077 } 1078 1079 done: 1080 if(fp) 1081 free(fp); 1082 while((fm = fmstk) ) 1083 { if(fm->eventf) 1084 (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),fm->ft); 1085 fmstk = fm->next; 1086 free(fm); 1087 } 1088 1089 SFend(f); 1090 1091 SFOPEN(f,0); 1092 1093 if(n_assign == 0 && inp < 0) 1094 n_assign = -1; 1095 1096 SFMTXRETURN(f,n_assign); 1097 } 1098