Add normal alloca() definition and implement a strdupa and friends

Change-Id: I21c9c21fd664fb11bc8496ace4a389f535a030d6
diff --git a/firmware/include/string-extra.h b/firmware/include/string-extra.h
index 6a9e0c7..9ab53d8 100644
--- a/firmware/include/string-extra.h
+++ b/firmware/include/string-extra.h
@@ -34,4 +34,38 @@
 #endif
 #endif
 
+/* copies a buffer of len bytes and null terminates it */
+static inline char * strmemcpy(char *dst, const char *src, size_t len)
+{
+    /* NOTE: for now, assumes valid parameters! */
+    *(char *)mempcpy(dst, src, len) = '\0';
+    return dst;
+}
+
+/* duplicate and null-terminate a memory block on the stack with alloca() */
+#define strmemdupa(s, l) \
+    ({ const char *___s = (s);          \
+       size_t ___l = (l);               \
+       char *___buf = alloca(___l + 1); \
+       strmemcpy(___buf, ___s, ___l); })
+
+/* strdupa and strndupa may already be provided by a system's string.h */
+
+#ifndef strdupa
+/* duplicate an entire string on the stack with alloca() */
+#define strdupa(s) \
+    ({ const char *__s = (s); \
+       strmemdupa((__s), strlen(__s)); })
+#endif /* strdupa */
+
+#ifndef strndupa
+/* duplicate a string on the stack with alloca(), truncating it if it is too
+   long */
+#define strndupa(s, n) \
+    ({ const char *__s = (s);     \
+       size_t __n = (n);          \
+       size_t __len = strlen(_s); \
+       strmemdupa(__s, MIN(__n, __len)); })
+#endif /* strndupa */
+
 #endif /* STRING_EXTRA_H */
diff --git a/firmware/libc/include/stdlib.h b/firmware/libc/include/stdlib.h
index 5755336..e24d6a5 100644
--- a/firmware/libc/include/stdlib.h
+++ b/firmware/libc/include/stdlib.h
@@ -31,6 +31,11 @@
 void *realloc(void *, size_t);
 int  atexit(void (*)(void));
 
+#ifdef  __GNUC__
+# undef  alloca
+# define alloca(size)   __builtin_alloca (size)
+#endif /* GCC.  */
+
 #define RAND_MAX INT_MAX
 
 void srand(unsigned int seed);
diff --git a/firmware/target/hosted/system-hosted.h b/firmware/target/hosted/system-hosted.h
index e60803f..5e7a7d7 100644
--- a/firmware/target/hosted/system-hosted.h
+++ b/firmware/target/hosted/system-hosted.h
@@ -22,7 +22,7 @@
 #ifndef __SYSTEM_HOSTED_H__
 #define __SYSTEM_HOSTED_H__
 
-#include "system.h"
+#ifndef __PCTOOL__
 
 static inline void commit_dcache(void) {}
 static inline void commit_discard_dcache(void) {}
@@ -34,4 +34,14 @@
     wait_for_interrupt();
 }
 
+#endif /* __PCTOOL__ */
+
+#if defined(WIN32) || defined(__PCTOOL__)
+
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+
+#endif /* WIN32 || __PCTOOL__ */
+
 #endif