1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 SFMBDCL(mbs) 144 145 if(*form == '^') /* complementing this set */ 146 { ac->yes = 0; 147 form += 1; 148 } 149 else ac->yes = 1; 150 151 for(c = 0; c <= SF_MAXCHAR; ++c) 152 ac->ok[c] = !ac->yes; 153 154 if(*form == ']' || *form == '-') /* special first char */ 155 { ac->ok[*form] = ac->yes; 156 form += 1; 157 } 158 ac->form = (char*)form; 159 160 if(flags&SFFMT_LONG) 161 SFMBCLR(&mbs); 162 for(n = 1; *form != ']'; form += n) 163 { if((c = *((uchar*)form)) == 0) 164 return NIL(char*); 165 166 if(*(form+1) == '-') 167 { endc = *((uchar*)(form+2)); 168 #if _has_multibyte 169 if(c >= 128 || endc >= 128 ) /* range must be ascii */ 170 goto one_char; 171 #endif 172 for(; c <= endc; ++c) 173 ac->ok[c] = ac->yes; 174 n = 3; 175 } 176 else 177 { one_char: 178 #if _has_multibyte /* true multi-byte chars must be checked differently */ 179 if((flags&SFFMT_LONG) && (n = (int)SFMBLEN(form,&mbs)) <= 0) 180 return NIL(char*); 181 if(n == 1) 182 #endif 183 ac->ok[c] = ac->yes; 184 } 185 } 186 187 ac->endf = (char*)form; 188 return (char*)(form+1); 189 } 190 191 #if _has_multibyte 192 #if __STD_C 193 static int _sfwaccept(wchar_t wc, Accept_t* ac) 194 #else 195 static int _sfwaccept(wc, ac) 196 wchar_t wc; 197 Accept_t* ac; 198 #endif 199 { 200 int endc, c, n; 201 wchar_t fwc; 202 char *form = ac->form; 203 SFMBDCL(mbs) 204 205 SFMBCLR(&mbs); 206 for(n = 1; *form != ']'; form += n) 207 { if((c = *((uchar*)form)) == 0) 208 return 0; 209 210 if(*(form+1) == '-') 211 { endc = *((uchar*)(form+2)); 212 if(c >= 128 || endc >= 128 ) /* range must be ascii */ 213 goto one_char; 214 n = 3; 215 } 216 else 217 { one_char: 218 if((n = mbrtowc(&fwc, form, ac->endf-form, &mbs)) > 1 && 219 wc == fwc ) 220 return ac->yes; 221 } 222 } 223 224 return !ac->yes; 225 } 226 227 #if _has_multibyte == 1 228 #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,(Void_t*)(mbs)) 229 #else 230 #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,NIL(Void_t*)) 231 #endif 232 233 #if __STD_C 234 static int _sfgetwc(Scan_t* sc, wchar_t* wc, int fmt, Accept_t* ac, Void_t *mbs) 235 #else 236 static int _sfgetwc(sc, wc, fmt, ac, mbs) 237 Scan_t* sc; /* the scanning handle */ 238 wchar_t* wc; /* to return a scanned wchar_t */ 239 int fmt; /* %s, %c, %[ */ 240 Accept_t* ac; /* accept handle for %[ */ 241 Void_t* mbs; /* multibyte parsing state */ 242 #endif 243 { 244 int n, v; 245 char b[16]; /* assuming that SFMBMAX <= 16! */ 246 247 /* shift left data so that there will be more room to back up on error. 248 this won't help streams with small buffers - c'est la vie! */ 249 if(sc->d > sc->f->data && (n = sc->endd - sc->d) > 0 && n < SFMBMAX) 250 { memcpy(sc->f->data, sc->d, n); 251 if(sc->f->endr == sc->f->endb) 252 sc->f->endr = sc->f->data+n; 253 if(sc->f->endw == sc->f->endb) 254 sc->f->endw = sc->f->data+n; 255 sc->f->endb = sc->f->data+n; 256 sc->d = sc->data = sc->f->data; 257 sc->endd = sc->f->endb; 258 if(!mbs) sc->f->endb = sc->endd; /* stop cc's "unused mbs" warning */ 259 } 260 261 for(n = 0; n < SFMBMAX; ) 262 { if((v = _scgetc((Void_t*)sc, 0)) <= 0) 263 goto no_match; 264 else b[n++] = v; 265 266 if(mbrtowc(wc, b, n, (mbstate_t*)mbs) == (size_t)(-1)) 267 goto no_match; /* malformed multi-byte char */ 268 else 269 { /* multi-byte char converted successfully */ 270 if(fmt == 'c') 271 return 1; 272 else if(fmt == 's') 273 { if(n > 1 || (n == 1 && !isspace(b[0]) ) ) 274 return 1; 275 else goto no_match; 276 } 277 else if(fmt == '[') 278 { if((n == 1 && ac->ok[b[0]]) || 279 (n > 1 && _sfwaccept(*wc,ac)) ) 280 return 1; 281 else goto no_match; 282 } 283 else /* if(fmt == '1') match a single wchar_t */ 284 { if(*wc == ac->wc) 285 return 1; 286 else goto no_match; 287 } 288 } 289 } 290 291 no_match: /* this unget is lossy on a stream with small buffer */ 292 if((sc->d -= n) < sc->data) 293 sc->d = sc->data; 294 return 0; 295 } 296 #endif /*_has_multibyte*/ 297 298 299 #if __STD_C 300 int sfvscanf(Sfio_t* f, reg const char* form, va_list args) 301 #else 302 int sfvscanf(f,form,args) 303 Sfio_t* f; /* file to be scanned */ 304 reg char* form; /* scanning format */ 305 va_list args; 306 #endif 307 { 308 reg int inp, shift, base, width; 309 ssize_t size; 310 int fmt, flags, dot, n_assign, v, n, n_input; 311 char *sp; 312 313 Accept_t acc; 314 315 Argv_t argv; 316 Sffmt_t *ft; 317 Fmt_t *fm, *fmstk; 318 319 Fmtpos_t* fp; 320 char *oform; 321 va_list oargs; 322 int argp, argn; 323 324 int decimal = 0, thousand = 0; 325 326 #if _has_multibyte 327 wchar_t wc; 328 SFMBDCL(fmbs) 329 SFMBDCL(mbs) 330 #endif 331 332 Void_t* value; /* location to assign scanned value */ 333 char* t_str; 334 ssize_t n_str; 335 336 /* local buffering system */ 337 Scan_t scd; 338 uchar *d, *endd, *data; 339 int peek; 340 #define SFbuf(f) (_sfbuf(f,&peek), (data = d = f->next), (endd = f->endb) ) 341 #define SFlen(f) (d - data) 342 #define SFinit(f) ((peek = f->extent < 0 && (f->flags&SF_SHARE)), SFbuf(f) ) 343 #define SFend(f) ((n_input += SFlen(f)), \ 344 (peek ? SFREAD(f,(Void_t*)data,SFlen(f)) : ((f->next = d),0)) ) 345 #define SFgetc(f,c) ((c) = (d < endd || (SFend(f), SFbuf(f), d < endd)) ? \ 346 (int)(*d++) : -1 ) 347 #define SFungetc(f,c) (d -= 1) 348 349 SFMTXDECL(f); 350 351 SFCVINIT(); /* initialize conversion tables */ 352 353 SFMTXENTER(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 do SFgetc(f,inp); while(isspace(inp)); /* skip starting blanks */ 418 SFungetc(f,inp); 419 goto match_1; 420 } 421 422 if(*form == '\0') 423 goto pop_fmt; 424 425 if(*form == '*') 426 { flags = SFFMT_SKIP; 427 form += 1; 428 } 429 else flags = 0; 430 431 /* matching some pattern */ 432 base = 10; size = -1; 433 width = dot = 0; 434 t_str = NIL(char*); n_str = 0; 435 value = NIL(Void_t*); 436 argp = -1; 437 438 loop_flags: /* LOOP FOR FLAGS, WIDTH, BASE, TYPE */ 439 switch((fmt = *form++) ) 440 { 441 case LEFTP : /* get the type which is enclosed in balanced () */ 442 t_str = (char*)form; 443 for(v = 1;;) 444 { switch(*form++) 445 { 446 case 0 : /* not balanceable, retract */ 447 form = t_str; 448 t_str = NIL(char*); 449 n_str = 0; 450 goto loop_flags; 451 case LEFTP : /* increasing nested level */ 452 v += 1; 453 continue; 454 case RIGHTP : /* decreasing nested level */ 455 if((v -= 1) != 0) 456 continue; 457 if(*t_str != '*' ) 458 n_str = (form-1) - t_str; 459 else 460 { t_str = (*_Sffmtintf)(t_str+1,&n); 461 if(*t_str == '$') 462 { if(!fp && 463 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 464 goto pop_fmt; 465 n = FP_SET(n,argn); 466 } 467 else n = FP_SET(-1,argn); 468 469 if(fp) 470 { t_str = fp[n].argv.s; 471 n_str = fp[n].ft.size; 472 } 473 else if(ft && ft->extf ) 474 { FMTSET(ft, form,args, 475 LEFTP, 0, 0, 0,0,0, 476 NIL(char*),0); 477 n = (*ft->extf) 478 (f,(Void_t*)&argv,ft); 479 if(n < 0) 480 goto pop_fmt; 481 if(!(ft->flags&SFFMT_VALUE) ) 482 goto t_arg; 483 if((t_str = argv.s) && 484 (n_str = (int)ft->size) < 0) 485 n_str = strlen(t_str); 486 } 487 else 488 { t_arg: 489 if((t_str = va_arg(args,char*)) ) 490 n_str = strlen(t_str); 491 } 492 } 493 goto loop_flags; 494 } 495 } 496 497 case '#' : /* alternative format */ 498 flags |= SFFMT_ALTER; 499 goto loop_flags; 500 501 case '.' : /* width & base */ 502 dot += 1; 503 if(isdigit(*form)) 504 { fmt = *form++; 505 goto dot_size; 506 } 507 else if(*form == '*') 508 { form = (*_Sffmtintf)(form+1,&n); 509 if(*form == '$') 510 { form += 1; 511 if(!fp && 512 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 513 goto pop_fmt; 514 n = FP_SET(n,argn); 515 } 516 else n = FP_SET(-1,argn); 517 518 if(fp) 519 v = fp[n].argv.i; 520 else if(ft && ft->extf ) 521 { FMTSET(ft, form,args, '.',dot, 0, 0,0,0, 522 NIL(char*), 0); 523 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 524 goto pop_fmt; 525 if(ft->flags&SFFMT_VALUE) 526 v = argv.i; 527 else v = (dot <= 2) ? va_arg(args,int) : 0; 528 } 529 else v = (dot <= 2) ? va_arg(args,int) : 0; 530 if(v < 0) 531 v = 0; 532 goto dot_set; 533 } 534 else goto loop_flags; 535 536 case '0' : case '1' : case '2' : case '3' : case '4' : 537 case '5' : case '6' : case '7' : case '8' : case '9' : 538 dot_size : 539 for(v = fmt-'0'; isdigit(*form); ++form) 540 v = v*10 + (*form - '0'); 541 542 if(*form == '$') 543 { form += 1; 544 if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 545 goto pop_fmt; 546 argp = v-1; 547 goto loop_flags; 548 } 549 550 dot_set : 551 if(dot == 0 || dot == 1) 552 width = v; 553 else if(dot == 2) 554 base = v; 555 goto loop_flags; 556 557 case 'z' : /* ssize_t or object size */ 558 case 'I' : /* object size */ 559 size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG; 560 if(*form == '*') 561 { form = (*_Sffmtintf)(form+1,&n); 562 if(*form == '$') 563 { form += 1; 564 if(!fp && 565 !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1))) 566 goto pop_fmt; 567 n = FP_SET(n,argn); 568 } 569 else n = FP_SET(-1,argn); 570 571 if(fp) /* use position list */ 572 size = fp[n].argv.i; 573 else if(ft && ft->extf ) 574 { FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0, 575 NIL(char*), 0); 576 if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 577 goto pop_fmt; 578 if(ft->flags&SFFMT_VALUE) 579 size = argv.i; 580 else size = va_arg(args,int); 581 } 582 else size = va_arg(args,int); 583 } 584 else if (fmt == 'z') 585 flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG; 586 else if(isdigit(*form)) 587 for(size = 0, n = *form; isdigit(n); n = *++form) 588 size = size*10 + (n - '0'); 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 '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