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