xref: /plan9/sys/src/cmd/unix/drawterm/libc/fmtquote.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
18ccd4a63SDavid du Colombier #include <u.h>
28ccd4a63SDavid du Colombier #include <libc.h>
38ccd4a63SDavid du Colombier #include "fmtdef.h"
48ccd4a63SDavid du Colombier 
58ccd4a63SDavid du Colombier /*
68ccd4a63SDavid du Colombier  * How many bytes of output UTF will be produced by quoting (if necessary) this string?
78ccd4a63SDavid du Colombier  * How many runes? How much of the input will be consumed?
80d601874SDavid du Colombier  * The parameter q is filled in by __quotesetup.
98ccd4a63SDavid du Colombier  * The string may be UTF or Runes (s or r).
108ccd4a63SDavid du Colombier  * Return count does not include NUL.
118ccd4a63SDavid du Colombier  * Terminate the scan at the first of:
128ccd4a63SDavid du Colombier  *	NUL in input
138ccd4a63SDavid du Colombier  *	count exceeded in input
148ccd4a63SDavid du Colombier  *	count exceeded on output
158ccd4a63SDavid du Colombier  * *ninp is set to number of input bytes accepted.
168ccd4a63SDavid du Colombier  * nin may be <0 initially, to avoid checking input by count.
178ccd4a63SDavid du Colombier  */
188ccd4a63SDavid du Colombier void
__quotesetup(char * s,Rune * r,int nin,int nout,Quoteinfo * q,int sharp,int runesout)190d601874SDavid du Colombier __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
208ccd4a63SDavid du Colombier {
218ccd4a63SDavid du Colombier 	int w;
228ccd4a63SDavid du Colombier 	Rune c;
238ccd4a63SDavid du Colombier 
248ccd4a63SDavid du Colombier 	q->quoted = 0;
258ccd4a63SDavid du Colombier 	q->nbytesout = 0;
268ccd4a63SDavid du Colombier 	q->nrunesout = 0;
278ccd4a63SDavid du Colombier 	q->nbytesin = 0;
288ccd4a63SDavid du Colombier 	q->nrunesin = 0;
298ccd4a63SDavid du Colombier 	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
308ccd4a63SDavid du Colombier 		if(nout < 2)
318ccd4a63SDavid du Colombier 			return;
328ccd4a63SDavid du Colombier 		q->quoted = 1;
338ccd4a63SDavid du Colombier 		q->nbytesout = 2;
348ccd4a63SDavid du Colombier 		q->nrunesout = 2;
358ccd4a63SDavid du Colombier 	}
360d601874SDavid du Colombier 	for(; nin!=0; nin--){
378ccd4a63SDavid du Colombier 		if(s)
388ccd4a63SDavid du Colombier 			w = chartorune(&c, s);
398ccd4a63SDavid du Colombier 		else{
408ccd4a63SDavid du Colombier 			c = *r;
418ccd4a63SDavid du Colombier 			w = runelen(c);
428ccd4a63SDavid du Colombier 		}
438ccd4a63SDavid du Colombier 
448ccd4a63SDavid du Colombier 		if(c == '\0')
458ccd4a63SDavid du Colombier 			break;
468ccd4a63SDavid du Colombier 		if(runesout){
478ccd4a63SDavid du Colombier 			if(q->nrunesout+1 > nout)
488ccd4a63SDavid du Colombier 				break;
498ccd4a63SDavid du Colombier 		}else{
508ccd4a63SDavid du Colombier 			if(q->nbytesout+w > nout)
518ccd4a63SDavid du Colombier 				break;
528ccd4a63SDavid du Colombier 		}
538ccd4a63SDavid du Colombier 
54*ec59a3ddSDavid du Colombier 		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=0 && fmtdoquote(c))){
558ccd4a63SDavid du Colombier 			if(!q->quoted){
568ccd4a63SDavid du Colombier 				if(runesout){
578ccd4a63SDavid du Colombier 					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
588ccd4a63SDavid du Colombier 						break;
598ccd4a63SDavid du Colombier 				}else{
608ccd4a63SDavid du Colombier 					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
618ccd4a63SDavid du Colombier 						break;
628ccd4a63SDavid du Colombier 				}
638ccd4a63SDavid du Colombier 				q->nrunesout += 2;	/* include quotes */
648ccd4a63SDavid du Colombier 				q->nbytesout += 2;	/* include quotes */
658ccd4a63SDavid du Colombier 				q->quoted = 1;
668ccd4a63SDavid du Colombier 			}
678ccd4a63SDavid du Colombier 			if(c == '\'')	{
688ccd4a63SDavid du Colombier 				if(runesout){
698ccd4a63SDavid du Colombier 					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
708ccd4a63SDavid du Colombier 						break;
718ccd4a63SDavid du Colombier 				}else{
728ccd4a63SDavid du Colombier 					if(1+q->nbytesout+w > nout)	/* no room for quotes */
738ccd4a63SDavid du Colombier 						break;
748ccd4a63SDavid du Colombier 				}
758ccd4a63SDavid du Colombier 				q->nbytesout++;
768ccd4a63SDavid du Colombier 				q->nrunesout++;	/* quotes reproduce as two characters */
778ccd4a63SDavid du Colombier 			}
788ccd4a63SDavid du Colombier 		}
798ccd4a63SDavid du Colombier 
808ccd4a63SDavid du Colombier 		/* advance input */
818ccd4a63SDavid du Colombier 		if(s)
828ccd4a63SDavid du Colombier 			s += w;
838ccd4a63SDavid du Colombier 		else
848ccd4a63SDavid du Colombier 			r++;
858ccd4a63SDavid du Colombier 		q->nbytesin += w;
868ccd4a63SDavid du Colombier 		q->nrunesin++;
878ccd4a63SDavid du Colombier 
888ccd4a63SDavid du Colombier 		/* advance output */
898ccd4a63SDavid du Colombier 		q->nbytesout += w;
908ccd4a63SDavid du Colombier 		q->nrunesout++;
918ccd4a63SDavid du Colombier 	}
928ccd4a63SDavid du Colombier }
938ccd4a63SDavid du Colombier 
948ccd4a63SDavid du Colombier static int
qstrfmt(char * sin,Rune * rin,Quoteinfo * q,Fmt * f)958ccd4a63SDavid du Colombier qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
968ccd4a63SDavid du Colombier {
978ccd4a63SDavid du Colombier 	Rune r, *rm, *rme;
988ccd4a63SDavid du Colombier 	char *t, *s, *m, *me;
998ccd4a63SDavid du Colombier 	Rune *rt, *rs;
1008ccd4a63SDavid du Colombier 	ulong fl;
1018ccd4a63SDavid du Colombier 	int nc, w;
1028ccd4a63SDavid du Colombier 
1038ccd4a63SDavid du Colombier 	m = sin;
1048ccd4a63SDavid du Colombier 	me = m + q->nbytesin;
1058ccd4a63SDavid du Colombier 	rm = rin;
1068ccd4a63SDavid du Colombier 	rme = rm + q->nrunesin;
1078ccd4a63SDavid du Colombier 
1088ccd4a63SDavid du Colombier 	w = f->width;
1098ccd4a63SDavid du Colombier 	fl = f->flags;
1108ccd4a63SDavid du Colombier 	if(f->runes){
1110d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
1128ccd4a63SDavid du Colombier 			return -1;
1138ccd4a63SDavid du Colombier 	}else{
1140d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
1158ccd4a63SDavid du Colombier 			return -1;
1168ccd4a63SDavid du Colombier 	}
1170d601874SDavid du Colombier 	t = (char*)f->to;
1180d601874SDavid du Colombier 	s = (char*)f->stop;
1190d601874SDavid du Colombier 	rt = (Rune*)f->to;
1200d601874SDavid du Colombier 	rs = (Rune*)f->stop;
1218ccd4a63SDavid du Colombier 	if(f->runes)
1228ccd4a63SDavid du Colombier 		FMTRCHAR(f, rt, rs, '\'');
1238ccd4a63SDavid du Colombier 	else
1248ccd4a63SDavid du Colombier 		FMTRUNE(f, t, s, '\'');
1258ccd4a63SDavid du Colombier 	for(nc = q->nrunesin; nc > 0; nc--){
1268ccd4a63SDavid du Colombier 		if(sin){
1278ccd4a63SDavid du Colombier 			r = *(uchar*)m;
1288ccd4a63SDavid du Colombier 			if(r < Runeself)
1298ccd4a63SDavid du Colombier 				m++;
1308ccd4a63SDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
1318ccd4a63SDavid du Colombier 				m += chartorune(&r, m);
1328ccd4a63SDavid du Colombier 			else
1338ccd4a63SDavid du Colombier 				break;
1348ccd4a63SDavid du Colombier 		}else{
1358ccd4a63SDavid du Colombier 			if(rm >= rme)
1368ccd4a63SDavid du Colombier 				break;
1378ccd4a63SDavid du Colombier 			r = *(uchar*)rm++;
1388ccd4a63SDavid du Colombier 		}
1398ccd4a63SDavid du Colombier 		if(f->runes){
1408ccd4a63SDavid du Colombier 			FMTRCHAR(f, rt, rs, r);
1418ccd4a63SDavid du Colombier 			if(r == '\'')
1428ccd4a63SDavid du Colombier 				FMTRCHAR(f, rt, rs, r);
1438ccd4a63SDavid du Colombier 		}else{
1448ccd4a63SDavid du Colombier 			FMTRUNE(f, t, s, r);
1458ccd4a63SDavid du Colombier 			if(r == '\'')
1468ccd4a63SDavid du Colombier 				FMTRUNE(f, t, s, r);
1478ccd4a63SDavid du Colombier 		}
1488ccd4a63SDavid du Colombier 	}
1498ccd4a63SDavid du Colombier 
1508ccd4a63SDavid du Colombier 	if(f->runes){
1518ccd4a63SDavid du Colombier 		FMTRCHAR(f, rt, rs, '\'');
1528ccd4a63SDavid du Colombier 		USED(rs);
1538ccd4a63SDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
1548ccd4a63SDavid du Colombier 		f->to = rt;
1550d601874SDavid du Colombier 		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
1568ccd4a63SDavid du Colombier 			return -1;
1578ccd4a63SDavid du Colombier 	}else{
1588ccd4a63SDavid du Colombier 		FMTRUNE(f, t, s, '\'');
1598ccd4a63SDavid du Colombier 		USED(s);
1608ccd4a63SDavid du Colombier 		f->nfmt += t - (char *)f->to;
1618ccd4a63SDavid du Colombier 		f->to = t;
1620d601874SDavid du Colombier 		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
1638ccd4a63SDavid du Colombier 			return -1;
1648ccd4a63SDavid du Colombier 	}
1658ccd4a63SDavid du Colombier 	return 0;
1668ccd4a63SDavid du Colombier }
1678ccd4a63SDavid du Colombier 
1688ccd4a63SDavid du Colombier int
__quotestrfmt(int runesin,Fmt * f)1690d601874SDavid du Colombier __quotestrfmt(int runesin, Fmt *f)
1708ccd4a63SDavid du Colombier {
1710d601874SDavid du Colombier 	int nin, outlen;
1728ccd4a63SDavid du Colombier 	Rune *r;
1738ccd4a63SDavid du Colombier 	char *s;
1748ccd4a63SDavid du Colombier 	Quoteinfo q;
1758ccd4a63SDavid du Colombier 
1760d601874SDavid du Colombier 	nin = -1;
1770d601874SDavid du Colombier 	if(f->flags&FmtPrec)
1780d601874SDavid du Colombier 		nin = f->prec;
1798ccd4a63SDavid du Colombier 	if(runesin){
1808ccd4a63SDavid du Colombier 		r = va_arg(f->args, Rune *);
1818ccd4a63SDavid du Colombier 		s = nil;
1828ccd4a63SDavid du Colombier 	}else{
1838ccd4a63SDavid du Colombier 		s = va_arg(f->args, char *);
1848ccd4a63SDavid du Colombier 		r = nil;
1858ccd4a63SDavid du Colombier 	}
1868ccd4a63SDavid du Colombier 	if(!s && !r)
1870d601874SDavid du Colombier 		return __fmtcpy(f, (void*)"<nil>", 5, 5);
1888ccd4a63SDavid du Colombier 
1898ccd4a63SDavid du Colombier 	if(f->flush)
1908ccd4a63SDavid du Colombier 		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
1918ccd4a63SDavid du Colombier 	else if(f->runes)
1928ccd4a63SDavid du Colombier 		outlen = (Rune*)f->stop - (Rune*)f->to;
1938ccd4a63SDavid du Colombier 	else
1948ccd4a63SDavid du Colombier 		outlen = (char*)f->stop - (char*)f->to;
1958ccd4a63SDavid du Colombier 
1960d601874SDavid du Colombier 	__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
1978ccd4a63SDavid du Colombier //print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
1988ccd4a63SDavid du Colombier 
1998ccd4a63SDavid du Colombier 	if(runesin){
2008ccd4a63SDavid du Colombier 		if(!q.quoted)
2010d601874SDavid du Colombier 			return __fmtrcpy(f, r, q.nrunesin);
2028ccd4a63SDavid du Colombier 		return qstrfmt(nil, r, &q, f);
2038ccd4a63SDavid du Colombier 	}
2048ccd4a63SDavid du Colombier 
2058ccd4a63SDavid du Colombier 	if(!q.quoted)
2060d601874SDavid du Colombier 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
2078ccd4a63SDavid du Colombier 	return qstrfmt(s, nil, &q, f);
2088ccd4a63SDavid du Colombier }
2098ccd4a63SDavid du Colombier 
2108ccd4a63SDavid du Colombier int
quotestrfmt(Fmt * f)2118ccd4a63SDavid du Colombier quotestrfmt(Fmt *f)
2128ccd4a63SDavid du Colombier {
2130d601874SDavid du Colombier 	return __quotestrfmt(0, f);
2148ccd4a63SDavid du Colombier }
2158ccd4a63SDavid du Colombier 
2168ccd4a63SDavid du Colombier int
quoterunestrfmt(Fmt * f)2178ccd4a63SDavid du Colombier quoterunestrfmt(Fmt *f)
2188ccd4a63SDavid du Colombier {
2190d601874SDavid du Colombier 	return __quotestrfmt(1, f);
2208ccd4a63SDavid du Colombier }
2218ccd4a63SDavid du Colombier 
2228ccd4a63SDavid du Colombier void
quotefmtinstall(void)2238ccd4a63SDavid du Colombier quotefmtinstall(void)
2248ccd4a63SDavid du Colombier {
2258ccd4a63SDavid du Colombier 	fmtinstall('q', quotestrfmt);
2268ccd4a63SDavid du Colombier 	fmtinstall('Q', quoterunestrfmt);
2278ccd4a63SDavid du Colombier }
2288ccd4a63SDavid du Colombier 
2298ccd4a63SDavid du Colombier int
__needsquotes(char * s,int * quotelenp)2300d601874SDavid du Colombier __needsquotes(char *s, int *quotelenp)
2318ccd4a63SDavid du Colombier {
2328ccd4a63SDavid du Colombier 	Quoteinfo q;
2338ccd4a63SDavid du Colombier 
2340d601874SDavid du Colombier 	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
2358ccd4a63SDavid du Colombier 	*quotelenp = q.nbytesout;
2368ccd4a63SDavid du Colombier 
2378ccd4a63SDavid du Colombier 	return q.quoted;
2388ccd4a63SDavid du Colombier }
2398ccd4a63SDavid du Colombier 
2408ccd4a63SDavid du Colombier int
__runeneedsquotes(Rune * r,int * quotelenp)2410d601874SDavid du Colombier __runeneedsquotes(Rune *r, int *quotelenp)
2428ccd4a63SDavid du Colombier {
2438ccd4a63SDavid du Colombier 	Quoteinfo q;
2448ccd4a63SDavid du Colombier 
2450d601874SDavid du Colombier 	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
2468ccd4a63SDavid du Colombier 	*quotelenp = q.nrunesout;
2478ccd4a63SDavid du Colombier 
2488ccd4a63SDavid du Colombier 	return q.quoted;
2498ccd4a63SDavid du Colombier }
250