14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1985-2009 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * Phong Vo <kpv@research.att.com> * 204887Schin * * 214887Schin ***********************************************************************/ 224887Schin #include "sfhdr.h" 234887Schin 244887Schin /* The main engine for reading formatted data 254887Schin ** 264887Schin ** Written by Kiem-Phong Vo. 274887Schin */ 284887Schin 294887Schin #define MAXWIDTH (int)(((uint)~0)>>1) /* max amount to scan */ 304887Schin 314887Schin /* 324887Schin * pull in a private strtold() 334887Schin */ 344887Schin 354887Schin #include "sfstrtof.h" 364887Schin 374887Schin /* refresh stream buffer - taking care of unseekable/share streams too */ 384887Schin #if __STD_C 394887Schin static void _sfbuf(Sfio_t* f, int* peek) 404887Schin #else 414887Schin static void _sfbuf(f, peek) 424887Schin Sfio_t* f; 434887Schin int* peek; 444887Schin #endif 454887Schin { 464887Schin if(f->next >= f->endb) 474887Schin { if(*peek) /* try peeking for a share stream if possible */ 484887Schin { f->mode |= SF_RV; 494887Schin if(SFFILBUF(f,-1) > 0) 504887Schin { f->mode |= SF_PEEK; 514887Schin return; 524887Schin } 534887Schin *peek = 0; /* can't peek, back to normal reads */ 544887Schin } 554887Schin (void)SFFILBUF(f,-1); 564887Schin } 574887Schin } 584887Schin 594887Schin /* buffer used during scanning of a double value or a multi-byte 604887Schin character. the fields mirror certain local variables in sfvscanf. */ 614887Schin typedef struct _scan_s 624887Schin { int error; /* get set by _sfdscan if no value specified */ 634887Schin int inp; /* last input character read */ 644887Schin int width; /* field width */ 654887Schin Sfio_t *f; /* stream being scanned */ 664887Schin uchar *d, *endd, *data; /* local buffering system */ 674887Schin int peek; /* != 0 if unseekable/share stream */ 684887Schin int n_input;/* number of input bytes processed */ 694887Schin } Scan_t; 704887Schin 714887Schin /* ds != 0 for scanning double values */ 724887Schin #define SCinit(sc,ds) ((sc)->inp = (sc)->error = -1, (sc)->f = f, \ 734887Schin ((sc)->width = (ds) ? width : -1), \ 744887Schin (sc)->d = d, (sc)->endd = endd, (sc)->data = data, \ 754887Schin (sc)->peek = peek, (sc)->n_input = n_input) 764887Schin #define SCend(sc,ds) (inp = (sc)->inp, f = (sc)->f, \ 774887Schin (width = (ds) ? (sc)->width : width), \ 784887Schin d = (sc)->d, endd = (sc)->endd, data = (sc)->data, \ 794887Schin peek = (sc)->peek, n_input = (sc)->n_input) 804887Schin 814887Schin #if __STD_C 824887Schin static int _scgetc(void* arg, int flag) 834887Schin #else 844887Schin static int _scgetc(arg, flag) 854887Schin void* arg; 864887Schin int flag; 874887Schin #endif 884887Schin { 894887Schin Scan_t *sc = (Scan_t*)arg; 904887Schin 914887Schin if (flag) 924887Schin { sc->error = flag; 934887Schin return 0; 944887Schin } 954887Schin 964887Schin /* if width >= 0, do not allow to exceed width number of bytes */ 974887Schin if(sc->width == 0) 984887Schin { sc->inp = -1; 994887Schin return 0; 1004887Schin } 1014887Schin 1024887Schin if(sc->d >= sc->endd) /* refresh local buffer */ 1034887Schin { sc->n_input += sc->d - sc->data; 1044887Schin if(sc->peek) 1054887Schin SFREAD(sc->f, sc->data, sc->d - sc->data); 1064887Schin else sc->f->next = sc->d; 1074887Schin 1084887Schin _sfbuf(sc->f, &sc->peek); 1094887Schin sc->data = sc->d = sc->f->next; 1104887Schin sc->endd = sc->f->endb; 1114887Schin 1124887Schin if(sc->d >= sc->endd) 1134887Schin { sc->inp = -1; 1144887Schin return 0; 1154887Schin } 1164887Schin } 1174887Schin 1184887Schin if((sc->width -= 1) >= 0) /* from _sfdscan */ 1194887Schin return (sc->inp = (int)(*sc->d++)); 1204887Schin else return ((int)(*sc->d++)); 1214887Schin } 1224887Schin 1234887Schin /* structure to match characters in a character class */ 1244887Schin typedef struct _accept_s 125*10898Sroland.mainz@nrubsig.org { char ok[SF_MAXCHAR+1]; 1264887Schin int yes; 1274887Schin char *form, *endf; 1284887Schin #if _has_multibyte 1294887Schin wchar_t wc; 1304887Schin #endif 1314887Schin } Accept_t; 1324887Schin 1334887Schin #if __STD_C 1344887Schin static char* _sfsetclass(const char* form, Accept_t* ac, int flags) 1354887Schin #else 1364887Schin static char* _sfsetclass(form, ac, flags) 1374887Schin char* form; /* format string */ 1384887Schin Accept_t* ac; /* values of accepted characters */ 1394887Schin int flags; /* SFFMT_LONG for wchar_t */ 1404887Schin #endif 1414887Schin { 1424887Schin int c, endc, n; 1434887Schin #if _has_multibyte 1444887Schin SFMBDCL(mbs) 1454887Schin #endif 1464887Schin 1474887Schin if(*form == '^') /* complementing this set */ 1484887Schin { ac->yes = 0; 1494887Schin form += 1; 1504887Schin } 1514887Schin else ac->yes = 1; 1524887Schin 1534887Schin for(c = 0; c <= SF_MAXCHAR; ++c) 1544887Schin ac->ok[c] = !ac->yes; 1554887Schin 1564887Schin if(*form == ']' || *form == '-') /* special first char */ 1574887Schin { ac->ok[*form] = ac->yes; 1584887Schin form += 1; 1594887Schin } 1604887Schin ac->form = (char*)form; 1614887Schin 1624887Schin if(flags&SFFMT_LONG) 1634887Schin SFMBCLR(&mbs); 1644887Schin for(n = 1; *form != ']'; form += n) 1654887Schin { if((c = *((uchar*)form)) == 0) 1664887Schin return NIL(char*); 1674887Schin 1684887Schin if(*(form+1) == '-') 1694887Schin { endc = *((uchar*)(form+2)); 1704887Schin #if _has_multibyte 1714887Schin if(c >= 128 || endc >= 128 ) /* range must be ascii */ 1724887Schin goto one_char; 1734887Schin #endif 1744887Schin for(; c <= endc; ++c) 1754887Schin ac->ok[c] = ac->yes; 1764887Schin n = 3; 1774887Schin } 1784887Schin else 1794887Schin { one_char: 1804887Schin #if _has_multibyte /* true multi-byte chars must be checked differently */ 1814887Schin if((flags&SFFMT_LONG) && (n = (int)SFMBLEN(form,&mbs)) <= 0) 1824887Schin return NIL(char*); 1834887Schin if(n == 1) 1844887Schin #endif 1854887Schin ac->ok[c] = ac->yes; 1864887Schin } 1874887Schin } 1884887Schin 1894887Schin ac->endf = (char*)form; 1904887Schin return (char*)(form+1); 1914887Schin } 1924887Schin 1934887Schin #if _has_multibyte 1944887Schin #if __STD_C 1954887Schin static int _sfwaccept(wchar_t wc, Accept_t* ac) 1964887Schin #else 1974887Schin static int _sfwaccept(wc, ac) 1984887Schin wchar_t wc; 1994887Schin Accept_t* ac; 2004887Schin #endif 2014887Schin { 2024887Schin int endc, c, n; 2034887Schin wchar_t fwc; 2044887Schin char *form = ac->form; 2054887Schin SFMBDCL(mbs) 2064887Schin 2074887Schin SFMBCLR(&mbs); 2084887Schin for(n = 1; *form != ']'; form += n) 2094887Schin { if((c = *((uchar*)form)) == 0) 2104887Schin return 0; 2114887Schin 2124887Schin if(*(form+1) == '-') 2134887Schin { endc = *((uchar*)(form+2)); 2144887Schin if(c >= 128 || endc >= 128 ) /* range must be ascii */ 2154887Schin goto one_char; 2164887Schin n = 3; 2174887Schin } 2184887Schin else 2194887Schin { one_char: 2204887Schin if((n = mbrtowc(&fwc, form, ac->endf-form, &mbs)) > 1 && 2214887Schin wc == fwc ) 2224887Schin return ac->yes; 2234887Schin } 2244887Schin } 2254887Schin 2264887Schin return !ac->yes; 2274887Schin } 2284887Schin 2294887Schin #if _has_multibyte == 1 2304887Schin #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,(Void_t*)(mbs)) 2314887Schin #else 2324887Schin #define SFgetwc(sc,wc,fmt,ac,mbs) _sfgetwc(sc,wc,fmt,ac,NIL(Void_t*)) 2334887Schin #endif 2344887Schin 2354887Schin #if __STD_C 2364887Schin static int _sfgetwc(Scan_t* sc, wchar_t* wc, int fmt, Accept_t* ac, Void_t *mbs) 2374887Schin #else 2384887Schin static int _sfgetwc(sc, wc, fmt, ac, mbs) 2394887Schin Scan_t* sc; /* the scanning handle */ 2404887Schin wchar_t* wc; /* to return a scanned wchar_t */ 2414887Schin int fmt; /* %s, %c, %[ */ 2424887Schin Accept_t* ac; /* accept handle for %[ */ 2434887Schin Void_t* mbs; /* multibyte parsing state */ 2444887Schin #endif 2454887Schin { 2464887Schin int n, v; 2474887Schin char b[16]; /* assuming that SFMBMAX <= 16! */ 2484887Schin 2494887Schin /* shift left data so that there will be more room to back up on error. 2504887Schin this won't help streams with small buffers - c'est la vie! */ 2514887Schin if(sc->d > sc->f->data && (n = sc->endd - sc->d) > 0 && n < SFMBMAX) 2524887Schin { memcpy(sc->f->data, sc->d, n); 2534887Schin if(sc->f->endr == sc->f->endb) 2544887Schin sc->f->endr = sc->f->data+n; 2554887Schin if(sc->f->endw == sc->f->endb) 2564887Schin sc->f->endw = sc->f->data+n; 2574887Schin sc->f->endb = sc->f->data+n; 2584887Schin sc->d = sc->data = sc->f->data; 2594887Schin sc->endd = sc->f->endb; 2604887Schin if(!mbs) sc->f->endb = sc->endd; /* stop cc's "unused mbs" warning */ 2614887Schin } 2624887Schin 2634887Schin for(n = 0; n < SFMBMAX; ) 2644887Schin { if((v = _scgetc((Void_t*)sc, 0)) <= 0) 2654887Schin goto no_match; 2664887Schin else b[n++] = v; 2674887Schin 2684887Schin if(mbrtowc(wc, b, n, (mbstate_t*)mbs) == (size_t)(-1)) 2694887Schin goto no_match; /* malformed multi-byte char */ 2704887Schin else 2714887Schin { /* multi-byte char converted successfully */ 2724887Schin if(fmt == 'c') 2734887Schin return 1; 2744887Schin else if(fmt == 's') 2754887Schin { if(n > 1 || (n == 1 && !isspace(b[0]) ) ) 2764887Schin return 1; 2774887Schin else goto no_match; 2784887Schin } 2794887Schin else if(fmt == '[') 2804887Schin { if((n == 1 && ac->ok[b[0]]) || 2814887Schin (n > 1 && _sfwaccept(*wc,ac)) ) 2824887Schin return 1; 2834887Schin else goto no_match; 2844887Schin } 2854887Schin else /* if(fmt == '1') match a single wchar_t */ 2864887Schin { if(*wc == ac->wc) 2874887Schin return 1; 2884887Schin else goto no_match; 2894887Schin } 2904887Schin } 2914887Schin } 2924887Schin 2934887Schin no_match: /* this unget is lossy on a stream with small buffer */ 2944887Schin if((sc->d -= n) < sc->data) 2954887Schin sc->d = sc->data; 2964887Schin return 0; 2974887Schin } 2984887Schin #endif /*_has_multibyte*/ 2994887Schin 3004887Schin 3014887Schin #if __STD_C 3024887Schin int sfvscanf(Sfio_t* f, reg const char* form, va_list args) 3034887Schin #else 3044887Schin int sfvscanf(f,form,args) 3054887Schin Sfio_t* f; /* file to be scanned */ 3064887Schin reg char* form; /* scanning format */ 3074887Schin va_list args; 3084887Schin #endif 3094887Schin { 3104887Schin reg int inp, shift, base, width; 3114887Schin ssize_t size; 3124887Schin int fmt, flags, dot, n_assign, v, n, n_input; 3134887Schin char *sp; 3144887Schin 3154887Schin Accept_t acc; 3164887Schin 3174887Schin Argv_t argv; 3184887Schin Sffmt_t *ft; 3194887Schin Fmt_t *fm, *fmstk; 3204887Schin 3214887Schin Fmtpos_t* fp; 3224887Schin char *oform; 3234887Schin va_list oargs; 3244887Schin int argp, argn; 3254887Schin 3264887Schin int decimal = 0, thousand = 0; 3274887Schin 3284887Schin #if _has_multibyte 3294887Schin wchar_t wc; 3304887Schin SFMBDCL(fmbs) 3314887Schin SFMBDCL(mbs) 3324887Schin #endif 3334887Schin 3344887Schin Void_t* value; /* location to assign scanned value */ 3354887Schin char* t_str; 3364887Schin ssize_t n_str; 3374887Schin 3384887Schin /* local buffering system */ 3394887Schin Scan_t scd; 3404887Schin uchar *d, *endd, *data; 3414887Schin int peek; 3424887Schin #define SFbuf(f) (_sfbuf(f,&peek), (data = d = f->next), (endd = f->endb) ) 3434887Schin #define SFlen(f) (d - data) 3444887Schin #define SFinit(f) ((peek = f->extent < 0 && (f->flags&SF_SHARE)), SFbuf(f) ) 3454887Schin #define SFend(f) ((n_input += SFlen(f)), \ 3464887Schin (peek ? SFREAD(f,(Void_t*)data,SFlen(f)) : ((f->next = d),0)) ) 3474887Schin #define SFgetc(f,c) ((c) = (d < endd || (SFend(f), SFbuf(f), d < endd)) ? \ 3484887Schin (int)(*d++) : -1 ) 3494887Schin #define SFungetc(f,c) (d -= 1) 3504887Schin 3518462SApril.Chin@Sun.COM SFMTXDECL(f); 3528462SApril.Chin@Sun.COM 3534887Schin SFCVINIT(); /* initialize conversion tables */ 3544887Schin 3558462SApril.Chin@Sun.COM SFMTXENTER(f,-1); 3564887Schin 3574887Schin if(!form || f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0) 3584887Schin SFMTXRETURN(f, -1); 3594887Schin SFLOCK(f,0); 3604887Schin 3614887Schin SFinit(f); /* initialize local buffering system */ 3624887Schin 3634887Schin n_assign = n_input = 0; inp = -1; 3644887Schin 3654887Schin fmstk = NIL(Fmt_t*); 3664887Schin ft = NIL(Sffmt_t*); 3674887Schin 3684887Schin fp = NIL(Fmtpos_t*); 3694887Schin argn = -1; 3704887Schin oform = (char*)form; 3714887Schin va_copy(oargs,args); 3724887Schin 3734887Schin SFSETLOCALE(&decimal, &thousand); 3744887Schin 3754887Schin loop_fmt: 3764887Schin SFMBCLR(&fmbs); 3774887Schin while((fmt = *form++)) 3784887Schin { if(fmt != '%') 3794887Schin { if(isspace(fmt)) 3804887Schin { if(fmt != '\n' || !(f->flags&SF_LINE)) 3814887Schin fmt = -1; 3824887Schin for(;;) 3834887Schin { if(SFgetc(f,inp) < 0 || inp == fmt) 3844887Schin goto loop_fmt; 3854887Schin else if(!isspace(inp)) 3864887Schin { SFungetc(f,inp); 3874887Schin goto loop_fmt; 3884887Schin } 3894887Schin } 3904887Schin } 3914887Schin else 3924887Schin { match_1: 3934887Schin #if _has_multibyte 3944887Schin if((n = (int)mbrtowc(&wc,form-1,SFMBMAX,&fmbs)) <= 0) 3954887Schin goto pop_fmt; 3964887Schin if(n > 1) 3974887Schin { acc.wc = wc; 3984887Schin SCinit(&scd,0); SFMBCLR(&mbs); 3994887Schin v = SFgetwc(&scd, &wc, '1', &acc, &mbs); 4004887Schin SCend(&scd,0); 4014887Schin if(v == 0) 4024887Schin goto pop_fmt; 4034887Schin form += n-1; 4044887Schin } 4054887Schin else 4064887Schin #endif 4074887Schin if(SFgetc(f,inp) != fmt) 4084887Schin { if(inp < 0) 4094887Schin goto done; 4104887Schin SFungetc(f,inp); 4114887Schin goto pop_fmt; 4124887Schin } 4134887Schin } 4144887Schin continue; 4154887Schin } 4164887Schin 4174887Schin if(*form == '%') 4184887Schin { form += 1; 4198462SApril.Chin@Sun.COM do SFgetc(f,inp); while(isspace(inp)); /* skip starting blanks */ 4208462SApril.Chin@Sun.COM SFungetc(f,inp); 4214887Schin goto match_1; 4224887Schin } 4234887Schin 4244887Schin if(*form == '\0') 4254887Schin goto pop_fmt; 4264887Schin 4274887Schin if(*form == '*') 4284887Schin { flags = SFFMT_SKIP; 4294887Schin form += 1; 4304887Schin } 4314887Schin else flags = 0; 4324887Schin 4334887Schin /* matching some pattern */ 4344887Schin base = 10; size = -1; 4354887Schin width = dot = 0; 4364887Schin t_str = NIL(char*); n_str = 0; 4374887Schin value = NIL(Void_t*); 4384887Schin argp = -1; 4394887Schin 4404887Schin loop_flags: /* LOOP FOR FLAGS, WIDTH, BASE, TYPE */ 4414887Schin switch((fmt = *form++) ) 4424887Schin { 4434887Schin case LEFTP : /* get the type which is enclosed in balanced () */ 4444887Schin t_str = (char*)form; 4454887Schin for(v = 1;;) 4464887Schin { switch(*form++) 4474887Schin { 4484887Schin case 0 : /* not balanceable, retract */ 4494887Schin form = t_str; 4504887Schin t_str = NIL(char*); 4514887Schin n_str = 0; 4524887Schin goto loop_flags; 4534887Schin case LEFTP : /* increasing nested level */ 4544887Schin v += 1; 4554887Schin continue; 4564887Schin case RIGHTP : /* decreasing nested level */ 4574887Schin if((v -= 1) != 0) 4584887Schin continue; 4594887Schin if(*t_str != '*' ) 4604887Schin n_str = (form-1) - t_str; 4614887Schin else 4624887Schin { t_str = (*_Sffmtintf)(t_str+1,&n); 4634887Schin if(*t_str == '$') 4644887Schin { if(!fp && 4654887Schin !(fp = (*_Sffmtposf) 4664887Schin (f,oform,oargs,ft,1)) ) 4674887Schin goto pop_fmt; 4684887Schin n = FP_SET(n,argn); 4694887Schin } 4704887Schin else n = FP_SET(-1,argn); 4714887Schin 4724887Schin if(fp) 4734887Schin { t_str = fp[n].argv.s; 4744887Schin n_str = fp[n].ft.size; 4754887Schin } 4764887Schin else if(ft && ft->extf ) 4774887Schin { FMTSET(ft, form,args, 4784887Schin LEFTP, 0, 0, 0,0,0, 4794887Schin NIL(char*),0); 4804887Schin n = (*ft->extf) 4814887Schin (f,(Void_t*)&argv,ft); 4824887Schin if(n < 0) 4834887Schin goto pop_fmt; 4844887Schin if(!(ft->flags&SFFMT_VALUE) ) 4854887Schin goto t_arg; 4864887Schin if((t_str = argv.s) && 4874887Schin (n_str = (int)ft->size) < 0) 4884887Schin n_str = strlen(t_str); 4894887Schin } 4904887Schin else 4914887Schin { t_arg: 4924887Schin if((t_str = va_arg(args,char*)) ) 4934887Schin n_str = strlen(t_str); 4944887Schin } 4954887Schin } 4964887Schin goto loop_flags; 4974887Schin } 4984887Schin } 4994887Schin 5004887Schin case '#' : /* alternative format */ 5014887Schin flags |= SFFMT_ALTER; 5024887Schin goto loop_flags; 5034887Schin 5044887Schin case '.' : /* width & base */ 5054887Schin dot += 1; 5064887Schin if(isdigit(*form)) 5074887Schin { fmt = *form++; 5084887Schin goto dot_size; 5094887Schin } 5104887Schin else if(*form == '*') 5114887Schin { form = (*_Sffmtintf)(form+1,&n); 5124887Schin if(*form == '$') 5134887Schin { form += 1; 5144887Schin if(!fp && 5154887Schin !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 5164887Schin goto pop_fmt; 5174887Schin n = FP_SET(n,argn); 5184887Schin } 5194887Schin else n = FP_SET(-1,argn); 5204887Schin 5214887Schin if(fp) 5224887Schin v = fp[n].argv.i; 5234887Schin else if(ft && ft->extf ) 5244887Schin { FMTSET(ft, form,args, '.',dot, 0, 0,0,0, 5254887Schin NIL(char*), 0); 5264887Schin if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 5274887Schin goto pop_fmt; 5284887Schin if(ft->flags&SFFMT_VALUE) 5294887Schin v = argv.i; 5304887Schin else v = (dot <= 2) ? va_arg(args,int) : 0; 5314887Schin } 5324887Schin else v = (dot <= 2) ? va_arg(args,int) : 0; 5334887Schin if(v < 0) 5344887Schin v = 0; 5354887Schin goto dot_set; 5364887Schin } 5374887Schin else goto loop_flags; 5384887Schin 5394887Schin case '0' : case '1' : case '2' : case '3' : case '4' : 5404887Schin case '5' : case '6' : case '7' : case '8' : case '9' : 5414887Schin dot_size : 5424887Schin for(v = fmt-'0'; isdigit(*form); ++form) 5434887Schin v = v*10 + (*form - '0'); 5444887Schin 5454887Schin if(*form == '$') 5464887Schin { form += 1; 5474887Schin if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) ) 5484887Schin goto pop_fmt; 5494887Schin argp = v-1; 5504887Schin goto loop_flags; 5514887Schin } 5524887Schin 5534887Schin dot_set : 5544887Schin if(dot == 0 || dot == 1) 5554887Schin width = v; 5564887Schin else if(dot == 2) 5574887Schin base = v; 5584887Schin goto loop_flags; 5594887Schin 5604887Schin case 'I' : /* object size */ 5614887Schin size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG; 5624887Schin if(isdigit(*form)) 5634887Schin { for(size = 0, n = *form; isdigit(n); n = *++form) 5644887Schin size = size*10 + (n - '0'); 5654887Schin } 5664887Schin else if(*form == '*') 5674887Schin { form = (*_Sffmtintf)(form+1,&n); 5684887Schin if(*form == '$') 5694887Schin { form += 1; 5704887Schin if(!fp && 5714887Schin !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1))) 5724887Schin goto pop_fmt; 5734887Schin n = FP_SET(n,argn); 5744887Schin } 5754887Schin else n = FP_SET(-1,argn); 5764887Schin 5774887Schin if(fp) /* use position list */ 5784887Schin size = fp[n].argv.i; 5794887Schin else if(ft && ft->extf ) 5804887Schin { FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0, 5814887Schin NIL(char*), 0); 5824887Schin if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) 5834887Schin goto pop_fmt; 5844887Schin if(ft->flags&SFFMT_VALUE) 5854887Schin size = argv.i; 5864887Schin else size = va_arg(args,int); 5874887Schin } 5884887Schin else size = va_arg(args,int); 5894887Schin } 5904887Schin goto loop_flags; 5914887Schin 5924887Schin case 'l' : 5934887Schin size = -1; flags &= ~SFFMT_TYPES; 5944887Schin if(*form == 'l') 5954887Schin { form += 1; 5964887Schin flags |= SFFMT_LLONG; 5974887Schin } 5984887Schin else flags |= SFFMT_LONG; 5994887Schin goto loop_flags; 6004887Schin case 'h' : 6014887Schin size = -1; flags &= ~SFFMT_TYPES; 6024887Schin if(*form == 'h') 6034887Schin { form += 1; 6044887Schin flags |= SFFMT_SSHORT; 6054887Schin } 6064887Schin else flags |= SFFMT_SHORT; 6074887Schin goto loop_flags; 6084887Schin case 'L' : 6094887Schin size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_LDOUBLE; 6104887Schin goto loop_flags; 6114887Schin case 'j' : 6124887Schin size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_JFLAG; 6134887Schin goto loop_flags; 6144887Schin case 'z' : 6154887Schin size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG; 6164887Schin goto loop_flags; 6174887Schin case 't' : 6184887Schin size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_TFLAG; 6194887Schin goto loop_flags; 6204887Schin case QUOTE : 6214887Schin if(thousand > 0) 6224887Schin flags |= SFFMT_THOUSAND; 6234887Schin goto loop_flags; 6244887Schin } 6254887Schin 6264887Schin /* set object size for scalars */ 6274887Schin if(flags & SFFMT_TYPES) 6284887Schin { if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n') 6294887Schin { if(flags&SFFMT_LONG) 6304887Schin size = sizeof(long); 6314887Schin else if(flags&SFFMT_SHORT) 6324887Schin size = sizeof(short); 6334887Schin else if(flags&SFFMT_SSHORT) 6344887Schin size = sizeof(char); 6354887Schin else if(flags&SFFMT_TFLAG) 6364887Schin size = sizeof(ptrdiff_t); 6374887Schin else if(flags&SFFMT_ZFLAG) 6384887Schin size = sizeof(size_t); 6394887Schin else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) ) 6404887Schin size = sizeof(Sflong_t); 6414887Schin else if(flags&SFFMT_IFLAG) 6424887Schin { if(size <= 0 || 6434887Schin size == sizeof(Sflong_t)*CHAR_BIT ) 6444887Schin size = sizeof(Sflong_t); 6454887Schin } 6464887Schin else if(size < 0) 6474887Schin size = sizeof(int); 6484887Schin } 6494887Schin else if(_Sftype[fmt]&SFFMT_FLOAT) 6504887Schin { if(flags&(SFFMT_LONG|SFFMT_LLONG)) 6514887Schin size = sizeof(double); 6524887Schin else if(flags&SFFMT_LDOUBLE) 6534887Schin size = sizeof(Sfdouble_t); 6544887Schin else if(flags&SFFMT_IFLAG) 6554887Schin { if(size <= 0) 6564887Schin size = sizeof(Sfdouble_t); 6574887Schin } 6584887Schin else if(size < 0) 6594887Schin size = sizeof(float); 6604887Schin } 6614887Schin else if(_Sftype[fmt]&SFFMT_CHAR) 6624887Schin { 6634887Schin #if _has_multibyte 6644887Schin if((flags&SFFMT_LONG) || fmt == 'C') 6654887Schin { size = sizeof(wchar_t) > sizeof(int) ? 6664887Schin sizeof(wchar_t) : sizeof(int); 6674887Schin } else 6684887Schin #endif 6694887Schin if(size < 0) 6704887Schin size = sizeof(int); 6714887Schin } 6724887Schin } 6734887Schin 6744887Schin argp = FP_SET(argp,argn); 6754887Schin if(fp) 6764887Schin { if(!(fp[argp].ft.flags&SFFMT_SKIP) ) 6774887Schin { n_assign += 1; 6784887Schin value = fp[argp].argv.vp; 6794887Schin size = fp[argp].ft.size; 6804887Schin if(ft && ft->extf && fp[argp].ft.fmt != fp[argp].fmt) 6814887Schin fmt = fp[argp].ft.fmt; 6824887Schin } 6834887Schin else flags |= SFFMT_SKIP; 6844887Schin } 6854887Schin else if(ft && ft->extf) 6864887Schin { FMTSET(ft, form,args, fmt, size,flags, width,0,base, t_str,n_str); 6874887Schin SFend(f); SFOPEN(f,0); 6884887Schin v = (*ft->extf)(f, (Void_t*)&argv, ft); 6894887Schin SFLOCK(f,0); SFbuf(f); 6904887Schin 6914887Schin if(v < 0) 6924887Schin goto pop_fmt; 6934887Schin else if(v > 0) /* extf comsumed v input bytes */ 6944887Schin { n_input += v; 6954887Schin if(!(ft->flags&SFFMT_SKIP) ) 6964887Schin n_assign += 1; 6974887Schin continue; 6984887Schin } 6994887Schin else /* if(v == 0): extf did not use input stream */ 7004887Schin { FMTGET(ft, form,args, fmt, size, flags, width,n,base); 7014887Schin 7024887Schin if((ft->flags&SFFMT_VALUE) && !(ft->flags&SFFMT_SKIP) ) 7034887Schin value = argv.vp; 7044887Schin } 7054887Schin } 7064887Schin 7074887Schin if(_Sftype[fmt] == 0) /* unknown pattern */ 7084887Schin goto pop_fmt; 7094887Schin 7104887Schin if(fmt == '!') 7114887Schin { if(!fp) 7124887Schin fp = (*_Sffmtposf)(f,oform,oargs,ft,1); 7134887Schin else goto pop_fmt; 7144887Schin 7154887Schin if(!(argv.ft = va_arg(args,Sffmt_t*)) ) 7164887Schin continue; 7174887Schin if(!argv.ft->form && ft ) /* change extension functions */ 7184887Schin { if(ft->eventf && 7194887Schin (*ft->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0) 7204887Schin continue; 7214887Schin fmstk->ft = ft = argv.ft; 7224887Schin } 7234887Schin else /* stack a new environment */ 7244887Schin { if(!(fm = (Fmt_t*)malloc(sizeof(Fmt_t))) ) 7254887Schin goto done; 7264887Schin 7274887Schin ft = fm->ft = argv.ft; 7284887Schin SFMBSET(ft->mbs, &fmbs); 7294887Schin if(ft->form) 7304887Schin { fm->form = (char*)form; SFMBCPY(&fm->mbs,&fmbs); 7314887Schin va_copy(fm->args,args); 7324887Schin 7334887Schin fm->oform = oform; 7344887Schin va_copy(fm->oargs,oargs); 7354887Schin fm->argn = argn; 7364887Schin fm->fp = fp; 7374887Schin 7384887Schin form = ft->form; SFMBCLR(ft->mbs); 7394887Schin va_copy(args,ft->args); 7404887Schin argn = -1; 7414887Schin fp = NIL(Fmtpos_t*); 7424887Schin oform = (char*)form; 7434887Schin va_copy(oargs,args); 7444887Schin } 7454887Schin else fm->form = NIL(char*); 7464887Schin 7474887Schin fm->eventf = ft->eventf; 7484887Schin fm->next = fmstk; 7494887Schin fmstk = fm; 7504887Schin } 7514887Schin continue; 7524887Schin } 7534887Schin 7544887Schin /* get the address to assign value */ 7554887Schin if(!value && !(flags&SFFMT_SKIP) ) 7564887Schin value = va_arg(args,Void_t*); 7574887Schin 7584887Schin if(fmt == 'n') /* return length of consumed input */ 7594887Schin { 7604887Schin #if !_ast_intmax_long 7614887Schin if(size == sizeof(Sflong_t) ) 7624887Schin *((Sflong_t*)value) = (Sflong_t)(n_input+SFlen(f)); 7634887Schin else 7644887Schin #endif 7654887Schin if(size == sizeof(long) ) 7664887Schin *((long*)value) = (long)(n_input+SFlen(f)); 7674887Schin else if(size == sizeof(short) ) 7684887Schin *((short*)value) = (short)(n_input+SFlen(f)); 7694887Schin else if(size == sizeof(uchar)) 7704887Schin *((uchar*)value) = (uchar)(n_input+SFlen(f)); 7714887Schin else *((int*)value) = (int)(n_input+SFlen(f)); 7724887Schin continue; 7734887Schin } 7744887Schin 7754887Schin /* if get here, start scanning input */ 7764887Schin if(width == 0) 7774887Schin width = fmt == 'c' ? 1 : MAXWIDTH; 7784887Schin 7794887Schin /* define the first input character */ 7804887Schin if(fmt == 'c' || fmt == '[' || fmt == 'C' ) 7814887Schin SFgetc(f,inp); 7824887Schin else 7834887Schin { do { SFgetc(f,inp); } 7844887Schin while(isspace(inp)); /* skip starting blanks */ 7854887Schin } 7864887Schin if(inp < 0) 7874887Schin goto done; 7884887Schin 7894887Schin if(_Sftype[fmt] == SFFMT_FLOAT) 7904887Schin { SFungetc(f,inp); SCinit(&scd,1); 7914887Schin argv.ld = _sfdscan((Void_t*)(&scd), _scgetc); 7924887Schin SCend(&scd,1); 7934887Schin 7944887Schin if(scd.error >= 0) 7954887Schin { if(inp >= 0) 7964887Schin SFungetc(f, inp); 7974887Schin goto pop_fmt; 7984887Schin } 7994887Schin 8004887Schin if(value) 8014887Schin { 8024887Schin #if !_ast_fltmax_double 8034887Schin if(size == sizeof(Sfdouble_t)) 8044887Schin *((Sfdouble_t*)value) = argv.ld; 8054887Schin else 8064887Schin #endif 8074887Schin if(size == sizeof(double)) 8084887Schin *((double*)value) = (double)argv.ld; 8094887Schin else *((float*)value) = (float)argv.ld; 8104887Schin 8114887Schin n_assign += 1; 8124887Schin } 8134887Schin } 8144887Schin else if(_Sftype[fmt] == SFFMT_UINT || fmt == 'p') 8154887Schin { if(inp == '-') 8164887Schin { SFungetc(f,inp); 8174887Schin goto pop_fmt; 8184887Schin } 8194887Schin else goto int_cvt; 8204887Schin } 8214887Schin else if(_Sftype[fmt] == SFFMT_INT) 8224887Schin { int_cvt: 8234887Schin if(inp == '-' || inp == '+') 8244887Schin { if(inp == '-') 8254887Schin flags |= SFFMT_MINUS; 8264887Schin while(--width > 0 && SFgetc(f,inp) >= 0) 8274887Schin if(!isspace(inp)) 8284887Schin break; 8294887Schin } 8304887Schin if(inp < 0) 8314887Schin goto done; 8324887Schin 8334887Schin if(fmt == 'o') 8344887Schin base = 8; 8354887Schin else if(fmt == 'x' || fmt == 'X' || fmt == 'p') 8364887Schin base = 16; 8374887Schin else if(fmt == 'i' && inp == '0') /* self-described data */ 8384887Schin { base = 8; 8394887Schin if(width > 1) /* peek to see if it's a base-16 */ 8404887Schin { if(SFgetc(f,inp) >= 0) 8414887Schin { if(inp == 'x' || inp == 'X') 8424887Schin base = 16; 8434887Schin SFungetc(f,inp); 8444887Schin } 8454887Schin inp = '0'; 8464887Schin } 8474887Schin } 8484887Schin 8494887Schin /* now convert */ 8504887Schin argv.lu = 0; 8514887Schin if(base == 16) 8524887Schin { sp = (char*)_Sfcv36; 8534887Schin shift = 4; 8544887Schin if(sp[inp] >= 16) 8554887Schin { SFungetc(f,inp); 8564887Schin goto pop_fmt; 8574887Schin } 8584887Schin if(inp == '0' && --width > 0) 8594887Schin { /* skip leading 0x or 0X */ 8604887Schin if(SFgetc(f,inp) >= 0 && 8614887Schin (inp == 'x' || inp == 'X') && --width > 0) 8624887Schin SFgetc(f,inp); 8634887Schin } 8644887Schin if(inp >= 0 && sp[inp] < 16) 8654887Schin goto base_shift; 8664887Schin } 8674887Schin else if(base == 10) 8684887Schin { for(n = v = 0;; ) 8694887Schin { /* fast base 10 conversion */ 8704887Schin #define TEN(x) (((x) << 3) + ((x) << 1) ) 8714887Schin if (inp >= '0' && inp <= '9') 8724887Schin { argv.lu = TEN(argv.lu) + (inp-'0'); 8734887Schin n += 1; 8744887Schin } 8754887Schin else if(inp == thousand) 8764887Schin { if((v && n != 3) || (!v && n > 3) ) 8774887Schin break; 8784887Schin v = 1; n = 0; 8794887Schin } 8804887Schin else break; 8814887Schin if((width -= 1) <= 0 || SFgetc(f,inp) < 0) 8824887Schin break; 8834887Schin } 8844887Schin if (!n && !v) 8854887Schin { SFungetc(f,inp); 8864887Schin goto pop_fmt; 8874887Schin } 8884887Schin 8894887Schin if(fmt == 'i' && inp == '#' && !(flags&SFFMT_ALTER) ) 8904887Schin { base = (int)argv.lu; 8914887Schin if(base < 2 || base > SF_RADIX) 8924887Schin goto pop_fmt; 8934887Schin argv.lu = 0; 8944887Schin sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64); 8954887Schin if(--width > 0 && 8964887Schin SFgetc(f,inp) >= 0 && sp[inp] < base) 8974887Schin goto base_conv; 8984887Schin } 8994887Schin } 9004887Schin else 9014887Schin { /* other bases */ 9024887Schin sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64); 9034887Schin if(base < 2 || base > SF_RADIX || sp[inp] >= base) 9044887Schin { SFungetc(f,inp); 9054887Schin goto pop_fmt; 9064887Schin } 9074887Schin 9084887Schin base_conv: /* check for power of 2 conversions */ 9094887Schin if((base & ~(base-1)) == base) 9104887Schin { if(base < 8) 9114887Schin shift = base < 4 ? 1 : 2; 9124887Schin else if(base < 32) 9134887Schin shift = base < 16 ? 3 : 4; 9144887Schin else shift = base < 64 ? 5 : 6; 9154887Schin 9164887Schin base_shift: do 9174887Schin { argv.lu = (argv.lu << shift) + sp[inp]; 9184887Schin } while(--width > 0 && 9194887Schin SFgetc(f,inp) >= 0 && sp[inp] < base); 9204887Schin } 9214887Schin else 9224887Schin { do 9234887Schin { argv.lu = (argv.lu * base) + sp[inp]; 9244887Schin } while(--width > 0 && 9254887Schin SFgetc(f,inp) >= 0 && sp[inp] < base); 9264887Schin } 9274887Schin } 9284887Schin 9294887Schin if(flags&SFFMT_MINUS) 9304887Schin argv.ll = -argv.ll; 9314887Schin 9324887Schin if(value) 9334887Schin { n_assign += 1; 9344887Schin 9354887Schin if(fmt == 'p') 9364887Schin #if _more_void_int 9374887Schin *((Void_t**)value) = (Void_t*)((ulong)argv.lu); 9384887Schin #else 9394887Schin *((Void_t**)value) = (Void_t*)((uint)argv.lu); 9404887Schin #endif 9414887Schin #if !_ast_intmax_long 9424887Schin else if(size == sizeof(Sflong_t)) 9434887Schin *((Sflong_t*)value) = argv.ll; 9444887Schin #endif 9454887Schin else if(size == sizeof(long)) 9464887Schin { if(fmt == 'd' || fmt == 'i') 9474887Schin *((long*)value) = (long)argv.ll; 9484887Schin else *((ulong*)value) = (ulong)argv.lu; 9494887Schin } 9504887Schin else if(size == sizeof(short)) 9514887Schin { if(fmt == 'd' || fmt == 'i') 9524887Schin *((short*)value) = (short)argv.ll; 9534887Schin else *((ushort*)value) = (ushort)argv.lu; 9544887Schin } 9554887Schin else if(size == sizeof(char) ) 9564887Schin { if(fmt == 'd' || fmt == 'i') 9574887Schin *((char*)value) = (char)argv.ll; 9584887Schin else *((uchar*)value) = (uchar)argv.lu; 9594887Schin } 9604887Schin else 9614887Schin { if(fmt == 'd' || fmt == 'i') 9624887Schin *((int*)value) = (int)argv.ll; 9634887Schin else *((uint*)value) = (uint)argv.lu; 9644887Schin } 9654887Schin } 9664887Schin } 9674887Schin else if(fmt == 'C' || fmt == 'S') 9684887Schin { fmt = fmt == 'C' ? 'c' : 's'; 9694887Schin flags = (flags & ~SFFMT_TYPES) | SFFMT_LONG; 9704887Schin goto do_string; 9714887Schin } 9724887Schin else if(fmt == 's' || fmt == 'c' || fmt == '[' ) 9734887Schin { do_string: 9744887Schin if(value) 9754887Schin { if(size < 0) 9764887Schin size = MAXWIDTH; 9774887Schin if(fmt != 'c') 9784887Schin size -= 1; 9794887Schin #if _has_multibyte 9804887Schin if(flags&SFFMT_LONG) 9814887Schin argv.ws = (wchar_t*)value; 9824887Schin else 9834887Schin #endif 9844887Schin argv.s = (char*)value; 9854887Schin } 9864887Schin else size = 0; 9874887Schin 9884887Schin if(fmt == '[' && !(form = _sfsetclass(form,&acc,flags)) ) 9894887Schin { SFungetc(f,inp); 9904887Schin goto pop_fmt; 9914887Schin } 9924887Schin 9934887Schin n = 0; /* count number of scanned characters */ 9944887Schin #if _has_multibyte 9954887Schin if(flags&SFFMT_LONG) 9964887Schin { SFungetc(f,inp); SCinit(&scd,0); SFMBCLR(&mbs); 9974887Schin for(; width > 0; --width) 9984887Schin { if(SFgetwc(&scd,&wc,fmt,&acc,&mbs) == 0) 9994887Schin break; 10004887Schin if((n += 1) <= size) 10014887Schin *argv.ws++ = wc; 10024887Schin } 10034887Schin SCend(&scd,0); 10044887Schin } 10054887Schin else 10064887Schin #endif 10074887Schin 10084887Schin if(fmt == 's') 10094887Schin { do 10104887Schin { if(isspace(inp)) 10114887Schin break; 10124887Schin if((n += 1) <= size) 10134887Schin *argv.s++ = inp; 10144887Schin } while(--width > 0 && SFgetc(f,inp) >= 0); 10154887Schin } 10164887Schin else if(fmt == 'c') 10174887Schin { do 10184887Schin { if((n += 1) <= size) 10194887Schin *argv.s++ = inp; 10204887Schin } while(--width > 0 && SFgetc(f,inp) >= 0); 10214887Schin } 10224887Schin else /* if(fmt == '[') */ 10234887Schin { do 10244887Schin { if(!acc.ok[inp]) 10254887Schin { if(n > 0 || (flags&SFFMT_ALTER) ) 10264887Schin break; 10274887Schin else 10284887Schin { SFungetc(f,inp); 10294887Schin goto pop_fmt; 10304887Schin } 10314887Schin } 10324887Schin if((n += 1) <= size) 10334887Schin *argv.s++ = inp; 10344887Schin } while(--width > 0 && SFgetc(f,inp) >= 0); 10354887Schin } 10364887Schin 10374887Schin if(value && (n > 0 || fmt == '[') ) 10384887Schin { n_assign += 1; 10394887Schin if(fmt != 'c' && size >= 0) 10404887Schin { 10414887Schin #if _has_multibyte 10424887Schin if(flags&SFFMT_LONG) 10434887Schin *argv.ws = 0; 10444887Schin else 10454887Schin #endif 10464887Schin *argv.s = 0; 10474887Schin } 10484887Schin } 10494887Schin } 10504887Schin 10514887Schin if(width > 0 && inp >= 0) 10524887Schin SFungetc(f,inp); 10534887Schin } 10544887Schin 10554887Schin pop_fmt: 10564887Schin if(fp) 10574887Schin { free(fp); 10584887Schin fp = NIL(Fmtpos_t*); 10594887Schin } 10604887Schin while((fm = fmstk) ) /* pop the format stack and continue */ 10614887Schin { if(fm->eventf) 10624887Schin { if(!form || !form[0]) 10634887Schin (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),ft); 10644887Schin else if((*fm->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0) 10654887Schin goto loop_fmt; 10664887Schin } 10674887Schin 10684887Schin fmstk = fm->next; 10694887Schin if((form = fm->form) ) 10704887Schin { SFMBCPY(&fmbs,&fm->mbs); 10714887Schin va_copy(args, fm->args); 10724887Schin oform = fm->oform; 10734887Schin va_copy(oargs,fm->oargs); 10744887Schin argn = fm->argn; 10754887Schin fp = fm->fp; 10764887Schin } 10774887Schin ft = fm->ft; 10784887Schin free(fm); 10794887Schin if(form && form[0]) 10804887Schin goto loop_fmt; 10814887Schin } 10824887Schin 10834887Schin done: 10844887Schin if(fp) 10854887Schin free(fp); 10864887Schin while((fm = fmstk) ) 10874887Schin { if(fm->eventf) 10884887Schin (*fm->eventf)(f,SF_FINAL,NIL(Void_t*),fm->ft); 10894887Schin fmstk = fm->next; 10904887Schin free(fm); 10914887Schin } 10924887Schin 10934887Schin SFend(f); 10944887Schin 10954887Schin SFOPEN(f,0); 10964887Schin 10974887Schin if(n_assign == 0 && inp < 0) 10984887Schin n_assign = -1; 10994887Schin 11004887Schin SFMTXRETURN(f,n_assign); 11014887Schin } 1102