/* public helper routine: fmt out a null terminated string already in hand */ int fmtstrcpy(Fmt *f, char *s) { int i, j; if(!s) return __fmtcpy(f, "<nil>", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ #ifdef PLAN9PORT Rune r; i = 0; for(j=0; j<f->prec && s[i]; j++) i += chartorune(&r, s+i); #else /* ANSI requires precision in bytes, not Runes */ for(i=0; i<f->prec; i++) if(s[i] == 0) break; j = utfnlen(s, i); /* won't print partial at end */ #endif return __fmtcpy(f, s, j, i); } return __fmtcpy(f, s, utflen(s), strlen(s)); }
/* public helper routine: fmt out a null terminated string already in hand */ int fmtstrcpy(Fmt *f, char *s) { int i, j; Rune r; if(!s) return __fmtcpy(f, "<nil>", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ i = 0; for(j=0; j<f->prec && s[i]; j++) i += chartorune(&r, s+i); return __fmtcpy(f, s, j, i); } return __fmtcpy(f, s, utflen(s), strlen(s)); }
int __errfmt(Fmt *f) { char buf[ERRMAX]; rerrstr(buf, sizeof buf); return __fmtcpy(f, buf, utflen(buf), strlen(buf)); }
/* public helper routine: fmt out a null terminated string already in hand */ int fmtstrcpy(Fmt *f, char *s) { int p, i; if(!s) return __fmtcpy(f, "<nil>", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ p = f->prec; for(i = 0; i < p; i++) if(s[i] == 0) break; return __fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */ } return __fmtcpy(f, s, utflen(s), strlen(s)); }
/* fmt out one character */ int __charfmt(Fmt *f) { char x[1]; x[0] = va_arg(f->args, int); f->prec = 1; return __fmtcpy(f, (const char*)x, 1, 1); }
static int floatfmt(Fmt *fmt, double f) { char s[341]; /* precision+exponent+sign+'.'+null */ xdtoa(fmt, s, f); fmt->flags &= FmtWidth|FmtLeft; __fmtcpy(fmt, s, strlen(s), strlen(s)); return 0; }
/* public helper routine: fmt out a null terminated rune string already in hand */ int fmtrunestrcpy(Fmt *f, Rune *s) { Rune *e; int n, p; if(!s) return __fmtcpy(f, "<nil>", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ p = f->prec; for(n = 0; n < p; n++) if(s[n] == 0) break; }else{ for(e = s; *e; e++) ; n = e - s; } return __fmtrcpy(f, s, n); }
int __efgfmt(Fmt *fmt) { double f; char s1[NSIGNIF+10]; int e, d, n; int c1, c2, c3, c4, ucase, sign, chr, prec, fl; f = va_arg(fmt->args, double); prec = FDEFLT; fl = fmt->flags; fmt->flags = 0; if(fl & FmtPrec) prec = fmt->prec; chr = fmt->r; ucase = 0; if(chr == 'E'){ chr = 'e'; ucase = 1; }else if(chr == 'F'){ chr = 'f'; ucase = 1; }else if(chr == 'G'){ chr = 'g'; ucase = 1; } if(prec > 0 && chr == 'g') prec--; if(prec < 0) prec = 0; xdodtoa(s1, f, chr, prec, &e, &sign); e--; if(*s1 == 'i' || *s1 == 'n'){ if(ucase){ if(*s1 == 'i'){ strcpy(s1, "INF"); }else{ strcpy(s1, "NAN"); } } fmt->flags = fl & (FmtWidth|FmtLeft); return __fmtcpy(fmt, (const void*)s1, 3, 3); } /* * copy into final place * c1 digits of leading '0' * c2 digits from conversion * c3 digits of trailing '0' * c4 digits after '.' */ c1 = 0; c2 = prec + 1; c3 = 0; c4 = prec; switch(chr) { default: chr = 'e'; break; case 'g': /* * decide on 'e' of 'f' style convers */ if(e >= -4 && e <= prec) { c1 = -e; c4 = prec - e; chr = 'h'; /* flag for 'f' style */ } break; case 'f': c1 = -e; if(c1 > prec) c1 = prec + 1; c2 += e; break; } /* * clean up c1 c2 and c3 */ if(c1 < 0) c1 = 0; if(c2 < 0) c2 = 0; if(c2 > NSIGNIF) { c3 = c2-NSIGNIF; c2 = NSIGNIF; } /* * trim trailing zeros for %g */ if(!(fl & FmtSharp) && (chr == 'g' || chr == 'h')){ if(c4 >= c3){ c4 -= c3; c3 = 0; }else{ c3 -= c4; c4 = 0; } while(c4 && c2 > 1 && s1[c2 - 1] == '0'){ c4--; c2--; } } /* * calculate the total length */ n = c1 + c2 + c3; if(sign || (fl & (FmtSign|FmtSpace))) n++; if(c4 || (fl & FmtSharp)){ n++; } if(chr == 'e' || chr == 'g'){ n += 4; if(e >= 100) n++; } /* * pad to width if right justified */ if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){ if(fl & FmtZero){ c1 += fmt->width - n; }else{ if(__fmtpad(fmt, fmt->width - n) < 0){ return -1; } } } /* * sign */ d = 0; if(sign) d = '-'; else if(fl & FmtSign) d = '+'; else if(fl & FmtSpace) d = ' '; if(d && fmtrune(fmt, d) < 0){ return -1; } /* * copy digits */ c4 = c1 + c2 + c3 - c4; if(c1 > 0){ if(fmtzdotpad(fmt, c1, c4) < 0){ return -1; } c4 -= c1; } d = 0; if(c4 >= 0 && c4 < c2){ if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0) return -1; d = c4; c2 -= c4; c4 = -1; } if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){ return -1; } c4 -= c2; if(c3 > 0){ if(fmtzdotpad(fmt, c3, c4) < 0){ return -1; } c4 -= c3; } /* * strip trailing '0' on g conv */ if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){ return -1; } if(chr == 'e' || chr == 'g') { d = 0; if(ucase) s1[d++] = 'E'; else s1[d++] = 'e'; c1 = e; if(c1 < 0) { s1[d++] = '-'; c1 = -c1; } else s1[d++] = '+'; if(c1 >= 100) { s1[d++] = c1/100 + '0'; c1 = c1%100; } s1[d++] = c1/10 + '0'; s1[d++] = c1%10 + '0'; if(__fmtcpy(fmt, s1, d, d) < 0){ return -1; } } if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){ if(__fmtpad(fmt, fmt->width - n) < 0){ return -1; } } return 0; }