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