#include "sfhdr.h" /* Dealing with $ argument addressing stuffs. ** ** Written by Kiem-Phong Vo. */ #if __STD_C static char* sffmtint(const char* str, int* v) #else static char* sffmtint(str, v) char* str; int* v; #endif { for(*v = 0; isdigit(*str); ++str) *v = *v * 10 + (*str - '0'); *v -= 1; return (char*)str; } #if __STD_C static Fmtpos_t* sffmtpos(Sfio_t* f, const char* form, va_list args, int type) #else static Fmtpos_t* sffmtpos(f,form,args,type) Sfio_t* f; char* form; va_list args; int type; #endif { int base, fmt, flags, dot, width, precis; ssize_t n_str, size; char *t_str, *sp; int v, n, skip, dollar, decimal, thousand; Sffmt_t *ft, savft; Fmtpos_t* fp; /* position array of arguments */ int argp, argn, maxp, need[FP_INDEX]; if(type < 0) fp = NIL(Fmtpos_t*); else if(!(fp = sffmtpos(f,form,args,-1)) ) return NIL(Fmtpos_t*); dollar = 0; argn = maxp = -1; while((n = *form) ) { if(n != '%') /* collect the non-pattern chars */ { sp = (char*)form++; while(*form && *form != '%') form += 1; continue; } else form += 1; if(*form == 0) break; else if(*form == '%') { form += 1; continue; } if(*form == '*' && type > 0) /* skip in scanning */ { skip = 1; form += 1; argp = -1; } else /* get the position of this argument */ { skip = 0; sp = sffmtint(form,&argp); if(*sp == '$') { dollar = 1; form = sp+1; } else argp = -1; } flags = dot = 0; t_str = NIL(char*); n_str = 0; size = width = precis = base = -1; for(n = 0; n < FP_INDEX; ++n) need[n] = -1; loop_flags: /* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */ switch((fmt = *form++) ) { case LEFTP : /* get the type enclosed in balanced parens */ t_str = (char*)form; for(v = 1;;) { switch(*form++) { case 0 : /* not balancable, retract */ form = t_str; t_str = NIL(char*); n_str = 0; goto loop_flags; case LEFTP : /* increasing nested level */ v += 1; continue; case RIGHTP : /* decreasing nested level */ if((v -= 1) != 0) continue; n_str = form-t_str; if(*t_str == '*') { t_str = sffmtint(t_str+1,&n); if(*t_str == '$') dollar = 1; else n = -1; if((n = FP_SET(n,argn)) > maxp) maxp = n; if(fp && fp[n].ft.fmt == 0) { fp[n].ft.fmt = LEFTP; fp[n].ft.form = (char*)form; } need[FP_STR] = n; } goto loop_flags; } } case '-' : flags |= SFFMT_LEFT; flags &= ~SFFMT_ZERO; goto loop_flags; case '0' : if(!(flags&SFFMT_LEFT) ) flags |= SFFMT_ZERO; goto loop_flags; case ' ' : if(!(flags&SFFMT_SIGN) ) flags |= SFFMT_BLANK; goto loop_flags; case '+' : flags |= SFFMT_SIGN; flags &= ~SFFMT_BLANK; goto loop_flags; case '#' : flags |= SFFMT_ALTER; goto loop_flags; case QUOTE: SFSETLOCALE(&decimal,&thousand); if(thousand) flags |= SFFMT_THOUSAND; goto loop_flags; case '.' : if((dot += 1) == 2) base = 0; /* for %s,%c */ if(isdigit(*form)) { fmt = *form++; goto dot_size; } else if(*form != '*') goto loop_flags; else form += 1; /* drop thru below */ case '*' : form = sffmtint(form,&n); if(*form == '$' ) { dollar = 1; form += 1; } else n = -1; if((n = FP_SET(n,argn)) > maxp) maxp = n; if(fp && fp[n].ft.fmt == 0) { fp[n].ft.fmt = '.'; fp[n].ft.size = dot; fp[n].ft.form = (char*)form; } if(dot <= 2) need[dot] = n; goto loop_flags; case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : dot_size : for(v = fmt - '0', fmt = *form; isdigit(fmt); fmt = *++form) v = v*10 + (fmt - '0'); if(dot == 0) width = v; else if(dot == 1) precis = v; else if(dot == 2) base = v; goto loop_flags; case 'I' : /* object length */ size = 0; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG; if(isdigit(*form) ) { for(n = *form; isdigit(n); n = *++form) size = size*10 + (n - '0'); } else if(*form == '*') { form = sffmtint(form+1,&n); if(*form == '$' ) { dollar = 1; form += 1; } else n = -1; if((n = FP_SET(n,argn)) > maxp) maxp = n; if(fp && fp[n].ft.fmt == 0) { fp[n].ft.fmt = 'I'; fp[n].ft.size = sizeof(int); fp[n].ft.form = (char*)form; } need[FP_SIZE] = n; } goto loop_flags; case 'l' : size = -1; flags &= ~SFFMT_TYPES; if(*form == 'l') { form += 1; flags |= SFFMT_LLONG; } else flags |= SFFMT_LONG; goto loop_flags; case 'h' : size = -1; flags &= ~SFFMT_TYPES; if(*form == 'h') { form += 1; flags |= SFFMT_SSHORT; } else flags |= SFFMT_SHORT; goto loop_flags; case 'L' : size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_LDOUBLE; goto loop_flags; } if(flags & (SFFMT_TYPES & ~SFFMT_IFLAG) ) { if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n') { size = (flags&SFFMT_LLONG) ? sizeof(Sflong_t) : (flags&SFFMT_LONG) ? sizeof(long) : (flags&SFFMT_SHORT) ? sizeof(short) : (flags&SFFMT_SSHORT) ? sizeof(char) : (flags&SFFMT_JFLAG) ? sizeof(Sflong_t) : (flags&SFFMT_TFLAG) ? sizeof(ptrdiff_t) : (flags&SFFMT_ZFLAG) ? sizeof(size_t) : -1; } else if(_Sftype[fmt]&SFFMT_FLOAT) { size = (flags&SFFMT_LDOUBLE) ? sizeof(Sfdouble_t) : (flags&(SFFMT_LONG|SFFMT_LLONG)) ? sizeof(double) : -1; } } if(skip) continue; if((argp = FP_SET(argp,argn)) > maxp) maxp = argp; if(dollar && fmt == '!') return NIL(Fmtpos_t*); if(fp && fp[argp].ft.fmt == 0) { fp[argp].ft.form = (char*)form; fp[argp].ft.fmt = fp[argp].fmt = fmt; fp[argp].ft.size = size; fp[argp].ft.flags = flags; fp[argp].ft.width = width; fp[argp].ft.precis = precis; fp[argp].ft.base = base; fp[argp].ft.t_str = t_str; fp[argp].ft.n_str = n_str; for(n = 0; n < FP_INDEX; ++n) fp[argp].need[n] = need[n]; } } if(!fp) /* constructing position array only */ { if(!dollar || !(fp = (Fmtpos_t*)malloc((maxp+1)*sizeof(Fmtpos_t))) ) return NIL(Fmtpos_t*); for(n = 0; n <= maxp; ++n) fp[n].ft.fmt = 0; return fp; } /* get value for positions */ for(n = 0, ft = NIL(Sffmt_t*); n <= maxp; ++n) { if(fp[n].ft.fmt == 0) /* gap: pretend it's a 'd' pattern */ { fp[n].ft.fmt = 'd'; fp[n].ft.width = 0; fp[n].ft.precis = 0; fp[n].ft.base = 0; fp[n].ft.size = 0; fp[n].ft.t_str = 0; fp[n].ft.n_str = 0; fp[n].ft.flags = 0; for(v = 0; v < FP_INDEX; ++v) fp[n].need[v] = -1; } if(ft && ft->extf) { fp[n].ft.version = ft->version; fp[n].ft.extf = ft->extf; fp[n].ft.eventf = ft->eventf; if((v = fp[n].need[FP_WIDTH]) >= 0 && v < n) fp[n].ft.width = fp[v].argv.i; if((v = fp[n].need[FP_PRECIS]) >= 0 && v < n) fp[n].ft.precis = fp[v].argv.i; if((v = fp[n].need[FP_BASE]) >= 0 && v < n) fp[n].ft.base = fp[v].argv.i; if((v = fp[n].need[FP_STR]) >= 0 && v < n) fp[n].ft.t_str = fp[v].argv.s; if((v = fp[n].need[FP_SIZE]) >= 0 && v < n) fp[n].ft.size = fp[v].argv.i; memcpy(ft,&fp[n].ft,sizeof(Sffmt_t)); va_copy(ft->args,args); ft->flags |= SFFMT_ARGPOS; v = (*ft->extf)(f, (Void_t*)(&fp[n].argv), ft); va_copy(args,ft->args); memcpy(&fp[n].ft,ft,sizeof(Sffmt_t)); if(v < 0) { memcpy(ft,&savft,sizeof(Sffmt_t)); ft = NIL(Sffmt_t*); } if(!(fp[n].ft.flags&SFFMT_VALUE) ) goto arg_list; } else { arg_list: if(fp[n].ft.fmt == LEFTP) { fp[n].argv.s = va_arg(args, char*); fp[n].ft.size = strlen(fp[n].argv.s); } else if(fp[n].ft.fmt == '.' || fp[n].ft.fmt == 'I') fp[n].argv.i = va_arg(args, int); else if(fp[n].ft.fmt == '!') { if(ft) memcpy(ft,&savft,sizeof(Sffmt_t)); fp[n].argv.ft = ft = va_arg(args, Sffmt_t*); if(ft->form) ft = NIL(Sffmt_t*); if(ft) memcpy(&savft,ft,sizeof(Sffmt_t)); } else if(type > 0) /* from sfvscanf */ fp[n].argv.vp = va_arg(args, Void_t*); else switch(_Sftype[fp[n].ft.fmt]) { case SFFMT_INT: case SFFMT_UINT: #if !_ast_intmax_long if(FMTCMP(size, Sflong_t, Sflong_t)) fp[n].argv.ll = va_arg(args, Sflong_t); else #endif if(FMTCMP(size, long, Sflong_t) ) fp[n].argv.l = va_arg(args, long); else fp[n].argv.i = va_arg(args, int); break; case SFFMT_FLOAT: #if !_ast_fltmax_double if(FMTCMP(size, Sfdouble_t, Sfdouble_t)) fp[n].argv.ld = va_arg(args,Sfdouble_t); else #endif fp[n].argv.d = va_arg(args,double); break; case SFFMT_POINTER: fp[n].argv.vp = va_arg(args,Void_t*); break; case SFFMT_BYTE: if(fp[n].ft.base >= 0) fp[n].argv.s = va_arg(args,char*); else fp[n].argv.c = (char)va_arg(args,int); break; default: /* unknown pattern */ break; } } } if(ft) memcpy(ft,&savft,sizeof(Sffmt_t)); return fp; } /* function to initialize conversion tables */ static int sfcvinit() { reg int d, l; for(d = 0; d <= SF_MAXCHAR; ++d) { _Sfcv36[d] = SF_RADIX; _Sfcv64[d] = SF_RADIX; } /* [0-9] */ for(d = 0; d < 10; ++d) { _Sfcv36[(uchar)_Sfdigits[d]] = d; _Sfcv64[(uchar)_Sfdigits[d]] = d; } /* [a-z] */ for(; d < 36; ++d) { _Sfcv36[(uchar)_Sfdigits[d]] = d; _Sfcv64[(uchar)_Sfdigits[d]] = d; } /* [A-Z] */ for(l = 10; d < 62; ++l, ++d) { _Sfcv36[(uchar)_Sfdigits[d]] = l; _Sfcv64[(uchar)_Sfdigits[d]] = d; } /* remaining digits */ for(; d < SF_RADIX; ++d) { _Sfcv36[(uchar)_Sfdigits[d]] = d; _Sfcv64[(uchar)_Sfdigits[d]] = d; } _Sftype['d'] = _Sftype['i'] = SFFMT_INT; _Sftype['u'] = _Sftype['o'] = _Sftype['x'] = _Sftype['X'] = SFFMT_UINT; _Sftype['e'] = _Sftype['E'] = _Sftype['g'] = _Sftype['G'] = _Sftype['f'] = SFFMT_FLOAT; _Sftype['s'] = _Sftype['n'] = _Sftype['p'] = _Sftype['!'] = SFFMT_POINTER; _Sftype['c'] = SFFMT_BYTE; _Sftype['['] = SFFMT_CLASS; return 1; } /* table for floating point and integer conversions */ Sftab_t _Sftable = { { 1e1, 1e2, 1e4, 1e8, 1e16, 1e32 }, /* _Sfpos10 */ { 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32 }, /* _Sfneg10 */ { '0','0', '0','1', '0','2', '0','3', '0','4', /* _Sfdec */ '0','5', '0','6', '0','7', '0','8', '0','9', '1','0', '1','1', '1','2', '1','3', '1','4', '1','5', '1','6', '1','7', '1','8', '1','9', '2','0', '2','1', '2','2', '2','3', '2','4', '2','5', '2','6', '2','7', '2','8', '2','9', '3','0', '3','1', '3','2', '3','3', '3','4', '3','5', '3','6', '3','7', '3','8', '3','9', '4','0', '4','1', '4','2', '4','3', '4','4', '4','5', '4','6', '4','7', '4','8', '4','9', '5','0', '5','1', '5','2', '5','3', '5','4', '5','5', '5','6', '5','7', '5','8', '5','9', '6','0', '6','1', '6','2', '6','3', '6','4', '6','5', '6','6', '6','7', '6','8', '6','9', '7','0', '7','1', '7','2', '7','3', '7','4', '7','5', '7','6', '7','7', '7','8', '7','9', '8','0', '8','1', '8','2', '8','3', '8','4', '8','5', '8','6', '8','7', '8','8', '8','9', '9','0', '9','1', '9','2', '9','3', '9','4', '9','5', '9','6', '9','7', '9','8', '9','9', }, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_", sfcvinit, 0, sffmtpos, sffmtint };