nvi: Bring in version 2.1.3 (update from 2.1.1)
[dragonfly.git] / contrib / nvi / common / mem.h
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  *      $Id: mem.h,v 10.17 2012/10/07 00:40:29 zy Exp $
10  */
11
12 #ifdef DEBUG
13 #define CHECK_TYPE(type, var)                                           \
14         type L__lp __attribute__((unused)) = var;
15 #else
16 #define CHECK_TYPE(type, var)
17 #endif
18
19 /* Increase the size of a malloc'd buffer.  Two versions, one that
20  * returns, one that jumps to an error label.
21  */
22 #define BINC_GOTO(sp, type, lp, llen, nlen) {                           \
23         CHECK_TYPE(type *, lp)                                          \
24         void *L__bincp;                                                 \
25         if ((nlen) > llen) {                                            \
26                 if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL)   \
27                         goto alloc_err;                                 \
28                 /*                                                      \
29                  * !!!                                                  \
30                  * Possible pointer conversion.                         \
31                  */                                                     \
32                 lp = L__bincp;                                          \
33         }                                                               \
34 }
35 #define BINC_GOTOC(sp, lp, llen, nlen)                                  \
36         BINC_GOTO(sp, char, lp, llen, nlen)
37 #define BINC_GOTOW(sp, lp, llen, nlen)                                  \
38         BINC_GOTO(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
39 #define BINC_RET(sp, type, lp, llen, nlen) {                            \
40         CHECK_TYPE(type *, lp)                                          \
41         void *L__bincp;                                                 \
42         if ((nlen) > llen) {                                            \
43                 if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL)   \
44                         return (1);                                     \
45                 /*                                                      \
46                  * !!!                                                  \
47                  * Possible pointer conversion.                         \
48                  */                                                     \
49                 lp = L__bincp;                                          \
50         }                                                               \
51 }
52 #define BINC_RETC(sp, lp, llen, nlen)                                   \
53         BINC_RET(sp, char, lp, llen, nlen)
54 #define BINC_RETW(sp, lp, llen, nlen)                                   \
55         BINC_RET(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T))
56
57 /*
58  * Get some temporary space, preferably from the global temporary buffer,
59  * from a malloc'd buffer otherwise.  Two versions, one that returns, one
60  * that jumps to an error label.
61  */
62 #define GET_SPACE_GOTO(sp, type, bp, blen, nlen) {                      \
63         CHECK_TYPE(type *, bp)                                          \
64         GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;                     \
65         if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {             \
66                 bp = NULL;                                              \
67                 blen = 0;                                               \
68                 BINC_GOTO(sp, type, bp, blen, nlen);                    \
69         } else {                                                        \
70                 BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);   \
71                 bp = (type *) L__gp->tmp_bp;                            \
72                 blen = L__gp->tmp_blen;                                 \
73                 F_SET(L__gp, G_TMP_INUSE);                              \
74         }                                                               \
75 }
76 #define GET_SPACE_GOTOC(sp, bp, blen, nlen)                             \
77         GET_SPACE_GOTO(sp, char, bp, blen, nlen)
78 #define GET_SPACE_GOTOW(sp, bp, blen, nlen)                             \
79         GET_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
80 #define GET_SPACE_RET(sp, type, bp, blen, nlen) {                       \
81         CHECK_TYPE(type *, bp)                                          \
82         GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;                     \
83         if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {             \
84                 bp = NULL;                                              \
85                 blen = 0;                                               \
86                 BINC_RET(sp, type, bp, blen, nlen);                     \
87         } else {                                                        \
88                 BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);    \
89                 bp = (type *) L__gp->tmp_bp;                            \
90                 blen = L__gp->tmp_blen;                                 \
91                 F_SET(L__gp, G_TMP_INUSE);                              \
92         }                                                               \
93 }
94 #define GET_SPACE_RETC(sp, bp, blen, nlen)                              \
95         GET_SPACE_RET(sp, char, bp, blen, nlen)
96 #define GET_SPACE_RETW(sp, bp, blen, nlen)                              \
97         GET_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
98
99 /*
100  * Add space to a GET_SPACE returned buffer.  Two versions, one that
101  * returns, one that jumps to an error label.
102  */
103 #define ADD_SPACE_GOTO(sp, type, bp, blen, nlen) {                      \
104         CHECK_TYPE(type *, bp)                                          \
105         GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;                     \
106         if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {             \
107                 F_CLR(L__gp, G_TMP_INUSE);                              \
108                 BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);   \
109                 bp = (type *) L__gp->tmp_bp;                            \
110                 blen = L__gp->tmp_blen;                                 \
111                 F_SET(L__gp, G_TMP_INUSE);                              \
112         } else                                                          \
113                 BINC_GOTO(sp, type, bp, blen, nlen);                    \
114 }
115 #define ADD_SPACE_GOTOC(sp, bp, blen, nlen)                             \
116         ADD_SPACE_GOTO(sp, char, bp, blen, nlen)
117 #define ADD_SPACE_GOTOW(sp, bp, blen, nlen)                             \
118         ADD_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
119 #define ADD_SPACE_RET(sp, type, bp, blen, nlen) {                       \
120         CHECK_TYPE(type *, bp)                                          \
121         GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;                     \
122         if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {             \
123                 F_CLR(L__gp, G_TMP_INUSE);                              \
124                 BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);    \
125                 bp = (type *) L__gp->tmp_bp;                            \
126                 blen = L__gp->tmp_blen;                                 \
127                 F_SET(L__gp, G_TMP_INUSE);                              \
128         } else                                                          \
129                 BINC_RET(sp, type, bp, blen, nlen);                     \
130 }
131 #define ADD_SPACE_RETC(sp, bp, blen, nlen)                              \
132         ADD_SPACE_RET(sp, char, bp, blen, nlen)
133 #define ADD_SPACE_RETW(sp, bp, blen, nlen)                              \
134         ADD_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T))
135
136 /* Free a GET_SPACE returned buffer. */
137 #define FREE_SPACE(sp, bp, blen) {                                      \
138         GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;                     \
139         if (L__gp != NULL && bp == L__gp->tmp_bp)                       \
140                 F_CLR(L__gp, G_TMP_INUSE);                              \
141         else                                                            \
142                 free(bp);                                               \
143 }
144 #define FREE_SPACEW(sp, bp, blen) {                                     \
145         CHECK_TYPE(CHAR_T *, bp)                                        \
146         FREE_SPACE(sp, (char *)bp, blen);                               \
147 }
148
149 /*
150  * Malloc a buffer, casting the return pointer.  Various versions.
151  *
152  * !!!
153  * The cast should be unnecessary, malloc(3) and friends return void *'s,
154  * which is all we need.  However, some systems that nvi needs to run on
155  * don't do it right yet, resulting in the compiler printing out roughly
156  * a million warnings.  After awhile, it seemed easier to put the casts
157  * in instead of explaining it all the time.
158  */
159 #define CALLOC(sp, p, cast, nmemb, size) {                              \
160         if ((p = (cast)calloc(nmemb, size)) == NULL)                    \
161                 msgq(sp, M_SYSERR, NULL);                               \
162 }
163 #define CALLOC_GOTO(sp, p, cast, nmemb, size) {                         \
164         if ((p = (cast)calloc(nmemb, size)) == NULL)                    \
165                 goto alloc_err;                                         \
166 }
167 #define CALLOC_NOMSG(sp, p, cast, nmemb, size) {                        \
168         p = (cast)calloc(nmemb, size);                                  \
169 }
170 #define CALLOC_RET(sp, p, cast, nmemb, size) {                          \
171         if ((p = (cast)calloc(nmemb, size)) == NULL) {                  \
172                 msgq(sp, M_SYSERR, NULL);                               \
173                 return (1);                                             \
174         }                                                               \
175 }
176
177 #define MALLOC(sp, p, cast, size) {                                     \
178         if ((p = (cast)malloc(size)) == NULL)                           \
179                 msgq(sp, M_SYSERR, NULL);                               \
180 }
181 #define MALLOC_GOTO(sp, p, cast, size) {                                \
182         if ((p = (cast)malloc(size)) == NULL)                           \
183                 goto alloc_err;                                         \
184 }
185 #define MALLOC_NOMSG(sp, p, cast, size) {                               \
186         p = (cast)malloc(size);                                         \
187 }
188 #define MALLOC_RET(sp, p, cast, size) {                                 \
189         if ((p = (cast)malloc(size)) == NULL) {                         \
190                 msgq(sp, M_SYSERR, NULL);                               \
191                 return (1);                                             \
192         }                                                               \
193 }
194
195 /*
196  * Resize a buffer, free any already held memory if we can't get more.
197  * FreeBSD's reallocf(3) does the same thing, but it's not portable yet.
198  */
199 #define REALLOC(sp, p, cast, size) {                                    \
200         cast newp;                                                      \
201         if ((newp = (cast)realloc(p, size)) == NULL) {                  \
202                 if (p != NULL)                                          \
203                         free(p);                                        \
204                 msgq(sp, M_SYSERR, NULL);                               \
205         }                                                               \
206         p = newp;                                                       \
207 }
208
209 /*
210  * Versions of bcopy(3) and bzero(3) that use the size of the
211  * initial pointer to figure out how much memory to manipulate.
212  */
213 #define BCOPY(p, t, len)        bcopy(p, t, (len) * sizeof(*(p)))
214 #define BZERO(p, len)           bzero(p, (len) * sizeof(*(p)))
215
216 /* 
217  * p2roundup --
218  *      Get next power of 2; convenient for realloc.
219  *
220  * Reference: FreeBSD /usr/src/lib/libc/stdio/getdelim.c
221  */
222 static __inline size_t
223 p2roundup(size_t n)
224 {
225         n--;
226         n |= n >> 1;
227         n |= n >> 2;
228         n |= n >> 4;
229         n |= n >> 8;
230         n |= n >> 16;
231 #if SIZE_T_MAX > 0xffffffffU
232         n |= n >> 32;
233 #endif
234         n++;
235         return (n);
236 }
237
238 /* Additional TAILQ helper. */
239 #define TAILQ_ENTRY_ISVALID(elm, field)                                 \
240         ((elm)->field.tqe_prev != NULL)