1 #ifndef _BUFFER_H_ 2 #define _BUFFER_H_ 3 #include "first.h" 4 5 struct tm; /* declaration */ 6 7 /** 8 * max size of a buffer which will just be reset 9 * to ->used = 0 instead of really freeing the buffer 10 */ 11 #define BUFFER_MAX_REUSE_SIZE 4096 12 13 /* generic string + binary data container; contains a terminating 0 in both 14 * cases 15 * 16 * used == 0 indicates a special "empty" state (unset config values); 17 * ptr might be NULL, too. 18 * 19 * copy/append functions will ensure used >= 1 20 * (i.e. never leave it in the special empty state) 21 */ 22 typedef struct { 23 char *ptr; 24 25 /* "used" includes a terminating 0 */ 26 uint32_t used; 27 /* size of allocated buffer at *ptr */ 28 uint32_t size; 29 } buffer; 30 31 /* create new buffer; either empty or copy given data */ 32 __attribute_malloc__ 33 __attribute_returns_nonnull__ 34 buffer* buffer_init(void); 35 36 __attribute_nonnull__() 37 __attribute_returns_nonnull__ 38 buffer* buffer_init_buffer(const buffer *src); 39 40 __attribute_returns_nonnull__ 41 buffer* buffer_init_string(const char *str); /* str can be NULL */ 42 43 void buffer_free(buffer *b); /* b can be NULL */ 44 45 /* reset b. if NULL != b && NULL != src, move src content to b. reset src. */ 46 __attribute_nonnull__() 47 void buffer_move(buffer * restrict b, buffer * restrict src); 48 49 /* make sure buffer is large enough to store a string of given size 50 * and a terminating zero. 51 * sets b to an empty string, and may drop old content. 52 * @return b->ptr 53 */ 54 __attribute_nonnull__() 55 __attribute_returns_nonnull__ 56 char* buffer_string_prepare_copy(buffer *b, size_t size); 57 58 /* allocate buffer large enough to be able to append a string of given size 59 * if b was empty (used == 0) it will contain an empty string (used == 1) 60 * afterwards 61 * "used" data is preserved; if not empty buffer must contain a 62 * zero terminated string. 63 */ 64 __attribute_nonnull__() 65 __attribute_returns_nonnull__ 66 char* buffer_string_prepare_append(buffer *b, size_t size); 67 68 /* extend and modify buffer for immediate addition of x bytes (differs from 69 * buffer_string_prepare_append() which only ensures space is available) 70 * returns pointer to which callers should immediately write x bytes 71 */ 72 __attribute_nonnull__() 73 __attribute_returns_nonnull__ 74 char* buffer_extend(buffer * const restrict b, size_t x); 75 76 /* use after prepare_(copy,append) when you have written data to the buffer 77 * to increase the buffer length by size. also sets the terminating zero. 78 * requires enough space is present for the terminating zero (prepare with the 79 * same size to be sure). 80 */ 81 __attribute_nonnull__() 82 void buffer_commit(buffer *b, size_t size); 83 84 /* clear buffer 85 * - invalidate buffer contents 86 * - unsets used chars but does not modify existing ptr contents 87 * (b->ptr *is not* set to an empty, '\0'-terminated string "") 88 */ 89 __attribute_nonnull__() 90 static inline void buffer_clear(buffer *b); 91 92 /* reset buffer 93 * - invalidate buffer contents 94 * - unsets used chars 95 * - keeps smaller buffer (unmodified) for reuse 96 * (b->ptr *is not* set to an empty, '\0'-terminated string "") 97 * - frees larger buffer (b->size > BUFFER_MAX_REUSE_SIZE) 98 */ 99 __attribute_nonnull__() 100 static inline void buffer_reset(buffer *b); 101 102 /* free buffer ptr 103 * - invalidate buffer contents; free ptr; reset ptr, used, size to 0 104 */ 105 __attribute_cold__ 106 __attribute_nonnull__() 107 void buffer_free_ptr(buffer *b); 108 109 void buffer_copy_string(buffer * restrict b, const char * restrict s); 110 void buffer_copy_string_len(buffer * restrict b, const char * restrict s, size_t len); 111 void buffer_copy_string_len_lc(buffer * restrict b, const char * restrict s, size_t len); 112 113 void buffer_append_string(buffer * restrict b, const char * restrict s); 114 void buffer_append_string_len(buffer * restrict b, const char * restrict s, size_t len); 115 void buffer_append_str2(buffer * restrict b, const char *s1, size_t len1, const char *s2, size_t len2); 116 void buffer_append_str3(buffer * restrict b, const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3); 117 118 #ifndef LI_CONST_IOVEC 119 #define LI_CONST_IOVEC 120 struct const_iovec { 121 const void *iov_base; 122 size_t iov_len; 123 }; 124 #endif 125 126 __attribute_nonnull__() 127 void buffer_append_iovec(buffer * restrict b, const struct const_iovec *iov, size_t n); 128 129 #define buffer_append_uint_hex(b,len) buffer_append_uint_hex_lc((b),(len)) 130 __attribute_nonnull__() 131 void buffer_append_uint_hex_lc(buffer *b, uintmax_t len); 132 __attribute_nonnull__() 133 void buffer_append_int(buffer *b, intmax_t val); 134 135 void buffer_append_strftime(buffer * restrict b, const char * restrict format, const struct tm * restrict tm); 136 137 /* '-', log_10 (2^bits) = bits * log 2 / log 10 < bits * 0.31, terminating 0 */ 138 #define LI_ITOSTRING_LENGTH (2 + (8 * sizeof(intmax_t) * 31 + 99) / 100) 139 140 __attribute_nonnull__() 141 size_t li_itostrn(char *buf, size_t buf_len, intmax_t val); 142 __attribute_nonnull__() 143 size_t li_utostrn(char *buf, size_t buf_len, uintmax_t val); 144 145 /* buf must be (at least) 2*s_len + 1 big. uses lower-case hex letters. */ 146 #define li_tohex(buf,buf_len,s,s_len) li_tohex_lc((buf),(buf_len),(s),(s_len)) 147 __attribute_nonnull__() 148 void li_tohex_lc(char * restrict buf, size_t buf_len, const char * restrict s, size_t s_len); 149 __attribute_nonnull__() 150 void li_tohex_uc(char * restrict buf, size_t buf_len, const char * restrict s, size_t s_len); 151 152 __attribute_nonnull__() 153 __attribute_pure__ 154 int buffer_eq_icase_ssn(const char * const a, const char * const b, const size_t len); 155 156 __attribute_nonnull__() 157 __attribute_pure__ 158 int buffer_eq_icase_ss(const char * const a, const size_t alen, const char * const b, const size_t blen); 159 160 __attribute_nonnull__() 161 __attribute_pure__ 162 int buffer_eq_icase_slen(const buffer * const b, const char * const s, const size_t slen); 163 164 __attribute_nonnull__() 165 __attribute_pure__ 166 int buffer_eq_slen(const buffer * const b, const char * const s, const size_t slen); 167 168 __attribute_nonnull__() 169 __attribute_pure__ 170 int buffer_is_equal(const buffer *a, const buffer *b); 171 172 __attribute_nonnull__() 173 void buffer_substr_replace (buffer * restrict b, size_t offset, size_t len, const buffer * restrict replace); 174 175 __attribute_nonnull__() 176 void buffer_append_string_encoded_hex_lc(buffer * restrict b, const char * restrict s, size_t len); 177 __attribute_nonnull__() 178 void buffer_append_string_encoded_hex_uc(buffer * restrict b, const char * restrict s, size_t len); 179 180 typedef enum { 181 ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */ 182 ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */ 183 ENCODING_HTML, /* & becomes & and so on */ 184 ENCODING_MINIMAL_XML /* minimal encoding for xml */ 185 } buffer_encoding_t; 186 187 void buffer_append_string_encoded(buffer * restrict b, const char * restrict s, size_t s_len, buffer_encoding_t encoding); 188 189 void buffer_append_string_encoded_json(buffer * restrict b, const char * restrict s, size_t len); 190 191 /* escape non-printable characters; simple escapes for \t, \r, \n; fallback to \xCC */ 192 __attribute_nonnull__() 193 void buffer_append_string_c_escaped(buffer * restrict b, const char * restrict s, size_t s_len); 194 195 __attribute_nonnull__() 196 void buffer_urldecode_path(buffer *b); 197 198 __attribute_nonnull__() 199 __attribute_pure__ 200 int buffer_is_valid_UTF8(const buffer *b); 201 202 __attribute_nonnull__() 203 void buffer_path_simplify(buffer *b); 204 205 __attribute_nonnull__() 206 void buffer_to_lower(buffer *b); 207 __attribute_nonnull__() 208 void buffer_to_upper(buffer *b); 209 210 211 /** deprecated */ 212 __attribute_const__ 213 char hex2int(unsigned char c); 214 215 int li_hex2bin (unsigned char *bin, size_t binlen, const char *hexstr, size_t len); 216 217 __attribute_pure__ 218 static inline int light_isdigit(int c); 219 static inline int light_isdigit(int c) { 220 return ((uint32_t)c-'0' <= '9'-'0'); 221 } 222 223 __attribute_pure__ 224 static inline int light_isxdigit(int c); 225 static inline int light_isxdigit(int c) { 226 return light_isdigit(c) || (((uint32_t)c | 0x20)-'a' <= 'f'-'a'); 227 } 228 229 __attribute_pure__ 230 static inline int light_isalpha(int c); 231 static inline int light_isalpha(int c) { 232 return (((uint32_t)c | 0x20)-'a' <= 'z'-'a'); 233 } 234 235 __attribute_pure__ 236 static inline int light_isalnum(int c); 237 static inline int light_isalnum(int c) { 238 return light_isdigit(c) || light_isalpha(c); 239 } 240 241 #define light_isupper(c) ((uint32_t)(c)-'A' <= 'Z'-'A') 242 #define light_islower(c) ((uint32_t)(c)-'a' <= 'z'-'a') 243 244 #define light_bshift(b) ((uint64_t)1uL << (b)) 245 #define light_btst(a,b) ((a) & ((uint64_t)1uL << (b))) 246 #define light_bclr(a,b) ((a) &= ~((uint64_t)1uL << (b))) 247 #define light_bset(a,b) ((a) |= ((uint64_t)1uL << (b))) 248 249 250 void buffer_append_path_len(buffer * restrict b, const char * restrict a, size_t alen); /* join strings with '/', if '/' not present */ 251 void buffer_copy_path_len2(buffer * restrict b, const char * restrict s1, size_t len1, const char * restrict s2, size_t len2); 252 253 __attribute_nonnull__() 254 __attribute_pure__ 255 static inline int buffer_has_slash_suffix (const buffer * const b); 256 257 __attribute_nonnull__() 258 __attribute_pure__ 259 static inline int buffer_has_pathsep_suffix (const buffer * const b); 260 261 #define BUFFER_INTLEN_PTR(x) (int)buffer_clen(x), (x)->ptr 262 #define BUF_PTR_LEN(x) (x)->ptr, buffer_clen(x) 263 264 #define CONST_LEN_STR(x) (uint32_t)sizeof(x)-1, x 265 #define CONST_STR_LEN(x) x, (uint32_t)sizeof(x) - 1 266 267 268 /* inline implementations */ 269 270 __attribute_nonnull__() 271 __attribute_pure__ 272 static inline int buffer_is_unset(const buffer *b); 273 static inline int buffer_is_unset(const buffer *b) { 274 return 0 == b->used; 275 } 276 277 __attribute_nonnull__() 278 __attribute_pure__ 279 static inline int buffer_is_blank(const buffer *b); 280 static inline int buffer_is_blank(const buffer *b) { 281 return b->used < 2; /* buffer_is_blank() || buffer_is_unset() */ 282 } 283 284 /* buffer "C" len (bytes) */ 285 __attribute_nonnull__() 286 __attribute_pure__ 287 static inline uint32_t buffer_clen (const buffer *b); 288 static inline uint32_t buffer_clen (const buffer *b) { 289 return b->used - (0 != b->used); 290 } 291 292 /* buffer space remaining to append string without reallocating */ 293 __attribute_nonnull__() 294 __attribute_pure__ 295 static inline uint32_t buffer_string_space(const buffer *b); 296 static inline uint32_t buffer_string_space(const buffer *b) { 297 return b->size ? b->size - (b->used | (0 == b->used)) : 0; 298 } 299 300 __attribute_nonnull__() 301 static inline void buffer_copy_buffer(buffer * restrict b, const buffer * restrict src); 302 static inline void buffer_copy_buffer(buffer * restrict b, const buffer * restrict src) { 303 buffer_copy_string_len(b, BUF_PTR_LEN(src)); 304 } 305 306 __attribute_nonnull__() 307 static inline void buffer_append_buffer(buffer * restrict b, const buffer * restrict src); 308 static inline void buffer_append_buffer(buffer * restrict b, const buffer * restrict src) { 309 buffer_append_string_len(b, BUF_PTR_LEN(src)); 310 } 311 312 __attribute_nonnull__() 313 static inline void buffer_truncate(buffer *b, uint32_t len); 314 static inline void buffer_truncate(buffer *b, uint32_t len) { 315 b->ptr[len] = '\0'; /* b->ptr must exist; use buffer_blank() for trunc 0 */ 316 b->used = len + 1; 317 } 318 319 __attribute_nonnull__() 320 static inline void buffer_blank(buffer *b); 321 static inline void buffer_blank(buffer *b) { 322 b->ptr ? buffer_truncate(b, 0) : (void)buffer_extend(b, 0); 323 } 324 325 /* append '/' to non-empty strings not ending in '/' */ 326 __attribute_nonnull__() 327 static inline void buffer_append_slash(buffer *b); 328 static inline void buffer_append_slash(buffer *b) { 329 const uint32_t len = buffer_clen(b); 330 if (len > 0 && '/' != b->ptr[len-1]) 331 buffer_append_string_len(b, CONST_STR_LEN("/")); 332 } 333 334 static inline void buffer_clear(buffer *b) { 335 b->used = 0; 336 } 337 338 static inline void buffer_reset(buffer *b) { 339 b->used = 0; 340 /* release buffer larger than BUFFER_MAX_REUSE_SIZE bytes */ 341 if (b->size > BUFFER_MAX_REUSE_SIZE) buffer_free_ptr(b); 342 } 343 344 static inline int buffer_has_slash_suffix (const buffer * const b) { 345 return (b->used > 1 && b->ptr[b->used-2] == '/'); 346 } 347 348 static inline int buffer_has_pathsep_suffix (const buffer * const b) { 349 return (b->used > 1 && b->ptr[b->used-2] == '/'); 350 } 351 352 353 /* backwards compat (deprecated; older interfaces) */ 354 355 #define buffer_append_string_buffer buffer_append_buffer 356 #define buffer_is_equal_caseless_string buffer_eq_icase_slen 357 #define buffer_is_equal_string buffer_eq_slen 358 359 #define BUFFER_APPEND_STRING_CONST(x, y) \ 360 buffer_append_string_len(x, y, sizeof(y) - 1) 361 362 #define BUFFER_COPY_STRING_CONST(x, y) \ 363 buffer_copy_string_len(x, y, sizeof(y) - 1) 364 365 #define CONST_BUF_LEN(x) ((x) ? (x)->ptr : NULL), buffer_string_length(x) 366 367 /* NULL buffer or empty buffer (used == 0); 368 * unset "string" (buffer) config options are initialized to used == 0, 369 * while setting an empty string leads to used == 1 370 */ 371 __attribute_pure__ 372 static inline int buffer_is_empty(const buffer *b); 373 static inline int buffer_is_empty(const buffer *b) { 374 return NULL == b || buffer_is_unset(b); 375 } 376 /* NULL buffer, empty buffer (used == 0) or empty string (used == 1) */ 377 __attribute_pure__ 378 static inline int buffer_string_is_empty(const buffer *b); 379 static inline int buffer_string_is_empty(const buffer *b) { 380 return NULL == b || buffer_is_blank(b); 381 } 382 383 /* buffer string length without terminating 0 */ 384 __attribute_pure__ 385 static inline uint32_t buffer_string_length(const buffer *b); 386 static inline uint32_t buffer_string_length(const buffer *b) { 387 return NULL != b ? buffer_clen(b) : 0; 388 } 389 390 /* sets string length: 391 * - deprecated; use buffer_truncate() or buffer_extend() instead 392 * - always stores a terminating zero to terminate the "new" string 393 * - does not modify the string data apart from terminating zero 394 * - reallocates the buffer iff needed 395 */ 396 __attribute_nonnull__() 397 static inline void buffer_string_set_length(buffer *b, uint32_t len); 398 static inline void buffer_string_set_length(buffer *b, uint32_t len) { 399 if (len < b->size) 400 buffer_truncate(b, len); 401 else 402 buffer_extend(b, len - buffer_clen(b)); 403 } 404 405 406 #include "ck.h" 407 #define force_assert(x) ck_assert(x) 408 #define log_failed_assert(file,line,msg) ck_bt_abort((file),(line),(msg)) 409 #define SEGFAULT() ck_bt_abort(__FILE__, __LINE__, "aborted") 410 411 412 #endif 413