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 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)(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