xref: /freebsd/contrib/less/xbuf.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
130a1828cSXin LI #include "less.h"
230a1828cSXin LI #include "xbuf.h"
330a1828cSXin LI 
430a1828cSXin LI /*
530a1828cSXin LI  * Initialize an expandable text buffer.
630a1828cSXin LI  */
7d713e089SXin LI public void xbuf_init(struct xbuffer *xbuf)
830a1828cSXin LI {
9*c77c4889SXin LI 	xbuf_init_size(xbuf, 16);
1030a1828cSXin LI }
1130a1828cSXin LI 
12*c77c4889SXin LI public void xbuf_init_size(struct xbuffer *xbuf, size_t init_size)
13*c77c4889SXin LI {
14*c77c4889SXin LI 	xbuf->data = NULL;
15*c77c4889SXin LI 	xbuf->size = xbuf->end = 0;
16*c77c4889SXin LI 	xbuf->init_size = init_size;
17*c77c4889SXin LI }
18*c77c4889SXin LI 
19*c77c4889SXin LI /*
20*c77c4889SXin LI  * Free buffer space in an xbuf.
21*c77c4889SXin LI  */
22d713e089SXin LI public void xbuf_deinit(struct xbuffer *xbuf)
2330a1828cSXin LI {
2430a1828cSXin LI 	if (xbuf->data != NULL)
2530a1828cSXin LI 		free(xbuf->data);
2630a1828cSXin LI 	xbuf_init(xbuf);
2730a1828cSXin LI }
2830a1828cSXin LI 
29*c77c4889SXin LI /*
30*c77c4889SXin LI  * Set xbuf to empty.
31*c77c4889SXin LI  */
32d713e089SXin LI public void xbuf_reset(struct xbuffer *xbuf)
3330a1828cSXin LI {
3430a1828cSXin LI 	xbuf->end = 0;
3530a1828cSXin LI }
3630a1828cSXin LI 
3730a1828cSXin LI /*
38*c77c4889SXin LI  * Add a byte to an xbuf.
3930a1828cSXin LI  */
40d713e089SXin LI public void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b)
4130a1828cSXin LI {
4230a1828cSXin LI 	if (xbuf->end >= xbuf->size)
4330a1828cSXin LI 	{
44d713e089SXin LI 		unsigned char *data;
45*c77c4889SXin LI 		if (ckd_add(&xbuf->size, xbuf->size, xbuf->size ? xbuf->size : xbuf->init_size))
46d713e089SXin LI 			out_of_memory();
47d713e089SXin LI 		data = (unsigned char *) ecalloc(xbuf->size, sizeof(unsigned char));
4830a1828cSXin LI 		if (xbuf->data != NULL)
4930a1828cSXin LI 		{
5030a1828cSXin LI 			memcpy(data, xbuf->data, xbuf->end);
5130a1828cSXin LI 			free(xbuf->data);
5230a1828cSXin LI 		}
5330a1828cSXin LI 		xbuf->data = data;
5430a1828cSXin LI 	}
55*c77c4889SXin LI 	xbuf->data[xbuf->end++] = b;
5630a1828cSXin LI }
5795270f73SXin LI 
58*c77c4889SXin LI /*
59*c77c4889SXin LI  * Add a char to an xbuf.
60*c77c4889SXin LI  */
61*c77c4889SXin LI public void xbuf_add_char(struct xbuffer *xbuf, char c)
62d713e089SXin LI {
63*c77c4889SXin LI 	xbuf_add_byte(xbuf, (unsigned char) c);
64*c77c4889SXin LI }
65*c77c4889SXin LI 
66*c77c4889SXin LI /*
67*c77c4889SXin LI  * Add arbitrary data to an xbuf.
68*c77c4889SXin LI  */
69*c77c4889SXin LI public void xbuf_add_data(struct xbuffer *xbuf, constant unsigned char *data, size_t len)
70*c77c4889SXin LI {
71*c77c4889SXin LI 	size_t i;
72d713e089SXin LI 	for (i = 0;  i < len;  i++)
73d713e089SXin LI 		xbuf_add_byte(xbuf, data[i]);
74d713e089SXin LI }
75d713e089SXin LI 
76*c77c4889SXin LI /*
77*c77c4889SXin LI  * Remove the last byte from an xbuf.
78*c77c4889SXin LI  */
79d713e089SXin LI public int xbuf_pop(struct xbuffer *buf)
8095270f73SXin LI {
8195270f73SXin LI 	if (buf->end == 0)
8295270f73SXin LI 		return -1;
83d713e089SXin LI 	return (int) buf->data[--(buf->end)];
8495270f73SXin LI }
8595270f73SXin LI 
86*c77c4889SXin LI /*
87*c77c4889SXin LI  * Set an xbuf to the contents of another xbuf.
88*c77c4889SXin LI  */
89d713e089SXin LI public void xbuf_set(struct xbuffer *dst, struct xbuffer *src)
9095270f73SXin LI {
9195270f73SXin LI 	xbuf_reset(dst);
92d713e089SXin LI 	xbuf_add_data(dst, src->data, src->end);
9395270f73SXin LI }
94d713e089SXin LI 
95*c77c4889SXin LI /*
96*c77c4889SXin LI  * Return xbuf data as a char*.
97*c77c4889SXin LI  */
98*c77c4889SXin LI public constant char * xbuf_char_data(constant struct xbuffer *xbuf)
99d713e089SXin LI {
100*c77c4889SXin LI 	return (constant char *)(xbuf->data);
101d713e089SXin LI }
102d713e089SXin LI 
103d713e089SXin LI 
104d713e089SXin LI /*
105d713e089SXin LI  * Helper functions for the ckd_add and ckd_mul macro substitutes.
106d713e089SXin LI  * These helper functions do not set *R on overflow, and assume that
107d713e089SXin LI  * arguments are nonnegative, that INTMAX_MAX <= UINTMAX_MAX, and that
108d713e089SXin LI  * sizeof is a reliable way to distinguish integer representations.
109d713e089SXin LI  * Despite these limitations they are good enough for 'less' on all
110d713e089SXin LI  * known practical platforms.  For more-complicated substitutes
111d713e089SXin LI  * without most of these limitations, see Gnulib's stdckdint module.
112d713e089SXin LI  */
113d713e089SXin LI #if !HAVE_STDCKDINT_H
114d713e089SXin LI /*
115d713e089SXin LI  * If the integer *R can represent VAL, store the value and return FALSE.
116d713e089SXin LI  * Otherwise, possibly set *R to an indeterminate value and return TRUE.
117d713e089SXin LI  * R has size RSIZE, and is signed if and only if RSIGNED is nonzero.
118d713e089SXin LI  */
119*c77c4889SXin LI static lbool help_fixup(void *r, uintmax val, int rsize, int rsigned)
120d713e089SXin LI {
121d713e089SXin LI 	if (rsigned)
122d713e089SXin LI 	{
123d713e089SXin LI 		if (rsize == sizeof (int))
124d713e089SXin LI 		{
125d713e089SXin LI 			int *pr = r;
126d713e089SXin LI 			if (INT_MAX < val)
127d713e089SXin LI 				return TRUE;
128f80a33eaSXin LI 			*pr = (int) val;
129d713e089SXin LI #ifdef LLONG_MAX
130d713e089SXin LI 		} else if (rsize == sizeof (long long))
131d713e089SXin LI 		{
132d713e089SXin LI 			long long *pr = r;
133d713e089SXin LI 			if (LLONG_MAX < val)
134d713e089SXin LI 				return TRUE;
135*c77c4889SXin LI 			*pr = (long long) val;
136d713e089SXin LI #endif
137d713e089SXin LI #ifdef INTMAX_MAX
138d713e089SXin LI 		} else if (rsize == sizeof (intmax_t)) {
139d713e089SXin LI 			intmax_t *pr = r;
140d713e089SXin LI 			if (INTMAX_MAX < val)
141d713e089SXin LI 				return TRUE;
142*c77c4889SXin LI 			*pr = (intmax_t) val;
143d713e089SXin LI #endif
144d713e089SXin LI 		} else /* rsize == sizeof (long) */
145d713e089SXin LI 		{
146d713e089SXin LI 			long *pr = r;
147d713e089SXin LI 			if (LONG_MAX < val)
148d713e089SXin LI 				return TRUE;
149f80a33eaSXin LI 			*pr = (long) val;
150d713e089SXin LI 		}
151d713e089SXin LI 	} else {
152d713e089SXin LI 		if (rsize == sizeof (unsigned)) {
153d713e089SXin LI 			unsigned *pr = r;
154d713e089SXin LI 			if (UINT_MAX < val)
155d713e089SXin LI 				return TRUE;
156f80a33eaSXin LI 			*pr = (unsigned) val;
157d713e089SXin LI 		} else if (rsize == sizeof (unsigned long)) {
158d713e089SXin LI 			unsigned long *pr = r;
159d713e089SXin LI 			if (ULONG_MAX < val)
160d713e089SXin LI 				return TRUE;
161f80a33eaSXin LI 			*pr = (unsigned long) val;
162d713e089SXin LI #ifdef ULLONG_MAX
163d713e089SXin LI 		} else if (rsize == sizeof (unsigned long long)) {
164*c77c4889SXin LI 			unsigned long long *pr = r;
165d713e089SXin LI 			if (ULLONG_MAX < val)
166d713e089SXin LI 				return TRUE;
167*c77c4889SXin LI 			*pr = (unsigned long long) val;
168d713e089SXin LI #endif
169d713e089SXin LI 		} else /* rsize == sizeof (uintmax) */
170d713e089SXin LI 		{
171d713e089SXin LI 			uintmax *pr = r;
172*c77c4889SXin LI 			*pr = (uintmax) val;
173d713e089SXin LI 		}
174d713e089SXin LI 	}
175d713e089SXin LI 	return FALSE;
176d713e089SXin LI }
177*c77c4889SXin LI 
178d713e089SXin LI /*
179d713e089SXin LI  * If *R can represent the mathematical sum of A and B, store the sum
180d713e089SXin LI  * and return FALSE.  Otherwise, possibly set *R to an indeterminate
181d713e089SXin LI  * value and return TRUE.  R has size RSIZE, and is signed if and only
182d713e089SXin LI  * if RSIGNED is nonzero.
183d713e089SXin LI  */
184*c77c4889SXin LI public lbool help_ckd_add(void *r, uintmax a, uintmax b, int rsize, int rsigned)
185d713e089SXin LI {
186d713e089SXin LI 	uintmax sum = a + b;
187d713e089SXin LI 	return sum < a || help_fixup(r, sum, rsize, rsigned);
188d713e089SXin LI }
189*c77c4889SXin LI 
190d713e089SXin LI /* Likewise, but for the product of A and B.  */
191*c77c4889SXin LI public lbool help_ckd_mul(void *r, uintmax a, uintmax b, int rsize, int rsigned)
192d713e089SXin LI {
193d713e089SXin LI 	uintmax product = a * b;
194d713e089SXin LI 	return ((b != 0 && a != product / b)
195d713e089SXin LI 		|| help_fixup(r, product, rsize, rsigned));
196d713e089SXin LI }
197d713e089SXin LI #endif
198