📄 sfvprintf.c
字号:
/* Copyright (c) Colorado School of Mines, 2006.*//* All rights reserved. */#include "sfhdr.h"/* The engine for formatting data.** 1. Argument positioning is done in sftable.c so any changes** made here should be reflected in sftable.c as well.** 2. For internationalization, Sfio only supports I/O of multibyte strings.** However, this code does provide minimal support so that Stdio functions** such as fwprintf/swprintf can be emulated (see stdvwprintf()).**** Written by Kiem-Phong Vo.*/#define HIGHBITI (~((~((uint)0)) >> 1))#define HIGHBITL (~((~((Sfulong_t)0)) >> 1))#define SFFMT_PREFIX (SFFMT_MINUS|SFFMT_SIGN|SFFMT_BLANK)#define FPRECIS 6 /* default precision for floats */#if _PACKAGE_ast#include <ccode.h>#else/* characters when using ebcdic or ascii */#if _chr_ebcdic#define CC_vt 013 /* vertical tab */#define CC_esc 047 /* escape */#define CC_bel 057 /* bell */#else#define CC_vt 013 /* vertical tab */#define CC_esc 033 /* escape */#define CC_bel 007 /* bell */#endif /* _chr_ebcdic */#endif /* _PACKAGE_ast */#if __STD_Cstatic int chr2str(char* buf, int v)#elsestatic int chr2str(buf, v)char* buf;int v;#endif{ if(isprint(v) && v != '\\') { *buf++ = v; return 1; } else { *buf++ = '\\'; switch(v) { case CC_bel: *buf++ = 'a'; return 2; case CC_vt: *buf++ = 'v'; return 2; case CC_esc: *buf++ = 'E'; return 2; case '\b': *buf++ = 'b'; return 2; case '\f': *buf++ = 'f'; return 2; case '\n': *buf++ = 'n'; return 2; case '\r': *buf++ = 'r'; return 2; case '\t': *buf++ = 't'; return 2; case '\\': *buf++ = '\\'; return 2; default: *buf++ = '0' + ((v >> 6) & 03); *buf++ = '0' + ((v >> 3) & 07); *buf++ = '0' + ((v >> 0) & 07); return 4; } }}/* On some platform(s), large functions are not compilable.** In such a case, the below macro should be defined non-zero so that** some in-lined macros will be made smaller, trading time for space.*/#if !defined(_sffmt_small) && defined(_UTS)#define _sffmt_small 1#endif#if __STD_Cint sfvprintf(Sfio_t* f, const char* form, va_list args)#elseint sfvprintf(f,form,args)Sfio_t* f; /* file to print to */char* form; /* format to use */va_list args; /* arg list if !argf */#endif{ int n, v, k, n_s, base, fmt, flags; Sflong_t lv; char *sp, *ssp, *endsp, *ep, *endep; int dot, width, precis, sign, decpt; ssize_t size; Sfdouble_t dval; char *tls[2], **ls; /* for %..[separ]s */ char* t_str; /* stuff between () */ ssize_t n_str; /* its length */ Argv_t argv; /* for extf to return value */ Sffmt_t *ft; /* format environment */ Fmt_t *fm, *fmstk; /* stack contexts */ char* oform; /* original format string */ va_list oargs; /* original arg list */ Fmtpos_t* fp; /* arg position list */ int argp, argn; /* arg position and number */#define SLACK 1024 char buf[SF_MAXDIGITS+SLACK], tmp[SF_MAXDIGITS], data[SF_GRAIN]; int decimal = 0, thousand = 0;#if _has_multibyte wchar_t* wsp; SFMBDCL(fmbs) /* state of format string */ SFMBDCL(mbs) /* state of some string */#endif /* local io system */ int w, n_output;#define SMputc(f,c) { if((w = SFFLSBUF(f,c)) >= 0 ) n_output += 1; \ else { SFBUF(f); goto done; } \ }#define SMnputc(f,c,n) { if((w = SFNPUTC(f,c,n)) > 0 ) n_output += 1; \ if(w != n) { SFBUF(f); goto done; } \ }#define SMwrite(f,s,n) { if((w = SFWRITE(f,(Void_t*)s,n)) > 0 ) n_output += w; \ if(w != n) { SFBUF(f); goto done; } \ }#if _sffmt_small /* these macros are made smaller at some performance cost */#define SFBUF(f)#define SFINIT(f) (n_output = 0)#define SFEND(f)#define SFputc(f,c) SMputc(f,c)#define SFnputc(f,c,n) SMnputc(f,c,n)#define SFwrite(f,s,n) SMwrite(f,s,n)#else uchar *d, *endd;#define SFBUF(f) (d = f->next, endd = f->endb)#define SFINIT(f) (SFBUF(f), n_output = 0)#define SFEND(f) ((n_output += d - f->next), (f->next = d))#define SFputc(f,c) { if(d < endd) { *d++ = (uchar)c; } \ else { SFEND(f); SMputc(f,c); SFBUF(f); } \ }#define SFnputc(f,c,n) { if(d+n <= endd) { while(n--) *d++ = (uchar)(c); } \ else { SFEND(f); SMnputc(f,c,n); SFBUF(f); } \ }#define SFwrite(f,s,n) { if(d+n <= endd) { while(n--) *d++ = (uchar)(*s++); } \ else { SFEND(f); SMwrite(f,s,n); SFBUF(f); } \ }#endif /* _sffmt_small */ SFCVINIT(); /* initialize conversion tables */ SFMTXSTART(f,-1); if(!form) SFMTXRETURN(f, -1); /* make sure stream is in write mode and buffer is not NULL */ if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0) SFMTXRETURN(f, -1); SFLOCK(f,0); if(!f->data && !(f->flags&SF_STRING)) { f->data = f->next = (uchar*)data; f->endb = f->data+sizeof(data); } SFINIT(f); tls[1] = NIL(char*); fmstk = NIL(Fmt_t*); ft = NIL(Sffmt_t*); oform = (char*)form; va_copy(oargs,args); argn = -1; fp = NIL(Fmtpos_t*);loop_fmt : SFMBCLR(&fmbs); /* clear multibyte states to parse the format string */ while((n = *form) ) { if(n != '%') /* collect the non-pattern chars */ { sp = (char*)form; for(;;) { form += SFMBLEN(form, &fmbs); if(*form == 0 || *form == '%') break; } n = form-sp; SFwrite(f,sp,n); continue; } else form += 1; flags = 0; size = width = precis = base = n_s = argp = -1; ssp = _Sfdigits; endep = ep = NIL(char*); endsp = sp = buf+(sizeof(buf)-1); t_str = NIL(char*); n_str = dot = 0; loop_flags: /* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */ switch((fmt = *form++) ) { case '\0': SFputc(f,'%'); goto pop_fmt; case '%' : SFputc(f,'%'); continue; 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; if(*t_str != '*' ) n_str = (form-1)-t_str; else { t_str = (*_Sffmtintf)(t_str+1,&n); if(*t_str == '$') { if(!fp && !(fp = (*_Sffmtposf) (f,oform,oargs,ft,0)) ) goto pop_fmt; n = FP_SET(n,argn); } else n = FP_SET(-1,argn); if(fp) { t_str = fp[n].argv.s; n_str = fp[n].ft.size; } else if(ft && ft->extf ) { FMTSET(ft, form,args, LEFTP, 0, 0, 0,0,0, NIL(char*),0); n = (*ft->extf) (f,(Void_t*)&argv,ft); if(n < 0) goto pop_fmt; if(!(ft->flags&SFFMT_VALUE) ) goto t_arg; if((t_str = argv.s) && (n_str = (int)ft->size) < 0) n_str = strlen(t_str); } else { t_arg: if((t_str = va_arg(args,char*)) ) n_str = strlen(t_str); } } goto loop_flags; } } case '-' : flags = (flags & ~SFFMT_ZERO) | SFFMT_LEFT; 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 = (flags & ~SFFMT_BLANK) | SFFMT_SIGN; goto loop_flags; case '#' : flags |= SFFMT_ALTER; goto loop_flags; case QUOTE: SFSETLOCALE(&decimal,&thousand); if(thousand > 0) flags |= SFFMT_THOUSAND; goto loop_flags; case '.' : dot += 1; if(dot == 1) { /* so base can be defined without setting precis */ if(*form != '.') precis = 0; } else if(dot == 2) { base = 0; /* for %s,%c */ v = form[0] == 'l' ? form[1] : form[0]; if(v == 'c' || v == 'C' || v == 's' || v == 'S') goto loop_flags; if(*form && !isalnum(*form)) { v = form[1] == 'l' ? form[2] : form[1]; if(v == 'c' || v == 'C' || v == 's' || v == 'S') { if(*form == '*') goto do_star; else { base = *form++; goto loop_flags; } } } } if(isdigit(*form) ) { fmt = *form++; goto dot_size; } else if(*form != '*') goto loop_flags; do_star: form += 1; /* fall thru for '*' */ case '*' : form = (*_Sffmtintf)(form,&n); if(*form == '$') { form += 1; if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,0)) ) goto pop_fmt; n = FP_SET(n,argn); } else n = FP_SET(-1,argn); if(fp) v = fp[n].argv.i; else if(ft && ft->extf) { FMTSET(ft, form,args, '.',dot, 0, 0,0,0, NIL(char*), 0); if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) goto pop_fmt; fmt = ft->fmt; flags = (flags&~SFFMT_TYPES) | (ft->flags&SFFMT_TYPES); if(ft->flags&SFFMT_VALUE) v = argv.i; else v = (dot <= 2) ? va_arg(args,int) : 0; } else v = dot <= 2 ? va_arg(args,int) : 0; goto dot_set; case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : dot_size : for(v = fmt - '0'; isdigit(*form); ++form) v = v*10 + (*form - '0'); if(*form == '$') { form += 1; if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,0)) ) goto pop_fmt; argp = v-1; goto loop_flags; } dot_set : if(dot == 0) { if((width = v) < 0) { width = -width; flags = (flags & ~SFFMT_ZERO) | SFFMT_LEFT; } } else if(dot == 1) precis = v; else if(dot == 2) base = v; goto loop_flags; case 'I' : /* object length */ size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG; if(isdigit(*form) ) { for(size = 0, n = *form; isdigit(n); n = *++form) size = size*10 + (n - '0'); } else if(*form == '*') { form = (*_Sffmtintf)(form+1,&n); if(*form == '$') { form += 1; if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,0))) goto pop_fmt; n = FP_SET(n,argn); } else n = FP_SET(-1,argn); if(fp) /* use position list */ size = fp[n].argv.i; else if(ft && ft->extf) { FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0, NIL(char*), 0); if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0) goto pop_fmt; if(ft->flags&SFFMT_VALUE) size = argv.i; else size = va_arg(args,int); } else size = va_arg(args,int); } 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; case 'j' : size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_JFLAG; goto loop_flags; case 'z' : size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG; goto loop_flags; case 't' : size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_TFLAG; goto loop_flags; default: break; } /* set object size for scalars */ if(flags & SFFMT_TYPES) { if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n') { if(flags&SFFMT_LONG) size = sizeof(long); else if(flags&SFFMT_SHORT) size = sizeof(short); else if(flags&SFFMT_SSHORT) size = sizeof(char); else if(flags&SFFMT_TFLAG) size = sizeof(ptrdiff_t); else if(flags&SFFMT_ZFLAG) size = sizeof(size_t); else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) ) size = sizeof(Sflong_t); else if(flags&SFFMT_IFLAG) { if(size <= 0 || size == sizeof(Sflong_t)*CHAR_BIT ) size = sizeof(Sflong_t); } else if(size < 0) size = sizeof(int); } else if(_Sftype[fmt]&SFFMT_FLOAT) { if(flags&(SFFMT_LONG|SFFMT_LLONG)) size = sizeof(double); else if(flags&SFFMT_LDOUBLE) size = sizeof(Sfdouble_t); else if(flags&SFFMT_IFLAG) { if(size <= 0) size = sizeof(Sfdouble_t); } else if(size < 0) size = sizeof(float); } else if(_Sftype[fmt]&SFFMT_CHAR) {#if _has_multibyte if((flags&SFFMT_LONG) || fmt == 'C') { size = sizeof(wchar_t) > sizeof(int) ? sizeof(wchar_t) : sizeof(int); } else#endif if(size < 0) size = sizeof(int); } } argp = FP_SET(argp,argn); if(fp) { if(ft && ft->extf && fp[argp].ft.fmt != fp[argp].fmt) fmt = fp[argp].ft.fmt; argv = fp[argp].argv; size = fp[argp].ft.size; } else if(ft && ft->extf ) /* extended processing */ { FMTSET(ft, form,args, fmt, size,flags, width,precis,base, t_str,n_str); SFEND(f); SFOPEN(f,0); v = (*ft->extf)(f, (Void_t*)(&argv), ft); SFLOCK(f,0); SFBUF(f); if(v < 0) /* no further processing */ goto pop_fmt; else if(v > 0) /* extf output v bytes */ { n_output += v; continue; } else /* extf did not output */ { FMTGET(ft, form,args, fmt, size,flags, width,precis,base); if(!(ft->flags&SFFMT_VALUE)) goto arg_list; else if(_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT) ) { if(size == sizeof(short)) { if(_Sftype[fmt]&SFFMT_INT) argv.i = argv.h; else argv.i = argv.uh; } else if(size == sizeof(char)) { if(_Sftype[fmt]&SFFMT_INT) argv.i = argv.c; else argv.i = argv.uc; } } else if(_Sftype[fmt]&SFFMT_FLOAT ) { if(size == sizeof(float) ) argv.d = argv.f; } else if(_Sftype[fmt]&SFFMT_CHAR) { if(base < 0) argv.i = (int)argv.c; } } } else { arg_list: switch(_Sftype[fmt]) { case SFFMT_INT: case SFFMT_UINT:#if !_ast_intmax_long if(size == sizeof(Sflong_t)) argv.ll = va_arg(args, Sflong_t); else#endif if(size == sizeof(long) ) argv.l = va_arg(args, long); else argv.i = va_arg(args, int); break; case SFFMT_FLOAT:#if !_ast_fltmax_double if(size == sizeof(Sfdouble_t)) argv.ld = va_arg(args,Sfdouble_t); else#endif argv.d = va_arg(args,double); break; case SFFMT_POINTER: argv.vp = va_arg(args,Void_t*); break; case SFFMT_CHAR: if(base >= 0) argv.s = va_arg(args,char*);#if _has_multibyte else if((flags & SFFMT_LONG) || fmt == 'C') { if(sizeof(wchar_t) <= sizeof(uint) ) argv.wc = (wchar_t)va_arg(args,uint); else argv.wc = va_arg(args,wchar_t); }#endif else argv.i = va_arg(args,int); break; default: /* unknown pattern */ break; } } switch(fmt) /* PRINTF DIRECTIVES */ { default : /* unknown directive */ form -= 1; argn -= 1; continue; case '!' : /* stacking a new environment */ if(!fp) fp = (*_Sffmtposf)(f,oform,oargs,ft,0); else goto pop_fmt; if(!argv.ft) goto pop_fmt; if(!argv.ft->form && ft ) /* change extension functions */ { if(ft->eventf && (*ft->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0) continue; fmstk->ft = ft = argv.ft; } else /* stack a new environment */ { if(!(fm = (Fmt_t*)malloc(sizeof(Fmt_t))) ) goto done; ft = fm->ft = argv.ft; SFMBSET(ft->mbs, &fmbs); if(ft->form) { fm->form = (char*)form; SFMBCPY(&fm->mbs,&fmbs); va_copy(fm->args,args); fm->oform = oform; va_copy(fm->oargs,oargs); fm->argn = argn; fm->fp = fp; form = ft->form; SFMBCLR(ft->mbs); va_copy(args,ft->args); argn = -1; fp = NIL(Fmtpos_t*); oform = (char*)form; va_copy(oargs,args); } else fm->form = NIL(char*); fm->eventf = ft->eventf; fm->next = fmstk; fmstk = fm; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -