xref: /csrg-svn/lib/libc/string/memmove.c (revision 41956)
1*41956Sbostic /*-
2*41956Sbostic  * Copyright (c) 1990 The Regents of the University of California.
3*41956Sbostic  * All rights reserved.
4*41956Sbostic  *
5*41956Sbostic  * This code is derived from software contributed to Berkeley by
6*41956Sbostic  * Chris Torek.
7*41956Sbostic  *
8*41956Sbostic  * %sccs.include.redist.c%
9*41956Sbostic  */
10*41956Sbostic 
11*41956Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*41956Sbostic static char sccsid[] = "@(#)memmove.c	5.1 (Berkeley) 05/15/90";
13*41956Sbostic #endif /* LIBC_SCCS and not lint */
14*41956Sbostic 
15*41956Sbostic #include <string.h>
16*41956Sbostic #include <sys/stdc.h>
17*41956Sbostic 
18*41956Sbostic /*
19*41956Sbostic  * sizeof(word) MUST BE A POWER OF TWO
20*41956Sbostic  * SO THAT wmask BELOW IS ALL ONES
21*41956Sbostic  */
22*41956Sbostic typedef int word;		/* "word" used for optimal copy speed */
23*41956Sbostic 
24*41956Sbostic #define	wsize	sizeof(word)
25*41956Sbostic #define	wmask	(wsize - 1)
26*41956Sbostic 
27*41956Sbostic /*
28*41956Sbostic  * Copy a block of memory, handling overlap.
29*41956Sbostic  */
30*41956Sbostic void *
31*41956Sbostic memmove(dst0, src0, length)
32*41956Sbostic 	void *dst0;
33*41956Sbostic 	const void *src0;
34*41956Sbostic 	register size_t length;
35*41956Sbostic {
36*41956Sbostic 	register char *dst = dst0;
37*41956Sbostic 	register const char *src = src0;
38*41956Sbostic 	register size_t t;
39*41956Sbostic 
40*41956Sbostic 	if (length == 0 || dst == src)
41*41956Sbostic 		return (dst0);	/* nothing to do */
42*41956Sbostic 
43*41956Sbostic 	/*
44*41956Sbostic 	 * Macros: loop-t-times; and loop-t-times, t>0
45*41956Sbostic 	 */
46*41956Sbostic #if mc68000 /* encourage dbra */
47*41956Sbostic #define	TLOOP(s) TLOOP1(s)
48*41956Sbostic #define	TLOOP1(s) while (--t != -1) { s; }
49*41956Sbostic #else
50*41956Sbostic #define	TLOOP(s) if (t) TLOOP1(s)
51*41956Sbostic #define	TLOOP1(s) do { s; } while (--t)
52*41956Sbostic #endif
53*41956Sbostic 
54*41956Sbostic 	if ((unsigned long)dst < (unsigned long)src) {
55*41956Sbostic 		/*
56*41956Sbostic 		 * Copy forward.
57*41956Sbostic 		 */
58*41956Sbostic 		t = (int)src;	/* only need low bits */
59*41956Sbostic 		if ((t | (int)dst) & wmask) {
60*41956Sbostic 			/*
61*41956Sbostic 			 * Try to align operands.  This cannot be done
62*41956Sbostic 			 * unless the low bits match.
63*41956Sbostic 			 */
64*41956Sbostic 			if ((t ^ (int)dst) & wmask || length < wsize)
65*41956Sbostic 				t = length;
66*41956Sbostic 			else
67*41956Sbostic 				t = wsize - (t & wmask);
68*41956Sbostic 			length -= t;
69*41956Sbostic 			TLOOP1(*dst++ = *src++);
70*41956Sbostic 		}
71*41956Sbostic 		/*
72*41956Sbostic 		 * Copy whole words, then mop up any trailing bytes.
73*41956Sbostic 		 */
74*41956Sbostic 		t = length / wsize;
75*41956Sbostic 		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
76*41956Sbostic 		t = length & wmask;
77*41956Sbostic 		TLOOP(*dst++ = *src++);
78*41956Sbostic 	} else {
79*41956Sbostic 		/*
80*41956Sbostic 		 * Copy backwards.  Otherwise essentially the same.
81*41956Sbostic 		 * Alignment works as before, except that it takes
82*41956Sbostic 		 * (t&wmask) bytes to align, not wsize-(t&wmask).
83*41956Sbostic 		 */
84*41956Sbostic 		src += length;
85*41956Sbostic 		dst += length;
86*41956Sbostic 		t = (int)src;
87*41956Sbostic 		if ((t | (int)dst) & wmask) {
88*41956Sbostic 			if ((t ^ (int)dst) & wmask || length <= wsize)
89*41956Sbostic 				t = length;
90*41956Sbostic 			else
91*41956Sbostic 				t &= wmask;
92*41956Sbostic 			length -= t;
93*41956Sbostic 			TLOOP1(*--dst = *--src);
94*41956Sbostic 		}
95*41956Sbostic 		t = length / wsize;
96*41956Sbostic 		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
97*41956Sbostic 		t = length & wmask;
98*41956Sbostic 		TLOOP(*--dst = *--src);
99*41956Sbostic 	}
100*41956Sbostic 	return (dst0);
101*41956Sbostic }
102