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