参考: http://www.cnblogs.com/kernel_hcy/archive/2009/11/04/1594134.html
字符串
lighttpd需要对字符串进行处理,源文件是buffer.c buffer.h
buffer的定义如下所示,注释写的很清晰。
/* 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;
相关函数
- buffer_reset
/* truncates to used == 0; frees large buffers, might keep smaller ones for reuse */
void buffer_reset(buffer *b); /* b can be NULL */
void buffer_reset(buffer *b) {
if (NULL == b) return;
/* limit don't reuse buffer larger than ... bytes */
if (b->size > BUFFER_MAX_REUSE_SIZE) {
free(b->ptr);
b->ptr = NULL;
b->size = 0;
} else if (b->size > 0) {
b->ptr[0] = '\0';
}
b->used = 0;
}
其中FFER_MAX_REUSE_SIZE
的定义在settings.h
中:
/**
* max size of a buffer which will just be reset
* to ->used = 0 instead of really freeing the buffer
*
* 64kB (no real reason, just a guess)
*/
#define BUFFER_MAX_REUSE_SIZE (4 * 1024)
也就是说,如果buffer的大小不超过4K,那么不会释放该空间,而是重新使用。
- buffer_move
/* reset b. if NULL != b && NULL != src, move src content to b. reset src. */
void buffer_move(buffer *b, buffer *src);
如果b和src均不为NULL时,将src的内容“剪切”到b中。(注意不是复制)
如果b为NULL,那么对src执行buffer_reset操作。
如果b不为空,那么先将b“清空”(buffer_reset(b), b的大小小于4K时,不回被free,记得吗),然后将b和src进行swap。源码如下所示:
void buffer_move(buffer *b, buffer *src) {
buffer tmp;
if (NULL == b) {
buffer_reset(src);
return;
}
buffer_reset(b);
if (NULL == src) return;
tmp = *src; *src = *b; *b = tmp;
}
- buffer_align_size
#define BUFFER_PIECE_SIZE 64
static size_t buffer_align_size(size_t size) {
size_t align = BUFFER_PIECE_SIZE - (size % BUFFER_PIECE_SIZE);
/* overflow on unsinged size_t is defined to wrap around */
if (size + align < size) return size;
return size + align;
}
保证buffer的大小是按照 BUFFER_PIECE_SIZE
对齐的
注意if判断,它处理了size+align有可能会溢出(overflow)的情况。这点以后要注意!
- buffer_alloc , buffer_realloc
/* make sure buffer is at least "size" big. discard old data */
static void buffer_alloc(buffer *b, size_t size) {
force_assert(NULL != b);
if (0 == size) size = 1;
if (size <= b->size) return;
if (NULL != b->ptr) free(b->ptr);
b->used = 0;
b->size = buffer_align_size(size);
b->ptr = malloc(b->size);
force_assert(NULL != b->ptr);
}
/* make sure buffer is at least "size" big. keep old data */
static void buffer_realloc(buffer *b, size_t size) {
force_assert(NULL != b);
if (0 == size) size = 1;
if (size <= b->size) return;
b->size = buffer_align_size(size);
b->ptr = realloc(b->ptr, b->size);
force_assert(NULL != b->ptr);
}
涉及到对空间的分配,逻辑很清晰。
- li_tohex
static const char hex_chars[] = "0123456789abcdef";
void li_tohex(char *buf, const char *s, size_t s_len) {
size_t i;
for (i = 0; i < s_len; i++) {
buf[2*i] = hex_chars[(s[i] >> 4) & 0x0F];
buf[2*i+1] = hex_chars[s[i] & 0x0F];
}
buf[2*s_len] = '\0';
}
该函数将字符串s中的字符转换为16进制,保存在buff中。例如字符‘A’将转换为 “41”。因此转换后长度翻倍。
我想到的一种转换方法是使用sprintf。
但是这里的方法更好。hex_chars
相当于一个字典。s[i]>>4 & 0x0F 是求16进制的高位数字,s[i] & 0x0F 是求16进制的地位数字,然后再hex_chars
中查找对应的字符。
- buffer_copy_string
void buffer_copy_string(buffer *b, const char *s) {
buffer_copy_string_len(b, s, NULL != s ? strlen(s) : 0);
}
这里对三目运算符的使用很优雅。