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
p2roundup(size_t n)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