diff --git a/CMakeLists.txt b/CMakeLists.txt index 29667456e..3edafc612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ SET(AWE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/titlebar.c ${CMAKE_CURRENT_SOURCE_DIR}/widget.c ${CMAKE_CURRENT_SOURCE_DIR}/window.c + ${CMAKE_CURRENT_SOURCE_DIR}/common/buffer.c ${CMAKE_CURRENT_SOURCE_DIR}/common/configopts.c ${CMAKE_CURRENT_SOURCE_DIR}/common/draw.c ${CMAKE_CURRENT_SOURCE_DIR}/common/markup.c diff --git a/common/buffer.c b/common/buffer.c new file mode 100644 index 000000000..1e9f79041 --- /dev/null +++ b/common/buffer.c @@ -0,0 +1,106 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright © 2006,2007,2008 Pierre Habouzit + */ + +#include +#include +#include + +#include "common/buffer.h" + +char buffer_slop[1]; + +void buffer_ensure(buffer_t *buf, int newlen) +{ + if (newlen < 0) + exit(EX_SOFTWARE); + + if (newlen < buf->size) + return; + + if (newlen < buf->offs + buf->size && buf->offs > buf->size / 4) { + /* Data fits in the current area, shift it left */ + memmove(buf->s - buf->offs, buf->s, buf->len + 1); + buf->s -= buf->offs; + buf->size += buf->offs; + buf->offs = 0; + return; + } + + buf->size = p_alloc_nr(buf->size + buf->offs); + if (buf->size < newlen + 1) + buf->size = newlen + 1; + if (buf->alloced && !buf->offs) { + p_realloc(&buf->s, buf->size); + } else { + char *new_area = xmalloc(buf->size); + memcpy(new_area, buf->s, buf->len + 1); + if (buf->alloced) + free(buf->s - buf->offs); + buf->alloced = true; + buf->s = new_area; + buf->offs = 0; + } +} + +void buffer_addvf(buffer_t *buf, const char *fmt, va_list args) +{ + int len; + va_list ap; + + va_copy(ap, args); + buffer_ensure(buf, BUFSIZ); + + len = vsnprintf(buf->s + buf->len, buf->size - buf->len, fmt, args); + if (unlikely(len < 0)) + return; + if (len >= buf->size - buf->len) { + buffer_ensure(buf, len); + vsnprintf(buf->s + buf->len, buf->size - buf->len, fmt, ap); + } + buf->len += len; + buf->s[buf->len] = '\0'; +} + +void buffer_addf(buffer_t *buf, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + buffer_addvf(buf, fmt, args); + va_end(args); +} + +char *buffer_detach(buffer_t *buf) +{ + char *res = buf->s; + if (!buf->alloced) + res = a_strdup(buf->s); + buffer_init(buf); + return res; +} diff --git a/common/buffer.h b/common/buffer.h new file mode 100644 index 000000000..7c79525da --- /dev/null +++ b/common/buffer.h @@ -0,0 +1,130 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright © 2006,2007,2008 Pierre Habouzit + */ + +#ifndef MC_BASE_BUFFER_H +#define MC_BASE_BUFFER_H + +#include "common/util.h" + +typedef struct buffer_t { + char *s; + int len, size; + unsigned alloced: 1; + unsigned offs :31; +} buffer_t; + +extern char buffer_slop[1]; + + +#define BUFFER_INIT (buffer_t){ .s = buffer_slop, .size = 1 } + +#define buffer_inita(b, sz) \ + ({ int __sz = (sz); assert (__sz < (64 << 10)); \ + buffer_init_buf((b), alloca(__sz), __sz); }) + +static inline buffer_t *buffer_init(buffer_t *buf) { + *buf = BUFFER_INIT; + return buf; +} +static inline void buffer_init_buf(buffer_t *b, void *buf, int size) { + *b = (buffer_t){ .s = buf, .size = size }; + b->s[0] = '\0'; +} +static inline void buffer_wipe(buffer_t *buf) { + if (buf->alloced) + free(buf->s - buf->offs); + buffer_init(buf); +} +static inline buffer_t *buffer_new(void) { + return buffer_init(p_new(buffer_t, 1)); +} +static inline void buffer_delete(buffer_t **buf) { + if (*buf) { + buffer_wipe(*buf); + p_delete(buf); + } +} + +char *buffer_detach(buffer_t *buf); +void buffer_ensure(buffer_t *buf, int len); +static inline void buffer_grow(buffer_t *buf, int extra) +{ + assert (extra >= 0); + if (buf->len + extra > buf->size) { + buffer_ensure(buf, buf->len + extra); + } +} + + +static inline void +buffer_splice(buffer_t *buf, int pos, int len, const void *data, int dlen) +{ + assert (pos >= 0 && len >= 0 && dlen >= 0); + + if (unlikely(pos > buf->len)) + pos = buf->len; + if (unlikely(len > buf->len - pos)) + len = buf->len - pos; + if (pos == 0 && len + buf->offs >= dlen) { + buf->offs += len - dlen; + buf->s += len - dlen; + buf->size -= len - dlen; + buf->len -= len - dlen; + len = dlen; + } else + if (len != dlen) { + buffer_ensure(buf, buf->len + dlen - len); + memmove(buf->s + pos + dlen, buf->s + pos + len, buf->len - pos - len); + buf->len += dlen - len; + buf->s[buf->len] = '\0'; + } + memcpy(buf->s + pos, data, dlen); +} + + +static inline void buffer_add(buffer_t *buf, void *data, int len) { + buffer_splice(buf, buf->len, 0, data, len); +} +static inline void buffer_adds(buffer_t *buf, const char *s) { + buffer_splice(buf, buf->len, 0, s, strlen(s)); +} +static inline void buffer_addc(buffer_t *buf, int c) { + buffer_grow(buf, 1); + buf->s[buf->len++] = c; + buf->s[buf->len] = '\0'; +} + +void buffer_addvf(buffer_t *buf, const char *fmt, va_list) + __attribute__((format(printf, 2, 0))); + +void buffer_addf(buffer_t *buf, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + +#endif /* MC_BASE_BUFFER_H */ diff --git a/common/markup.c b/common/markup.c index 62fed8b7e..a7bc6c8c1 100644 --- a/common/markup.c +++ b/common/markup.c @@ -170,7 +170,7 @@ markup_parser_data_new(const char **elements, const char **elements_sub, ssize_t p = p_new(markup_parser_data_t, 1); - p->text = p_new(char, 1); + buffer_init(&p->text); p->elements = elements; p->elements_sub = elements_sub; p->attribute_names = p_new(char **, nelem); @@ -202,7 +202,7 @@ markup_parser_data_delete(markup_parser_data_t **p) p_delete(&(*p)->attribute_names); p_delete(&(*p)->attribute_values); - p_delete(&(*p)->text); + buffer_wipe(&p->text); p_delete(p); } diff --git a/common/markup.h b/common/markup.h index f0306c74a..fc002d441 100644 --- a/common/markup.h +++ b/common/markup.h @@ -22,11 +22,11 @@ #ifndef AWESOME_COMMON_MARKUP_H #define AWESOME_COMMON_MARKUP_H -#include "common/util.h" +#include "common/buffer.h" typedef struct { - char *text; + buffer_t text; const char **elements; const char **elements_sub; char ***attribute_names; diff --git a/common/util.h b/common/util.h index deeb16817..409216caf 100644 --- a/common/util.h +++ b/common/util.h @@ -27,6 +27,7 @@ #include #include #include +#include /** A list of possible position, not sex related */ typedef enum