summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Gayot <duskcoder@gmail.com>2013-12-21 23:09:09 +0100
committerOlivier Gayot <duskcoder@gmail.com>2014-01-18 13:43:52 +0100
commit3522c68dcd38e3eef393771d65aff6de2f815da3 (patch)
treeabe4ba88238482dbfb6fdebcded3f5c3626d1c7d
parent9f25faad5fe732e498942818dc45de78ce7f3766 (diff)
rb: add ascii support
in order to be able to deal with strings (i.e null terminated), we provide a new set of functions rb_puts rb_printf / rb_vprintf rb_gets / rb_gets2
-rw-r--r--Makefile2
-rw-r--r--rb_str.h54
-rw-r--r--src/rb_str.c120
3 files changed, 175 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 62eefa6..98d1a73 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ CFLAGS += -W -Wall -std=c99 -Wextra
CFLAGS += -I./
CFLAGS += -D _GNU_SOURCE
NAME = librb.a
-SRC = src/rb.c
+SRC = src/rb.c src/rb_str.c
AR = ar rc
diff --git a/rb_str.h b/rb_str.h
new file mode 100644
index 0000000..f48d685
--- /dev/null
+++ b/rb_str.h
@@ -0,0 +1,54 @@
+#ifndef RB_STR_H
+#define RB_STR_H
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "rb.h"
+
+/*
+ * locate in the ring buffer pointed to by rb the first string ending by the
+ * string pointed to by string and return it. the string returned is
+ * allocated using malloc and should be freed by the developer.
+ * if no such delimiter can be found, NULL is returned and the ring buffer
+ * is left unmodified. Otherwise, the string is removed from it.
+ * nb: the delimiter is discarded in the returned string
+ *
+ * common use case:
+ * request = rb_gets(rb, "\r\n")
+ */
+char *rb_gets(t_rb *rb, const char *delim);
+
+/*
+ * same as the above function but takes a null terminated array of delimiters
+ * the function will return the shortest string matching the criteria.
+ * if two or more delimiters are found at the same place in the ring buffer,
+ * the longest will be discarded
+ *
+ * common use case:
+ * request = rb_gets(rb, (const char *[]){"\n", "\r", "\r\n"})
+ * which will return a request disregarding whether netcat or telnet is used
+ */
+char *rb_gets2(t_rb *rb, const char *const *delim);
+
+/*
+ * this functions writes str to the ring buffer pointed by rb. If the ring
+ * buffer is not large enough to contain all the data, the beginning will be
+ * overriden. However, a buffer overflow is not susceptible to happen.
+ */
+static inline t_rb *rb_puts(t_rb *rb, const char *str)
+{
+ return rb_put(rb, str, strlen(str));
+}
+
+t_rb *rb_vprintf(t_rb *rb, const char *fmt, va_list list);
+
+/*
+ * function which behaves like sprintf but which writes into a ring buffer
+ * if the ring buffer is not large enough to contain all the data,
+ * the beginning will be overriden. However, a buffer overflow will not occur
+ */
+ __attribute__((format(printf, 2, 3)))
+t_rb *rb_printf(t_rb *rb, const char *fmt, ...);
+
+#endif /* RB_STR_H */
diff --git a/src/rb_str.c b/src/rb_str.c
new file mode 100644
index 0000000..b80628f
--- /dev/null
+++ b/src/rb_str.c
@@ -0,0 +1,120 @@
+#include <malloc.h>
+
+#include "rb_str.h"
+
+typedef uint8_t byte;
+
+static char *__rb_gets2(t_rb *rb, const char *const *delim,
+ const byte *data, size_t size)
+{
+ char *ret = NULL;
+ char *b_ptr = NULL;
+ char *ptr;
+ size_t b_len; /* length of the current best delimiter */
+ size_t len;
+
+ for (; *delim != NULL; ++delim) {
+ len = strlen(*delim);
+ ptr = memmem(data, size, *delim, len);
+
+ if (ptr == NULL)
+ continue;
+
+ if ((b_ptr == NULL) || (ptr < b_ptr)
+ || ((ptr == b_ptr) && len > b_len))
+ {
+ b_ptr = ptr;
+ b_len = len;
+ }
+ }
+
+ if (b_ptr != NULL) {
+ ret = strndup((const char *)data, (size_t)b_ptr - (size_t)data);
+
+ /* TODO replace with an appropriate function */
+ rb_get(rb, NULL, (size_t)b_ptr - (size_t)data + b_len);
+ }
+
+ return ret;
+}
+
+char *rb_gets2(t_rb *rb, const char *const *delim)
+{
+ size_t size;
+ char *ret;
+ byte *data;
+
+ data = malloc((rb->size_filled) * sizeof(byte));
+
+ if (data == NULL) {
+ return NULL;
+ }
+
+ size = rb_peek(rb, data, rb->size_filled);
+
+ ret = __rb_gets2(rb, delim, data, size);
+
+ free(data);
+
+ return ret;
+}
+
+char *rb_gets(t_rb *rb, const char *delimit)
+{
+ char *data = malloc((rb->size_filled) * sizeof(char));
+
+ if (data == NULL) {
+ return NULL;
+ }
+
+ size_t size = rb_peek(rb, data, rb->size_filled);
+ void *ptr = memmem(data, size, delimit, strlen(delimit));
+ char *ret = NULL;
+
+ if (ptr != NULL) {
+ ret = strndup(data, (size_t)ptr - (size_t)data);
+ /*
+ * TODO replace by a function which only removes data from the
+ * ring buffer
+ */
+ rb_get(rb, data, (size_t)ptr - (size_t)data + strlen(delimit));
+ }
+
+ free(data);
+
+ return ret;
+}
+
+t_rb *rb_vprintf(t_rb *rb, const char *fmt, va_list ap)
+{
+ char *buffer;
+
+ if (vasprintf(&buffer, fmt, ap) < 0) {
+ /*
+ * TODO the manual says that the content of buffer is undefined,
+ * we should reconsider the use of vasprintf()
+ */
+
+ return rb;
+ }
+
+ rb_puts(rb, buffer);
+
+ free(buffer);
+
+ return rb;
+}
+
+ __attribute__((format(printf, 2, 3)))
+t_rb *rb_printf(t_rb *rb, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ rb_vprintf(rb, fmt, ap);
+
+ va_end(ap);
+
+ return rb;
+}