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 "lib9.h" 15 #include "fmtdef.h" 16 17 /* 18 * How many bytes of output UTF will be produced by quoting (if necessary) this string? 19 * How many runes? How much of the input will be consumed? 20 * The parameter q is filled in by _quotesetup. 21 * The string may be UTF or Runes (s or r). 22 * Return count does not include NUL. 23 * Terminate the scan at the first of: 24 * NUL in input 25 * count exceeded in input 26 * count exceeded on output 27 * *ninp is set to number of input bytes accepted. 28 * nin may be <0 initially, to avoid checking input by count. 29 */ 30 void 31 _quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout) 32 { 33 int w; 34 Rune c; 35 36 q->quoted = 0; 37 q->nbytesout = 0; 38 q->nrunesout = 0; 39 q->nbytesin = 0; 40 q->nrunesin = 0; 41 if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ 42 if(nout < 2) 43 return; 44 q->quoted = 1; 45 q->nbytesout = 2; 46 q->nrunesout = 2; 47 } 48 for(; nin!=0; nin-=w){ 49 if(s) 50 w = chartorune(&c, s); 51 else{ 52 c = *r; 53 w = runelen(c); 54 } 55 56 if(c == '\0') 57 break; 58 if(runesout){ 59 if(q->nrunesout+1 > nout) 60 break; 61 }else{ 62 if(q->nbytesout+w > nout) 63 break; 64 } 65 66 if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ 67 if(!q->quoted){ 68 if(runesout){ 69 if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ 70 break; 71 }else{ 72 if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ 73 break; 74 } 75 q->nrunesout += 2; /* include quotes */ 76 q->nbytesout += 2; /* include quotes */ 77 q->quoted = 1; 78 } 79 if(c == '\'') { 80 if(runesout){ 81 if(1+q->nrunesout+1 > nout) /* no room for quotes */ 82 break; 83 }else{ 84 if(1+q->nbytesout+w > nout) /* no room for quotes */ 85 break; 86 } 87 q->nbytesout++; 88 q->nrunesout++; /* quotes reproduce as two characters */ 89 } 90 } 91 92 /* advance input */ 93 if(s) 94 s += w; 95 else 96 r++; 97 q->nbytesin += w; 98 q->nrunesin++; 99 100 /* advance output */ 101 q->nbytesout += w; 102 q->nrunesout++; 103 } 104 } 105 106 static int 107 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) 108 { 109 Rune r, *rm, *rme; 110 char *t, *s, *m, *me; 111 Rune *rt, *rs; 112 ulong fl; 113 int nc, w; 114 115 m = sin; 116 me = m + q->nbytesin; 117 rm = rin; 118 rme = rm + q->nrunesin; 119 120 w = f->width; 121 fl = f->flags; 122 if(f->runes){ 123 if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0) 124 return -1; 125 }else{ 126 if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0) 127 return -1; 128 } 129 t = f->to; 130 s = f->stop; 131 rt = f->to; 132 rs = f->stop; 133 if(f->runes) 134 FMTRCHAR(f, rt, rs, '\''); 135 else 136 FMTRUNE(f, t, s, '\''); 137 for(nc = q->nrunesin; nc > 0; nc--){ 138 if(sin){ 139 r = *(uchar*)m; 140 if(r < Runeself) 141 m++; 142 else if((me - m) >= UTFmax || fullrune(m, me-m)) 143 m += chartorune(&r, m); 144 else 145 break; 146 }else{ 147 if(rm >= rme) 148 break; 149 r = *rm++; 150 } 151 if(f->runes){ 152 FMTRCHAR(f, rt, rs, r); 153 if(r == '\'') 154 FMTRCHAR(f, rt, rs, r); 155 }else{ 156 FMTRUNE(f, t, s, r); 157 if(r == '\'') 158 FMTRUNE(f, t, s, r); 159 } 160 } 161 162 if(f->runes){ 163 FMTRCHAR(f, rt, rs, '\''); 164 USED(rs); 165 f->nfmt += rt - (Rune *)f->to; 166 f->to = rt; 167 if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0) 168 return -1; 169 }else{ 170 FMTRUNE(f, t, s, '\''); 171 USED(s); 172 f->nfmt += t - (char *)f->to; 173 f->to = t; 174 if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0) 175 return -1; 176 } 177 return 0; 178 } 179 180 int 181 _quotestrfmt(int runesin, Fmt *f) 182 { 183 int outlen; 184 Rune *r; 185 char *s; 186 Quoteinfo q; 187 188 f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */ 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, "<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, -1, 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 } 260