Skip to content

Commit 9817d01

Browse files
committed
FIX: FIND string! tag! misses < and >
resolves: Oldes/Rebol-issues#1160
1 parent 3846021 commit 9817d01

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed

src/core/s-find.c

+48
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,54 @@
402402
return NOT_FOUND;
403403
}
404404

405+
/***********************************************************************
406+
**
407+
*/ REBCNT Find_Str_Tag(REBSER *ser1, REBCNT head, REBCNT index, REBCNT tail, REBINT skip, REBSER *ser2, REBCNT index2, REBCNT len, REBCNT flags)
408+
/*
409+
** General purpose find a tag in a string.
410+
**
411+
** Supports: forward/reverse with skip, cased/uncase, Unicode/byte.
412+
**
413+
** Skip can be set positive or negative (for reverse).
414+
**
415+
** Flags are set according to ALL_FIND_REFS
416+
**
417+
***********************************************************************/
418+
{
419+
REBUNI c1;
420+
REBUNI c2;
421+
REBCNT n = 0;
422+
REBOOL uncase = !(flags & AM_FIND_CASE); // uncase = case insenstive
423+
424+
for (; index >= head && index < tail; index += skip) {
425+
c1 = GET_ANY_CHAR(ser1, index);
426+
if (c1 == '<') {
427+
index++;
428+
for (n = 0; n < len; n++) {
429+
c1 = GET_ANY_CHAR(ser1, index + n);
430+
c2 = GET_ANY_CHAR(ser2, index2 + n);
431+
if (uncase && c1 < UNICODE_CASES && c2 < UNICODE_CASES) {
432+
if (LO_CASE(c1) != LO_CASE(c2)) break;
433+
}
434+
else {
435+
if (c1 != c2) break;
436+
}
437+
}
438+
if (n == len) {
439+
c1 = GET_ANY_CHAR(ser1, index + n);
440+
if (c1 == '>') {
441+
if (flags & AM_FIND_TAIL) return index + len + 1;
442+
return index-1;
443+
}
444+
}
445+
}
446+
if (flags & AM_FIND_MATCH) break;
447+
}
448+
449+
return NOT_FOUND;
450+
}
451+
452+
405453
/***********************************************************************
406454
**
407455
*/ REBCNT Find_Str_Str_Any(REBSER *ser1, REBCNT head, REBCNT index, REBCNT tail, REBINT skip, REBSER *ser2, REBCNT index2, REBCNT len, REBCNT flags, REBVAL *wild)

src/core/t-string.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ static REBCNT find_string(REBSER *series, REBCNT index, REBCNT end, REBVAL *targ
118118

119119
if (flags & AM_FIND_SAME) flags |= AM_FIND_CASE; // /SAME has same functionality as /CASE for any-string!
120120

121-
if (ANY_BINSTR(target)) {
121+
//O: not using ANY_BINSTR as TAG is now handled separately
122+
if (VAL_TYPE(target) >= REB_BINARY && VAL_TYPE(target) < REB_TAG) {
122123
// Do the optimal search or the general search?
123124
if (BYTE_SIZE(series) && VAL_BYTE_SIZE(target) && !(flags & ~(AM_FIND_CASE|AM_FIND_MATCH))) {
124125
return Find_Byte_Str(series, start, VAL_BIN_DATA(target), len, !GET_FLAG(flags, ARG_FIND_CASE-1), GET_FLAG(flags, ARG_FIND_MATCH-1));
@@ -128,6 +129,10 @@ static REBCNT find_string(REBSER *series, REBCNT index, REBCNT end, REBVAL *targ
128129
return Find_Str_Str(series, start, index, end, skip, VAL_SERIES(target), VAL_INDEX(target), len, flags & (AM_FIND_MATCH | AM_FIND_CASE | AM_FIND_TAIL));
129130
}
130131
}
132+
else if (IS_TAG(target)) {
133+
return Find_Str_Tag(series, start, index, end, skip, VAL_SERIES(target), VAL_INDEX(target), len, flags & (AM_FIND_MATCH | AM_FIND_CASE | AM_FIND_TAIL));
134+
}
135+
//O: next condition is always false! It could be removed.
131136
else if (IS_BINARY(target)) {
132137
return Find_Byte_Str(series, start, VAL_BIN_DATA(target), len, 0, GET_FLAG(flags, ARG_FIND_MATCH-1));
133138
}

src/tests/units/series-test.r3

+14
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ Rebol [
2626
;@@ https://github.com/Oldes/Rebol-issues/issues/237
2727
--assert "23" = find "123" 2
2828

29+
--test-- "FIND string! tag!"
30+
;@@ https://github.com/Oldes/Rebol-issues/issues/1160
31+
--assert "<a>" = find "<a>" <a>
32+
--assert "b" = find/tail "<a>b" <a>
33+
--assert "<a>3" = find/last "1<a>2<a>3" <a>
34+
--assert "<a>b" = find/match "<a>b" <a>
35+
--assert "b" = find/match/tail "<a>b" <a>
36+
--assert "<a>b" = find/match next "a<a>b" <a>
37+
--assert "<a>b" = find/reverse tail "a<a>b" <a>
38+
--assert none? find/skip "a<a>b" <a> 2
39+
--assert "<a>b" = find/skip "aa<a>b" <a> 2
40+
--assert "<A>" = find/case "<a><A>" <A>
41+
--assert "<a href=''>" = find "foo<a href=''>" <a href=''>
42+
2943
--test-- "FIND %file %file"
3044
;@@ https://github.com/Oldes/Rebol-issues/issues/624
3145
--assert %file = find %file %file

0 commit comments

Comments
 (0)