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--){ 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'\'') || (fmtdoquote!=0 && fmtdoquote(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 = (char*)f->to; 118 s = (char*)f->stop; 119 rt = (Rune*)f->to; 120 rs = (Rune*)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 nin, outlen; 172 Rune *r; 173 char *s; 174 Quoteinfo q; 175 176 nin = -1; 177 if(f->flags&FmtPrec) 178 nin = f->prec; 179 if(runesin){ 180 r = va_arg(f->args, Rune *); 181 s = nil; 182 }else{ 183 s = va_arg(f->args, char *); 184 r = nil; 185 } 186 if(!s && !r) 187 return __fmtcpy(f, (void*)"<nil>", 5, 5); 188 189 if(f->flush) 190 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ 191 else if(f->runes) 192 outlen = (Rune*)f->stop - (Rune*)f->to; 193 else 194 outlen = (char*)f->stop - (char*)f->to; 195 196 __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); 197 //print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); 198 199 if(runesin){ 200 if(!q.quoted) 201 return __fmtrcpy(f, r, q.nrunesin); 202 return qstrfmt(nil, r, &q, f); 203 } 204 205 if(!q.quoted) 206 return __fmtcpy(f, s, q.nrunesin, q.nbytesin); 207 return qstrfmt(s, nil, &q, f); 208 } 209 210 int 211 quotestrfmt(Fmt *f) 212 { 213 return __quotestrfmt(0, f); 214 } 215 216 int 217 quoterunestrfmt(Fmt *f) 218 { 219 return __quotestrfmt(1, f); 220 } 221 222 void 223 quotefmtinstall(void) 224 { 225 fmtinstall('q', quotestrfmt); 226 fmtinstall('Q', quoterunestrfmt); 227 } 228 229 int 230 __needsquotes(char *s, int *quotelenp) 231 { 232 Quoteinfo q; 233 234 __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0); 235 *quotelenp = q.nbytesout; 236 237 return q.quoted; 238 } 239 240 int 241 __runeneedsquotes(Rune *r, int *quotelenp) 242 { 243 Quoteinfo q; 244 245 __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0); 246 *quotelenp = q.nrunesout; 247 248 return q.quoted; 249 } 250