/* * The authors of this software are Rob Pike and Ken Thompson. * Copyright (c) 2002 by Lucent Technologies. * 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 MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ #include #include #include "fmt.h" #include "fmtdef.h" extern int (*doquote)(int); /* * 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, int nin, int nout, Quoteinfo *q, int sharp) { int c; q->quoted = 0; q->nbytesout = 0; q->nrunesout = 0; q->nbytesin = 0; q->nrunesin = 0; if(sharp || nin==0 || *s=='\0'){ if(nout < 2) return; q->quoted = 1; q->nbytesout = 2; q->nrunesout = 2; } for(; nin!=0; nin-=1){ c = *s; if(c == '\0') break; if(q->nrunesout+1 > nout) break; if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ if(!q->quoted){ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ break; q->nrunesout += 2; /* include quotes */ q->nbytesout += 2; /* include quotes */ q->quoted = 1; } if(c == '\'') { q->nbytesout++; q->nrunesout++; /* quotes reproduce as two characters */ } } /* advance input */ s++; q->nbytesin++; q->nrunesin++; /* advance output */ q->nbytesout++; q->nrunesout++; } } static int qstrfmt(char *sin, Quoteinfo *q, Fmt *f) { int r; char *t, *s, *m, *me; ulong fl; int nc, w; m = sin; me = m + q->nbytesin; w = f->width; fl = f->flags; if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) return -1; t = f->to; s = f->stop; FMTCHAR(f, t, s, '\''); for(nc = q->nrunesin; nc > 0; nc--){ r = *(uchar*)m++; FMTCHAR(f, t, s, r); if(r == '\'') FMTCHAR(f, t, s, r); } FMTCHAR(f, t, s, '\''); f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) return -1; return 0; } int __quotestrfmt(int runesin, Fmt *f) { int outlen; char *s; Quoteinfo q; f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */ s = va_arg(f->args, char *); if(!s) return __fmtcpy(f, "", 5, 5); if(f->flush) outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ else outlen = (char*)f->stop - (char*)f->to; __quotesetup(s, -1, outlen, &q, f->flags&FmtSharp); if(!q.quoted) return __fmtcpy(f, s, q.nrunesin, q.nbytesin); return qstrfmt(s, &q, f); } int quotestrfmt(Fmt *f) { return __quotestrfmt(0, f); } void quotefmtinstall(void) { fmtinstall('q', quotestrfmt); } int __needsquotes(char *s, int *quotelenp) { Quoteinfo q; __quotesetup(s, -1, 0x7FFFFFFF, &q, 0); *quotelenp = q.nbytesout; return q.quoted; }