echo x - Makefile
sed '/^X/s///' > Makefile << '/'
X.SUFFIXES: .o .x .s
XCFLAGS= -Di8088 -D_POSIX_SOURCE -D_MINIX
X.x.o:
X	/usr/lib/cpp $(CFLAGS) $< | as -o $*.o
X
XOBJECTS = memchr.o memcmp.o memcpy.o memmove.o memset.o \
X	strcat.o strchr.o strcmp.o strcoll.o strcpy.o strcspn.o \
X	strerror.o strlen.o strncat.o strncmp.o strncpy.o strpbrk.o \
X	strrchr.o strspn.o strstr.o strtok.o strxfrm.o
X
Xall: $(OBJECTS)
X
Xclean:	
X	@rm -f *.o *.s *.bak
/
echo x - memchr.x
sed '/^X/s///' > memchr.x << '/'
X/* memchr.x
X *	void *memchr(const void *s, int c, size_t n)
X *
X *	Returns a pointer to the first occurrence of c (converted to
X *	unsigned char) in the object pointed to by s, NULL if none.
X */
X
X.define	_memchr
X.text
X_memchr:
X	mov	bx,di		/* save di */
X	mov	di,sp
X	xor	dx,dx		/* default result is NULL */
X	mov	cx,6(di)
X	jcxz	exit		/* early exit if n == 0 */
X	movb	al,4(di)
X	mov	di,2(di)
X	cld
X	repne
X	scasb
X	jne	exit
X#ifdef i8088
X	dec	di
X	mov	dx,di
X#else
X	lea	dx,-1(di)
X#endif
Xexit:
X	mov	di,bx		/* restore di */
X	mov	ax,dx
X	ret
/
echo x - memcmp.x
sed '/^X/s///' > memcmp.x << '/'
X/* memcmp.x
X *	int memcmp(const void *s1, const void *s2, size_t n)
X *
X *	Compares the first n characters of the objects pointed to by
X *	s1 and s2.  Returns zero if all characters are identical, a
X *	positive number if s1 greater than s2, a negative number otherwise.
X */
X
X#define BYTE_LIMIT 10		/* if n is above this, work with words */
X
X.define	_memcmp
X.text
X_memcmp:
X	mov	bx,sp
X	push	si
X	push	di
X	xor	ax,ax		/* default return is equality */
X	mov	cx,6(bx)
X	jcxz	exit		/* early exit if n == 0 */
X	mov	si,2(bx)
X	mov	di,4(bx)
X	cmp	si,di
X	je	exit		/* early exit if s1 == s2 */
X	cld
X	cmp	cx,*BYTE_LIMIT
X	ja	word_compare
Xbyte_compare:
X	repe
X	cmpb
X	jne	one_past_mismatch
X	pop	di
X	pop	si
X	ret
Xword_compare:
X	test	si,#1		/* align s1 on word boundary */
X	jz	word_aligned
X	cmpb
X	jne	one_past_mismatch
X	dec	cx
Xword_aligned:
X	mov	dx,cx		/* save count */
X	shr	cx,#1		/* compare words, not bytes */
X	jz	almost_done
X	repe
X	cmp
X	je	almost_done
X	sub	si,#2
X	sub	di,#2
X	cmpb
X	jne	one_past_mismatch
X	jmp	at_mismatch
Xalmost_done:
X	test	dx,#1
X	jz	exit
X	jmp	at_mismatch
Xone_past_mismatch:
X	dec	si
X	dec	di
Xat_mismatch:
X	xorb	ah,ah
X	movb	al,(si)
X	subb	al,(di)
X	sbbb	ah,ah
Xexit:
X	pop	di
X	pop	si
X	ret
/
echo x - memcpy.x
sed '/^X/s///' > memcpy.x << '/'
X/* memcpy.s */
X/*	void *memcpy(void *s1, const void *s2, size_t n); */
X
X/*	Copy n characters from the object pointed to by s2 into the */
X/*	object pointed to by s1.  If the objects overlap, the result */
X/*	is undefined. */
X
X/*	Optimized for the common case of s being a large word-aligned */
X/*	buffer, of even length.  Compared to the old code, there are */
X/*	slight time penalties for unaligned buffers and those of odd */
X/*	length.  There is also a slight time penalty for n < 4, and a */
X/*	serious time penalty for s1 == s2 --- neither is very common. */
X
X.extern	_memcpy
X.text
X_memcpy:
X	mov	bx,si		/* save si and di */
X	mov	dx,di
X	mov	di,sp
X	mov	cx,6(di)
X	mov	si,4(di)
X	mov	di,2(di)
X	mov	ax,di		/* save a copy of s1 */
X	cld
X	test	si,#1		/* if not word aligned */
X	jnz	align_for_words	/*   go align things */
X	shr	cx,#1		/* move words, not bytes */
X	rep	movsw
X	jb	move_last_byte	/* if not even words, go move the last one */
X	mov	si,bx		/* restore si and di */
X	mov	di,dx
X	ret
Xalign_for_words:
X	jcxz	exit		/* n == 0: early exit */
X	movsb
X	dec	cx
X	shr	cx,#1		/* following code replicated for speed */
X	rep	movsw
X	jb	move_last_byte
X	mov	si,bx
X	mov	di,dx
X	ret
Xmove_last_byte:
X	movsb
Xexit:
X	mov	si,bx		/* restore si and di */
X	mov	di,dx
X	ret
/
echo x - memmove.x
sed '/^X/s///' > memmove.x << '/'
X/* memmove.x
X *	void *memmove(void *s1, const void *s2, size_t n)
X *
X *	Copy n characters from the object pointed to by s2 into the
X *	object pointed to by s1.  Copying takes place as if the n
X *	characters pointed to by s2 are first copied to a temporary
X *	area and then copied to the object pointed to by s1.
X *
X *	Per X3J11, memcpy may have undefined results if the objects
X *	overlap; since the performance penalty is insignificant, we
X *	use the safe memmove code for it as well.
X */
X
X#define BYTE_LIMIT 10		/* if n is above this, work with words */
X
X.define	_memmove
X.text
X_memmove:
X	mov	bx,si		/* save si and di */
X	mov	dx,di
X	mov	di,sp
X	mov	cx,6(di)
X	mov	si,4(di)
X	mov	di,2(di)
X	mov	ax,di		/* save a copy of s1 */
X	jcxz	exit		/* early exit if n == 0 */
X	sub	di,si
X	je	exit		/* early exit if s1 == s2 */
X	jb	left_to_right	/* left to right if s1 < s2 */
X	cmp	di,cx
X	jae	left_to_right	/* left to right if no overlap */
Xright_to_left:
X	mov	di,ax		/* retrieve s1 */
X	std
X	add	si,cx		/* compute where objects end */
X	dec	si
X	add	di,cx
X	dec	di
X	cmp	cx,#BYTE_LIMIT
X	jbe	byte_move
X	test	si,#1		/* align source on word boundary */
X	jnz	word_unaligned
X	movb
X	dec	cx
Xword_unaligned:
X	dec	si		/* adjust to word boundary */
X	dec	di
X	shr	cx,#1		/* move words, not bytes */
X	rep
X	movw
X	jnb	exit
X#ifdef i8088
X	inc	si		/* fix up addresses for right to left moves */
X	inc	di
X	movb			/* move leftover byte */
X#else
X	movb	cl,1(si)
X	movb	1(di),cl	/* move leftover byte */
X#endif
X	jmp	exit
Xleft_to_right:
X	mov	di,ax		/* retrieve s1 */
X	cld
X	cmp	cx,#BYTE_LIMIT
X	jbe	byte_move
X	test	si,#1		/* align source on word boundary */
X	jz	word_move
X	movb
X	dec	cx
Xword_move:
X	shr	cx,#1		/* move words, not bytes */
X	rep
X	movw
X	adc	cx,cx		/* set up to move leftover byte */
Xbyte_move:
X	rep
X	movb
Xexit:
X	cld			/* restore direction flag */
X	mov	si,bx		/* restore si and di */
X	mov	di,dx
X	ret
/
echo x - memset.x
sed '/^X/s///' > memset.x << '/'
X/* memset.x
X *	void *memset(void *s, int c, size_t n)
X *
X *	Copies the value of c (converted to unsigned char) into the
X *	first n locations of the object pointed to by s.
X */
X
X#ifdef i80386
X#define BYTE_LIMIT	16	/* if n is above this, work with doublewords */
X#define SIZE_OVERRIDE	.byte 102 /* force 32 bits */
X#define SHLAX(n)	.byte 193,224,n
X#define SHRCX(n)	.byte 193,233,n
X#else
X#define BYTE_LIMIT	10	/* if n is above this, work with words */
X#endif
X
X.define	_memset
X.text
X_memset:
X	push	di
X	mov	di,sp
X	mov	cx,8(di)
X	movb	al,6(di)
X	mov	di,4(di)
X	mov	bx,di		/* return value is s */
X	jcxz	exit		/* early exit if n == 0 */
X	cld
X	cmp	cx,*BYTE_LIMIT
X	jbe	byte_set
X	movb	ah,al		/* set up second byte */
X	test	di,#1		/* align on word boundary */
X	jz	word_aligned
X	stosb
X	dec	cx
Xword_aligned:
X#ifdef i80386
X	test	di,#2		/* align on doubleword boundary */
X	jz	dword_aligned
X	stos
X	sub	cx,*2
Xdword_aligned:
X	mov	dx,ax		/* duplicate byte in all bytes of EAX */
X	SIZE_OVERRIDE
X	SHLAX	(16)
X	mov	ax,dx
X	mov	dx,cx		/* save count */
X	SHRCX	(2)
X	rep
X	SIZE_OVERRIDE
X	stos
X	and	dx,#3		/* set up to set leftover bytes */
X	mov	cx,dx
X#else
X	shr	cx,#1		/* set words, not bytes */
X	rep
X	stos
X	adc	cx,cx		/* set up to set leftover byte */
X#endif
Xbyte_set:
X	rep
X	stosb
Xexit:
X	pop	di
X	mov	ax,bx
X	ret
/
echo x - strcat.x
sed '/^X/s///' > strcat.x << '/'
X/* strcat.x
X *	char *strcat(char *s1, const char *s2)
X *
X *	Concatenates the string pointed to by s2 onto the end of the
X *	string pointed to by s1.  Returns s1.
X */
X
X.define _strcat
X.text
X_strcat:
X	mov	bx,si		/* save si and di */
X	mov	dx,di
X	mov	si,sp
X	mov	di,2(si)
X	push	di		/* save return value */
X	mov	si,4(si)
X	cmpb	(si),*0
X	je	exit		/* early exit if s2 is the null string */
X	cld
X	mov	cx,#-1		/* find end of s1 */
X	xorb	al,al
X	repne
X	scasb
X	dec	di		/* point back at null character */
X	test	si,#1		/* align source on word boundary */
X	jz	word_copy
X	movb
Xword_copy:			/* loop to copy words */
X	lods
X	orb	al,al
X	jz	move_last_byte	/* exit if low byte == 0 */
X	stos
X	orb	ah,ah
X	jnz	word_copy
X	jmp	exit
Xmove_last_byte:
X	stosb			/* add odd zero byte */
Xexit:
X	mov	si,bx
X	mov	di,dx
X	pop	ax
X	ret
/
echo x - strchr.x
sed '/^X/s///' > strchr.x << '/'
X/* strchr.x
X *	char *strchr(const char *s, int c)
X *
X *	Returns location of the first occurrence of c (converted to char)
X *	in the string pointed to by s.  Returns NULL if c does not occur.
X */
X
X.define	_strchr
X.text
X_strchr:
X	mov	bx,si		/* save si */
X	mov	si,sp
X	movb	dl,4(si)
X	mov	si,2(si)
X	cld
X	test	si,#1		/* align string on word boundary */
X	jz	word_loop
X	lodsb
X	cmpb	al,dl
X	je	one_past
X	orb	al,al
X	jz	no_match
Xword_loop:			/* look for c word by word */
X	lods
X	cmpb	al,dl
X	je	two_past
X	orb	al,al
X	jz	no_match
X	cmpb	ah,dl
X	je	one_past
X	orb	ah,ah
X	jnz	word_loop
Xno_match:
X	xor	ax,ax
X	mov	si,bx		/* restore si */
X	ret
Xtwo_past:
X	dec	si
Xone_past:
X#ifdef i8088
X	dec	si
X	mov	ax,si
X#else
X	lea	ax,-1(si)
X#endif
X	mov	si,bx		/* restore si */
X	ret
/
echo x - strcmp.x
sed '/^X/s///' > strcmp.x << '/'
X/* strcmp.x
X *	int strcmp(const char *s1, const char *s2)
X *
X *	Compares the strings pointed to by s1 and s2.  Returns zero if
X *	strings are identical, a positive number if s1 greater than s2,
X *	and a negative number otherwise.
X */
X
X.define	_strcmp
X.text
X_strcmp:
X	mov	bx,si		/* save si and di */
X	mov	cx,di
X	mov	di,sp
X	mov	si,2(di)
X	mov	di,4(di)
X	xor	ax,ax		/* default return is equality */
X	cmp	si,di
X	je	exit		/* early exit if s1 == s2 */
X	cld
X	test	si,#1		/* align s1 on word boundary */
X	jz	setup_loop
X	lodsb
X	orb	al,al
X	jz	last_byte_test
X	cmpb	al,(di)
X	jne	last_byte_test
X	inc	di
Xsetup_loop:
X	sub	di,#2		/* set up for faster loop */
Xword_loop:			/* loop through string by words */
X	lods
X	add	di,#2
X	orb	al,al
X	jz	last_byte_test
X	cmp	ax,(di)
X	jne	find_mismatch
X	orb	ah,ah
X	jnz	word_loop
X	xor	ax,ax
X	jmp	exit
Xfind_mismatch:
X	cmpb	al,(di)
X	jne	last_byte_test
X	movb	al,ah
X	inc	di
Xlast_byte_test:			/* Expects: (al)=char of s1; (di)->char of s2 */
X	xorb	ah,ah
X	subb	al,(di)
X	sbbb	ah,ah
Xexit:
X	mov	si,bx		/* restore si and di */
X	mov	di,cx
X	ret
/
echo x - strcoll.x
sed '/^X/s///' > strcoll.x << '/'
X/* strcoll.x
X *	int strcoll(const char *s1, const char *s2)
X *
X *	Compares the strings pointed to by s1 and s2, in light of the
X *	current locale.  Returns zero if the strings are identical, a
X *	positive number if s1 is greater than s2, and a negative number
X *	otherwise.
X *
X *	Note that this is a BOGUS implementation, since I haven't the
X *	slightest idea what ANSI is prattling about with respect to locale.
X */
X
X.define _strcoll
X.text
X.extern _strcmp
X_strcoll:
X	jmp	_strcmp
/
echo x - strcpy.x
sed '/^X/s///' > strcpy.x << '/'
X/* strcpy.x
X *	char *strcpy(char *s1, const char *s2)
X *
X *	Copy the string pointed to by s2, including the terminating null
X *	character, into the array pointed to by s1.  Returns s1.
X */
X
X.define	_strcpy
X.text
X_strcpy:
X	mov	bx,si		/* save si and di */
X	mov	cx,di
X	mov	di,sp
X	mov	si,4(di)
X	mov	di,2(di)
X	mov	dx,di
X	cld
X	test	si,#1		/* align source on word boundary */
X	jz	word_copy
X	lodsb
X	stosb
X	orb	al,al
X	jz	exit
Xword_copy:			/* loop to copy words */
X	lods
X	orb	al,al
X	jz	move_last_byte	/* early exit if low byte == 0 */
X	stos
X	orb	ah,ah
X	jnz	word_copy
X	jmp	exit
Xmove_last_byte:
X	stosb			/* add odd zero byte */
Xexit:
X	mov	ax,dx
X	mov	si,bx		/* restore si and di */
X	mov	di,cx
X	ret
/
echo x - strcspn.x
sed '/^X/s///' > strcspn.x << '/'
X/* strcspn.x
X *	size_t strcspn(const char *s1, const char *s2)
X *
X *	Returns the length of the longest prefix of the string pointed
X *	to by s1 that has none of the characters in the string s2.
X */
X
X.define	_strcspn
X.text
X_strcspn:
X	push	bp
X	mov	bp,sp
X	push	si
X	push	di
X	mov	si,4(bp)
X	mov	di,6(bp)
X	cld
X	mov	bx,#-1		/* set up count (-1 for faster loops) */
X	cmpb	(di),*0
X	jz	s1_length	/* if s2 is null, we return length of s1 */
X	cmpb	1(di),*0
X	jz	find_match	/* if s2 has length one, we take a shortcut */
X	mov	cx,bx		/* find length of s2 */
X	xorb	al,al
X	repne
X	scasb
X	not	cx
X	dec	cx
X	mov	dx,cx		/* save length of s2 */
Xs1_loop:			/* loop over s1 looking for matches with s2 */
X	lodsb
X	inc	bx
X	orb	al,al
X	jz	exit
X	mov	di,6(bp)
X	mov	cx,dx
X	repne
X	scasb
X	jne	s1_loop
X	jmp	exit
Xs1_length:			/* find length of s1 */
X	mov	di,si
X	mov	cx,bx
X	xorb	al,al
X	repne
X	scasb
X	not	cx
X	dec	cx
X	mov	bx,cx
X	jmp	exit
Xfind_match:			/* find a match for *s2 in s1 */
X	movb	dl,(di)
X	test	si,#1		/* align source on word boundary */
X	jz	word_loop
X	lodsb
X	inc	bx
X	orb	al,al
X	je	exit
X	cmpb	al,dl
X	je	exit
Xword_loop:
X	lods
X	inc	bx
X	orb	al,al
X	je	exit
X	cmpb	al,dl
X	je	exit
X	inc	bx
X	orb	ah,ah
X	je	exit
X	cmpb	ah,dl
X	jne	word_loop
Xexit:
X	mov	ax,bx
X	pop	di
X	pop	si
X	mov	sp,bp
X	pop	bp
X	ret
/
echo x - strerror.x
sed '/^X/s///' > strerror.x << '/'
X/* strerror.x
X *	char *strerror(int errnum)
X *
X *	Returns a pointer to an appropriate error message string.
X */
X
X.define	_strerror
X.data
X.extern	__sys_nerr, __sys_errlist
Xunknown: .asciz 'Unknown error'
X.text
X_strerror:
X	mov	bx,sp
X	mov	bx,2(bx)
X	mov	ax,#unknown	/* default return is "Unknown error" */
X	or	bx,bx
X	jle	exit
X	cmp	bx,__sys_nerr
X	jge	exit
X	sal	bx,#1
X	mov	ax,__sys_errlist(bx)
Xexit:
X	ret
/
echo x - strlen.x
sed '/^X/s///' > strlen.x << '/'
X/* strlen.x
X *	size_t strlen(const char *s)
X *
X *	Returns the length of the string pointed to by s.
X */
X
X.define	_strlen
X.text
X_strlen:
X	mov	bx,di		/* save di */
X	mov	di,sp
X	mov	di,2(di)
X	mov	cx,#-1
X	xorb	al,al
X	cld
X	repne
X	scasb
X	not	cx		/* silly trick gives length (including null) */
X	dec	cx		/* forget about null */
X	mov	ax,cx
X	mov	di,bx		/* restore di */
X	ret
/
echo x - strncat.x
sed '/^X/s///' > strncat.x << '/'
X/* strncat.x
X *	char *strncat(char *s1, const char *s2, size_t n)
X *
X *	Concatenates up to n characters of the string pointed to by s2
X *	onto the end of the string pointed to by s1.  A terminating
X *	null character is always appended.  Returns s1.
X */
X
X.define	_strncat
X.text
X_strncat:
X	mov	bx,si		/* save si and di */
X	mov	dx,di
X	mov	si,sp
X	mov	cx,6(si)
X	mov	di,2(si)
X	push	di		/* save return value */
X	jcxz	exit		/* early exit if n == 0 */
X	cld
X	mov	cx,#-1		/* find end of s1 */
X	xorb	al,al
X	repne
X	scasb
X	dec	di
X	mov	cx,6(si)
X	mov	si,4(si)
Xbyte_loop:			/* loop to copy bytes */
X	lodsb
X	stosb
X	orb	al,al
X	loopnz	byte_loop
X	jz	exit
X	movb	(di),*0		/* add terminating null character */
Xexit:
X	mov	si,bx		/* restore si and di */
X	mov	di,dx
X	pop	ax
X	ret
/
echo x - strncmp.x
sed '/^X/s///' > strncmp.x << '/'
X/* strncmp.x
X *	int strncmp(const char *s1, const char *s2, size_t n)
X *
X *	Compares up to n characters from the strings pointed to by s1
X *	and s2.  Returns zero if the (possibly null terminated) arrays
X *	are identical, a positive number if s1 is greater than s2, and
X *	a negative number otherwise.
X */
X
X.define	_strncmp
X.text
X_strncmp:
X	mov	bx,sp
X	push	si
X	push	di
X	xor	ax,ax		/* default result is equality */
X	mov	cx,6(bx)
X	jcxz	exit		/* early exit if n == 0 */
X	mov	si,2(bx)
X	mov	di,4(bx)
X	cmp	si,di
X	je	exit		/* early exit if s1 == s2 */
X	cld
X	test	si,#1		/* align s1 on word boundary */
X	jz	setup_loop
X	lodsb
X	orb	al,al
X	jz	last_byte_test
X	cmpb	al,(di)
X	jne	last_byte_test
X	xor	ax,ax
X	dec	cx
X	jz	exit		/* early exit if n == 1 */
X	inc	di
Xsetup_loop:
X	mov	dx,cx		/* save count */
X	shr	cx,#1		/* work with words, not bytes */
X	jz	fetch_last_byte
X	sub	di,#2		/* set up for faster loop */
Xword_loop:			/* loop through string by words */
X	lods
X	add	di,#2
X	orb	al,al
X	jz	last_byte_test
X	cmp	ax,(di)
X	jne	find_mismatch
X	orb	ah,ah
X	loopnz	word_loop
X	mov	ax,#0		/* zero return value (without setting flags) */
X	jz	exit
X	test	dx,#1		/* check for odd byte at end */
X	jz	exit
X	add	di,#2
Xfetch_last_byte:
X	movb	al,(si)
X	jmp	last_byte_test
Xfind_mismatch:			/* check word for mismatched byte */
X	cmpb	al,(di)
X	jne	last_byte_test
X	movb	al,ah
X	inc	di
Xlast_byte_test:			/* Expects: (al)=char of s1; (di)->char of s2 */
X	xorb	ah,ah
X	subb	al,(di)
X	sbbb	ah,ah
Xexit:
X	pop	di
X	pop	si
X	ret
/
echo x - strncpy.x
sed '/^X/s///' > strncpy.x << '/'
X/* strncpy.x
X *	char *strncpy(char *s1, const char *s2, size_t n)
X *
X *	Copy up to n characters from the string pointed to by s2 to
X *	the array pointed to by s1.  If the source string is shorter
X *	than n characters, the remainder of the destination is padded
X *	with null characters.  If the source is longer than n characters,
X *	the destination will not be null terminated.  Returns s1.
X */
X
X#define BYTE_LIMIT 10		/* if n is above this, zero fill with words */
X
X.define	_strncpy
X.text
X_strncpy:
X	mov	bx,sp
X	push	si
X	push	di
X	mov	cx,6(bx)
X	jcxz	exit		/* early exit if n == 0 */
X	mov	di,2(bx)
X	mov	si,4(bx)
X	cld
X	cmpb	(si),*0
X	je	zero_fill	/* if s2 has length zero, take a short cut */
X	test	si,#1		/* align source on word boundary */
X	jz	set_length
X	movb
X	dec	cx
X	jz	exit		/* early exit if n == 1 */
Xset_length:
X	mov	dx,cx		/* save count */
X	shr	cx,#1		/* copy words, not bytes */
X	jz	last_byte
Xword_copy:			/* loop to copy words */
X	lods
X	orb	al,al
X	jz	restore_length	/* early exit if low byte == 0 */
X	stos
X	orb	ah,ah
X	loopnz	word_copy
X	jz	restore_length
Xlast_byte:
X	test	dx,#1		/* move leftover byte */
X	jz	exit
X	movb
X	jmp	exit
Xrestore_length:			/* retrieve remaining length (in bytes) */
X	shl	cx,#1
X	and	dx,#1
X	add	cx,dx
X	jz	exit
Xzero_fill:			/* add null characters if necessary */
X	xor	ax,ax
X	cmp	cx,*BYTE_LIMIT
X	jbe	zero_bytes
X	test	di,#1		/* align destination on word boundary */
X	jz	zero_words
X	stosb
X	dec	cx
Xzero_words:
X	shr	cx,#1		/* zero words, not bytes */
X	rep
X	stos
X	adc	cx,cx		/* set up for leftover byte */
Xzero_bytes:
X	rep
X	stosb
Xexit:
X	pop	di
X	pop	si
X	mov	ax,2(bx)
X	ret
/
echo x - strpbrk.x
sed '/^X/s///' > strpbrk.x << '/'
X/* strpbrk.x
X *	char *strpbrk(const char *s1, const char *s2)
X *
X *	Returns the address of the first character of the string pointed
X *	to by s1 that is in the string pointed to by s2.  Returns NULL
X *	if no such character exists.
X */
X
X.define	_strpbrk
X.text
X_strpbrk:
X	mov	bx,sp
X	push	si
X	push	di
X	mov	si,2(bx)
X	mov	di,4(bx)
X	mov	bx,di		/* save a copy of s2 */
X	cld
X	xor	ax,ax		/* default return value is NULL */
X	cmpb	(di),*0
X	jz	exit		/* if s2 has length zero, we are done */
X	cmpb	1(di),*0
X	jz	find_match	/* if s2 has length one, we take a shortcut */
X	mov	cx,#-1		/* find length of s2 */
X	repne
X	scasb
X	not	cx
X	dec	cx
X	mov	dx,cx		/* save length of s2 */
Xs1_loop:			/* loop through s1 to find matches with s2 */
X	lodsb
X	orb	al,al
X	jz	exit
X	mov	di,bx
X	mov	cx,dx
X	repne
X	scasb
X	jne	s1_loop
X#ifdef i8088
X	dec	si
X	mov	ax,si
X#else
X	lea	ax,-1(si)
X#endif
X	pop	di
X	pop	si
X	ret
Xfind_match:			/* find a match for *s2 in s1 */
X	movb	dl,(di)
X	test	si,#1		/* align source on word boundary */
X	jz	word_loop
X	lodsb
X	cmpb	al,dl
X	je	one_past
X	orb	al,al
X	jz	no_match
Xword_loop:
X	lods
X	cmpb	al,dl
X	je	two_past
X	orb	al,al
X	jz	no_match
X	cmpb	ah,dl
X	je	one_past
X	orb	ah,ah
X	jnz	word_loop
Xno_match:
X	xor	ax,ax
X	pop	di
X	pop	si
X	ret
Xtwo_past:
X	dec	si
Xone_past:
X#ifdef i8088
X	dec	si
X	mov	ax,si
X#else
X	lea	ax,-1(si)
X#endif
Xexit:
X	pop	di
X	pop	si
X	ret
/
echo x - strrchr.x
sed '/^X/s///' > strrchr.x << '/'
X/* strrchr.x
X *	char *strrchr(const char *s, int c)
X *
X *	Locates final occurrence of c (as unsigned char) in string s.
X */
X
X.define	_strrchr
X.text
X_strrchr:
X	mov	bx,di		/* save di */
X	mov	di,sp
X	xor	dx,dx		/* default result is NULL */
X	movb	ah,4(di)
X	mov	di,2(di)
X	cld
X	mov	cx,#-1		/* find end of string */
X	xorb	al,al
X	repne
X	scasb
X	not	cx		/* silly trick gives length (including null) */
X	dec	di		/* point back at null character */
X	movb	al,ah		/* find last occurrence of c */
X	std
X	repne
X	scasb
X	jne	exit
X#ifdef i8088
X	inc	di
X	mov	dx,di
X#else
X	lea	dx,1(di)
X#endif
Xexit:
X	cld			/* clear direction flag */
X	mov	di,bx		/* restore di */
X	mov	ax,dx
X	ret
/
echo x - strspn.x
sed '/^X/s///' > strspn.x << '/'
X/* strspn.x
X *	size_t strspn(const char *s1, const char *s2)
X *
X *	Returns the length of the longest prefix of the string pointed
X *	to by s1 that is made up of the characters in the string s2.
X */
X
X.define	_strspn
X.text
X_strspn:
X	push	bp
X	mov	bp,sp
X	push	si
X	push	di
X	mov	si,4(bp)
X	mov	di,6(bp)
X	cld
X	xor	bx,bx		/* default return value is zero */
X	cmpb	(di),*0
X	jz	exit		/* if s2 has length zero, we are done */
X	cmpb	1(di),*0
X	jz	find_mismatch	/* if s2 has length one, we take a shortcut */
X	mov	cx,#-1		/* find length of s2 */
X	xorb	al,al
X	repne
X	scasb
X	not	cx
X	dec	cx
X	mov	dx,cx		/* save length of s2 */
X	dec	bx		/* set up byte count for faster loop */
Xs1_loop:			/* loop over s1 looking for matches with s2 */
X	lodsb
X	inc	bx
X	orb	al,al
X	jz	exit
X	mov	di,6(bp)
X	mov	cx,dx
X	repne
X	scasb
X	je	s1_loop
X	jmp	exit
Xfind_mismatch:			/* find a character in s1 that is not *s2 */
X	movb	al,(di)
X	mov	di,si
X	mov	cx,#-1
X	repe
X	scasb
X	dec	di		/* point back at mismatch */
X	mov	bx,di
X	sub	bx,si		/* number of matched characters */
Xexit:
X	mov	ax,bx
X	pop	di
X	pop	si
X	mov	sp,bp
X	pop	bp
X	ret
/
echo x - strstr.x
sed '/^X/s///' > strstr.x << '/'
X/* strstr.x
X *	char * strstr(const char *s1, const char *s2)
X *
X *	Returns a pointer to the first occurrence in the string pointed
X *	to by s1 that is made up of the characters in the string s2.
X */
X
X.define	_strstr
X.text
X_strstr:
X	push	bp
X	mov	bp,sp
X	sub	sp,#2		/* make room for locals */
X	push	si
X	push	di
X	mov	si,4(bp)
X	mov	di,6(bp)
X	mov	bx,si		/* default result is s1 */
X	movb	ah,(di)		/* fetch first character of s2 */
X	orb	ah,ah
X	je	exit		/* if s2 is null, we are done */
X	cld
X	mov	cx,#-1		/* find length of s2 */
X	xorb	al,al
X	repne
X	scasb
X	not	cx
X	dec	cx
X	mov	-2(bp),cx	/* save length of s2 */
X	mov	cx,#-1		/* find length + 1 of s1 */
X	mov	di,si
X	repne
X	scasb
X	not	cx
X	sub	cx,-2(bp)	/* !s1| - |s2| + 1 is number of possibilities */
X	jbe	not_found	/* if !s1| < |s2|, give up right now */
X	mov	dx,cx
X	inc	dx		/* set up for faster loop */
X	dec	bx
Xs1_loop:
X	dec	dx
X	jz	not_found
X	inc	bx
X	cmpb	ah,(bx)
X	jne	s1_loop		/* no match on first character - try another */
X	mov	di,6(bp)
X	mov	si,bx
X	mov	cx,-2(bp)
X	repe
X	cmpb
X	jne	s1_loop
X	jmp	exit
Xnot_found:
X	xor	bx,bx
Xexit:
X	mov	ax,bx
X	pop	di
X	pop	si
X	mov	sp,bp
X	pop	bp
X	ret
/
echo x - strtok.x
sed '/^X/s///' > strtok.x << '/'
X/* strtok.x
X *	char *strtok(char *s1, const char *s2)
X *
X *	Returns a pointer to the "next" token in s1.  Tokens are 
X *	delimited by the characters in the string pointed to by s2.
X */
X
X.define	_strtok
X.data
Xscan:	.data2	0
X.text
X_strtok:
X	push	bp
X	mov	bp,sp
X	push	si
X	push	di
X	cld
X	mov	bx,4(bp)
X	or	bx,bx		/* if s ~= NULL, */
X	jnz	s2_length	/*   we start a new string */
X	mov	bx,scan
X	or	bx,bx		/* if old string exhausted, */
X	jz	exit		/*   exit early */
Xs2_length:			/* find length of s2 */
X	mov	di,6(bp)
X	mov	cx,#-1
X	xorb	al,al
X	repne
X	scasb
X	not	cx
X	dec	cx
X	jz	string_finished	/* if s2 has length zero, we are done */
X	mov	dx,cx		/* save length of s2 */
X
X	mov	si,bx
X	xor	bx,bx		/* return value is NULL */
Xdelim_loop:			/* dispose of leading delimiters */
X	lodsb
X	orb	al,al
X	jz	string_finished
X	mov	di,6(bp)
X	mov	cx,dx
X	repne
X	scasb
X	je	delim_loop
X
X	lea	bx,-1(si)	/* return value is start of token */
Xtoken_loop:			/* find end of token */
X	lodsb
X	orb	al,al
X	jz	string_finished
X	mov	di,6(bp)
X	mov	cx,dx
X	repne
X	scasb
X	jne	token_loop
X	movb	-1(si),*0	/* terminate token */
X	mov	scan,si		/* set up for next call */
X	jmp	exit
Xstring_finished:
X	mov	scan,#0		/* ensure NULL return in future */
Xexit:
X	mov	ax,bx
X	pop	di
X	pop	si
X	mov	sp,bp
X	pop	bp
X	ret
/
echo x - strxfrm.x
sed '/^X/s///' > strxfrm.x << '/'
X/* strxfrm.x
X *	size_t strxfrm(char *s1, const char *s2, size_t n)
X *
X *	Transforms the string pointed to by s2 into s1.  The effect of
X *	the transformation is to make strcmp() act the same on transformed
X *	strings as strcoll() does on the original strings.  Returns the
X *	length of the transformed string.
X *
X *	Note that this is a BOGUS implementation, since I haven't the
X *	slightest idea what ANSI is prattling about with respect to locale.
X *	It is equivalent to the C code:
X *
X *	int strxfrm(char *s1, char *s2, int n)
X *	{
X *	  strncpy(s1, s2, n);
X *	  return strlen(s2);
X *	}
X */
X
X.define _strxfrm
X.text
X.extern _strncpy, _strlen
X_strxfrm:
X	mov	bx,sp		/* quick and dirty call to strncpy() */
X	push	6(bx)
X	push	4(bx)
X	push	2(bx)
X	call	_strncpy
X	add	sp,#6
X	push	4(bx)		/* followed by a call to strlen() */
X	call	_strlen
X	add	sp,#2
X	ret
/
