Skip to content

Commit 0fa74fc

Browse files
committed
A flag for ${...} style escape sequences.
Currently I'm supporting digits here only. In the future named groups would go here too.
1 parent e6a0675 commit 0fa74fc

5 files changed

Lines changed: 119 additions & 22 deletions

File tree

include/re/groups.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ enum re_interpolate_flags {
1515
* means group \0 followed by literal "123".
1616
*/
1717
RE_INTERPOLATE_SINGLE_DIGIT = 1 << 0,
18+
19+
/*
20+
* Enable \{...} syntax for groups.
21+
* Multiple digits are permitted within the braces, regardless
22+
* of whether RE_INTERPOLATE_SINGLE_DIGIT is set or not.
23+
* At least one digit must be present.
24+
*/
25+
RE_INTERPOLATE_BRACES = 1 << 1
1826
};
1927

2028
/*

src/libre/re_interpolate.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ re_interpolate(const char *fmt, char esc, enum re_interpolate_flags flags,
4343
enum {
4444
STATE_LIT,
4545
STATE_ESC,
46-
STATE_DIGIT
46+
STATE_DIGIT,
47+
STATE_OPEN_BRACE,
48+
STATE_INSIDE_BRACES,
4749
} state;
4850

4951
assert(esc != '\0');
@@ -92,6 +94,15 @@ re_interpolate(const char *fmt, char esc, enum re_interpolate_flags flags,
9294
continue;
9395
}
9496

97+
if ((flags & RE_INTERPOLATE_BRACES) && *p == '{') {
98+
if (start != NULL) {
99+
start->byte = p - fmt;
100+
}
101+
102+
state = STATE_OPEN_BRACE;
103+
continue;
104+
}
105+
95106
if (isdigit((unsigned char) *p)) {
96107
group = *p - '0';
97108
state = STATE_DIGIT;
@@ -162,6 +173,60 @@ re_interpolate(const char *fmt, char esc, enum re_interpolate_flags flags,
162173
OUT_CHAR(*p);
163174
continue;
164175

176+
case STATE_OPEN_BRACE:
177+
assert((flags & RE_INTERPOLATE_BRACES));
178+
179+
/* RE_INTERPOLATE_SINGLE_DIGIT does not apply inside braces */
180+
if (isdigit((unsigned char) *p)) {
181+
group = *p - '0';
182+
183+
/* see STATE_DIGIT */
184+
if (group > groupc) {
185+
group = groupc + 1;
186+
}
187+
188+
state = STATE_INSIDE_BRACES;
189+
continue;
190+
}
191+
192+
/* at least one digit is required */
193+
goto error;
194+
195+
case STATE_INSIDE_BRACES:
196+
assert((flags & RE_INTERPOLATE_BRACES));
197+
198+
/* RE_INTERPOLATE_SINGLE_DIGIT does not apply inside braces */
199+
if (isdigit((unsigned char) *p)) {
200+
group *= 10;
201+
group += *p - '0';
202+
203+
/* see STATE_DIGIT */
204+
if (group > groupc) {
205+
group = groupc + 1;
206+
}
207+
continue;
208+
}
209+
210+
if (group == 0) {
211+
OUT_GROUP(group0);
212+
} else if (group <= groupc) {
213+
assert(groupv[group - 1] != NULL);
214+
OUT_GROUP(groupv[group - 1]);
215+
} else if (nonexistent == NULL) {
216+
/* see STATE_DIGIT */
217+
goto error;
218+
} else {
219+
OUT_GROUP(nonexistent);
220+
}
221+
222+
if (*p == '}') {
223+
group = 0;
224+
state = STATE_LIT;
225+
continue;
226+
}
227+
228+
goto error;
229+
165230
default:
166231
assert(!"unreached");
167232
goto error;

