xref: /freebsd/contrib/nvi/common/mem.h (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1 /*-
2  * Copyright (c) 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1993, 1994, 1995, 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #ifdef DEBUG
11 #define CHECK_TYPE(type, var)						\
12 	type L__lp __attribute__((unused)) = var;
13 #else
14 #define CHECK_TYPE(type, var)
15 #endif
16 
17 /* Increase the size of a malloc'd buffer.  Two versions, one that
18  * returns, one that jumps to an error label.
19  */
20 #define	BINC_GOTO(sp, type, lp, llen, nlen) do {			\
21 	CHECK_TYPE(type *, lp)						\
22 	void *L__bincp;							\
23 	if ((nlen) > llen) {						\
24 		if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL)	\
25 			goto alloc_err;					\
26 		/*							\
27 		 * !!!							\
28 		 * Possible pointer conversion.				\
29 		 */							\
30 		lp = L__bincp;						\
31 	}								\
32 } while (0)
33 #define	BINC_GOTOC(sp, lp, llen, nlen)					\
34 	BINC_GOTO(sp, char, lp, llen, nlen)
35 #define	BINC_GOTOW(sp, lp, llen, nlen)					\
36 	BINC_GOTO(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
37 #define	BINC_RET(sp, type, lp, llen, nlen) do {				\
38 	CHECK_TYPE(type *, lp)						\
39 	void *L__bincp;							\
40 	if ((nlen) > llen) {						\
41 		if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL)	\
42 			return (1);					\
43 		/*							\
44 		 * !!!							\
45 		 * Possible pointer conversion.				\
46 		 */							\
47 		lp = L__bincp;						\
48 	}								\
49 } while (0)
50 #define	BINC_RETC(sp, lp, llen, nlen)					\
51 	BINC_RET(sp, char, lp, llen, nlen)
52 #define	BINC_RETW(sp, lp, llen, nlen)					\
53 	BINC_RET(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
54 
55 /*
56  * Get some temporary space, preferably from the global temporary buffer,
57  * from a malloc'd buffer otherwise.  Two versions, one that returns, one
58  * that jumps to an error label.
59  */
60 #define	GET_SPACE_GOTO(sp, type, bp, blen, nlen) do {			\
61 	CHECK_TYPE(type *, bp)						\
62 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
63 	if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {		\
64 		bp = NULL;						\
65 		blen = 0;						\
66 		BINC_GOTO(sp, type, bp, blen, nlen); 			\
67 	} else {							\
68 		BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
69 		bp = (type *) L__gp->tmp_bp;				\
70 		blen = L__gp->tmp_blen;					\
71 		F_SET(L__gp, G_TMP_INUSE);				\
72 	}								\
73 } while (0)
74 #define	GET_SPACE_GOTOC(sp, bp, blen, nlen)				\
75 	GET_SPACE_GOTO(sp, char, bp, blen, nlen)
76 #define	GET_SPACE_GOTOW(sp, bp, blen, nlen)				\
77 	GET_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
78 #define	GET_SPACE_RET(sp, type, bp, blen, nlen) do {			\
79 	CHECK_TYPE(type *, bp)						\
80 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
81 	if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {		\
82 		bp = NULL;						\
83 		blen = 0;						\
84 		BINC_RET(sp, type, bp, blen, nlen);			\
85 	} else {							\
86 		BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
87 		bp = (type *) L__gp->tmp_bp;				\
88 		blen = L__gp->tmp_blen;					\
89 		F_SET(L__gp, G_TMP_INUSE);				\
90 	}								\
91 } while (0)
92 #define	GET_SPACE_RETC(sp, bp, blen, nlen)				\
93 	GET_SPACE_RET(sp, char, bp, blen, nlen)
94 #define	GET_SPACE_RETW(sp, bp, blen, nlen)				\
95 	GET_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
96 
97 /*
98  * Add space to a GET_SPACE returned buffer.  Two versions, one that
99  * returns, one that jumps to an error label.
100  */
101 #define	ADD_SPACE_GOTO(sp, type, bp, blen, nlen) do {			\
102 	CHECK_TYPE(type *, bp)						\
103 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
104 	if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {		\
105 		F_CLR(L__gp, G_TMP_INUSE);				\
106 		BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
107 		bp = (type *) L__gp->tmp_bp;				\
108 		blen = L__gp->tmp_blen;					\
109 		F_SET(L__gp, G_TMP_INUSE);				\
110 	} else								\
111 		BINC_GOTO(sp, type, bp, blen, nlen);			\
112 } while (0)
113 #define	ADD_SPACE_GOTOC(sp, bp, blen, nlen)				\
114 	ADD_SPACE_GOTO(sp, char, bp, blen, nlen)
115 #define	ADD_SPACE_GOTOW(sp, bp, blen, nlen)				\
116 	ADD_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
117 #define	ADD_SPACE_RET(sp, type, bp, blen, nlen) do {			\
118 	CHECK_TYPE(type *, bp)						\
119 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
120 	if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {		\
121 		F_CLR(L__gp, G_TMP_INUSE);				\
122 		BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
123 		bp = (type *) L__gp->tmp_bp;				\
124 		blen = L__gp->tmp_blen;					\
125 		F_SET(L__gp, G_TMP_INUSE);				\
126 	} else								\
127 		BINC_RET(sp, type, bp, blen, nlen);			\
128 } while (0)
129 #define	ADD_SPACE_RETC(sp, bp, blen, nlen)				\
130 	ADD_SPACE_RET(sp, char, bp, blen, nlen)
131 #define	ADD_SPACE_RETW(sp, bp, blen, nlen)				\
132 	ADD_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
133 
134 /* Free a GET_SPACE returned buffer. */
135 #define	FREE_SPACE(sp, bp, blen) do {					\
136 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
137 	if (L__gp != NULL && bp == L__gp->tmp_bp)			\
138 		F_CLR(L__gp, G_TMP_INUSE);				\
139 	else								\
140 		free(bp);						\
141 } while (0)
142 #define	FREE_SPACEW(sp, bp, blen) do {					\
143 	CHECK_TYPE(CHAR_T *, bp)					\
144 	FREE_SPACE(sp, (char *)bp, blen);				\
145 } while (0)
146 
147 /*
148  * Malloc a buffer, casting the return pointer.  Various versions.
149  */
150 #define	CALLOC(sp, p, nmemb, size) do {					\
151 	if ((p = calloc(nmemb, size)) == NULL)				\
152 		msgq(sp, M_SYSERR, NULL);				\
153 } while (0)
154 #define	CALLOC_GOTO(sp, p, nmemb, size) do {				\
155 	if ((p = calloc(nmemb, size)) == NULL)				\
156 		goto alloc_err;						\
157 } while (0)
158 #define	CALLOC_RET(sp, p, nmemb, size) do {				\
159 	if ((p = calloc(nmemb, size)) == NULL) {			\
160 		msgq(sp, M_SYSERR, NULL);				\
161 		return (1);						\
162 	}								\
163 } while (0)
164 
165 #define	MALLOC(sp, p, size) do {					\
166 	if ((p = malloc(size)) == NULL)					\
167 		msgq(sp, M_SYSERR, NULL);				\
168 } while (0)
169 #define	MALLOC_GOTO(sp, p, size) do {					\
170 	if ((p = malloc(size)) == NULL)					\
171 		goto alloc_err;						\
172 } while (0)
173 #define	MALLOC_RET(sp, p, size) do {					\
174 	if ((p = malloc(size)) == NULL) {				\
175 		msgq(sp, M_SYSERR, NULL);				\
176 		return (1);						\
177 	}								\
178 } while (0)
179 
180 /*
181  * Resize a buffer, free any already held memory if we can't get more.
182  * FreeBSD's reallocf(3) does the same thing, but it's not portable yet.
183  */
184 #define	REALLOC(sp, p, cast, size) do {					\
185 	cast newp;							\
186 	if ((newp = realloc(p, size)) == NULL) {			\
187 		free(p);						\
188 		msgq(sp, M_SYSERR, NULL);				\
189 	}								\
190 	p = newp;							\
191 } while (0)
192 
193 /*
194  * p2roundup --
195  *	Get next power of 2; convenient for realloc.
196  *
197  * Reference: FreeBSD /usr/src/lib/libc/stdio/getdelim.c
198  */
199 static __inline size_t
200 p2roundup(size_t n)
201 {
202 	n--;
203 	n |= n >> 1;
204 	n |= n >> 2;
205 	n |= n >> 4;
206 	n |= n >> 8;
207 	n |= n >> 16;
208 #if SIZE_T_MAX > 0xffffffffU
209 	n |= n >> 32;
210 #endif
211 	n++;
212 	return (n);
213 }
214 
215 /* Additional TAILQ helper. */
216 #define TAILQ_ENTRY_ISVALID(elm, field)					\
217 	((elm)->field.tqe_prev != NULL)
218