summaryrefslogtreecommitdiff
path: root/data/lighttpd/lighttpd-1.4.53/src/buffer.h
blob: df461e1a8bc500f001d326c3530e735b1f356639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#ifndef _BUFFER_H_
#define _BUFFER_H_
#include "first.h"

struct tm;              /* declaration */

/* generic string + binary data container; contains a terminating 0 in both
 * cases
 *
 * used == 0 indicates a special "empty" state (unset config values); ptr
 * might be NULL too then. otherwise an empty string has used == 1 (and ptr[0]
 * == 0);
 *
 * copy/append functions will ensure used >= 1 (i.e. never leave it in the
 * special empty state); only buffer_copy_buffer will copy the special empty
 * state.
 */
typedef struct {
	char *ptr;

	/* "used" includes a terminating 0 */
	size_t used;
	/* size of allocated buffer at *ptr */
	size_t size;
} buffer;

/* create new buffer; either empty or copy given data */
buffer* buffer_init(void);
buffer* buffer_init_buffer(const buffer *src); /* src can  be NULL */
buffer* buffer_init_string(const char *str); /* str can  be NULL */

void buffer_free(buffer *b); /* b can be NULL */
/* truncates to used == 0; frees large buffers, might keep smaller ones for reuse */
void buffer_reset(buffer *b); /* b can be NULL */

/* reset b. if NULL != b && NULL != src, move src content to b. reset src. */
void buffer_move(buffer *b, buffer *src);

/* make sure buffer is large enough to store a string of given size
 * and a terminating zero.
 * sets b to an empty string, and may drop old content.
 * @return b->ptr
 */
char* buffer_string_prepare_copy(buffer *b, size_t size);

/* allocate buffer large enough to be able to append a string of given size
 * if b was empty (used == 0) it will contain an empty string (used == 1)
 * afterwards
 * "used" data is preserved; if not empty buffer must contain a
 * zero terminated string.
 */
char* buffer_string_prepare_append(buffer *b, size_t size);

/* use after prepare_(copy,append) when you have written data to the buffer
 * to increase the buffer length by size. also sets the terminating zero.
 * requires enough space is present for the terminating zero (prepare with the
 * same size to be sure).
 */
void buffer_commit(buffer *b, size_t size);

/* sets string length:
 * - always stores a terminating zero to terminate the "new" string
 * - does not modify the string data apart from terminating zero
 * - reallocates the buffer iff needed
 */
void buffer_string_set_length(buffer *b, size_t len);

/* clear buffer
 * - invalidate buffer contents
 * - unsets used chars but does not modify existing ptr contents
 *   (b->ptr *is not* set to an empty, '\0'-terminated string "")
 */
static inline void buffer_clear(buffer *b);

void buffer_copy_string(buffer *b, const char *s);
void buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
static inline void buffer_copy_buffer(buffer *b, const buffer *src);

void buffer_append_string(buffer *b, const char *s);
void buffer_append_string_len(buffer *b, const char *s, size_t s_len);
static inline void buffer_append_string_buffer(buffer *b, const buffer *src);

#define buffer_append_uint_hex(b,len) buffer_append_uint_hex_lc((b),(len))
void buffer_append_uint_hex_lc(buffer *b, uintmax_t len);
void buffer_append_int(buffer *b, intmax_t val);
void buffer_copy_int(buffer *b, intmax_t val);

void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm);

/* '-', log_10 (2^bits) = bits * log 2 / log 10 < bits * 0.31, terminating 0 */
#define LI_ITOSTRING_LENGTH (2 + (8 * sizeof(intmax_t) * 31 + 99) / 100)

void li_itostrn(char *buf, size_t buf_len, intmax_t val);
void li_utostrn(char *buf, size_t buf_len, uintmax_t val);

/* buf must be (at least) 2*s_len + 1 big. uses lower-case hex letters. */
#define li_tohex(buf,buf_len,s,s_len) li_tohex_lc((buf),(buf_len),(s),(s_len))
void li_tohex_lc(char *buf, size_t buf_len, const char *s, size_t s_len);
void li_tohex_uc(char *buf, size_t buf_len, const char *s, size_t s_len);

/* NULL buffer or empty buffer (used == 0);
 * unset "string" (buffer) config options are initialized to used == 0,
 * while setting an empty string leads to used == 1
 */