tests/re_interpolate/re_interpolate0.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ int main(void) {
4747

4848
test("x", 0, g0, "x");
4949
test("x", 4, gn, "x");
50+
test("{", 0, g0, "{");
51+
test("{", 4, gn, "{");
52+
test("}", 0, g0, "}");
53+
test("}", 4, gn, "}");
5054

5155
test("\001", 0, g0, "\001");
5256
test("\001", 4, gn, "\001");

tests/re_interpolate/re_interpolate1.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
static unsigned failed;
1616

1717
static void
18-
test_err(const char *fmt, size_t groupc, const char *groupv[], const char *ne,
18+
test_err(const char *fmt, enum re_interpolate_flags flags,
19+
size_t groupc, const char *groupv[], const char *ne,
1920
unsigned expected_start, unsigned expected_end)
2021
{
2122
struct re_pos start, end;
@@ -27,7 +28,7 @@ test_err(const char *fmt, size_t groupc, const char *groupv[], const char *ne,
2728
outs[0] = 'x';
2829

2930
/* for these tests we're expecting to error */
30-
if (re_interpolate(fmt, '$', 0, "<g0>", groupc, groupv, ne, outs, sizeof outs, &start, &end)) {
31+
if (re_interpolate(fmt, '$', flags, "<g0>", groupc, groupv, ne, outs, sizeof outs, &start, &end)) {
3132
printf("%s/%zu XXX\n", fmt, groupc);
3233
failed++;
3334
return;
@@ -53,22 +54,31 @@ int main(void) {
5354
const char *gn[] = { "one", "two", "three", "four" };
5455
const char **g0 = NULL;
5556

56-
test_err("$", 0, g0, ne, 0, 1);
57-
test_err("$x", 0, g0, ne, 0, 1);
58-
test_err("$ ", 4, gn, ne, 0, 1);
59-
test_err("$\\01", 0, g0, ne, 0, 1);
57+
test_err("$", 0, 0, g0, ne, 0, 1);
58+
test_err("$x", 0, 0, g0, ne, 0, 1);
59+
test_err("$ ", 0, 4, gn, ne, 0, 1);
60+
test_err("$\\01", 0, 0, g0, ne, 0, 1);
6061

61-
test_err("$0$", 0, g0, ne, 2, 3);
62-
test_err("$$$x", 4, gn, ne, 2, 3);
62+
test_err("$0$", 0, 0, g0, ne, 2, 3);
63+
test_err("$$$x", 0, 4, gn, ne, 2, 3);
6364

64-
test_err("xyz$1", 0, gn, NULL, 3, 5);
65-
test_err("xyz$2", 1, gn, NULL, 3, 5);
65+
test_err("xyz$1", 0, 0, gn, NULL, 3, 5);
66+
test_err("xyz$2", 0, 1, gn, NULL, 3, 5);
6667

67-
test_err("01234567890", 1, gn, ne, 0, 10);
68-
test_err("$$$$$$$$$$$$$$$$$$$$", 1, gn, ne, 0, 20);
69-
test_err("$1$1$1$$", 1, gn, ne, 0, 8);
70-
test_err("$1$1$1x", 1, gn, ne, 0, 7);
71-
test_err("xxxyyyzzz$$", 1, gn, ne, 0, 11);
68+
test_err("01234567890", 0, 1, gn, ne, 0, 10);
69+
test_err("$$$$$$$$$$$$$$$$$$$$", 0, 1, gn, ne, 0, 20);
70+
test_err("$1$1$1$$", 0, 1, gn, ne, 0, 8);
71+
test_err("$1$1$1x", 0, 1, gn, ne, 0, 7);
72+
test_err("xxxyyyzzz$$", 0, 1, gn, ne, 0, 11);
73+
74+
test_err("${", 0, 4, gn, ne, 0, 1);
75+
test_err("${}", 0, 4, gn, ne, 0, 1);
76+
test_err("${}x", 0, 4, gn, ne, 0, 1);
77+
test_err("${1}x", 0, 4, gn, ne, 0, 1);
78+
79+
test_err("${", RE_INTERPOLATE_BRACES, 4, gn, ne, 1, 2);
80+
test_err("${}", RE_INTERPOLATE_BRACES, 4, gn, ne, 1, 2);
81+
test_err("${}x", RE_INTERPOLATE_BRACES, 4, gn, ne, 1, 2);
7282

7383
return failed;
7484
}

tests/re_interpolate/re_interpolate2.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
static unsigned failed;
1616

1717
static void
18-
test(const char *fmt, bool expected)
18+
test(const char *fmt, enum re_interpolate_flags flags, bool expected)
1919
{
2020
bool r;
2121

2222
assert(fmt != NULL);
2323

24-
r = re_interpolate(fmt, '$', 0, "<g0>", 0, NULL, "<ne>", NULL, 0, NULL, NULL);
24+
r = re_interpolate(fmt, '$', flags, "<g0>", 0, NULL, "<ne>", NULL, 0, NULL, NULL);
2525

2626
failed += r != expected;
2727

@@ -30,10 +30,20 @@ test(const char *fmt, bool expected)
3030
}
3131

3232
int main(void) {
33-
test("", true);
34-
test("abc", true);
35-
test("$$", true);
36-
test("$x", false);
33+
test("", 0, true);
34+
test("abc", 0, true);
35+
test("$$", 0, true);
36+
test("$x", 0, false);
37+
test("{", 0, true);
38+
test("}", 0, true);
39+
40+
test("{", RE_INTERPOLATE_BRACES, true);
41+
test("}", RE_INTERPOLATE_BRACES, true);
42+
43+
test("${", RE_INTERPOLATE_BRACES, false);
44+
test("${}", RE_INTERPOLATE_BRACES, false);
45+
test("$}{", RE_INTERPOLATE_BRACES, false);
46+
test("{$}", RE_INTERPOLATE_BRACES, false);
3747

3848
return failed;
3949
}

0 commit comments

Comments
 (0)