-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuffer.c
143 lines (124 loc) · 3.44 KB
/
buffer.c
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
/*
* Generic dynamically-allocated auto-growing in-memory buffers.
*
* Written by Solar Designer <solar at openwall.com> in 2006,
* revised by ABC <abc at openwall.com> in 2014 (buffer_appenduc() function).
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2006 Solar Designer <solar at openwall.com>
* Copyright (c) 2014 ABC <abc at openwall.com>
* and it is hereby released to the general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "buffer.h"
int buffer_init(struct buffer *buf, size_t size)
{
if (!size)
size = BUFFER_GROW_STEP;
buf->start = malloc(size);
if (!buf->start) {
buf->end = buf->ptr = buf->start;
return buf->error = -1;
}
buf->end = buf->start + size;
buf->ptr = buf->start;
return buf->error = 0;
}
void buffer_free(struct buffer *buf)
{
free(buf->start);
buf->end = buf->ptr = buf->start = NULL;
buf->error = -1;
}
static int buffer_grow(struct buffer *buf, size_t length)
{
char *new_start;
size_t new_size;
if (length <= buf->end - buf->ptr)
return 0;
if (length > BUFFER_GROW_MAX || !buf->start || buf->error)
return buf->error = -1;
new_size = buf->ptr - buf->start + length + BUFFER_GROW_STEP;
if (new_size > BUFFER_GROW_MAX)
return buf->error = -1;
new_start = realloc(buf->start, new_size);
if (!new_start)
return buf->error = -1;
buf->ptr = new_start + (buf->ptr - buf->start);
buf->start = new_start;
buf->end = new_start + new_size;
return 0;
}
int buffer_append(struct buffer *buf, const char *what, size_t length)
{
if (length > buf->end - buf->ptr && buffer_grow(buf, length))
return -1;
memcpy(buf->ptr, what, length);
buf->ptr += length;
return 0;
}
int buffer_appendc(struct buffer *buf, char what)
{
if (buf->ptr >= buf->end && buffer_grow(buf, 1))
return -1;
*(buf->ptr++) = what;
return 0;
}
/* append utf-8 char */
void buffer_appenduc(struct buffer *buf, unsigned int what)
{
if (what <= 0x007f) {
buffer_appendc(buf, what);
} else if (what <= 0x07ff) {
buffer_appendc(buf, 0xc0 | (what >> 6));
buffer_appendc(buf, 0x80 | (what & 0x3f));
} else if (what <= 0xffff) {
buffer_appendc(buf, 0xe0 | (what >> 12));
buffer_appendc(buf, 0x80 | ((what >> 6) & 0x3f));
buffer_appendc(buf, 0x80 | (what & 0x3f));
} else if (what <= 0x10ffff) {
buffer_appendc(buf, 0xf0 | (what >> 18));
buffer_appendc(buf, 0x80 | ((what >> 12) & 0x3f));
buffer_appendc(buf, 0x80 | ((what >> 6) & 0x3f));
buffer_appendc(buf, 0x80 | (what & 0x3f));
} else {
buffer_appenduc(buf, 0xfffd); /* replacement character */
}
}
int buffer_appendf(struct buffer *buf, const char *fmt, ...)
{
va_list args;
size_t length, size;
int n;
length = 1;
size = buf->end - buf->ptr;
do {
if (length > size) {
if (buffer_grow(buf, length))
return -1;
size = buf->end - buf->ptr;
}
va_start(args, fmt);
n = vsnprintf(buf->ptr, size, fmt, args);
va_end(args);
if (n >= 0) {
if (n < size) {
buf->ptr += n;
return 0;
}
length = n + 1;
} else {
length = size << 1;
}
} while (length > size);
return buf->error = -1;
}