unix/fiss

lib/libfmt/fmtquote.c in master
Repositories | Summary | Log | Files | LICENSE

fmtquote.c (5183B) download


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