fmtquote.c (5023B)
1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ 2 #include <stdarg.h> 3 #include <string.h> 4 #include "plan9.h" 5 #include "fmt.h" 6 #include "fmtdef.h" 7 8 /* 9 * How many bytes of output UTF will be produced by quoting (if necessary) this string? 10 * How many runes? How much of the input will be consumed? 11 * The parameter q is filled in by __quotesetup. 12 * The string may be UTF or Runes (s or r). 13 * Return count does not include NUL. 14 * Terminate the scan at the first of: 15 * NUL in input 16 * count exceeded in input 17 * count exceeded on output 18 * *ninp is set to number of input bytes accepted. 19 * nin may be <0 initially, to avoid checking input by count. 20 */ 21 void 22 __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout) 23 { 24 int w; 25 Rune c; 26 27 q->quoted = 0; 28 q->nbytesout = 0; 29 q->nrunesout = 0; 30 q->nbytesin = 0; 31 q->nrunesin = 0; 32 if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ 33 if(nout < 2) 34 return; 35 q->quoted = 1; 36 q->nbytesout = 2; 37 q->nrunesout = 2; 38 } 39 for(; nin!=0; nin--){ 40 if(s) 41 w = chartorune(&c, s); 42 else{ 43 c = *r; 44 w = runelen(c); 45 } 46 47 if(c == '\0') 48 break; 49 if(runesout){ 50 if(q->nrunesout+1 > nout) 51 break; 52 }else{ 53 if(q->nbytesout+w > nout) 54 break; 55 } 56 57 if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){ 58 if(!q->quoted){ 59 if(runesout){ 60 if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ 61 break; 62 }else{ 63 if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ 64 break; 65 } 66 q->nrunesout += 2; /* include quotes */ 67 q->nbytesout += 2; /* include quotes */ 68 q->quoted = 1; 69 } 70 if(c == '\'') { 71 if(runesout){ 72 if(1+q->nrunesout+1 > nout) /* no room for quotes */ 73 break; 74 }else{ 75 if(1+q->nbytesout+w > nout) /* no room for quotes */ 76 break; 77 } 78 q->nbytesout++; 79 q->nrunesout++; /* quotes reproduce as two characters */ 80 } 81 } 82 83 /* advance input */ 84 if(s) 85 s += w; 86 else 87 r++; 88 q->nbytesin += w; 89 q->nrunesin++; 90 91 /* advance output */ 92 q->nbytesout += w; 93 q->nrunesout++; 94 95 #ifndef PLAN9PORT 96 /* ANSI requires precision in bytes, not Runes. */ 97 nin-= w-1; /* and then n-- in the loop */ 98 #endif 99 } 100 } 101 102 static int 103 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) 104 { 105 Rune r, *rm, *rme; 106 char *t, *s, *m, *me; 107 Rune *rt, *rs; 108 ulong fl; 109 int nc, w; 110 111 m = sin; 112 me = m + q->nbytesin; 113 rm = rin; 114 rme = rm + q->nrunesin; 115 116 fl = f->flags; 117 w = 0; 118 if(fl & FmtWidth) 119 w = f->width; 120 if(f->runes){ 121 if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0) 122 return -1; 123 }else{ 124 if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) 125 return -1; 126 } 127 t = (char*)f->to; 128 s = (char*)f->stop; 129 rt = (Rune*)f->to; 130 rs = (Rune*)f->stop; 131 if(f->runes) 132 FMTRCHAR(f, rt, rs, '\''); 133 else 134 FMTRUNE(f, t, s, '\''); 135 for(nc = q->nrunesin; nc > 0; nc--){ 136 if(sin){ 137 r = *(uchar*)m; 138 if(r < Runeself) 139 m++; 140 else if((me - m) >= UTFmax || fullrune(m, me-m)) 141 m += chartorune(&r, m); 142 else 143 break; 144 }else{ 145 if(rm >= rme) 146 break; 147 r = *(uchar*)rm++; 148 } 149 if(f->runes){ 150 FMTRCHAR(f, rt, rs, r); 151 if(r == '\'') 152 FMTRCHAR(f, rt, rs, r); 153 }else{ 154 FMTRUNE(f, t, s, r); 155 if(r == '\'') 156 FMTRUNE(f, t, s, r); 157 } 158 } 159 160 if(f->runes){ 161 FMTRCHAR(f, rt, rs, '\''); 162 USED(rs); 163 f->nfmt += rt - (Rune *)f->to; 164 f->to = rt; 165 if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0) 166 return -1; 167 }else{ 168 FMTRUNE(f, t, s, '\''); 169 USED(s); 170 f->nfmt += t - (char *)f->to; 171 f->to = t; 172 if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) 173 return -1; 174 } 175 return 0; 176 } 177 178 int 179 __quotestrfmt(int runesin, Fmt *f) 180 { 181 int nin, outlen; 182 Rune *r; 183 char *s; 184 Quoteinfo q; 185 186 nin = -1; 187 if(f->flags&FmtPrec) 188 nin = f->prec; 189 if(runesin){ 190 r = va_arg(f->args, Rune *); 191 s = nil; 192 }else{ 193 s = va_arg(f->args, char *); 194 r = nil; 195 } 196 if(!s && !r) 197 return __fmtcpy(f, (void*)"<nil>", 5, 5); 198 199 if(f->flush) 200 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ 201 else if(f->runes) 202 outlen = (Rune*)f->stop - (Rune*)f->to; 203 else 204 outlen = (char*)f->stop - (char*)f->to; 205 206 __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); 207 /*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */ 208 209 if(runesin){ 210 if(!q.quoted) 211 return __fmtrcpy(f, r, q.nrunesin); 212 return qstrfmt(nil, r, &q, f); 213 } 214 215 if(!q.quoted) 216 return __fmtcpy(f, s, q.nrunesin, q.nbytesin); 217 return qstrfmt(s, nil, &q, f); 218 } 219 220 int 221 quotestrfmt(Fmt *f) 222 { 223 return __quotestrfmt(0, f); 224 } 225 226 int 227 quoterunestrfmt(Fmt *f) 228 { 229 return __quotestrfmt(1, f); 230 } 231 232 void 233 quotefmtinstall(void) 234 { 235 fmtinstall('q', quotestrfmt); 236 fmtinstall('Q', quoterunestrfmt); 237 } 238 239 int 240 __needsquotes(char *s, int *quotelenp) 241 { 242 Quoteinfo q; 243 244 __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0); 245 *quotelenp = q.nbytesout; 246 247 return q.quoted; 248 } 249 250 int 251 __runeneedsquotes(Rune *r, int *quotelenp) 252 { 253 Quoteinfo q; 254 255 __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0); 256 *quotelenp = q.nrunesout; 257 258 return q.quoted; 259 }