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