fmtquote.c (3609B)
1 /* 2 * The authors of this software are Rob Pike and Ken Thompson. 3 * Copyright (c) 2002 by Lucent Technologies. 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose without fee is hereby granted, provided that this entire notice 6 * is included in all copies of any software which is or includes a copy 7 * or modification of this software and in all copies of the supporting 8 * documentation for such software. 9 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 10 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY 11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13 */ 14 #include <u.h> 15 #include <libc.h> 16 #include "fmt.h" 17 #include "fmtdef.h" 18 19 extern int (*doquote)(int); 20 21 /* 22 * How many bytes of output UTF will be produced by quoting (if necessary) this string? 23 * How many runes? How much of the input will be consumed? 24 * The parameter q is filled in by _quotesetup. 25 * The string may be UTF or Runes (s or r). 26 * Return count does not include NUL. 27 * Terminate the scan at the first of: 28 * NUL in input 29 * count exceeded in input 30 * count exceeded on output 31 * *ninp is set to number of input bytes accepted. 32 * nin may be <0 initially, to avoid checking input by count. 33 */ 34 void 35 __quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp) 36 { 37 int c; 38 39 q->quoted = 0; 40 q->nbytesout = 0; 41 q->nrunesout = 0; 42 q->nbytesin = 0; 43 q->nrunesin = 0; 44 if(sharp || nin==0 || *s=='\0'){ 45 if(nout < 2) 46 return; 47 q->quoted = 1; 48 q->nbytesout = 2; 49 q->nrunesout = 2; 50 } 51 for(; nin!=0; nin-=1){ 52 c = *s; 53 54 if(c == '\0') 55 break; 56 if(q->nrunesout+1 > nout) 57 break; 58 59 if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ 60 if(!q->quoted){ 61 if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ 62 break; 63 q->nrunesout += 2; /* include quotes */ 64 q->nbytesout += 2; /* include quotes */ 65 q->quoted = 1; 66 } 67 if(c == '\'') { 68 q->nbytesout++; 69 q->nrunesout++; /* quotes reproduce as two characters */ 70 } 71 } 72 73 /* advance input */ 74 s++; 75 q->nbytesin++; 76 q->nrunesin++; 77 78 /* advance output */ 79 q->nbytesout++; 80 q->nrunesout++; 81 } 82 } 83 84 static int 85 qstrfmt(char *sin, Quoteinfo *q, Fmt *f) 86 { 87 int r; 88 char *t, *s, *m, *me; 89 ulong fl; 90 int nc, w; 91 92 m = sin; 93 me = m + q->nbytesin; 94 95 w = f->width; 96 fl = f->flags; 97 if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) 98 return -1; 99 t = f->to; 100 s = f->stop; 101 FMTCHAR(f, t, s, '\''); 102 for(nc = q->nrunesin; nc > 0; nc--){ 103 r = *(uchar*)m++; 104 FMTCHAR(f, t, s, r); 105 if(r == '\'') 106 FMTCHAR(f, t, s, r); 107 } 108 109 FMTCHAR(f, t, s, '\''); 110 f->nfmt += t - (char *)f->to; 111 f->to = t; 112 if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) 113 return -1; 114 return 0; 115 } 116 117 int 118 __quotestrfmt(int runesin, Fmt *f) 119 { 120 int outlen; 121 char *s; 122 Quoteinfo q; 123 124 f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */ 125 s = va_arg(f->args, char *); 126 if(!s) 127 return __fmtcpy(f, "<nil>", 5, 5); 128 129 if(f->flush) 130 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ 131 else 132 outlen = (char*)f->stop - (char*)f->to; 133 134 __quotesetup(s, -1, outlen, &q, f->flags&FmtSharp); 135 136 if(!q.quoted) 137 return __fmtcpy(f, s, q.nrunesin, q.nbytesin); 138 return qstrfmt(s, &q, f); 139 } 140 141 int 142 quotestrfmt(Fmt *f) 143 { 144 return __quotestrfmt(0, f); 145 } 146 147 void 148 quotefmtinstall(void) 149 { 150 fmtinstall('q', quotestrfmt); 151 } 152 153 int 154 __needsquotes(char *s, int *quotelenp) 155 { 156 Quoteinfo q; 157 158 __quotesetup(s, -1, 0x7FFFFFFF, &q, 0); 159 *quotelenp = q.nbytesout; 160 161 return q.quoted; 162 }