summaryrefslogtreecommitdiff
path: root/cmark/src/buffer.c
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:41:54 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:41:54 +0300
commit3d2121f5d6555744ce5aa502088fc2b34dc26d38 (patch)
tree53f42c08746171878b57f5b6ffe1eb841da9d45d /cmark/src/buffer.c
parent6bf7c5ce92ff6237c0b17c332873805018812b40 (diff)
parent64efa3b3b3d35f2ffb604b57a8a9c89047cb420b (diff)
downloadProject-Tick-3d2121f5d6555744ce5aa502088fc2b34dc26d38.tar.gz
Project-Tick-3d2121f5d6555744ce5aa502088fc2b34dc26d38.zip
Add 'cmark/' from commit '64efa3b3b3d35f2ffb604b57a8a9c89047cb420b'
git-subtree-dir: cmark git-subtree-mainline: 6bf7c5ce92ff6237c0b17c332873805018812b40 git-subtree-split: 64efa3b3b3d35f2ffb604b57a8a9c89047cb420b
Diffstat (limited to 'cmark/src/buffer.c')
-rw-r--r--cmark/src/buffer.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/cmark/src/buffer.c b/cmark/src/buffer.c
new file mode 100644
index 0000000000..f3159948ce
--- /dev/null
+++ b/cmark/src/buffer.c
@@ -0,0 +1,209 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark_ctype.h"
+#include "buffer.h"
+
+/* Used as default value for cmark_strbuf->ptr so that people can always
+ * assume ptr is non-NULL and zero terminated even for new cmark_strbufs.
+ */
+unsigned char cmark_strbuf__initbuf[1];
+
+#ifndef MIN
+#define MIN(x, y) ((x < y) ? x : y)
+#endif
+
+void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
+ bufsize_t initial_size) {
+ buf->mem = mem;
+ buf->asize = 0;
+ buf->size = 0;
+ buf->ptr = cmark_strbuf__initbuf;
+
+ if (initial_size > 0)
+ cmark_strbuf_grow(buf, initial_size);
+}
+
+static inline void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
+ cmark_strbuf_grow(buf, buf->size + add);
+}
+
+void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
+ assert(target_size > 0);
+
+ if (target_size < buf->asize)
+ return;
+
+ if (target_size > (bufsize_t)(INT32_MAX / 2)) {
+ fprintf(stderr,
+ "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n",
+ (INT32_MAX / 2));
+ abort();
+ }
+
+ /* Oversize the buffer by 50% to guarantee amortized linear time
+ * complexity on append operations. */
+ bufsize_t new_size = target_size + target_size / 2;
+ new_size += 1;
+ new_size = (new_size + 7) & ~7;
+
+ buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL,
+ new_size);
+ buf->asize = new_size;
+}
+
+void cmark_strbuf_free(cmark_strbuf *buf) {
+ if (!buf)
+ return;
+
+ if (buf->ptr != cmark_strbuf__initbuf)
+ buf->mem->free(buf->ptr);
+
+ cmark_strbuf_init(buf->mem, buf, 0);
+}
+
+void cmark_strbuf_clear(cmark_strbuf *buf) {
+ buf->size = 0;
+
+ if (buf->asize > 0)
+ buf->ptr[0] = '\0';
+}
+
+void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len) {
+ if (len <= 0 || data == NULL) {
+ cmark_strbuf_clear(buf);
+ } else {
+ if (data != buf->ptr) {
+ if (len >= buf->asize)
+ cmark_strbuf_grow(buf, len);
+ memmove(buf->ptr, data, len);
+ }
+ buf->size = len;
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
+ S_strbuf_grow_by(buf, 1);
+ buf->ptr[buf->size++] = (unsigned char)(c & 0xFF);
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len) {
+ if (len <= 0)
+ return;
+
+ S_strbuf_grow_by(buf, len);
+ memmove(buf->ptr + buf->size, data, len);
+ buf->size += len;
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
+ cmark_strbuf_put(buf, (const unsigned char *)string, (bufsize_t)strlen(string));
+}
+
+unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
+ unsigned char *data = buf->ptr;
+
+ if (buf->asize == 0) {
+ /* return an empty string */
+ return (unsigned char *)buf->mem->calloc(1, 1);
+ }
+
+ cmark_strbuf_init(buf->mem, buf, 0);
+ return data;
+}
+
+void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
+ if (len < 0)
+ len = 0;
+
+ if (len < buf->size) {
+ buf->size = len;
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
+ if (n > 0) {
+ if (n > buf->size)
+ n = buf->size;
+ buf->size = buf->size - n;
+ if (buf->size)
+ memmove(buf->ptr, buf->ptr + n, buf->size);
+
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_rtrim(cmark_strbuf *buf) {
+ if (!buf->size)
+ return;
+
+ while (buf->size > 0) {
+ if (!cmark_isspace(buf->ptr[buf->size - 1]))
+ break;
+
+ buf->size--;
+ }
+
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_trim(cmark_strbuf *buf) {
+ bufsize_t i = 0;
+
+ if (!buf->size)
+ return;
+
+ while (i < buf->size && cmark_isspace(buf->ptr[i]))
+ i++;
+
+ cmark_strbuf_drop(buf, i);
+
+ cmark_strbuf_rtrim(buf);
+}
+
+// Destructively modify string, collapsing consecutive
+// space and newline characters into a single space.
+void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
+ bool last_char_was_space = false;
+ bufsize_t r, w;
+
+ for (r = 0, w = 0; r < s->size; ++r) {
+ if (cmark_isspace(s->ptr[r])) {
+ if (!last_char_was_space) {
+ s->ptr[w++] = ' ';
+ last_char_was_space = true;
+ }
+ } else {
+ s->ptr[w++] = s->ptr[r];
+ last_char_was_space = false;
+ }
+ }
+
+ cmark_strbuf_truncate(s, w);
+}
+
+// Destructively unescape a string: remove backslashes before punctuation chars.
+void cmark_strbuf_unescape(cmark_strbuf *buf) {
+ bufsize_t r, w;
+
+ for (r = 0, w = 0; r < buf->size; ++r) {
+ if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
+ r++;
+
+ buf->ptr[w++] = buf->ptr[r];
+ }
+
+ cmark_strbuf_truncate(buf, w);
+}