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