966174f805e55056bc538aa6c527aca6cc8111ca
[musl] / src / string / wcsstr.c
1 #include <wchar.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5
6 static wchar_t *naive_wcsstr(const wchar_t *h, const wchar_t *n)
7 {
8         size_t i;
9         for (i=0; n[i] && h[i]; i++)
10         for (   ; n[i] != h[i]; h++, i=0);
11         return n[i] ? 0 : (wchar_t *)h;
12 }
13
14 #define MAX(a,b) ((a)>(b)?(a):(b))
15 #define MIN(a,b) ((a)<(b)?(a):(b))
16
17 static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
18 {
19         const wchar_t *z;
20         size_t l, ip, jp, k, p, ms, p0, mem, mem0;
21
22         /* Computing length of needle */
23         for (l=0; n[l] && h[l]; l++);
24         if (n[l]) return 0; /* hit the end of h */
25
26         /* Compute maximal suffix */
27         ip = -1; jp = 0; k = p = 1;
28         while (jp+k<l) {
29                 if (n[ip+k] == n[jp+k]) {
30                         if (k == p) {
31                                 jp += p;
32                                 k = 1;
33                         } else k++;
34                 } else if (n[ip+k] > n[jp+k]) {
35                         jp += k;
36                         k = 1;
37                         p = jp - ip;
38                 } else {
39                         ip = jp++;
40                         k = p = 1;
41                 }
42         }
43         ms = ip;
44         p0 = p;
45
46         /* And with the opposite comparison */
47         ip = -1; jp = 0; k = p = 1;
48         while (jp+k<l) {
49                 if (n[ip+k] == n[jp+k]) {
50                         if (k == p) {
51                                 jp += p;
52                                 k = 1;
53                         } else k++;
54                 } else if (n[ip+k] < n[jp+k]) {
55                         jp += k;
56                         k = 1;
57                         p = jp - ip;
58                 } else {
59                         ip = jp++;
60                         k = p = 1;
61                 }
62         }
63         if (ip+1 > ms+1) ms = ip;
64         else p = p0;
65
66         /* Periodic needle? */
67         if (wmemcmp(n, n+p, ms+1)) {
68                 mem0 = 0;
69                 p = MAX(ms, l-ms-1) + 1;
70         } else mem0 = l-p;
71         mem = 0;
72
73         /* Initialize incremental end-of-haystack pointer */
74         z = h;
75
76         /* Search loop */
77         for (;;) {
78                 /* Update incremental end-of-haystack pointer */
79                 if (z-h < l) {
80                         /* Fast estimate for MIN(l,63) */
81                         size_t grow = l | 63;
82                         const wchar_t *z2 = wmemchr(z, 0, grow);
83                         if (z2) {
84                                 z = z2;
85                                 if (z-h < l) return 0;
86                         } else z += grow;
87                 }
88
89                 /* Compare right half */
90                 for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
91                 if (n[k]) {
92                         h += k-ms;
93                         mem = 0;
94                         continue;
95                 }
96                 /* Compare left half */
97                 for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
98                 if (k == mem) return (wchar_t *)h;
99                 h += p;
100                 mem = mem0;
101         }
102 }
103
104 wchar_t *wcsstr(const wchar_t *h, const wchar_t *n)
105 {
106         /* Return immediately on empty needle or haystack */
107         if (!n[0]) return (wchar_t *)h;
108         if (!h[0]) return 0;
109
110         /* Use faster algorithms for short needles */
111         h = wcschr(h, *n);
112         if (!h || !n[1]) return (wchar_t *)h;
113         if (!h[1]) return 0;
114         if (!n[2] || !n[3] || !n[4]) return naive_wcsstr(h, n);
115
116         return twoway_wcsstr(h, n);
117 }