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