From a7badc76b6db41797b31f28e29d03002d9fce79e Mon Sep 17 00:00:00 2001
From: Mario Domenech Goulart <mario.goulart@gmail.com>
Date: Fri, 27 Jun 2014 15:50:18 -0300
Subject: [PATCH] C_substring_copy: use C_memmove instead of C_memcpy when s1
 and s2 are the same string

Fixes #1135 (related to string-copy!).
---
 chicken.h               |   11 ++++++++---
 tests/srfi-13-tests.scm |   12 ++++++++++++
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/chicken.h b/chicken.h
index 4a3c77a..59e518f 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1260,9 +1260,14 @@ extern double trunc(double);
 #define C_i_char_greater_or_equal_p(x, y)  C_mk_bool(C_character_code(x) >= C_character_code(y))
 #define C_i_char_less_or_equal_p(x, y)  C_mk_bool(C_character_code(x) <= C_character_code(y))
 #define C_substring_copy(s1, s2, start1, end1, start2) \
-                                        (C_memcpy((C_char *)C_data_pointer(s2) + C_unfix(start2), \
-                                                  (C_char *)C_data_pointer(s1) + C_unfix(start1), \
-                                                  C_unfix(end1) - C_unfix(start1) ), C_SCHEME_UNDEFINED)
+                                       ((C_char *)C_data_pointer(s1) == (C_char *)C_data_pointer(s2)    \
+                                         ?    C_memmove((C_char *)C_data_pointer(s2) + C_unfix(start2), \
+                                                        (C_char *)C_data_pointer(s1) + C_unfix(start1), \
+                                                        C_unfix(end1) - C_unfix(start1) ) \
+                                         :    C_memcpy((C_char *)C_data_pointer(s2) + C_unfix(start2), \
+                                                       (C_char *)C_data_pointer(s1) + C_unfix(start1), \
+                                                       C_unfix(end1) - C_unfix(start1) ) \
+                                         , C_SCHEME_UNDEFINED)
 #define C_substring_compare(s1, s2, start1, start2, len) \
                                         C_mk_bool(C_memcmp((C_char *)C_data_pointer(s1) + C_unfix(start1), \
                                                            (C_char *)C_data_pointer(s2) + C_unfix(start2), \
diff --git a/tests/srfi-13-tests.scm b/tests/srfi-13-tests.scm
index 1262b82..8df378a 100644
--- a/tests/srfi-13-tests.scm
+++ b/tests/srfi-13-tests.scm
@@ -115,6 +115,18 @@
        (let ((x (string-copy "abcdefg")))
          (string-copy! x 2 "ZABCDEFG" 3 6)
          x))
+
+;; From Guile.  Thanks to Mark H Weaver.
+(test "string-copy!: overlapping src and dest, moving right"
+      "aabce"
+      (let ((str (string-copy "abcde")))
+	(string-copy! str 1 str 0 3) str))
+
+(test "string-copy!: overlapping src and dest, moving left"
+      "bcdde"
+      (let ((str (string-copy "abcde")))
+	(string-copy! str 0 str 1 4) str))
+
 (test "string-take" "Pete S"  (string-take "Pete Szilagyi" 6))
 (test "string-take" ""        (string-take "Pete Szilagyi" 0))
 (test "string-take" "Pete Szilagyi" (string-take "Pete Szilagyi" 13))
-- 
1.7.10.4