static inline int buffer_is_empty(const buffer *b);
/* NULL buffer, empty buffer (used == 0) or empty string (used == 1) */
static inline int buffer_string_is_empty(const buffer *b);

int buffer_is_equal(const buffer *a, const buffer *b);
int buffer_is_equal_right_len(const buffer *a, const buffer *b, size_t len);
int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len);
int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len);
int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len);

void buffer_substr_replace (buffer *b, size_t offset, size_t len, const buffer *replace);

void buffer_append_string_encoded_hex_lc(buffer *b, const char *s, size_t len);
void buffer_append_string_encoded_hex_uc(buffer *b, const char *s, size_t len);

typedef enum {
	ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
	ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
	ENCODING_HTML,         /* & becomes &amp; and so on */
	ENCODING_MINIMAL_XML   /* minimal encoding for xml */
} buffer_encoding_t;

void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);

/* escape non-printable characters; simple escapes for \t, \r, \n; fallback to \xCC */
void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len);

/* to upper case, replace non alpha-numerics with '_'; if is_http_header prefix with "HTTP_" unless s is "content-type" */
void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header);

void buffer_urldecode_path(buffer *url);
void buffer_urldecode_query(buffer *url);
int buffer_is_valid_UTF8(const buffer *b);
void buffer_path_simplify(buffer *dest, buffer *src);

void buffer_to_lower(buffer *b);
void buffer_to_upper(buffer *b);


/** deprecated */
char hex2int(unsigned char c);
char int2hex(char i);

static inline int light_isdigit(int c);
static inline int light_isxdigit(int c);
static inline int light_isalpha(int c);
static inline int light_isalnum(int c);

static inline int light_isdigit(int c) {
	return (c >= '0' && c <= '9');
}

static inline int light_isxdigit(int c) {
	return light_isdigit(c) || (c |= 32, c >= 'a' && c <= 'f');
}

static inline int light_isalpha(int c) {
	return (c |= 32, c >= 'a' && c <= 'z');
}

static inline int light_isalnum(int c) {
	return light_isdigit(c) || light_isalpha(c);
}


static inline size_t buffer_string_length(const buffer *b); /* buffer string length without terminating 0 */
static inline size_t buffer_string_space(const buffer *b); /* maximum length of string that can be stored without reallocating */
static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty strings not ending in '/' */
void buffer_append_path_len(buffer *b, const char *a, size_t alen); /* join strings with '/', if '/' not present */

#define BUFFER_APPEND_STRING_CONST(x, y) \
	buffer_append_string_len(x, y, sizeof(y) - 1)

#define BUFFER_COPY_STRING_CONST(x, y) \
	buffer_copy_string_len(x, y, sizeof(y) - 1)

#define CONST_STR_LEN(x) x, (x) ? sizeof(x) - 1 : 0
#define CONST_BUF_LEN(x) ((x) ? (x)->ptr : NULL), buffer_string_length(x)


#define LI_NORETURN __attribute_noreturn__

__attribute_cold__
void log_failed_assert(const char *filename, unsigned int line, const char *msg) LI_NORETURN;
#define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
#define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");

/* inline implementations */

static inline int buffer_is_empty(const buffer *b) {
	return NULL == b || 0 == b->used;
}
static inline int buffer_string_is_empty(const buffer *b) {
	return NULL == b || b->used < 2;
}

static inline size_t buffer_string_length(const buffer *b) {
	return NULL != b && 0 != b->used ? b->used - 1 : 0;
}

static inline size_t buffer_string_space(const buffer *b) {
	return NULL != b && b->size ? b->size - (b->used | (0 == b->used)) : 0;
}

static inline void buffer_copy_buffer(buffer *b, const buffer *src) {
	buffer_copy_string_len(b, CONST_BUF_LEN(src));
}

static inline void buffer_append_string_buffer(buffer *b, const buffer *src) {
	buffer_append_string_len(b, CONST_BUF_LEN(src));
}

static inline void buffer_append_slash(buffer *b) {
	size_t len = buffer_string_length(b);
	if (len > 0 && '/' != b->ptr[len-1]) BUFFER_APPEND_STRING_CONST(b, "/");
}

static inline void buffer_clear(buffer *b) {
	b->used = 0;
}

#endif