| /* | 
 |  * The authors of this software are Rob Pike and Ken Thompson. | 
 |  *              Copyright (c) 2002 by Lucent Technologies. | 
 |  * Permission to use, copy, modify, and distribute this software for any | 
 |  * purpose without fee is hereby granted, provided that this entire notice | 
 |  * is included in all copies of any software which is or includes a copy | 
 |  * or modification of this software and in all copies of the supporting | 
 |  * documentation for such software. | 
 |  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED | 
 |  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY | 
 |  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY | 
 |  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. | 
 |  */ | 
 | #include <u.h> | 
 | #include <libc.h> | 
 | #include "fmt.h" | 
 | #include "fmtdef.h" | 
 |  | 
 | extern int (*doquote)(int); | 
 |  | 
 | /* | 
 |  * How many bytes of output UTF will be produced by quoting (if necessary) this string? | 
 |  * How many runes? How much of the input will be consumed? | 
 |  * The parameter q is filled in by _quotesetup. | 
 |  * The string may be UTF or Runes (s or r). | 
 |  * Return count does not include NUL. | 
 |  * Terminate the scan at the first of: | 
 |  *	NUL in input | 
 |  *	count exceeded in input | 
 |  *	count exceeded on output | 
 |  * *ninp is set to number of input bytes accepted. | 
 |  * nin may be <0 initially, to avoid checking input by count. | 
 |  */ | 
 | void | 
 | __quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp) | 
 | { | 
 | 	int c; | 
 |  | 
 | 	q->quoted = 0; | 
 | 	q->nbytesout = 0; | 
 | 	q->nrunesout = 0; | 
 | 	q->nbytesin = 0; | 
 | 	q->nrunesin = 0; | 
 | 	if(sharp || nin==0 || *s=='\0'){ | 
 | 		if(nout < 2) | 
 | 			return; | 
 | 		q->quoted = 1; | 
 | 		q->nbytesout = 2; | 
 | 		q->nrunesout = 2; | 
 | 	} | 
 | 	for(; nin!=0; nin-=1){ | 
 | 		c = *s; | 
 |  | 
 | 		if(c == '\0') | 
 | 			break; | 
 | 		if(q->nrunesout+1 > nout) | 
 | 			break; | 
 |  | 
 | 		if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ | 
 | 			if(!q->quoted){ | 
 | 				if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */ | 
 | 					break; | 
 | 				q->nrunesout += 2;	/* include quotes */ | 
 | 				q->nbytesout += 2;	/* include quotes */ | 
 | 				q->quoted = 1; | 
 | 			} | 
 | 			if(c == '\'')	{ | 
 | 				q->nbytesout++; | 
 | 				q->nrunesout++;	/* quotes reproduce as two characters */ | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* advance input */ | 
 | 		s++; | 
 | 		q->nbytesin++; | 
 | 		q->nrunesin++; | 
 |  | 
 | 		/* advance output */ | 
 | 		q->nbytesout++; | 
 | 		q->nrunesout++; | 
 | 	} | 
 | } | 
 |  | 
 | static int | 
 | qstrfmt(char *sin, Quoteinfo *q, Fmt *f) | 
 | { | 
 | 	int r; | 
 | 	char *t, *s, *m, *me; | 
 | 	ulong fl; | 
 | 	int nc, w; | 
 |  | 
 | 	m = sin; | 
 | 	me = m + q->nbytesin; | 
 |  | 
 | 	w = f->width; | 
 | 	fl = f->flags; | 
 | 	if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) | 
 | 		return -1; | 
 | 	t = f->to; | 
 | 	s = f->stop; | 
 | 	FMTCHAR(f, t, s, '\''); | 
 | 	for(nc = q->nrunesin; nc > 0; nc--){ | 
 | 		r = *(uchar*)m++; | 
 | 		FMTCHAR(f, t, s, r); | 
 | 		if(r == '\'') | 
 | 			FMTCHAR(f, t, s, r); | 
 | 	} | 
 |  | 
 | 	FMTCHAR(f, t, s, '\''); | 
 | 	f->nfmt += t - (char *)f->to; | 
 | 	f->to = t; | 
 | 	if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) | 
 | 		return -1; | 
 | 	return 0; | 
 | } | 
 |  | 
 | int | 
 | __quotestrfmt(int runesin, Fmt *f) | 
 | { | 
 | 	int outlen; | 
 | 	char *s; | 
 | 	Quoteinfo q; | 
 |  | 
 | 	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */ | 
 | 	s = va_arg(f->args, char *); | 
 | 	if(!s) | 
 | 		return __fmtcpy(f, "<nil>", 5, 5); | 
 |  | 
 | 	if(f->flush) | 
 | 		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */ | 
 | 	else | 
 | 		outlen = (char*)f->stop - (char*)f->to; | 
 |  | 
 | 	__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp); | 
 |  | 
 | 	if(!q.quoted) | 
 | 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin); | 
 | 	return qstrfmt(s, &q, f); | 
 | } | 
 |  | 
 | int | 
 | quotestrfmt(Fmt *f) | 
 | { | 
 | 	return __quotestrfmt(0, f); | 
 | } | 
 |  | 
 | void | 
 | quotefmtinstall(void) | 
 | { | 
 | 	fmtinstall('q', quotestrfmt); | 
 | } | 
 |  | 
 | int | 
 | __needsquotes(char *s, int *quotelenp) | 
 | { | 
 | 	Quoteinfo q; | 
 |  | 
 | 	__quotesetup(s, -1, 0x7FFFFFFF, &q, 0); | 
 | 	*quotelenp = q.nbytesout; | 
 |  | 
 | 	return q.quoted; | 
 | } |