1 /* 2 * Copyright (C) 1984-2026 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information, see the README file. 8 */ 9 10 #include "less.h" 11 #include "xbuf.h" 12 13 /* 14 * Initialize an expandable text buffer. 15 */ 16 public void xbuf_init(struct xbuffer *xbuf) 17 { 18 xbuf_init_size(xbuf, 16); 19 } 20 21 public void xbuf_init_size(struct xbuffer *xbuf, size_t init_size) 22 { 23 xbuf->data = NULL; 24 xbuf->size = xbuf->end = 0; 25 xbuf->init_size = init_size; 26 } 27 28 /* 29 * Free buffer space in an xbuf. 30 */ 31 public void xbuf_deinit(struct xbuffer *xbuf) 32 { 33 if (xbuf->data != NULL) 34 free(xbuf->data); 35 xbuf_init(xbuf); 36 } 37 38 /* 39 * Set xbuf to empty. 40 */ 41 public void xbuf_reset(struct xbuffer *xbuf) 42 { 43 xbuf->end = 0; 44 } 45 46 /* 47 * Add a byte to an xbuf. 48 */ 49 public void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b) 50 { 51 if (xbuf->end >= xbuf->size) 52 { 53 unsigned char *data; 54 if (ckd_add(&xbuf->size, xbuf->size, xbuf->size ? xbuf->size : xbuf->init_size)) 55 out_of_memory(); 56 data = (unsigned char *) ecalloc(xbuf->size, sizeof(unsigned char)); 57 if (xbuf->data != NULL) 58 { 59 memcpy(data, xbuf->data, xbuf->end); 60 free(xbuf->data); 61 } 62 xbuf->data = data; 63 } 64 xbuf->data[xbuf->end++] = b; 65 } 66 67 /* 68 * Add a char to an xbuf. 69 */ 70 public void xbuf_add_char(struct xbuffer *xbuf, char c) 71 { 72 xbuf_add_byte(xbuf, (unsigned char) c); 73 } 74 75 /* 76 * Add arbitrary data to an xbuf. 77 */ 78 public void xbuf_add_data(struct xbuffer *xbuf, constant void *vdata, size_t len) 79 { 80 constant unsigned char *data = (constant unsigned char *) vdata; 81 size_t i; 82 for (i = 0; i < len; i++) 83 xbuf_add_byte(xbuf, data[i]); 84 } 85 86 /* 87 * Remove the last byte from an xbuf. 88 */ 89 public int xbuf_pop(struct xbuffer *buf) 90 { 91 if (buf->end == 0) 92 return -1; 93 return (int) buf->data[--(buf->end)]; 94 } 95 96 /* 97 * Set an xbuf to the contents of another xbuf. 98 */ 99 public void xbuf_set(struct xbuffer *dst, constant struct xbuffer *src) 100 { 101 xbuf_reset(dst); 102 xbuf_add_data(dst, src->data, src->end); 103 } 104 105 /* 106 * Return xbuf data as a char*. 107 */ 108 public constant char * xbuf_char_data(constant struct xbuffer *xbuf) 109 { 110 return (constant char *)(xbuf->data); 111 } 112 113 114 /* 115 * Helper functions for the ckd_add and ckd_mul macro substitutes. 116 * These helper functions do not set *R on overflow, and assume that 117 * arguments are nonnegative, that INTMAX_MAX <= UINTMAX_MAX, and that 118 * sizeof is a reliable way to distinguish integer representations. 119 * Despite these limitations they are good enough for 'less' on all 120 * known practical platforms. For more-complicated substitutes 121 * without most of these limitations, see Gnulib's stdckdint module. 122 */ 123 #if !HAVE_STDCKDINT_H 124 /* 125 * If the integer *R can represent VAL, store the value and return FALSE. 126 * Otherwise, possibly set *R to an indeterminate value and return TRUE. 127 * R has size RSIZE, and is signed if and only if RSIGNED is nonzero. 128 */ 129 static lbool help_fixup(void *r, uintmax val, int rsize, int rsigned) 130 { 131 if (rsigned) 132 { 133 if (rsize == sizeof (int)) 134 { 135 int *pr = r; 136 if (INT_MAX < val) 137 return TRUE; 138 *pr = (int) val; 139 #ifdef LLONG_MAX 140 } else if (rsize == sizeof (long long)) 141 { 142 long long *pr = r; 143 if (LLONG_MAX < val) 144 return TRUE; 145 *pr = (long long) val; 146 #endif 147 #ifdef INTMAX_MAX 148 } else if (rsize == sizeof (intmax_t)) { 149 intmax_t *pr = r; 150 if (INTMAX_MAX < val) 151 return TRUE; 152 *pr = (intmax_t) val; 153 #endif 154 } else /* rsize == sizeof (long) */ 155 { 156 long *pr = r; 157 if (LONG_MAX < val) 158 return TRUE; 159 *pr = (long) val; 160 } 161 } else { 162 if (rsize == sizeof (unsigned)) { 163 unsigned *pr = r; 164 if (UINT_MAX < val) 165 return TRUE; 166 *pr = (unsigned) val; 167 } else if (rsize == sizeof (unsigned long)) { 168 unsigned long *pr = r; 169 if (ULONG_MAX < val) 170 return TRUE; 171 *pr = (unsigned long) val; 172 #ifdef ULLONG_MAX 173 } else if (rsize == sizeof (unsigned long long)) { 174 unsigned long long *pr = r; 175 if (ULLONG_MAX < val) 176 return TRUE; 177 *pr = (unsigned long long) val; 178 #endif 179 } else /* rsize == sizeof (uintmax) */ 180 { 181 uintmax *pr = r; 182 *pr = (uintmax) val; 183 } 184 } 185 return FALSE; 186 } 187 188 /* 189 * If *R can represent the mathematical sum of A and B, store the sum 190 * and return FALSE. Otherwise, possibly set *R to an indeterminate 191 * value and return TRUE. R has size RSIZE, and is signed if and only 192 * if RSIGNED is nonzero. 193 */ 194 public lbool help_ckd_add(void *r, uintmax a, uintmax b, int rsize, int rsigned) 195 { 196 uintmax sum = a + b; 197 return sum < a || help_fixup(r, sum, rsize, rsigned); 198 } 199 200 /* Likewise, but for the product of A and B. */ 201 public lbool help_ckd_mul(void *r, uintmax a, uintmax b, int rsize, int rsigned) 202 { 203 uintmax product = a * b; 204 return ((b != 0 && a != product / b) 205 || help_fixup(r, product, rsize, rsigned)); 206 } 207 #endif 208