Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kcc-5/lib/memstr.c
There are 7 other files named memstr.c in the archive. Click here to see a list.
/*
** MEMSTR - KCC Byte String library routines.
**
** Contains ANSI functions MEMSET, MEMCPY, MEMCMP, MEMCHR.
** Also S5/BSD function MEMCCPY.
** Also BSD routines BZERO, BCOPY, BCMP.
** (C) Copyright 1986 by Ken Harrenstien, SRI International
**
** BSD functions:
** BZERO(cp1, cnt) - Zero byte string
** BCOPY(from, to, cnt) - Copy byte string
** BCMP(cp1, cp2, cnt) - Compare byte strings
** char *cp1, *cp2, *from, *to;
** int cnt;
**
** These routines are written in assembler to take advantage
** of special machine instructions such as BLT which greatly speed up
** execution.
*/
#include "c-env.h"
#include "string.h" /* Get our declarations! */
#if CPU_PDP10
static void
tablestuff() /* Dummy to include extra assembler stuff */
{
#asm
A=1 /* KCC functions return value in this AC */
B=2
C=3
D=C+1
E=D+1
T=E+1
TT=7
P=17
%brkev==17 /* Use 15. chars as breakeven point. This length or less */
/* uses default byte-by-byte loop; more than this invokes */
/* hairy optimization code. */
/* Assumption is that all code in PDP-10 C will never use any char ptrs */
/* for other than 7, 8, or 9 bytes. We further assume that while */
/* running non-extended, only local-format BPs will be seen, and when */
/* running extended (in non-zero section), only global one-word BPs */
/* will be seen. There are a few places where the code checks on this */
/* (when convenient) but recovery from abuse cannot always be relied */
/* on. Note that the KL string instructions such as MOVSLJ are not */
/* generally used, first because they do not exist on KA/KI processors, */
/* and second because they are not much faster than a regular byte */
/* loop! */
/* Global-format P&S table
** <Local LH>,,<#bytes/wd><00><offset> ; <Global P&S>
*/
$$gbpt: 0 /* 44 - really a local-fmt ptr! */
/* 6-bit bytes: size 06 */
440600,,060000 /* 45 */
360600,,060000 /* 46 */
300600,,060005 /* 47 */
220600,,060004 /* 50 */
140600,,060003 /* 51 */
060600,,060002 /* 52 */
000600,,060001 /* 53 */
/* 8-bit bytes (size 10) */
441000,,040000 /* 54 */
341000,,040000 /* 55 */
241000,,040003 /* 56 */
141000,,040002 /* 57 */
041000,,040001 /* 60 */
/* 7-bit bytes (size 07) */
440700,,050000 /* 61 */
350700,,050000 /* 62 */
260700,,050004 /* 63 */
170700,,050003 /* 64 */
100700,,050002 /* 65 */
010700,,050001 /* 66 */
/* 9-bit bytes (size 11) */
441100,,040000 /* 67 */
331100,,040000 /* 70 */
221100,,040003 /* 71 */
111100,,040002 /* 72 */
001100,,040001 /* 73 */
/* 18-bit bytes (size 22) */
442200,,020000 /* 74 */
222200,,020000 /* 75 */
002200,,020001 /* 76 */
000000,,0 /* 77 ; Illegal */
#endasm /* End of table and declaration stuff */
}
#endif /* CPU_PDP10 */
/* BSD functions BZERO, BCOPY, BCMP
*/
void
bzero(array, n)
char *array; /* Address of byte array */
int n; /* number of bytes in array to zero */
{
(void) memset(array, 0, n);
}
void
bcopy(from, to, n)
char *from, *to;
int n;
{
(void) memcpy(to, from, n); /* Standard routine has args in other order! */
}
int
bcmp(array1, array2, n)
char *array1, *array2;
int n;
{
return memcmp(array1, array2, n); /* Can do tail recursion here! */
}
/************************* MEMSET *******************************/
char *
memset(s, c, n)
char *s;
register int c;
register int n;
{
#if !(CPU_PDP10)
if (n > 0) {
register char *to = s;
*to = c;
do *++to = c;
while (--n);
}
return s;
#else /* CPU_PDP10 */
#asm
skipg d,-3(p) /* Get # of bytes */
jrst bzeret /* Count negative or zero */
skipn c,-1(p) /* Get char pointer (byte ptr) */
jrst bzeret /* Ignore if pointer zero. */
skipe a,-2(p) /* Get the char value to use */
jrst bzero1 /* If not zero, for now use simple byte loop, ugh. */
caile d,%brkev /* More bytes than breakeven point? */
jrst bzerhk /* Yes, try to do special stuff! */
/* Not enough bytes to make fancy hacking worthwhile. */
bzero1: dpb a,c /* Set first byte. */
sojle d,bzeret /* Then decrement count and fall into loop. */
idpb a,c
sojg d,.-1
bzeret: move 1,-1(p) /* Sigh, must return original pointer! Barf. */
popj p,
/* Try to do fancy stuff. */
bzerhk: jumpge p,bzerox /* Jump if extended (pdl ptr positive) */
/* Non-extended fancy stuff for zeroing. */
/* Assume local-format byte pointer. */
/* First zero bytes until at beg of word... */
bzer30: dpb a,c
sojle d,bzeret
bzero4: idpb a,c
tlne c,720000 /* Stop when P=0 (6, 9, 18 bits) or 4 (8) or 1 (7) */
sojg d,bzero4
sojl d,bzeret
/* (c)+1 now points to words to clear. Must find how many */
/* words, plus remaining # bytes, to clear. Requires determining */
/* byte size, ugh. Assumes one of 6,7,8,9,18. */
tlnn c,001000 /* 8 or 9? */
jrst [ tlnn c,000400 /* 7? */
jrst [ tlnn c,002000 /* 6 or 18? */
jrst [ idivi d,6 /* 6 */
jrst bzero5]
lsh d,-1 /* 18 */
lsh e,-<44-1> /* Set up remainder */
jrst bzero5]
idivi d,5 /* 7 */
jrst bzero5]
lshc d,-2 /* Divide by 4 ; 8 or 9 */
lsh e,-<44-2> /* Get remainder right-justified. */
bzero5: setzm 1(c) /* Clear 1st word */
movsi b,1(c) /* <from>,, */
hrri b,2(c) /* ,,<to> */
addi c,(d) /* Get addr of last word (BP points to end) */
blt b,(c) /* Zero the words */
jumple e,bzeret /* Take care of any remaining bytes. */
idpb a,c
sojg e,.-1
jrst bzeret
/* Running in non-zero section, so assume BP is global one-wd format. */
/* d/ # bytes */
/* c/ bp */
/* a/ 0 */
bzerox: ldb b,[360600,,c] /* Get the 6-bit P&S field */
skipg e,$$gbpt-44(b) /* Get table entry for it */
jrst [ ibp c /* Odd - ensure points to 1st byte. */
jumpl c,.+1 /* If not still global fmt, was a 44 local! */
jrst bzer30] /* Try to hack it as local-fmt ptr. */
andi e,77 /* Get # bytes of roundup needed. */
jumple e,bzerx4(e) /* If 0, skip rounding. */
subi d,(e) /* Subtract # of bytes we will clear here */
dpb a,c
sojle e,bzerx3
idpb a,c
sojg e,.-1
bzerx3: ibp c /* -1 adjust BP then treat like 0 */
bzerx4: /* 0 BP is word-aligned. */
/* C/ BP pointing to 1st byte in word */
/* D/ # bytes left to clear */
ldb e,[140600,,$$gbpt-44(b)] /* Get # bytes per word */
idivi d,(e) /* Get # words to zap, remaining # bytes in e. */
jumple d,[skiple d,e
jrst bzero1 /* If more bytes to zero, use byte loop. */
jrst bzeret]
move b,e /* Save remainder */
move e,c /* Get "source" BP */
tlz e,770000 /* Clear the P&S field */
xmovei t,1(e) /* Get "dest" addr (1 greater) */
setzm (e) /* Zap 1st word */
sosle d
xblt==<020000,,0>
extend d,[xblt] /* Do extended BLT */
skipg d,b /* Now check for remaining bytes */
jrst bzeret /* None, all done. */
dpb t,[003600,,c] /* Put final dest addr +1 back in BP */
jrst bzero1 /* More bytes to zero, use byte loop. */
#endasm
#endif /* CPU_PDP10 */ /* End of MEMSET */
}
/********************* MEMCPY *****************************/
char *
memcpy(s1, s2, n)
char *s1; /* To here */
register char *s2; /* From here */
register int n; /* number of bytes to copy */
{
#if !(CPU_PDP10)
register char * to = s1;
if(n > 0) do { *to++ = *s2++; } while(--n);
return s1;
#else /* CPU_PDP10 */
#asm
/* General AC usage: */
/* a,b/ scratch */
/* c/ # bytes */
/* d/ # remainder */
/* e/ Source BP (from) */
/* t/ Dest BP (to) */
skipg c,-3(p) /* Get 3rd arg, # of bytes */
jrst bcpret /* Nothing to copy, just return */
caig c,%brkev /* Ensure worthwhile to do hairy stuff. */
jrst bcpy40 /* Naw, just do trivially. */
skipge e,-2(p) /* Get 2nd arg, source BP */
jrst bcpy50 /* Sign bit set, assume global ptr. */
skipg t,-1(p) /* Assume local fmt, get 1st arg, dest BP */
jrst bcpy42 /* Not same fmt, for now default to trivial case. */
/* Both BPs are local format; make final check for sameness */
bcpy10: move a,e
xor a,t /* XOR the two byte pointers */
tlne a,-1 /* Check for same LH */
jrst [ tlnn a,007700 /* Nope - check for same size... */
tlnn a,770000 /* Size same, check for alignment */
jrst bcpy42 /* Must use byte loop; size different, or */
/* using indexing/indirection (ugh!) */
jrst bcpy60] /* Same size, different alignment, go do hair. */
/* Local-format BPs have same size and alignment, so hack */
/* BLT word-move optimization! */
caml e,[331100,,0] /* Must be 331100, 341000, 350700, or 360600. */
jrst bcpy33 /* Points to beg of word! */
/* This test flunks 18-bit start (222200) but */
/* we'll put up with that. */
/* Doesnt point to beg of word, must get things aligned. */
ldb a,e
dpb a,t
jrst bcpy32
bcpy31: ildb a,e
idpb a,t
bcpy32: tlne e,720000 /* Stop when P=0 (6,9,18) or 04 (8) or 01 (7). */
sojg c,bcpy31
sojle c,bcpy90
ibp e /* Then point to beg of next wd. */
ibp t
/* (E) and (T) now point to word locs for moving (from, to). */
/* Find # words, plus remaining # bytes, to move. Requires determining */
/* byte size, ugh. Assumes one of 6,7,8,9,18. */
bcpy33: tlnn t,001000 /* 8 or 9? */
jrst [ tlnn t,000400 /* 7? */
jrst [ tlnn t,002000 /* 6 or 18? */
jrst [ idivi c,6 /* 6 */
jrst bcpy34]
lsh c,-1 /* 18 */
lsh d,-<44-1> /* Set up remainder */
jrst bcpy34]
idivi c,5 /* 7 */
jrst bcpy34]
lshc c,-2 /* Divide by 4 ; 8 or 9 */
lsh d,-<44-2> /* Get remainder right-justified. */
/* c/ # wds */
/* d/ # bytes remainder */
bcpy34: jumple c,bcpy35
movsi b,(e) /* <from>,, */
hrri b,(t) /* ,,<to> */
addi t,(c) /* Get addr of last word + 1 (BP points to end) */
blt b,-1(t) /* Copy the words */
bcpy35: caig d,0 /* Take care of any remaining bytes */
jrst bcpret /* Done. */
addi e,(c) /* Sigh, must also point to last source word. */
move c,d
jrst bcpy42 /* Go copy the remainder by hand (start with LDB) */
/* Trivial case. Strings which dont have same alignment or size */
/* all come here. */
/* Note that the KL extended instruction MOVSLJ is */
/* slightly faster than this byte loop, but tis painful to */
/* conditionalize this. MOVSLJ is done for global BPs however */
/* since then we know the instruction will exist. */
bcpy40: skipe e,-2(p) /* Source BP */
skipn t,-1(p) /* Dest BP */
jrst bcpret /* Null pointer arg, just return. */
jumpl t,bcpy45 /* If using global-format BPs, use MOVSLJ. */
bcpy42: ldb a,e /* Get byte */
dpb a,t /* Store it */
sojle c,bcpy90
bcpy43: ildb a,e
idpb a,t
sojg c,bcpy43
bcpy90:
bcpret: move 1,-1(p) /* Sigh, must return s1 as result, bletch */
popj p,
/* Trivial case using MOVSLJ. */
/* First need to get BPs into canonical shape. */
bcpy45: ldb a,e /* Get byte */
dpb a,t /* Store it */
sojle c,bcpy90
move a,c /* AC+0: source string length */
move b,e /* AC+1,2: source byte ptr */
move d,c /* AC+3: dest string length */
move e,t /* AC+4,5: dest byte ptr */
MOVSLJ==:<016000,,0> /* Subinstr of EXTEND */
EXTEND A,[MOVSLJ] /* DO IT! */
trn
jrst bcpret
#endasm
#asm
/*;;;;;;;;;;;;;;;;;;;;;; MEMCPY (cont) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
/* Global-format BP hacking. Already have source BP in e. */
bcpy50: skipl t,-1(p) /* Get dest BP (to) */
jrst bcpy42 /* Not same format, handle as trivial slow case. */
/* c/ # bytes */
/* e/ Source BP */
/* t/ Dest BP */
ldb b,[360600,,e] /* Get P&S field for source */
ldb d,[360600,,t] /* Ditto for dest */
caie b,(d)
jrst [ move a,$$gbpt-44(b) /* Different size or alignment. Check. */
xor a,$$gbpt-44(d)
tlne a,007700 /* See if have same byte size */
jrst bcpy45 /* No, must hack like trivial case. */
jrst bcpy56] /* Same size, do word-move hair. */
/* P&S field is identical, so BPs are word-aligned and we can do */
/* fast BLT! */
skipg d,$$gbpt-44(b) /* Get table entry for it */
jrst [ ibp e /* Hmm, ensure points to 1st byte. */
ibp t
jumpl e,bcpy55 /* Ensure still global-fmt ptrs... */
jrst bcpy10] /* Ugh, must have been local-fmt with P=44! */
andi d,77 /* Get # bytes of roundup needed. */
jumple d,bcpy55 /* If 0, skip rounding. */
subi c,(d) /* Subtract # of bytes we will copy here */
ldb a,e
dpb a,t
sojle d,bcpy54
bcpy53: ildb a,e
idpb a,t
sojg d,bcpy53
bcpy54: ibp e
ibp t
ldb b,[360600,,t] /* Get P&S field again */
/* BPs are now word-aligned (point to 1st byte in word). */
bcpy55: ldb d,[140600,,$$gbpt-44(b)] /* Get # bytes per word */
idivi c,(d) /* Get # words (remainder in d) */
exch c,d
jumple d,[jumpg c,bcpy42
jrst bcpret] /* Return */
/* Set up to transfer at least 1 word. */
tlz e,770000 /* Must flush P&S field from BPs */
tlz t,770000
EXTEND D,[XBLT] /* Do it! */
jumple c,bcpy90 /* If no remaining bytes, done. */
rot b,-6 /* Must put P&S field back (alignment is OK) */
ior e,b
ior t,b
jrst bcpy42 /* Then finish off with byte-loop copy. */
/* Handle word-move hair for global-format BPs which have same */
/* byte size but different alignment. */
bcpy56: cail d,70 /* Only hack 9-bit bytes for now. */
caile d,73
jrst bcpy45
/* Must get dest ptr to beg of word */
bcpy57: tlnn t,070000 /* Check for value 70 */
jrst bcpy58
ldb a,e
dpb a,t
ibp e
ibp t
sojg c,bcpy57
jrst bcpret /* Return */
bcpy58: ldb tt,[360600,,e] /* Save current source-BP P&S */
tlz e,770000 /* Flush P&S so can do indexing */
tlz t,770000
lshc c,-2 /* Divide by 2 */
lsh d,-<44-2> /* Get remainder in D */
move a,(e) /* Get 1st source word */
aoja e,@<.+1-70>(tt) /* Dispatch on P of 70-73 */
setz bcpx90 /* P=70=33, beg of word (shouldnt happen) */
setz bcpx91 /* P=71=22, 3 bytes needed from source wd */
setz bcpx92 /* P=72=11, 2 bytes needed from source wd */
setz bcpx93 /* P=73=00, 1 byte needed from source wd */
bcpy59: skipg c,d
jrst bcpret /* Return */
ior t,[700000,,0] /* Set dest P=70=33, beg of word */
rot tt,-6
ior e,tt /* Set source P to original val */
soja e,bcpy42
bcpx90: jrst bcpret /* Return */
/* Source P=71=22, 3 valid bytes in A */
bcpx91: move b,(e)
lshc a,<11*1>
movem a,(t)
lshc a,<11*<4-1>>
addi e,1 /* Sigh... for extended addrs */
addi t,1
sojg c,bcpx91
jrst bcpy59
/* Source P=11, 2 valid bytes in A */
bcpx92: move b,(e)
lshc a,<11*2>
movem a,(t)
lshc a,<11*<4-2>>
addi e,1
addi t,1
sojg c,bcpx92
jrst bcpy59
/* Source P=00, 1 valid byte in A */
bcpx93: move b,(e)
lshc a,<11*3>
movem a,(t)
lshc a,<11*<4-3>>
addi e,1
addi t,1
sojg c,bcpx93
jrst bcpy59
#endasm
#asm
/*;;;;;;;;;;;;;;;;;;;;;; MEMCPY (cont) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
/* Special hair to handle case of byte strings which are same size */
/* but do not have same alignment (so BLT cannot be done). We can still */
/* save a considerable amount of time by using word moves and shifts, which */
/* are 3 to 5 times faster than the alternatives (timed on a 2060): */
/* Hairy stuff: .7-.8 usec/char */
/* ILDB/IDPB: 3.5 usec/char */
/* MOVSLJ: 2.1 usec/char */
/* C/ count */
/* E/ source BP (local fmt) */
/* T/ Dest BP (local fmt) */
/* First order of business is getting dest ptr word-aligned. */
bcpy60: caml t,[331100,,0]
jrst bcpy63 /* Already word-aligned (unless 18-bit bp 222200) */
ldb a,e
dpb a,t
jrst bcpy62
bcpy61: ildb a,e
idpb a,t
bcpy62: tlne t,720000 /* Stop when P=00 or 04 or 01. */
sojg c,bcpy61
sojle c,bcpy90
ibp e
ibp t
/* Dest is now word-aligned. Further steps depend on byte size. */
bcpy63: tlnn t,000100 /* 7 or 9 bits? (07 or 11) */
jrst bcpy42 /* Nope, just punt for now. */
tlnn t,001000 /* 9-bit bytes? */
jrst bcpy70 /* Nope, 7-bit, go do them. */
/* Copy unaligned 9-bit bytes! */
lshc c,-2 /* Divide by 4 */
lsh d,-<44-2> /* Get 2 bits of remainder right-justified. */
ldb b,[360200,,e] /* Get low 2 bits of P from source BP */
move a,(e) /* Get 1st source word set up. */
aoja e,@.+1(b) /* Dispatch on value of 0,1,2,3. */
/* Note sign bit (SETZ) must be set to prevent extended-format */
/* indirection when in non-zero section. Barf. */
setz bcpy66 /* 0 = P=00, 1 byte needed from source wd */
setz bcpy65 /* 1 = P=11, 2 bytes needed from source wd */
setz bcpy64 /* 2 = P=22, 3 bytes needed from source wd */
setz bcpy34 /* 3 = P=33, 4 bytes? Is word-aligned, shouldnt happen */
/* but just in case, go hack BLT. */
/* Source P=22, 3 valid bytes in A */
bcpy64: move b,(e)
lshc a,<11*1>
movem a,(t)
lshc a,<11*<4-1>>
addi e,1 /* Sigh... for extended addr possibility. */
addi t,1
sojg c,bcpy64
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Source P=11, 2 valid bytes in A */
bcpy65: move b,(e)
lshc a,<11*2>
movem a,(t)
lshc a,<11*<4-2>>
addi e,1
addi t,1
sojg c,bcpy65
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Source P=00, 1 valid byte in A */
bcpy66: move b,(e)
lshc a,<11*3>
movem a,(t)
lshc a,<11*<4-3>>
addi e,1
addi t,1
sojg c,bcpy66
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Copy non-aligned 7-bit bytes. */
bcpy70: idivi c,5 /* Divide by 5, get rem in D */
ldb b,[360200,,e] /* Get low 2 bits of P from source BP */
move a,(e) /* Get 1st source word set up. */
lsh a,-1
aoja e,@.+1(b) /* Dispatch on value of 0,1,2,3. */
/* See note for previous table re SETZs. */
setz bcpy76 /* 0 = P=10, 2 bytes needed from source wd */
setz bcpy78 /* 1 = P=01, 1 bytes needed from source wd */
setz bcpy72 /* 2 = P=26, 4 bytes needed from source wd */
setz bcpy74 /* 3 = P=17, 3 bytes needed from source wd */
/* Source P=26 (4 valid bytes in A) */
bcpy72: move b,(e)
lshc a,<7*1>
lsh a,1
movem a,(t)
lshc a,<7*<5-1>>
addi e,1
addi t,1
sojg c,bcpy72
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Source P=17 (3 valid bytes in A) */
bcpy74: move b,(e)
lshc a,<7*2>
lsh a,1
movem a,(t)
lshc a,<7*<5-2>>
addi e,1
addi t,1
sojg c,bcpy74
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Source P=10 (2 valid bytes in A) */
bcpy76: move b,(e)
lshc a,<7*3>
lsh a,1
movem a,(t)
lshc a,<7*<5-3>>
addi e,1
addi t,1
sojg c,bcpy76
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Source P=01 (1 valid byte in A) */
bcpy78: move b,(e)
lshc a,<7*4>
lsh a,1
movem a,(t)
lshc a,<7*<5-4>>
addi e,1
addi t,1
sojg c,bcpy78
skipg c,d
jrst bcpret /* Return */
soja e,bcpy42
/* Copy non-aligned 8-bit bytes. */
bcpy80: jrst bcpy42 /* Also punt for now. */
#endasm
#endif /* CPU_PDP10 */
} /* End of MEMCPY */
/************************ MEMCMP ******************************
**
** This implements the ANSI memcmp() function.
** Compares two byte strings.
*/
int
memcmp(s1, s2, n)
register char *s1, *s2;
register int n;
{
#if !(CPU_PDP10)
register int res;
if(n > 0)
do { if (res = (*s1++ - *s2++))
return(res);
} while(--n);
return(0);
#else /* CPU_PDP10 */
#asm
skipg e,-3(p) /* Get 3rd arg, # of bytes */
jrst [ setz a,
popj p,]
move c,-2(p)
move d,-1(p)
ldb a,c
ldb b,d
came a,b
jrst bcmp9
sojle e,bcmp9
bcmp5: ildb a,c
ildb b,d
camn a,b
sojg e,bcmp5
bcmp9: sub a,b /* Return difference byte1-byte2. */
popj p,
#endasm
#endif /* CPU_PDP10 */
} /* End of MEMCMP */
/************************ MEMCHR ******************************
**
** This implements the ANSI memchr() function.
** Searches for the first occurrence of a byte in the
** object pointed to by S.
*/
char *
memchr(s, c, n)
register char *s;
int c;
register int n;
{
#if !(CPU_PDP10)
register unsigned char ch = c;
if(n > 0) {
do { if (*s++ == ch) return s-1; }
while (--n);
}
return NULL;
#else /* CPU_PDP10 */
#asm
skipe a,-1(p) /* Get 1st arg, byte pointer */
skipg c,-3(p) /* Get 3rd arg, # bytes. */
jrst memch9 /* If bad ptr or count, fail. */
move b,-2(p) /* Get 2nd arg, byte to look for. */
ldb d,a /* Get 1st byte */
caia /* Skip into loop */
memch5: ildb d,a
cain d,(b)
popj p, /* If match, just return current pointer! */
sojg c,memch5
memch9: setz a, /* Failed, return NULL */
/* Drop thru to return. */
#endasm
#endif /* CPU_PDP10 */
} /* End of MEMCHR */
/************************ MEMCCPY ******************************
**
** This implements the S5/BSD (but not ANSI!) memccpy() function.
** Acts like memcpy() but also stops if it copies a byte of a
** specified value.
** Returns NULL if counted out, otherwise returns pointer to first
** destination location past the final copied byte.
*/
char *
memccpy(dest, src, c, n)
register char *dest, *src;
register int n, c;
{
#if !(CPU_PDP10)
if(n > 0) {
do { if ((*dest++ = *src++) == c) return dest; }
while (--n);
}
return NULL;
#else /* CPU_PDP10 */
#asm
skipe a,-1(p) /* Get 1st arg, dest byte pointer */
skipg c,-4(p) /* Get 4th arg, # bytes. */
jrst memcc8 /* If bad ptr or count, fail. */
move d,-2(p) /* Get 2nd arg, source byte pointer */
move b,-3(p) /* Get 3rd arg, byte to look for. */
ldb e,d /* Get 1st byte */
dpb e,a /* Store it */
jrst memcc6 /* Now can enter real loop. */
memcc5: ildb e,d /* Get next byte */
idpb e,a /* Store it */
memcc6: cain e,(b) /* Compare to see if done */
jrst memcc9 /* Yep, stop */
sojg c,memcc5 /* Continue loop, drop thru if counted out. */
memcc8: tdza a,a /* Counted out or bad args, return NULL */
memcc9: ibp a /* Hit byte value, return ptr to next dest location. */
popj p,
#endasm
#endif /* CPU_PDP10 */
} /* End of MEMCCPY */
/************************ MEMMOVE ******************************
**
** This implements the ANSI memmove() function.
** Acts like memcpy() but does overlapping moves properly.
** This has not yet been optimized for the PDP-10. See comments
** at end of routine.
*/
#define GAPLEN 1024 /* Size of gap-handling buffer */
char *
memmove(dest, src, n)
char *dest;
register char *src;
register int n;
{
register char *to;
register int gap;
char buff[GAPLEN];
if (n <= 0) return dest; /* Sanity check */
if (((gap = dest - src) <= 0) /* If dest <= src, */
|| (gap >= n)) /* or if gap big enuf, */
return memcpy(dest, src, n); /* OK to use plain copy! */
/* Bah, source has its bottom part overlapped by dest.
** Must copy backwards, or do something cleverer.
*/
if (n <= GAPLEN) { /* String small enough for simple hack? */
memcpy(buff, src, n); /* Yep, copy whole thing into temp buffer */
return memcpy(dest, buff, n); /* Then from buffer to dest */
}
/* Could see whether or not to try copying "gap" bytes at a time,
** from bottom of source to bottom of dest, until all done.
** This would be very slow for small gaps, though.
*/
/* Give up, do feeble-minded byte-by-byte backwards copying.
*/
to = dest+n; /* Point at last dest loc */
src += n; /* Ditto for source */
do { *--to = *--src; } while (--n);
return dest;
} /* End of MEMMOVE */
#if CPU_PDP10
/*
Some things that could be done to optimize memmove for the PDP-10
would be:
Check dest/src pointers to see if word-aligned. If so, can
use a sequence like this:
Non-extended addressing Extended-addressing (KLs)
MOVE A,src+n MOVN A,n
MOVE B,n MOVE B,src+n
POP A,gap(A) MOVE C,dest+n
SOJG B,.-1 EXTEND A,[XBLT]
The main trouble is all the checking needed to figure out if the pointers
are OK, and then setting things up.
*/
#endif /* CPU_PDP10 */