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 /* 216 * is_aligned -- 217 * Determine whether the program can safely read an object with an 218 * alignment requirement from ptr. 219 * 220 * See also: https://clang.llvm.org/docs/LanguageExtensions.html#alignment-builtins 221 */ 222 static __inline int 223 is_aligned(void *ptr, size_t alignment) { 224 return ((uintptr_t)ptr % alignment) == 0; 225 } 226 227 /* Additional TAILQ helper. */ 228 #define TAILQ_ENTRY_ISVALID(elm, field) \ 229 ((elm)->field.tqe_prev != NULL) 230