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