📄 fmt.c
字号:
* account for new digit */ if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/ z1--; else /* 9.99 => 10.00 */ point++; } z2 = 0; ndigits = newndigits; } sufwid = 0; break; } /* * if %g is given without FmtSharp, remove trailing zeros. * must do after truncation, so that e.g. print %.3g 1.001 * produces 1, not 1.00. sorry, but them's the rules. */ if(realchr == 'g' && !(fl & FmtSharp)) { if(z1+ndigits+z2 >= point) { if(z1+ndigits < point) z2 = point - (z1+ndigits); else{ z2 = 0; while(z1+ndigits > point && digits[ndigits-1] == '0') ndigits--; } } } /* * compute width of all digits and decimal point and suffix if any */ wid = z1+ndigits+z2; if(wid > point) wid += dotwid; else if(wid == point){ if(fl & FmtSharp) wid += dotwid; else point++; /* do not print any decimal point */ } wid += sufwid; /* * determine sign */ sign = 0; if(neg) sign = '-'; else if(fl & FmtSign) sign = '+'; else if(fl & FmtSpace) sign = ' '; if(sign) wid++; /* * compute padding */ pad = 0; if((fl & FmtWidth) && fmt->width > wid) pad = fmt->width - wid; if(pad && !(fl & FmtLeft) && (fl & FmtZero)){ z1 += pad; point += pad; pad = 0; } /* * format the actual field. too bad about doing this twice. */ if(fmt->runes){ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) return -1; rt = (Rune*)fmt->to; rs = (Rune*)fmt->stop; if(sign) FMTRCHAR(fmt, rt, rs, sign); while(z1>0 || ndigits>0 || z2>0) { if(z1 > 0){ z1--; c = '0'; }else if(ndigits > 0){ ndigits--; c = *digits++; }else{ z2--; c = '0'; } FMTRCHAR(fmt, rt, rs, c); if(--point == 0) { for(p = dot; *p; ){ p += chartorune(&r, p); FMTRCHAR(fmt, rt, rs, r); } } } fmt->nfmt += rt - (Rune*)fmt->to; fmt->to = rt; if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) return -1; if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) return -1; }else{ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0) return -1; t = (char*)fmt->to; s = (char*)fmt->stop; if(sign) FMTCHAR(fmt, t, s, sign); while(z1>0 || ndigits>0 || z2>0) { if(z1 > 0){ z1--; c = '0'; }else if(ndigits > 0){ ndigits--; c = *digits++; }else{ z2--; c = '0'; } FMTCHAR(fmt, t, s, c); if(--point == 0) for(p=dot; *p; p++) FMTCHAR(fmt, t, s, *p); } fmt->nfmt += t - (char*)fmt->to; fmt->to = t; if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) return -1; if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0) return -1; } return 0;}/* -------------- fmt.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"enum{ Maxfmt = 64};typedef struct Convfmt Convfmt;struct Convfmt{ int c; volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */};static struct{ /* lock by calling __fmtlock, __fmtunlock */ int nfmt; Convfmt fmt[Maxfmt];} fmtalloc;static Convfmt knownfmt[] = { { ' ', __flagfmt }, { '#', __flagfmt }, { '%', __percentfmt }, { '\'', __flagfmt }, { '+', __flagfmt }, { ',', __flagfmt }, { '-', __flagfmt }, { 'C', __runefmt }, /* Plan 9 addition */ { 'E', __efgfmt },#ifndef PLAN9PORT { 'F', __efgfmt }, /* ANSI only */#endif { 'G', __efgfmt },#ifndef PLAN9PORT { 'L', __flagfmt }, /* ANSI only */#endif { 'S', __runesfmt }, /* Plan 9 addition */ { 'X', __ifmt }, { 'b', __ifmt }, /* Plan 9 addition */ { 'c', __charfmt }, { 'd', __ifmt }, { 'e', __efgfmt }, { 'f', __efgfmt }, { 'g', __efgfmt }, { 'h', __flagfmt },#ifndef PLAN9PORT { 'i', __ifmt }, /* ANSI only */#endif { 'l', __flagfmt }, { 'n', __countfmt }, { 'o', __ifmt }, { 'p', __ifmt }, { 'r', __errfmt }, { 's', __strfmt },#ifdef PLAN9PORT { 'u', __flagfmt },#else { 'u', __ifmt },#endif { 'x', __ifmt }, { 0, nil }};int (*fmtdoquote)(int);/* * __fmtlock() must be set */static int__fmtinstall(int c, Fmts f){ Convfmt *p, *ep; if(c<=0 || c>=65536) return -1; if(!f) f = __badfmt; ep = &fmtalloc.fmt[fmtalloc.nfmt]; for(p=fmtalloc.fmt; p<ep; p++) if(p->c == c) break; if(p == &fmtalloc.fmt[Maxfmt]) return -1; p->fmt = f; if(p == ep){ /* installing a new format character */ fmtalloc.nfmt++; p->c = c; } return 0;}intfmtinstall(int c, int (*f)(Fmt*)){ int ret; __fmtlock(); ret = __fmtinstall(c, f); __fmtunlock(); return ret;}static Fmtsfmtfmt(int c){ Convfmt *p, *ep; ep = &fmtalloc.fmt[fmtalloc.nfmt]; for(p=fmtalloc.fmt; p<ep; p++) if(p->c == c){ while(p->fmt == nil) /* loop until value is updated */ ; return p->fmt; } /* is this a predefined format char? */ __fmtlock(); for(p=knownfmt; p->c; p++) if(p->c == c){ __fmtinstall(p->c, p->fmt); __fmtunlock(); return p->fmt; } __fmtunlock(); return __badfmt;}void*__fmtdispatch(Fmt *f, void *fmt, int isrunes){ Rune rune, r; int i, n; f->flags = 0; f->width = f->prec = 0; for(;;){ if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ fmt = (char*)fmt + chartorune(&rune, (char*)fmt); r = rune; } f->r = r; switch(r){ case '\0': return nil; case '.': f->flags |= FmtWidth|FmtPrec; continue; case '0': if(!(f->flags & FmtWidth)){ f->flags |= FmtZero; continue; } /* fall through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = 0; while(r >= '0' && r <= '9'){ i = i * 10 + r - '0'; if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ r = *(char*)fmt; fmt = (char*)fmt + 1; } } if(isrunes) fmt = (Rune*)fmt - 1; else fmt = (char*)fmt - 1; numflag: if(f->flags & FmtWidth){ f->flags |= FmtPrec; f->prec = i; }else{ f->flags |= FmtWidth; f->width = i; } continue; case '*': i = va_arg(f->args, int); if(i < 0){ /* * negative precision => * ignore the precision. */ if(f->flags & FmtPrec){ f->flags &= ~FmtPrec; f->prec = 0; continue; } i = -i; f->flags |= FmtLeft; } goto numflag; } n = (*fmtfmt(r))(f); if(n < 0) return nil; if(n == 0) return fmt; }}/* -------------- fmtfd.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * public routine for final flush of a formatting buffer * to a file descriptor; returns total char count. */intfmtfdflush(Fmt *f){ if(__fmtFdFlush(f) <= 0) return -1; return f->nfmt;}/* * initialize an output buffer for buffered printing */intfmtfdinit(Fmt *f, int fd, char *buf, int size){ f->runes = 0; f->start = buf; f->to = buf; f->stop = buf + size; f->flush = __fmtFdFlush; f->farg = (void*)(uintptr_t)fd; f->flags = 0; f->nfmt = 0; fmtlocaleinit(f, nil, nil, nil); return 0;}/* -------------- fmtfdflush.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <unistd.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * generic routine for flushing a formatting buffer * to a file descriptor */int__fmtFdFlush(Fmt *f){ int n; n = (char*)f->to - (char*)f->start; if(n && write((uintptr)f->farg, f->start, n) != n) return 0; f->to = f->start; return 1;}/* -------------- fmtlocale.c --------------- *//* Copyright (c) 2004 Google Inc.; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * Fill in the internationalization stuff in the State structure. * For nil arguments, provide the sensible defaults: * decimal is a period * thousands separator is a comma * thousands are marked every three digits */voidfmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping){ if(decimal == nil || decimal[0] == '\0') decimal = "."; if(thousands == nil) thousands = ","; if(grouping == nil) grouping = "\3"; f->decimal = decimal; f->thousands = thousands; f->grouping = grouping;}/* * We are about to emit a digit in e.g. %'d. If that digit would * overflow a thousands (e.g.) grouping, tell the caller to emit * the thousands separator. Always advance the digit counter * and pointer into the grouping descriptor. */int__needsep(int *ndig, char **grouping){ int group; (*ndig)++; group = *(unsigned char*)*grouping; /* CHAR_MAX means no further grouping. \0 means we got the empty string */ if(group == 0xFF || group == 0x7f || group == 0x00) return 0; if(*ndig > group){ /* if we're at end of string, continue with this grouping; else advance */ if((*grouping)[1] != '\0') (*grouping)++; *ndig = 1; return 1; } return 0;}/* -------------- fmtlock.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"void__fmtlock(void){}void__fmtunlock(void){}/* -------------- fmtnull.c --------------- *//* Copyright (c) 2004 Google Inc.; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * Absorb output without using resources. */static Rune nullbuf[32];static int__fmtnullflush(Fmt *f){ f->to = nullbuf; f->nfmt = 0; return 0;}intfmtnullinit(Fmt *f){ memset(&f, 0, sizeof *f); f->runes = 1; f->start = nullbuf; f->to = nullbuf; f->stop = nullbuf+nelem(nullbuf); f->flush = __fmtnullflush; fmtlocaleinit(f, nil, nil, nil); return 0;}/* -------------- fmtprint.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * format a string into the output buffer * designed for formats which themselves call fmt, * but ignore any width flags */intfmtprint(Fmt *f, char *fmt, ...){ va_list va; int n; f->flags = 0; f->width = 0; f->prec = 0; VA_COPY(va, f->args); VA_END(f->args); va_start(f->args, fmt); n = dofmt(f, fmt); va_end(f->args); f->flags = 0; f->width = 0; f->prec = 0; VA_COPY(f->args,va); VA_END(va); if(n >= 0) return 0; return n;}/* -------------- fmtquote.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * How many bytes of output UTF will be produced by quoting (if necessary) this string? * How many runes? How much of the input will be consumed? * The parameter q is filled in by __quotesetup. * The string may be UTF or Runes (s or r). * Return count does not include NUL. * Terminate the scan at the first of: * NUL in input * count exceeded in input * count exceeded on output * *ninp is set to number of input bytes accepted. * nin may be <0 initially, to avoid checking input by count. */void__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout){ int w; Rune c; q->quoted = 0; q->nbytesout = 0; q->nrunesout = 0; q->nbytesin = 0; q->nrunesin = 0; if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ if(nout < 2) return; q->quoted = 1; q->nbytesout = 2; q->nrunesout = 2; } for(; nin!=0; nin--){ if(s) w = chartorune(&c, s); else{ c = *r; w = runelen(c); } if(c == '\0') break; if(runesout){ if(q->nrunesout+1 > nout) break; }else{ if(q->nbytesout+w > nout) break; } if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){ if(!q->quoted){ if(runesout){ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ break; }else{ if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ break; } q->nrunesout += 2; /* include quotes */ q->nbytesout += 2; /* include quotes */ q->quoted = 1; } if(c == '\'') { if(runesout){ if(1+q->nrunesout+1 > nout) /* no room for quotes */ break; }else{ if(1+q->nbytesout+w > nout) /* no room for quotes */ break; } q->nbytesout++; q->nrunesout++; /* quotes reproduce as two characters */ } } /* advance input */ if(s) s += w; else r++; q->nbytesin += w; q->nrunesin++; /* advance output */ q->nbytesout += w; q->nrunesout++;#ifndef PLAN9PORT /* ANSI requires precision in bytes, not Runes. */ nin-= w-1; /* and then n-- in the loop */#endif }}static intqstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f){ Rune r, *rm, *rme; char *t, *s, *m, *me; Rune *rt, *rs; ulong fl; int nc, w; m = sin; me = m + q->nbytesin; rm = rin; rme = rm + q->nrunesin; fl = f->flags; w = 0; if(fl & FmtWidth) w = f->width; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) return -1; } t = (char*)f->to;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -