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