diff options
Diffstat (limited to 'lib/slist.c')
-rw-r--r-- | lib/slist.c | 127 |
1 files changed, 88 insertions, 39 deletions
diff --git a/lib/slist.c b/lib/slist.c index b110350..46e516e 100644 --- a/lib/slist.c +++ b/lib/slist.c | |||
@@ -28,38 +28,47 @@ struct gray_slist_bucket { | |||
28 | struct gray_slist { | 28 | struct gray_slist { |
29 | struct gray_slist_bucket *head, *tail; | 29 | struct gray_slist_bucket *head, *tail; |
30 | struct gray_slist_bucket *free; | 30 | struct gray_slist_bucket *free; |
31 | int ec; /* error code */ | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | static struct gray_slist_bucket * | 34 | static struct gray_slist_bucket * |
34 | alloc_bucket(size_t size) | 35 | alloc_bucket(size_t size) |
35 | { | 36 | { |
36 | struct gray_slist_bucket *p = gray_malloc(sizeof(*p) + size); | 37 | struct gray_slist_bucket *p = malloc(sizeof(*p) + size); |
37 | p->buf = (char*)(p + 1); | 38 | if (p) { |
38 | p->level = 0; | 39 | p->buf = (char*)(p + 1); |
39 | p->size = size; | 40 | p->level = 0; |
40 | p->next = NULL; | 41 | p->size = size; |
42 | p->next = NULL; | ||
43 | } | ||
41 | return p; | 44 | return p; |
42 | } | 45 | } |
43 | 46 | ||
44 | static void | 47 | static int |
45 | alloc_pool(gray_slist_t slist, size_t size) | 48 | alloc_pool(gray_slist_t slist, size_t size) |
46 | { | 49 | { |
47 | struct gray_slist_bucket *p = alloc_bucket(GRAY_SLIST_BUCKET_SIZE); | 50 | struct gray_slist_bucket *p = alloc_bucket(GRAY_SLIST_BUCKET_SIZE); |
51 | if (!p) { | ||
52 | slist->ec = errno; | ||
53 | return 1; | ||
54 | } | ||
48 | if (slist->tail) | 55 | if (slist->tail) |
49 | slist->tail->next = p; | 56 | slist->tail->next = p; |
50 | else | 57 | else |
51 | slist->head = p; | 58 | slist->head = p; |
52 | slist->tail = p; | 59 | slist->tail = p; |
60 | return 0; | ||
53 | } | 61 | } |
54 | 62 | ||
55 | static size_t | 63 | static ssize_t |
56 | copy_chars(gray_slist_t slist, const char *str, size_t n) | 64 | copy_chars(gray_slist_t slist, const char *str, size_t n) |
57 | { | 65 | { |
58 | size_t rest; | 66 | size_t rest; |
59 | 67 | ||
60 | 68 | if (!slist->head || slist->tail->level == slist->tail->size) { | |
61 | if (!slist->head || slist->tail->level == slist->tail->size) | 69 | if (alloc_pool(slist, GRAY_SLIST_BUCKET_SIZE)) |
62 | alloc_pool(slist, GRAY_SLIST_BUCKET_SIZE); | 70 | return -1; |
71 | } | ||
63 | rest = slist->tail->size - slist->tail->level; | 72 | rest = slist->tail->size - slist->tail->level; |
64 | if (n > rest) | 73 | if (n > rest) |
65 | n = rest; | 74 | n = rest; |
@@ -69,13 +78,28 @@ copy_chars(gray_slist_t slist, const char *str, size_t n) | |||
69 | } | 78 | } |
70 | 79 | ||
71 | gray_slist_t | 80 | gray_slist_t |
72 | gray_slist_create() | 81 | gray_slist_create(void) |
73 | { | 82 | { |
74 | gray_slist_t slist = gray_malloc(sizeof(*slist)); | 83 | gray_slist_t slist = malloc(sizeof(*slist)); |
75 | slist->head = slist->tail = slist->free = 0; | 84 | if (slist) { |
85 | slist->head = slist->tail = slist->free = 0; | ||
86 | slist->ec = 0; | ||
87 | } | ||
76 | return slist; | 88 | return slist; |
77 | } | 89 | } |
78 | 90 | ||
91 | int | ||
92 | gray_slist_err(gray_slist_t slist) | ||
93 | { | ||
94 | return slist->ec; | ||
95 | } | ||
96 | |||
97 | void | ||
98 | gray_slist_clerr(gray_slist_t slist) | ||
99 | { | ||
100 | slist->ec = 0; | ||
101 | } | ||
102 | |||
79 | void | 103 | void |
80 | gray_slist_clear(gray_slist_t slist) | 104 | gray_slist_clear(gray_slist_t slist) |
81 | { | 105 | { |
@@ -84,14 +108,15 @@ gray_slist_clear(gray_slist_t slist) | |||
84 | slist->free = slist->head; | 108 | slist->free = slist->head; |
85 | slist->head = slist->tail = NULL; | 109 | slist->head = slist->tail = NULL; |
86 | } | 110 | } |
111 | gray_slist_clerr(slist); | ||
87 | } | 112 | } |
88 | 113 | ||
89 | 114 | ||
90 | void | 115 | void |
91 | gray_slist_free(gray_slist_t *slist) | 116 | gray_slist_free(gray_slist_t *slist) |
92 | { | 117 | { |
93 | struct gray_slist_bucket *p; | ||
94 | if (*slist) { | 118 | if (*slist) { |
119 | struct gray_slist_bucket *p; | ||
95 | gray_slist_clear(*slist); | 120 | gray_slist_clear(*slist); |
96 | for (p = (*slist)->free; p; ) { | 121 | for (p = (*slist)->free; p; ) { |
97 | struct gray_slist_bucket *next = p->next; | 122 | struct gray_slist_bucket *next = p->next; |
@@ -103,21 +128,27 @@ gray_slist_free(gray_slist_t *slist) | |||
103 | *slist = NULL; | 128 | *slist = NULL; |
104 | } | 129 | } |
105 | 130 | ||
106 | void | 131 | ssize_t |
107 | gray_slist_append(gray_slist_t slist, const char *str, size_t n) | 132 | gray_slist_append(gray_slist_t slist, const char *str, size_t n) |
108 | { | 133 | { |
109 | const char *ptr = str; | 134 | ssize_t total; |
110 | while (n) { | 135 | |
111 | size_t s = copy_chars(slist, ptr, n); | 136 | if (slist->ec) |
112 | ptr += s; | 137 | return -1; |
113 | n -= s; | 138 | total = 0; |
139 | while (total < n) { | ||
140 | ssize_t s = copy_chars(slist, str + total, n - total); | ||
141 | if (s == -1) | ||
142 | return -1; | ||
143 | total += s; | ||
114 | } | 144 | } |
145 | return total; | ||
115 | } | 146 | } |
116 | 147 | ||
117 | void | 148 | ssize_t |
118 | gray_slist_append_char(gray_slist_t slist, char c) | 149 | gray_slist_append_char(gray_slist_t slist, char c) |
119 | { | 150 | { |
120 | gray_slist_append(slist, &c, 1); | 151 | return gray_slist_append(slist, &c, 1); |
121 | } | 152 | } |
122 | 153 | ||
123 | size_t | 154 | size_t |
@@ -130,17 +161,22 @@ gray_slist_size(gray_slist_t slist) | |||
130 | return size; | 161 | return size; |
131 | } | 162 | } |
132 | 163 | ||
133 | size_t | 164 | ssize_t |
134 | gray_slist_coalesce(gray_slist_t slist) | 165 | gray_slist_coalesce(gray_slist_t slist) |
135 | { | 166 | { |
136 | size_t size; | 167 | size_t size; |
137 | 168 | ||
138 | if (slist->head && slist->head->next == NULL) | 169 | if (slist->ec) |
170 | return -1; | ||
171 | else if (slist->head && slist->head->next == NULL) | ||
139 | size = slist->head->level; | 172 | size = slist->head->level; |
140 | else { | 173 | else { |
141 | size = gray_slist_size(slist); | 174 | size = gray_slist_size(slist); |
142 | struct gray_slist_bucket *bucket = alloc_bucket(size); | 175 | struct gray_slist_bucket *bucket, *p; |
143 | struct gray_slist_bucket *p; | 176 | |
177 | bucket = alloc_bucket(size); | ||
178 | if (!bucket) | ||
179 | return -1; | ||
144 | 180 | ||
145 | for (p = slist->head; p; ) { | 181 | for (p = slist->head; p; ) { |
146 | struct gray_slist_bucket *next = p->next; | 182 | struct gray_slist_bucket *next = p->next; |
@@ -165,7 +201,10 @@ gray_slist_head(gray_slist_t slist, size_t *psize) | |||
165 | void * | 201 | void * |
166 | gray_slist_finish(gray_slist_t slist) | 202 | gray_slist_finish(gray_slist_t slist) |
167 | { | 203 | { |
168 | gray_slist_coalesce(slist); | 204 | if (slist->ec) |
205 | return NULL; | ||
206 | if (gray_slist_coalesce(slist) == -1) | ||
207 | return NULL; | ||
169 | gray_slist_clear(slist); | 208 | gray_slist_clear(slist); |
170 | return slist->free->buf; | 209 | return slist->free->buf; |
171 | } | 210 | } |
@@ -174,14 +213,16 @@ gray_slist_finish(gray_slist_t slist) | |||
174 | #define to_num(c) \ | 213 | #define to_num(c) \ |
175 | (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 )) | 214 | (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 )) |
176 | 215 | ||
177 | void | 216 | int |
178 | gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, | 217 | gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, |
179 | int len, int base) | 218 | int len, int base) |
180 | { | 219 | { |
181 | int i; | 220 | int i; |
182 | int val = 0; | 221 | int val = 0; |
183 | char *start = text; | 222 | char *start = text; |
184 | 223 | ||
224 | if (slist->ec) | ||
225 | return -1; | ||
185 | if (text[0] == '\\') { | 226 | if (text[0] == '\\') { |
186 | text++; | 227 | text++; |
187 | if (base == 16) | 228 | if (base == 16) |
@@ -196,14 +237,17 @@ gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, | |||
196 | } | 237 | } |
197 | 238 | ||
198 | if (i == 0) { | 239 | if (i == 0) { |
199 | gray_slist_append(slist, start, 1); | 240 | if (gray_slist_append(slist, start, 1) != 1) |
241 | return -1; | ||
200 | if (pend) | 242 | if (pend) |
201 | *pend = start + 1; | 243 | *pend = start + 1; |
202 | } else { | 244 | } else { |
203 | gray_slist_append_char(slist, val); |