📄 fmt.c
字号:
/* * The authors of this software are Rob Pike and Ken Thompson, * with contributions from Mike Burrows and Sean Dorward. * * Copyright (c) 2002-2006 by Lucent Technologies. * Portions Copyright (c) 2004 Google Inc. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */#include <stdio.h>#include <math.h>#include <float.h>#include <string.h>#include <stdlib.h>#include <errno.h>#include <stdarg.h>#include <assert.h>#include <ctype.h>#include <unistd.h>#include "u.h"#include "utf.h"#include "fmt.h"#define PLAN9PORT /* Get Plan 9 verbs *//* * compiler directive on Plan 9 */#ifndef USED#define USED(x) if(x);else#endif/* * nil cannot be ((void*)0) on ANSI C, * because it is used for function pointers */#undef nil#define nil 0#undef nelem#define nelem(x) (sizeof (x)/sizeof (x)[0])/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE *//* * dofmt -- format to a buffer * the number of characters formatted is returned, * or -1 if there was an error. * if the buffer is ever filled, flush is called. * it should reset the buffer and return whether formatting should continue. */typedef int (*Fmts)(Fmt*);typedef struct Quoteinfo Quoteinfo;struct Quoteinfo{ int quoted; /* if set, string must be quoted */ int nrunesin; /* number of input runes that can be accepted */ int nbytesin; /* number of input bytes that can be accepted */ int nrunesout; /* number of runes that will be generated */ int nbytesout; /* number of bytes that will be generated */};/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */double __Inf(int sign);double __NaN(void);int __badfmt(Fmt *f);int __charfmt(Fmt *f);int __countfmt(Fmt *f);int __efgfmt(Fmt *fmt);int __errfmt(Fmt *f);int __flagfmt(Fmt *f);int __fmtFdFlush(Fmt *f);int __fmtcpy(Fmt *f, const void *vm, int n, int sz);void* __fmtdispatch(Fmt *f, void *fmt, int isrunes);void * __fmtflush(Fmt *f, void *t, int len);void __fmtlock(void);int __fmtpad(Fmt *f, int n);double __fmtpow10(int n);int __fmtrcpy(Fmt *f, const void *vm, int n);void __fmtunlock(void);int __ifmt(Fmt *f);int __isInf(double d, int sign);int __isNaN(double d);int __needsep(int*, char**);int __needsquotes(char *s, int *quotelenp);int __percentfmt(Fmt *f);void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);int __quotestrfmt(int runesin, Fmt *f);int __rfmtpad(Fmt *f, int n);int __runefmt(Fmt *f);int __runeneedsquotes(Rune *r, int *quotelenp);int __runesfmt(Fmt *f);int __strfmt(Fmt *f);#define FMTCHAR(f, t, s, c)\ do{\ if(t + 1 > (char*)s){\ t = (char*)__fmtflush(f, t, 1);\ if(t != nil)\ s = (char*)f->stop;\ else\ return -1;\ }\ *t++ = c;\ }while(0)#define FMTRCHAR(f, t, s, c)\ do{\ if(t + 1 > (Rune*)s){\ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\ if(t != nil)\ s = (Rune*)f->stop;\ else\ return -1;\ }\ *t++ = c;\ }while(0)#define FMTRUNE(f, t, s, r)\ do{\ Rune _rune;\ int _runelen;\ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\ t = (char*)__fmtflush(f, t, _runelen);\ if(t != nil)\ s = (char*)f->stop;\ else\ return -1;\ }\ if(r < Runeself)\ *t++ = r;\ else{\ _rune = r;\ t += runetochar(t, &_rune);\ }\ }while(0)#ifdef va_copy# define VA_COPY(a,b) va_copy(a,b)# define VA_END(a) va_end(a)#else# define VA_COPY(a,b) (a) = (b)# define VA_END(a)#endif/* ---------- end preamble -------- *//* -------------- charstod.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* * Reads a floating-point number by interpreting successive characters * returned by (*f)(vp). The last call it makes to f terminates the * scan, so is not a character in the number. It may therefore be * necessary to back up the input stream up one byte after calling charstod. */doublefmtcharstod(int(*f)(void*), void *vp){ double num, dem; int neg, eneg, dig, exp, c; num = 0; neg = 0; dig = 0; exp = 0; eneg = 0; c = (*f)(vp); while(c == ' ' || c == '\t') c = (*f)(vp); if(c == '-' || c == '+'){ if(c == '-') neg = 1; c = (*f)(vp); } while(c >= '0' && c <= '9'){ num = num*10 + c-'0'; c = (*f)(vp); } if(c == '.') c = (*f)(vp); while(c >= '0' && c <= '9'){ num = num*10 + c-'0'; dig++; c = (*f)(vp); } if(c == 'e' || c == 'E'){ c = (*f)(vp); if(c == '-' || c == '+'){ if(c == '-'){ dig = -dig; eneg = 1; } c = (*f)(vp); } while(c >= '0' && c <= '9'){ exp = exp*10 + c-'0'; c = (*f)(vp); } } exp -= dig; if(exp < 0){ exp = -exp; eneg = !eneg; } dem = __fmtpow10(exp); if(eneg) num /= dem; else num *= dem; if(neg) return -num; return num;}/* -------------- dofmt.c --------------- *//* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE *//* Copyright (c) 2004 Google Inc.; see LICENSE */// #include <stdarg.h>// #include <string.h>// #include "plan9.h"// #include "fmt.h"// #include "fmtdef.h"/* format the output into f->to and return the number of characters fmted */intdofmt(Fmt *f, char *fmt){ Rune rune, *rt, *rs; int r; char *t, *s; int n, nfmt; nfmt = f->nfmt; for(;;){ if(f->runes){ rt = (Rune*)f->to; rs = (Rune*)f->stop; while((r = *(uchar*)fmt) && r != '%'){ if(r < Runeself) fmt++; else{ fmt += chartorune(&rune, fmt); r = rune; } FMTRCHAR(f, rt, rs, r); } fmt++; f->nfmt += rt - (Rune *)f->to; f->to = rt; if(!r) return f->nfmt - nfmt; f->stop = rs; }else{ t = (char*)f->to; s = (char*)f->stop; while((r = *(uchar*)fmt) && r != '%'){ if(r < Runeself){ FMTCHAR(f, t, s, r); fmt++; }else{ n = chartorune(&rune, fmt); if(t + n > s){ t = (char*)__fmtflush(f, t, n); if(t != nil) s = (char*)f->stop; else return -1; } while(n--) *t++ = *fmt++; } } fmt++; f->nfmt += t - (char *)f->to; f->to = t; if(!r) return f->nfmt - nfmt; f->stop = s; } fmt = (char*)__fmtdispatch(f, fmt, 0); if(fmt == nil) return -1; }}void *__fmtflush(Fmt *f, void *t, int len){ if(f->runes) f->nfmt += (Rune*)t - (Rune*)f->to; else f->nfmt += (char*)t - (char *)f->to; f->to = t; if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ f->stop = f->to; return nil; } return f->to;}/* * put a formatted block of memory sz bytes long of n runes into the output buffer, * left/right justified in a field of at least f->width characters (if FmtWidth is set) */int__fmtpad(Fmt *f, int n){ char *t, *s; int i; t = (char*)f->to; s = (char*)f->stop; for(i = 0; i < n; i++) FMTCHAR(f, t, s, ' '); f->nfmt += t - (char *)f->to; f->to = t; return 0;}int__rfmtpad(Fmt *f, int n){ Rune *t, *s; int i; t = (Rune*)f->to; s = (Rune*)f->stop; for(i = 0; i < n; i++) FMTRCHAR(f, t, s, ' '); f->nfmt += t - (Rune *)f->to; f->to = t; return 0;}int__fmtcpy(Fmt *f, const void *vm, int n, int sz){ Rune *rt, *rs, r; char *t, *s, *m, *me; ulong fl; int nc, w; m = (char*)vm; me = m + sz; fl = f->flags; w = 0; if(fl & FmtWidth) w = f->width; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) return -1; rt = (Rune*)f->to; rs = (Rune*)f->stop; for(nc = n; nc > 0; nc--){ r = *(uchar*)m; if(r < Runeself) m++; else if((me - m) >= UTFmax || fullrune(m, me-m)) m += chartorune(&r, m); else break; FMTRCHAR(f, rt, rs, r); } f->nfmt += rt - (Rune *)f->to; f->to = rt; if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) return -1; t = (char*)f->to; s = (char*)f->stop; for(nc = n; nc > 0; nc--){ r = *(uchar*)m; if(r < Runeself) m++; else if((me - m) >= UTFmax || fullrune(m, me-m)) m += chartorune(&r, m); else break; FMTRUNE(f, t, s, r); } f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - n) < 0) return -1; } return 0;}int__fmtrcpy(Fmt *f, const void *vm, int n){ Rune r, *m, *me, *rt, *rs; char *t, *s; ulong fl; int w; m = (Rune*)vm; fl = f->flags; w = 0; if(fl & FmtWidth) w = f->width; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) return -1; rt = (Rune*)f->to; rs = (Rune*)f->stop; for(me = m + n; m < me; m++) FMTRCHAR(f, rt, rs, *m); f->nfmt += rt - (Rune *)f->to; f->to = rt; if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) return -1; t = (char*)f->to; s = (char*)f->stop; for(me = m + n; m < me; m++){ r = *m; FMTRUNE(f, t, s, r); } f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - n) < 0) return -1; } return 0;}/* 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);}/* fmt out one rune */int__runefmt(Fmt *f){ Rune x[1]; x[0] = va_arg(f->args, int); return __fmtrcpy(f, (const void*)x, 1);}/* public helper routine: fmt out a null terminated string already in hand */intfmtstrcpy(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));}/* fmt out a null terminated utf string */int__strfmt(Fmt *f){ char *s; s = va_arg(f->args, char *); return fmtstrcpy(f, s);}/* public helper routine: fmt out a null terminated rune string already in hand */intfmtrunestrcpy(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);}/* fmt out a null terminated rune string */int__runesfmt(Fmt *f){ Rune *s; s = va_arg(f->args, Rune *); return fmtrunestrcpy(f, s);}/* fmt a % */int__percentfmt(Fmt *f){ Rune x[1]; x[0] = f->r; f->prec = 1; return __fmtrcpy(f, (const void*)x, 1);}/* fmt an integer */int__ifmt(Fmt *f){ char buf[140], *p, *conv; /* 140: for 64 bits of binary + 3-byte sep every 4 digits */ uvlong vu; ulong u; int neg, base, i, n, fl, w, isv; int ndig, len, excess, bytelen; char *grouping; char *thousands; neg = 0; fl = f->flags; isv = 0; vu = 0; u = 0;#ifndef PLAN9PORT /* * Unsigned verbs for ANSI C */ switch(f->r){ case 'o': case 'p': case 'u': case 'x': case 'X': fl |= FmtUnsigned; fl &= ~(FmtSign|FmtSpace); break; }#endif if(f->r == 'p'){ u = (ulong)va_arg(f->args, void*); f->r = 'x'; fl |= FmtUnsigned; }else if(fl & FmtVLong){ isv = 1; if(fl & FmtUnsigned) vu = va_arg(f->args, uvlong); else vu = va_arg(f->args, vlong); }else if(fl & FmtLong){ if(fl & FmtUnsigned) u = va_arg(f->args, ulong); else u = va_arg(f->args, long); }else if(fl & FmtByte){ if(fl & FmtUnsigned) u = (uchar)va_arg(f->args, int); else u = (char)va_arg(f->args, int); }else if(fl & FmtShort){ if(fl & FmtUnsigned) u = (ushort)va_arg(f->args, int); else u = (short)va_arg(f->args, int); }else{ if(fl & FmtUnsigned) u = va_arg(f->args, uint); else u = va_arg(f->args, int); } conv = "0123456789abcdef"; grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */ thousands = f->thousands; switch(f->r){ case 'd': case 'i': case 'u': base = 10; grouping = f->grouping; break; case 'X': conv = "0123456789ABCDEF"; /* fall through */ case 'x': base = 16; thousands = ":"; break; case 'b': base = 2; thousands = ":"; break; case 'o': base = 8; break; default: return -1; } if(!(fl & FmtUnsigned)){ if(isv && (vlong)vu < 0){ vu = -(vlong)vu; neg = 1; }else if(!isv && (long)u < 0){ u = -(long)u; neg = 1; } } p = buf + sizeof buf - 1; n = 0; /* in runes */ excess = 0; /* number of bytes > number runes */ ndig = 0; len = utflen(thousands); bytelen = strlen(thousands); if(isv){ while(vu){ i = vu % base; vu /= base; if((fl & FmtComma) && n % 4 == 3){ *p-- = ','; n++; } if((fl & FmtApost) && __needsep(&ndig, &grouping)){ n += len; excess += bytelen - len; p -= bytelen; memmove(p+1, thousands, bytelen); } *p-- = conv[i]; n++; } }else{ while(u){ i = u % base; u /= base; if((fl & FmtComma) && n % 4 == 3){ *p-- = ','; n++; } if((fl & FmtApost) && __needsep(&ndig, &grouping)){ n += len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -