summaryrefslogtreecommitdiffstats
path: root/private/crt32/string/i386/strstr.asm
blob: 81a9b76bd491343126df9d78c55c0e6583620981 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
	page	,132
	title	strstr - search for one string inside another
;***
;strstr.asm - search for one string inside another
;
;	Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
;
;Purpose:
;	defines strstr() - search for one string inside another
;
;Revision History:
;	02-02-88  SKS	Rewritten from scratch.  Now works correctly with
;			strings > 32 KB in length.  Also smaller and faster.
;	03-01-88  SKS	Ensure that ES = DS right away (Small/Medium models)
;	05-18-88  SJM	Add model-independent (large model) ifdef
;	08-04-88  SJM	convert to cruntime/ add 32-bit support
;	08-18-88  PHG	Corrected return value when src is empty string
;			to conform with ANSI.
;	08-23-88  JCR	Minor 386 cleanup
;	10-26-88  JCR	General cleanup for 386-only code
;	03-26-90  GJF	Changed to _stdcall. Also, fixed the copyright.
;	05-10-91  GJF	Back to _cdecl, sigh...
;
;*******************************************************************************

	.xlist
	include cruntime.inc
	.list

page
;***
;char *strstr(string1, string2) - search for string2 in string1
;
;Purpose:
;	finds the first occurrence of string2 in string1
;
;Entry:
;	char *string1 - string to search in
;	char *string2 - string to search for
;
;Exit:
;	returns a pointer to the first occurrence of string2 in
;	string1, or NULL if string2 does not occur in string1
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

	CODESEG

	public	strstr
strstr proc \
	uses esi edi ebx, \
	dst:ptr byte, \
	src:ptr byte

	local	srclen:IWORD


	mov	edi, (src)	; di = src
	xor	eax,eax 	; Scan for null at end of (src)
	or	ecx,-1		; cx = -1
repnz	scasb
	not	ecx
	dec	ecx
	jecxz	short empty_src ; src == "" ?
	dec	ecx		; CX = strlen(src)-1
	mov	(srclen),ecx

	mov	edi,(dst)
	mov	ebx,edi 	; BX will keep the current offset into (dst)

	xor	eax,eax 	; Scan for null at end of (dst)
	or	ecx,-1		; cx = -1
repnz	scasb
	not	ecx
	dec	ecx		; CX = strlen(dst)

	mov	edx,ecx 	; Save strlen(dst) in DX

	sub	edx,(srclen)	; DX = strlen(dst) - (strlen(src)-1)
	jbe	short not_found ; strlen(dst) <= (strlen(src)-1)
				; target is longer than source?
	mov	edi,ebx 	; restore ES:DI = (dst)

findnext:
	mov	esi,IWORD ptr (src)
	lodsb			; Get the first byte of the source
	mov	edi,ebx 	; restore position in source
	mov	ecx,edx 	; count of possible starting bytes in src
;
;	CX, DX = number of bytes left in source where target can still fit
;	DI, BX = current position in (dst)
;	DS:SI = (src) + 1
;	AL = *(src)
;

repne	scasb			; find next occurrence of *(target) in dst
	jne	short not_found ; out of string -- return NULL

	mov	edx,ecx 	; update count of acceptable bytes left in dst
	mov	ebx,edi 	; save current offset in dst

	mov	ecx,(srclen)
	jecxz	short match	; single character src string?

repe	cmpsb
	jne	short findnext

;
; Match!  Return (BX-1)
;
match:
	lea	eax,[ebx-1]
	jmp	short retval

empty_src:			; empty src string, return dst (ANSI mandated)
	mov	eax,(dst)	; eax = dst
	jmp	short retval	; return

not_found:
	xor	eax,eax

retval:

ifdef	_STDCALL_
	ret	2*DPSIZE	; _stdcall return
else
	ret			; _cdecl return
endif

strstr	endp
	end