about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2021-11-06 19:05:14 +0100
committerLeah Neukirchen <leah@vuxu.org>2021-11-06 19:05:14 +0100
commit8ba5282b9982e1d49199f816a1ec4148a232d8df (patch)
treef678e7380603197aca2de723fd14bea42f9def60
parent9955555698fb864ff44defcc84c4bdd3807344af (diff)
downloadlibste-8ba5282b9982e1d49199f816a1ec4148a232d8df.tar.gz
libste-8ba5282b9982e1d49199f816a1ec4148a232d8df.tar.xz
libste-8ba5282b9982e1d49199f816a1ec4148a232d8df.zip
add comparison of several string copying variants
-rw-r--r--comparison.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/comparison.c b/comparison.c
new file mode 100644
index 0000000..65bb7de
--- /dev/null
+++ b/comparison.c
@@ -0,0 +1,230 @@
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef __GLIBC__
+#include <bsd/string.h>
+#endif
+
+#include "ste.h"
+
+/* Task: write a function that appends three char* arguments into
+   a 1024 byte fixed buffer and return a pointer to it.
+   Return NULL if the strings don't fit.  */
+
+/* Annotations of suboptimal behavior:
+   (T)  traverses the string to find the end
+   (I)  doesn't support incremental string construction
+   (L)  overhead strlen
+   (Z)  buffer is not NUL-terminated at time of truncation detection
+   */
+
+char *
+path3_stecpy(char *a, char *b, char *c)
+{
+	static char buf[1024];
+	char *end = buf + sizeof buf;
+
+	char *pos = buf;
+	pos = stecpy(pos, end, a);
+	pos = stecpy(pos, end, b);
+	pos = stecpy(pos, end, c);
+
+	if (pos == end)
+		return 0;
+	return buf;
+}
+
+char *str_ecpy(char *to, char *e, char *from);
+
+char *
+path3_strecpy(char *a, char *b, char *c)
+{
+	static char buf[1024];
+	char *end = buf + sizeof buf;
+
+	char *pos = buf;
+	pos = str_ecpy(pos, end, a);
+	pos = str_ecpy(pos, end, b);
+	pos = str_ecpy(pos, end, c);
+
+	if (pos == end - 1)  // almost the same as stecpy but easier to get wrong
+		return 0;
+	return buf;
+}
+
+char *
+path3_strncat(char *a, char *b, char *c)
+{
+	static char buf[1024];
+	size_t n = sizeof buf - 1;
+
+	buf[0] = 0;
+	if (strlen(a) > n)	// (L)
+		return 0;
+	strncat(buf, a, n);
+	n -= strlen(a);		// (L)
+	if (strlen(b) > n)	// (L)
+		return 0;
+	strncat(buf, b, n);	// (T)
+	n -= strlen(b);		// (L)
+	if (strlen(c) > n)	// (L)
+		return 0;
+	strncat(buf, c, n);	// (T)
+
+	return buf;
+}
+
+char *
+path3_strlcat(char *a, char *b, char *c)
+{
+	static char buf[1024];
+
+	strlcpy(buf, a, sizeof buf);
+	strlcat(buf, b, sizeof buf);   // (T)
+	if (strlcat(buf, c, sizeof buf) >= sizeof buf)   // (T)
+		return 0;
+
+	return buf;
+}
+
+char *
+path3_snprintf(char *a, char *b, char *c)
+{
+	static char buf[1024];
+
+	if (snprintf(buf, sizeof buf, "%s%s%s", a, b, c) >= sizeof buf)   // (I)
+		return 0;
+
+	return buf;
+}
+
+ssize_t str_scpy(char *dst, const char *src, size_t count);
+
+char *
+path3_strscpy(char *a, char *b, char *c)
+{
+	static char buf[1024];
+
+	ssize_t r;
+	size_t l = 0;
+	r = str_scpy(buf + l, a, sizeof buf - l);
+	if (r < 0)
+		return 0;
+	l += r;
+	r = str_scpy(buf + l, b, sizeof buf - l);
+	if (r < 0)
+		return 0;
+	l += r;
+	r = str_scpy(buf + l, c, sizeof buf - l);
+	if (r < 0)
+		return 0;
+
+	return buf;
+}
+
+char *
+path3_memcpy(char *a, char *b, char *c)
+{
+	static char buf[1024];
+	size_t s = 0;
+
+	if (strlen(a) >= sizeof buf - s)   // (L)
+		return 0;
+	memcpy(buf + s, a, strlen(a));
+	s += strlen(a);
+
+	if (strlen(b) >= sizeof buf - s)   // (L)
+		return 0;
+	memcpy(buf + s, b, strlen(b));
+	s += strlen(b);
+
+	if (strlen(c) >= sizeof buf - s)   // (L)
+		return 0;
+	memcpy(buf + s, c, strlen(c));
+
+	return buf;
+}
+
+size_t str_copyb(char *s, const char *t, size_t max);
+
+char *
+path3_str_copyb(char *a, char *b, char *c)
+{
+	static char buf[1024];
+
+	size_t n = 0;
+
+	n += str_copyb(buf + n, a, sizeof buf - n);
+	if (n == sizeof buf)
+		return 0;	// (Z)
+	n += str_copyb(buf + n, b, sizeof buf - n);
+	if (n == sizeof buf)
+		return 0;	// (Z)
+	n += str_copyb(buf + n, c, sizeof buf - n);
+	if (n == sizeof buf)
+		return 0;	// (Z)
+
+	return buf;
+}
+
+int
+main()
+{
+	printf("%s\n", path3_stecpy("abc", "def", "ghi"));
+	printf("%s\n", path3_strecpy("abc", "def", "ghi"));
+	printf("%s\n", path3_strncat("abc", "def", "ghi"));
+	printf("%s\n", path3_strlcat("abc", "def", "ghi"));
+	printf("%s\n", path3_snprintf("abc", "def", "ghi"));
+	printf("%s\n", path3_strscpy("abc", "def", "ghi"));
+	printf("%s\n", path3_memcpy("abc", "def", "ghi"));
+	printf("%s\n", path3_str_copyb("abc", "def", "ghi"));
+}
+
+
+
+/* Plan 9 strecpy(3) */
+char*
+str_ecpy(char *to, char *e, char *from)
+{
+	if (to >= e)
+		return to;
+
+	to = memccpy(to, from, '\0', e - to);
+	if (!to) {
+		to = e - 1;
+		*to = '\0';
+	} else {
+		to--;
+	}
+
+	return to;
+}
+
+/* Linux kernel strscpy */
+ssize_t
+str_scpy(char *dst, const char *src, size_t count)
+{
+        if (count == 0)
+                return -E2BIG;  // no space for trailing null
+
+        char *end = memccpy(dst, src, 0, count);
+        if (!end) {
+                dst[count] = 0;
+                return -E2BIG;
+        }
+
+        return end - dst - 1;
+}
+
+/* djb-style, but with proper integer widths */
+size_t
+str_copyb(char *s, const char *t, size_t max)
+{
+	size_t len = 0;
+
+	while (max-- > 0) {
+		if (!(*s = *t)) { return len; } ++s; ++t; ++len;
+	}
+
+	return len;
+}