From 931d716e1000b50a66b012815a412619d16fc957 Mon Sep 17 00:00:00 2001
From: Haru <haru@dotalux.com>
Date: Mon, 22 Feb 2016 20:55:20 +0100
Subject: Implemented aStrndup()

- aStrndup() behaves similarly to the POSIX function strdup(). It
  allocates sufficient memory for a copy of the passed string, copies
  it, and returns a pointer to the copy. A maximum number of characters
  is copied (and a NUL terminator is always appended after the end).

Signed-off-by: Haru <haru@dotalux.com>
---
 src/common/memmgr.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/common/memmgr.h |  2 ++
 2 files changed, 65 insertions(+)

diff --git a/src/common/memmgr.c b/src/common/memmgr.c
index 6b01eb846..15e55fbeb 100644
--- a/src/common/memmgr.c
+++ b/src/common/memmgr.c
@@ -184,6 +184,36 @@ char* aStrdup_(const char *p, const char *file, int line, const char *func)
 	}
 	return ret;
 }
+
+/**
+ * Copies a string to a newly allocated buffer, setting a maximum length.
+ *
+ * The string is always NULL-terminated. If the string is longer than `size`,
+ * then `size` bytes are copied, not including the appended NULL terminator.
+ *
+ * @warning
+ *   If malloc is out of memory, throws a fatal error and aborts the program.
+ *
+ * @param p the source string to copy.
+ * @param size The maximum string length to copy.
+ * @param file @see ALC_MARK.
+ * @param line @see ALC_MARK.
+ * @param func @see ALC_MARK.
+ * @return the copied string.
+ */
+char *aStrndup_(const char *p, size_t size, const char *file, int line, const char *func)
+{
+	size_t len = strnlen(p, size);
+	char *ret = MALLOC(len + 1, file, line, func);
+	if (ret == NULL) {
+		ShowFatalError("%s:%d: in func %s: aStrndup error out of memory!\n", file, line, func);
+		exit(EXIT_FAILURE);
+	}
+	memcpy(ret, p, len);
+	ret[len] = '\0';
+	return ret;
+}
+
 void aFree_(void *p, const char *file, int line, const char *func)
 {
 	// ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p);
@@ -478,6 +508,37 @@ char *mstrdup_(const char *p, const char *file, int line, const char *func) {
 	}
 }
 
+/**
+ * Copies a string to a newly allocated buffer, setting a maximum length.
+ *
+ * The string is always NULL-terminated. If the string is longer than `size`,
+ * then `size` bytes are copied, not including the appended NULL terminator.
+ *
+ * @warning
+ *   If malloc is out of memory, throws a fatal error and aborts the program.
+ *
+ * @param p the source string to copy.
+ * @param size The maximum string length to copy.
+ * @param file @see ALC_MARK.
+ * @param line @see ALC_MARK.
+ * @param func @see ALC_MARK.
+ * @return the copied string.
+ * @retval NULL if the source string is NULL or in case of error.
+ */
+char *mstrndup_(const char *p, size_t size, const char *file, int line, const char *func)
+{
+	if (p == NULL) {
+		return NULL;
+	} else {
+		size_t len = strnlen(p, size);
+		char *string = iMalloc->malloc(len + 1, file, line, func);
+		memcpy(string, p, len);
+		string[len] = '\0';
+		return string;
+	}
+}
+
+
 void mfree_(void *ptr, const char *file, int line, const char *func) {
 	struct unit_head *head;
 
@@ -947,6 +1008,7 @@ void malloc_defaults(void) {
 	iMalloc->realloc  = mrealloc_;
 	iMalloc->reallocz = mreallocz_;
 	iMalloc->astrdup  = mstrdup_;
+	iMalloc->astrndup = mstrndup_;
 	iMalloc->free     = mfree_;
 #else
 	iMalloc->malloc   = aMalloc_;
@@ -954,6 +1016,7 @@ void malloc_defaults(void) {
 	iMalloc->realloc  = aRealloc_;
 	iMalloc->reallocz = aReallocz_;/* not using memory manager huhum o.o perhaps we could still do something about */
 	iMalloc->astrdup  = aStrdup_;
+	iMalloc->astrndup = aStrndup_;
 	iMalloc->free     = aFree_;
 #endif
 	iMalloc->post_shutdown = NULL;
diff --git a/src/common/memmgr.h b/src/common/memmgr.h
index 5975f55c4..680947466 100644
--- a/src/common/memmgr.h
+++ b/src/common/memmgr.h
@@ -52,6 +52,7 @@
 #	define aRealloc(p,n) (iMalloc->realloc((p),(n),ALC_MARK))
 #	define aReallocz(p,n) (iMalloc->reallocz((p),(n),ALC_MARK))
 #	define aStrdup(p)    (iMalloc->astrdup((p),ALC_MARK))
+#	define aStrndup(p,n) (iMalloc->astrndup((p),(n),ALC_MARK))
 #	define aFree(p)      (iMalloc->free((p),ALC_MARK))
 
 /////////////// Buffer Creation /////////////////
@@ -85,6 +86,7 @@ struct malloc_interface {
 	void* (*realloc)(void *p, size_t size, const char *file, int line, const char *func);
 	void* (*reallocz)(void *p, size_t size, const char *file, int line, const char *func);
 	char* (*astrdup)(const char *p, const char *file, int line, const char *func);
+	char *(*astrndup)(const char *p, size_t size, const char *file, int line, const char *func);
 	void  (*free)(void *p, const char *file, int line, const char *func);
 	/* */
 	void (*memory_check)(void);
-- 
cgit v1.2.3-70-g09d2