xref: /dragonfly/contrib/nvi2/common/mem.h (revision 07bc39c2f4bbca56f12568e06d89da17f2eeb965)
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) {                                 \
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 }
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) {                                  \
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 }
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) {                            \
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 }
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) {                             \
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 }
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) {                            \
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 }
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) {                             \
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 }
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) {                                            \
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 }
142 #define   FREE_SPACEW(sp, bp, blen) {                                           \
143           CHECK_TYPE(CHAR_T *, bp)                                              \
144           FREE_SPACE(sp, (char *)bp, blen);                                     \
145 }
146 
147 /*
148  * Malloc a buffer, casting the return pointer.  Various versions.
149  */
150 #define   CALLOC(sp, p, nmemb, size) {                                          \
151           if ((p = calloc(nmemb, size)) == NULL)                                \
152                     msgq(sp, M_SYSERR, NULL);                                   \
153 }
154 #define   CALLOC_GOTO(sp, p, nmemb, size) {                                     \
155           if ((p = calloc(nmemb, size)) == NULL)                                \
156                     goto alloc_err;                                                       \
157 }
158 #define   CALLOC_RET(sp, p, nmemb, size) {                                      \
159           if ((p = calloc(nmemb, size)) == NULL) {                              \
160                     msgq(sp, M_SYSERR, NULL);                                   \
161                     return (1);                                                           \
162           }                                                                               \
163 }
164 
165 #define   MALLOC(sp, p, size) {                                                           \
166           if ((p = malloc(size)) == NULL)                                                 \
167                     msgq(sp, M_SYSERR, NULL);                                   \
168 }
169 #define   MALLOC_GOTO(sp, p, size) {                                            \
170           if ((p = malloc(size)) == NULL)                                                 \
171                     goto alloc_err;                                                       \
172 }
173 #define   MALLOC_RET(sp, p, size) {                                             \
174           if ((p = malloc(size)) == NULL) {                                     \
175                     msgq(sp, M_SYSERR, NULL);                                   \
176                     return (1);                                                           \
177           }                                                                               \
178 }
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) {                                          \
185           cast newp;                                                                      \
186           if ((newp = realloc(p, size)) == NULL) {                              \
187                     free(p);                                                    \
188                     msgq(sp, M_SYSERR, NULL);                                   \
189           }                                                                               \
190           p = newp;                                                             \
191 }
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