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) 241