19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include "fmtdef.h"
49a747e4fSDavid du Colombier
59a747e4fSDavid du Colombier /*
69a747e4fSDavid du Colombier * How many bytes of output UTF will be produced by quoting (if necessary) this string?
79a747e4fSDavid du Colombier * How many runes? How much of the input will be consumed?
89a747e4fSDavid du Colombier * The parameter q is filled in by _quotesetup.
99a747e4fSDavid du Colombier * The string may be UTF or Runes (s or r).
109a747e4fSDavid du Colombier * Return count does not include NUL.
119a747e4fSDavid du Colombier * Terminate the scan at the first of:
129a747e4fSDavid du Colombier * NUL in input
139a747e4fSDavid du Colombier * count exceeded in input
149a747e4fSDavid du Colombier * count exceeded on output
159a747e4fSDavid du Colombier * *ninp is set to number of input bytes accepted.
169a747e4fSDavid du Colombier * nin may be <0 initially, to avoid checking input by count.
179a747e4fSDavid du Colombier */
189a747e4fSDavid du Colombier void
_quotesetup(char * s,Rune * r,int nin,int nout,Quoteinfo * q,int sharp,int runesout)199a747e4fSDavid du Colombier _quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
209a747e4fSDavid du Colombier {
219a747e4fSDavid du Colombier int w;
229a747e4fSDavid du Colombier Rune c;
239a747e4fSDavid du Colombier
249a747e4fSDavid du Colombier q->quoted = 0;
259a747e4fSDavid du Colombier q->nbytesout = 0;
269a747e4fSDavid du Colombier q->nrunesout = 0;
279a747e4fSDavid du Colombier q->nbytesin = 0;
289a747e4fSDavid du Colombier q->nrunesin = 0;
299a747e4fSDavid du Colombier if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
309a747e4fSDavid du Colombier if(nout < 2)
319a747e4fSDavid du Colombier return;
329a747e4fSDavid du Colombier q->quoted = 1;
339a747e4fSDavid du Colombier q->nbytesout = 2;
349a747e4fSDavid du Colombier q->nrunesout = 2;
359a747e4fSDavid du Colombier }
36*67031067SDavid du Colombier for(; nin!=0; nin--){
379a747e4fSDavid du Colombier if(s)
389a747e4fSDavid du Colombier w = chartorune(&c, s);
399a747e4fSDavid du Colombier else{
409a747e4fSDavid du Colombier c = *r;
419a747e4fSDavid du Colombier w = runelen(c);
429a747e4fSDavid du Colombier }
439a747e4fSDavid du Colombier
449a747e4fSDavid du Colombier if(c == '\0')
459a747e4fSDavid du Colombier break;
469a747e4fSDavid du Colombier if(runesout){
479a747e4fSDavid du Colombier if(q->nrunesout+1 > nout)
489a747e4fSDavid du Colombier break;
499a747e4fSDavid du Colombier }else{
509a747e4fSDavid du Colombier if(q->nbytesout+w > nout)
519a747e4fSDavid du Colombier break;
529a747e4fSDavid du Colombier }
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
559a747e4fSDavid du Colombier if(!q->quoted){
569a747e4fSDavid du Colombier if(runesout){
579a747e4fSDavid du Colombier if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
589a747e4fSDavid du Colombier break;
599a747e4fSDavid du Colombier }else{
609a747e4fSDavid du Colombier if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
619a747e4fSDavid du Colombier break;
629a747e4fSDavid du Colombier }
639a747e4fSDavid du Colombier q->nrunesout += 2; /* include quotes */
649a747e4fSDavid du Colombier q->nbytesout += 2; /* include quotes */
659a747e4fSDavid du Colombier q->quoted = 1;
669a747e4fSDavid du Colombier }
679a747e4fSDavid du Colombier if(c == '\'') {
68d9306527SDavid du Colombier if(runesout){
69d9306527SDavid du Colombier if(1+q->nrunesout+1 > nout) /* no room for quotes */
70d9306527SDavid du Colombier break;
71d9306527SDavid du Colombier }else{
72d9306527SDavid du Colombier if(1+q->nbytesout+w > nout) /* no room for quotes */
73d9306527SDavid du Colombier break;
74d9306527SDavid du Colombier }
759a747e4fSDavid du Colombier q->nbytesout++;
769a747e4fSDavid du Colombier q->nrunesout++; /* quotes reproduce as two characters */
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier }
799a747e4fSDavid du Colombier
809a747e4fSDavid du Colombier /* advance input */
819a747e4fSDavid du Colombier if(s)
829a747e4fSDavid du Colombier s += w;
839a747e4fSDavid du Colombier else
849a747e4fSDavid du Colombier r++;
859a747e4fSDavid du Colombier q->nbytesin += w;
869a747e4fSDavid du Colombier q->nrunesin++;
879a747e4fSDavid du Colombier
889a747e4fSDavid du Colombier /* advance output */
899a747e4fSDavid du Colombier q->nbytesout += w;
909a747e4fSDavid du Colombier q->nrunesout++;
919a747e4fSDavid du Colombier }
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier static int
qstrfmt(char * sin,Rune * rin,Quoteinfo * q,Fmt * f)959a747e4fSDavid du Colombier qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier Rune r, *rm, *rme;
989a747e4fSDavid du Colombier char *t, *s, *m, *me;
999a747e4fSDavid du Colombier Rune *rt, *rs;
1009a747e4fSDavid du Colombier ulong fl;
1019a747e4fSDavid du Colombier int nc, w;
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier m = sin;
1049a747e4fSDavid du Colombier me = m + q->nbytesin;
1059a747e4fSDavid du Colombier rm = rin;
1069a747e4fSDavid du Colombier rme = rm + q->nrunesin;
1079a747e4fSDavid du Colombier
1089a747e4fSDavid du Colombier w = f->width;
1099a747e4fSDavid du Colombier fl = f->flags;
1109a747e4fSDavid du Colombier if(f->runes){
1119a747e4fSDavid du Colombier if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
1129a747e4fSDavid du Colombier return -1;
1139a747e4fSDavid du Colombier }else{
1149a747e4fSDavid du Colombier if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
1159a747e4fSDavid du Colombier return -1;
1169a747e4fSDavid du Colombier }
1179a747e4fSDavid du Colombier t = f->to;
1189a747e4fSDavid du Colombier s = f->stop;
1199a747e4fSDavid du Colombier rt = f->to;
1209a747e4fSDavid du Colombier rs = f->stop;
1219a747e4fSDavid du Colombier if(f->runes)
1229a747e4fSDavid du Colombier FMTRCHAR(f, rt, rs, '\'');
1239a747e4fSDavid du Colombier else
1249a747e4fSDavid du Colombier FMTRUNE(f, t, s, '\'');
1259a747e4fSDavid du Colombier for(nc = q->nrunesin; nc > 0; nc--){
1269a747e4fSDavid du Colombier if(sin){
1279a747e4fSDavid du Colombier r = *(uchar*)m;
1289a747e4fSDavid du Colombier if(r < Runeself)
1299a747e4fSDavid du Colombier m++;
1309a747e4fSDavid du Colombier else if((me - m) >= UTFmax || fullrune(m, me-m))
1319a747e4fSDavid du Colombier m += chartorune(&r, m);
1329a747e4fSDavid du Colombier else
1339a747e4fSDavid du Colombier break;
1349a747e4fSDavid du Colombier }else{
1359a747e4fSDavid du Colombier if(rm >= rme)
1369a747e4fSDavid du Colombier break;
1379a747e4fSDavid du Colombier r = *(uchar*)rm++;
1389a747e4fSDavid du Colombier }
1399a747e4fSDavid du Colombier if(f->runes){
1409a747e4fSDavid du Colombier FMTRCHAR(f, rt, rs, r);
1419a747e4fSDavid du Colombier if(r == '\'')
1429a747e4fSDavid du Colombier FMTRCHAR(f, rt, rs, r);
1439a747e4fSDavid du Colombier }else{
1449a747e4fSDavid du Colombier FMTRUNE(f, t, s, r);
1459a747e4fSDavid du Colombier if(r == '\'')
1469a747e4fSDavid du Colombier FMTRUNE(f, t, s, r);
1479a747e4fSDavid du Colombier }
1489a747e4fSDavid du Colombier }
1499a747e4fSDavid du Colombier
1509a747e4fSDavid du Colombier if(f->runes){
1519a747e4fSDavid du Colombier FMTRCHAR(f, rt, rs, '\'');
1529a747e4fSDavid du Colombier USED(rs);
1539a747e4fSDavid du Colombier f->nfmt += rt - (Rune *)f->to;
1549a747e4fSDavid du Colombier f->to = rt;
1559a747e4fSDavid du Colombier if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
1569a747e4fSDavid du Colombier return -1;
1579a747e4fSDavid du Colombier }else{
1589a747e4fSDavid du Colombier FMTRUNE(f, t, s, '\'');
1599a747e4fSDavid du Colombier USED(s);
1609a747e4fSDavid du Colombier f->nfmt += t - (char *)f->to;
1619a747e4fSDavid du Colombier f->to = t;
1629a747e4fSDavid du Colombier if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
1639a747e4fSDavid du Colombier return -1;
1649a747e4fSDavid du Colombier }
1659a747e4fSDavid du Colombier return 0;
1669a747e4fSDavid du Colombier }
1679a747e4fSDavid du Colombier
1689a747e4fSDavid du Colombier int
_quotestrfmt(int runesin,Fmt * f)1699a747e4fSDavid du Colombier _quotestrfmt(int runesin, Fmt *f)
1709a747e4fSDavid du Colombier {
171*67031067SDavid du Colombier int nin, outlen;
1729a747e4fSDavid du Colombier Rune *r;
1739a747e4fSDavid du Colombier char *s;
1749a747e4fSDavid du Colombier Quoteinfo q;
1759a747e4fSDavid du Colombier
176*67031067SDavid du Colombier nin = -1;
177*67031067SDavid du Colombier if(f->flags&FmtPrec)
178*67031067SDavid du Colombier nin = f->prec;
1799a747e4fSDavid du Colombier if(runesin){
1809a747e4fSDavid du Colombier r = va_arg(f->args, Rune *);
1819a747e4fSDavid du Colombier s = nil;
1829a747e4fSDavid du Colombier }else{
1839a747e4fSDavid du Colombier s = va_arg(f->args, char *);
1849a747e4fSDavid du Colombier r = nil;
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier if(!s && !r)
1879a747e4fSDavid du Colombier return _fmtcpy(f, "<nil>", 5, 5);
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier if(f->flush)
1909a747e4fSDavid du Colombier outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
1919a747e4fSDavid du Colombier else if(f->runes)
1929a747e4fSDavid du Colombier outlen = (Rune*)f->stop - (Rune*)f->to;
1939a747e4fSDavid du Colombier else
1949a747e4fSDavid du Colombier outlen = (char*)f->stop - (char*)f->to;
1959a747e4fSDavid du Colombier
196*67031067SDavid du Colombier _quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
1979a747e4fSDavid du Colombier //print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
1989a747e4fSDavid du Colombier
1999a747e4fSDavid du Colombier if(runesin){
2009a747e4fSDavid du Colombier if(!q.quoted)
2019a747e4fSDavid du Colombier return _fmtrcpy(f, r, q.nrunesin);
2029a747e4fSDavid du Colombier return qstrfmt(nil, r, &q, f);
2039a747e4fSDavid du Colombier }
2049a747e4fSDavid du Colombier
2059a747e4fSDavid du Colombier if(!q.quoted)
2069a747e4fSDavid du Colombier return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
2079a747e4fSDavid du Colombier return qstrfmt(s, nil, &q, f);
2089a747e4fSDavid du Colombier }
2099a747e4fSDavid du Colombier
2109a747e4fSDavid du Colombier int
quotestrfmt(Fmt * f)2119a747e4fSDavid du Colombier quotestrfmt(Fmt *f)
2129a747e4fSDavid du Colombier {
2139a747e4fSDavid du Colombier return _quotestrfmt(0, f);
2149a747e4fSDavid du Colombier }
2159a747e4fSDavid du Colombier
2169a747e4fSDavid du Colombier int
quoterunestrfmt(Fmt * f)2179a747e4fSDavid du Colombier quoterunestrfmt(Fmt *f)
2189a747e4fSDavid du Colombier {
2199a747e4fSDavid du Colombier return _quotestrfmt(1, f);
2209a747e4fSDavid du Colombier }
2219a747e4fSDavid du Colombier
2229a747e4fSDavid du Colombier void
quotefmtinstall(void)2239a747e4fSDavid du Colombier quotefmtinstall(void)
2249a747e4fSDavid du Colombier {
2259a747e4fSDavid du Colombier fmtinstall('q', quotestrfmt);
2269a747e4fSDavid du Colombier fmtinstall('Q', quoterunestrfmt);
2279a747e4fSDavid du Colombier }
2289a747e4fSDavid du Colombier
2299a747e4fSDavid du Colombier int
_needsquotes(char * s,int * quotelenp)2309a747e4fSDavid du Colombier _needsquotes(char *s, int *quotelenp)
2319a747e4fSDavid du Colombier {
2329a747e4fSDavid du Colombier Quoteinfo q;
2339a747e4fSDavid du Colombier
2349a747e4fSDavid du Colombier _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
2359a747e4fSDavid du Colombier *quotelenp = q.nbytesout;
2369a747e4fSDavid du Colombier
2379a747e4fSDavid du Colombier return q.quoted;
2389a747e4fSDavid du Colombier }
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier int
_runeneedsquotes(Rune * r,int * quotelenp)2419a747e4fSDavid du Colombier _runeneedsquotes(Rune *r, int *quotelenp)
2429a747e4fSDavid du Colombier {
2439a747e4fSDavid du Colombier Quoteinfo q;
2449a747e4fSDavid du Colombier
2459a747e4fSDavid du Colombier _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
2469a747e4fSDavid du Colombier *quotelenp = q.nrunesout;
2479a747e4fSDavid du Colombier
2489a747e4fSDavid du Colombier return q.quoted;
2499a747e4fSDavid du Colombier }
250