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