internal/bytealg: support systems that don't have memmem

Change-Id: Ideddebaeeda8d57425e76ff1ea35b9c45a8b31d8
Reviewed-on: https://go-review.googlesource.com/138839
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/config.h.in b/libgo/config.h.in
index de57d0c..d47969d 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -141,6 +141,9 @@
 /* Define to 1 if you have the `matherr' function. */
 #undef HAVE_MATHERR
 
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
diff --git a/libgo/configure b/libgo/configure
index f7996e1..356ad2b 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -14781,7 +14781,7 @@
 fi
 
 
-for ac_func in strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr
+for ac_func in strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr memmem
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/libgo/configure.ac b/libgo/configure.ac
index 20ce205..e2193a5 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -544,7 +544,7 @@
 
 AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
 
-AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr)
+AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr memmem)
 AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
 AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
 
diff --git a/libgo/go/internal/bytealg/bytealg.c b/libgo/go/internal/bytealg/bytealg.c
index 39c060f..988dfaa 100644
--- a/libgo/go/internal/bytealg/bytealg.c
+++ b/libgo/go/internal/bytealg/bytealg.c
@@ -10,6 +10,33 @@
 #include "runtime.h"
 #include "array.h"
 
+#ifndef HAVE_MEMMEM
+
+#define memmem goMemmem
+
+static const void *goMemmem(const void *in, size_t inl, const void *s, size_t sl) {
+	const char *p;
+	char first;
+	const char *stop;
+
+	if (sl == 0) {
+		return in;
+	}
+	if (inl < sl) {
+		return nil;
+	}
+	first = *(const char *)(s);
+	stop = (const char *)(in) + (inl - sl);
+	for (p = (const char *)(in); p <= stop; p++) {
+		if (*p == first && __builtin_memcmp(p + 1, (const char *)(s) + 1, sl - 1) == 0) {
+			return (const void *)(p);
+		}
+	}
+	return nil;
+}
+
+#endif
+
 intgo Compare(struct __go_open_array, struct __go_open_array)
   __asm__(GOSYM_PREFIX "internal_bytealg.Compare")
   __attribute__((no_split_stack));