xref: /plan9/sys/src/libc/fmt/fmtquote.c (revision 67031067871d8cd705958f437682c703f042b640)
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