Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
ccan
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mirror
ccan
Commits
f103f73f
Commit
f103f73f
authored
Nov 22, 2012
by
Rusty Russell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tal/str: accept take() for arguments.
Signed-off-by:
Rusty Russell
<
rusty@rustcorp.com.au
>
parent
d873aaec
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
251 additions
and
85 deletions
+251
-85
ccan/tal/str/_info
ccan/tal/str/_info
+1
-0
ccan/tal/str/str.c
ccan/tal/str/str.c
+107
-56
ccan/tal/str/str.h
ccan/tal/str/str.h
+17
-15
ccan/tal/str/test/run-strreg.c
ccan/tal/str/test/run-strreg.c
+37
-13
ccan/tal/str/test/run.c
ccan/tal/str/test/run.c
+89
-1
No files found.
ccan/tal/str/_info
View file @
f103f73f
...
...
@@ -45,6 +45,7 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/str\n");
printf("ccan/tal\n");
printf("ccan/take\n");
return 0;
}
...
...
ccan/tal/str/str.c
View file @
f103f73f
...
...
@@ -9,98 +9,149 @@
#include <regex.h>
#include <stdarg.h>
#include <unistd.h>
#include <ccan/tal/tal.h>
#include <ccan/str/str.h>
#include <ccan/tal/tal.h>
#include <ccan/take/take.h>
char
**
strsplit
(
const
void
*
ctx
,
const
char
*
string
,
const
char
*
delims
,
enum
strsplit
flags
)
char
**
strsplit
(
const
tal_t
*
ctx
,
const
char
*
string
,
const
char
*
delims
,
enum
strsplit
flags
)
{
char
**
lines
=
NULL
;
char
**
parts
,
*
str
;
size_t
max
=
64
,
num
=
0
;
lines
=
tal_arr
(
ctx
,
char
*
,
max
+
1
);
parts
=
tal_arr
(
ctx
,
char
*
,
max
+
1
);
if
(
unlikely
(
!
parts
))
{
if
(
taken
(
string
))
tal_free
(
string
);
if
(
taken
(
delims
))
tal_free
(
delims
);
return
NULL
;
}
str
=
tal_strdup
(
parts
,
string
);
if
(
unlikely
(
!
str
))
goto
fail
;
if
(
unlikely
(
!
delims
)
&&
is_taken
(
delims
))
goto
fail
;
if
(
flags
==
STR_NO_EMPTY
)
str
ing
+=
strspn
(
string
,
delims
);
str
+=
strspn
(
str
,
delims
);
while
(
*
str
ing
!=
'\0'
)
{
size_t
len
=
strcspn
(
str
ing
,
delims
),
dlen
;
while
(
*
str
!=
'\0'
)
{
size_t
len
=
strcspn
(
str
,
delims
),
dlen
;
lines
[
num
]
=
tal_arr
(
lines
,
char
,
len
+
1
);
memcpy
(
lines
[
num
],
string
,
len
);
lines
[
num
][
len
]
=
'\0'
;
string
+=
len
;
dlen
=
strspn
(
string
,
delims
);
parts
[
num
]
=
str
;
dlen
=
strspn
(
str
+
len
,
delims
);
parts
[
num
][
len
]
=
'\0'
;
if
(
flags
==
STR_EMPTY_OK
&&
dlen
)
dlen
=
1
;
str
ing
+=
dlen
;
if
(
++
num
==
max
)
tal_resize
(
&
lines
,
max
*=
2
+
1
)
;
str
+=
len
+
dlen
;
if
(
++
num
==
max
&&
!
tal_resize
(
&
parts
,
max
*=
2
+
1
)
)
goto
fail
;
}
lines
[
num
]
=
NULL
;
return
lines
;
parts
[
num
]
=
NULL
;
if
(
taken
(
delims
))
tal_free
(
delims
);
return
parts
;
fail:
tal_free
(
parts
);
if
(
taken
(
delims
))
tal_free
(
delims
);
return
NULL
;
}
char
*
strjoin
(
const
void
*
ctx
,
char
*
strings
[],
const
char
*
delim
,
enum
strjoin
flags
)
char
*
strjoin
(
const
tal_t
*
ctx
,
char
*
strings
[],
const
char
*
delim
,
enum
strjoin
flags
)
{
unsigned
int
i
;
char
*
ret
=
tal_strdup
(
ctx
,
""
)
;
size_t
totlen
=
0
,
dlen
=
strlen
(
delim
)
;
char
*
ret
=
NULL
;
size_t
totlen
=
0
,
dlen
;
if
(
unlikely
(
!
strings
)
&&
is_taken
(
strings
))
goto
fail
;
if
(
unlikely
(
!
delim
)
&&
is_taken
(
delim
))
goto
fail
;
dlen
=
strlen
(
delim
);
ret
=
tal_arr
(
ctx
,
char
,
dlen
*
2
+
1
);
if
(
!
ret
)
goto
fail
;
ret
[
0
]
=
'\0'
;
for
(
i
=
0
;
strings
[
i
];
i
++
)
{
size_t
len
=
strlen
(
strings
[
i
]);
if
(
flags
==
STR_NO_TRAIL
&&
!
strings
[
i
+
1
])
dlen
=
0
;
tal_resize
(
&
ret
,
totlen
+
len
+
dlen
+
1
);
if
(
!
tal_resize
(
&
ret
,
totlen
+
len
+
dlen
+
1
))
goto
fail
;
memcpy
(
ret
+
totlen
,
strings
[
i
],
len
);
totlen
+=
len
;
memcpy
(
ret
+
totlen
,
delim
,
dlen
);
totlen
+=
dlen
;
}
ret
[
totlen
]
=
'\0'
;
out:
if
(
taken
(
strings
))
tal_free
(
strings
);
if
(
taken
(
delim
))
tal_free
(
delim
);
return
ret
;
fail:
ret
=
tal_free
(
ret
);
goto
out
;
}
bool
strreg
(
const
void
*
ctx
,
const
char
*
string
,
const
char
*
regex
,
...)
bool
strreg
(
const
tal_t
*
ctx
,
const
char
*
string
,
const
char
*
regex
,
...)
{
size_t
nmatch
=
1
+
strcount
(
regex
,
"("
);
regmatch_t
*
matches
=
tal_arr
(
ctx
,
regmatch_t
,
nmatch
)
;
regmatch_t
matches
[
nmatch
]
;
regex_t
r
;
bool
ret
;
if
(
!
matches
||
regcomp
(
&
r
,
regex
,
REG_EXTENDED
)
!=
0
)
return
false
;
if
(
regexec
(
&
r
,
string
,
nmatch
,
matches
,
0
)
==
0
)
{
unsigned
int
i
;
va_list
ap
;
ret
=
true
;
va_start
(
ap
,
regex
);
for
(
i
=
1
;
i
<
nmatch
;
i
++
)
{
char
**
arg
;
arg
=
va_arg
(
ap
,
char
**
);
if
(
arg
)
{
/* eg. ([a-z])? can give "no match". */
if
(
matches
[
i
].
rm_so
==
-
1
)
*
arg
=
NULL
;
else
{
*
arg
=
tal_strndup
(
ctx
,
string
+
matches
[
i
].
rm_so
,
matches
[
i
].
rm_eo
-
matches
[
i
].
rm_so
);
if
(
!*
arg
)
{
ret
=
false
;
break
;
}
bool
ret
=
false
;
unsigned
int
i
;
va_list
ap
;
if
(
unlikely
(
!
regex
)
&&
is_taken
(
regex
))
goto
fail_no_re
;
if
(
regcomp
(
&
r
,
regex
,
REG_EXTENDED
)
!=
0
)
goto
fail_no_re
;
if
(
unlikely
(
!
string
)
&&
is_taken
(
string
))
goto
fail
;
if
(
regexec
(
&
r
,
string
,
nmatch
,
matches
,
0
)
!=
0
)
goto
fail
;
ret
=
true
;
va_start
(
ap
,
regex
);
for
(
i
=
1
;
i
<
nmatch
;
i
++
)
{
char
**
arg
=
va_arg
(
ap
,
char
**
);
if
(
arg
)
{
/* eg. ([a-z])? can give "no match". */
if
(
matches
[
i
].
rm_so
==
-
1
)
*
arg
=
NULL
;
else
{
*
arg
=
tal_strndup
(
ctx
,
string
+
matches
[
i
].
rm_so
,
matches
[
i
].
rm_eo
-
matches
[
i
].
rm_so
);
/* FIXME: If we fail, we set some and leak! */
if
(
!*
arg
)
{
ret
=
false
;
break
;
}
}
}
va_end
(
ap
);
}
else
ret
=
false
;
tal_free
(
matches
);
}
va_end
(
ap
);
fail:
regfree
(
&
r
);
fail_no_re:
if
(
taken
(
regex
))
tal_free
(
regex
);
if
(
taken
(
string
))
tal_free
(
string
);
return
ret
;
}
ccan/tal/str/str.h
View file @
f103f73f
...
...
@@ -13,16 +13,18 @@ enum strsplit {
/**
* strsplit - Split string into an array of substrings
* @ctx: the
parent to tal from (often NULL)
* @string: the string to split
* @delims: delimiters where lines should be split.
* @ctx: the
context to tal from (often NULL).
* @string: the string to split
(can be take()).
* @delims: delimiters where lines should be split
(can be take())
.
* @flags: whether to include empty substrings.
*
* This function splits a single string into multiple strings. The
* original string is untouched: an array is allocated (using tal)
* pointing to copies of each substring. Multiple delimiters result
* in empty substrings. By definition, no delimiters will appear in
* the substrings.
* This function splits a single string into multiple strings.
*
* If @string is take(), the returned array will point into the
* mangled @string.
*
* Multiple delimiters result in empty substrings. By definition, no
* delimiters will appear in the substrings.
*
* The final char * in the array will be NULL.
*
...
...
@@ -43,8 +45,8 @@ enum strsplit {
* return long_lines;
* }
*/
char
**
strsplit
(
const
void
*
ctx
,
const
char
*
string
,
const
char
*
delims
,
enum
strsplit
flags
);
char
**
strsplit
(
const
tal_t
*
ctx
,
const
char
*
string
,
const
char
*
delims
,
enum
strsplit
flags
);
enum
strjoin
{
STR_TRAIL
,
...
...
@@ -53,9 +55,9 @@ enum strjoin {
/**
* strjoin - Join an array of substrings into one long string
* @ctx: the context to tal from (often NULL)
* @strings: the NULL-terminated array of strings to join
* @delim: the delimiter to insert between the strings
* @ctx: the context to tal from (often NULL)
.
* @strings: the NULL-terminated array of strings to join
(can be take())
* @delim: the delimiter to insert between the strings
(can be take())
* @flags: whether to add a delimieter to the end
*
* This function joins an array of strings into a single string. The
...
...
@@ -80,8 +82,8 @@ char *strjoin(const void *ctx, char *strings[], const char *delim,
/**
* strreg - match and extract from a string via (extended) regular expressions.
* @ctx: the context to tal from (often NULL)
* @string: the string to try to match
.
* @regex: the regular expression to match
.
* @string: the string to try to match
(can be take())
* @regex: the regular expression to match
(can be take())
* ...: pointers to strings to allocate for subexpressions.
*
* Returns true if we matched, in which case any parenthesized
...
...
ccan/tal/str/test/run-strreg.c
View file @
f103f73f
...
...
@@ -2,16 +2,6 @@
#include <ccan/tal/str/str.c>
#include <ccan/tap/tap.h>
static
unsigned
int
tal_total_blocks
(
tal_t
*
ctx
)
{
unsigned
int
num
=
1
;
tal_t
*
i
;
for
(
i
=
tal_first
(
ctx
);
i
;
i
=
tal_next
(
ctx
,
i
))
num
++
;
return
num
;
}
static
bool
find_parent
(
tal_t
*
child
,
tal_t
*
parent
)
{
tal_t
*
i
;
...
...
@@ -26,12 +16,11 @@ static bool find_parent(tal_t *child, tal_t *parent)
int
main
(
int
argc
,
char
*
argv
[])
{
void
*
ctx
=
tal_strdup
(
NULL
,
"toplevel"
);
unsigned
int
top_blocks
=
tal_total_blocks
(
ctx
);
char
*
a
,
*
b
;
/* If it accesses this, it will crash. */
char
**
invalid
=
(
char
**
)
1L
;
plan_tests
(
25
);
plan_tests
(
40
);
/* Simple matching. */
ok1
(
strreg
(
ctx
,
"hello world!"
,
"hello"
)
==
true
);
ok1
(
strreg
(
ctx
,
"hello world!"
,
"hi"
)
==
false
);
...
...
@@ -88,7 +77,42 @@ int main(int argc, char *argv[])
tal_free
(
a
);
/* No leaks! */
ok1
(
tal_total_blocks
(
ctx
)
==
top_blocks
);
ok1
(
!
tal_first
(
ctx
));
/* NULL arg with take means always fail. */
ok1
(
strreg
(
ctx
,
take
(
NULL
),
"((hello|goodbye) world)"
,
&
b
,
NULL
,
invalid
)
==
false
);
/* Take string. */
a
=
tal_strdup
(
ctx
,
"hello world!"
);
ok1
(
strreg
(
ctx
,
take
(
a
),
"([a-z]+)"
,
&
b
,
invalid
)
==
true
);
ok1
(
streq
(
b
,
"hello"
));
ok1
(
tal_parent
(
b
)
==
ctx
);
tal_free
(
b
);
ok1
(
tal_first
(
ctx
)
==
NULL
);
/* Take regex. */
a
=
tal_strdup
(
ctx
,
"([a-z]+)"
);
ok1
(
strreg
(
ctx
,
"hello world!"
,
take
(
a
),
&
b
,
invalid
)
==
true
);
ok1
(
streq
(
b
,
"hello"
));
ok1
(
tal_parent
(
b
)
==
ctx
);
tal_free
(
b
);
ok1
(
tal_first
(
ctx
)
==
NULL
);
/* Take both. */
a
=
tal_strdup
(
ctx
,
"([a-z]+)"
);
ok1
(
strreg
(
ctx
,
take
(
tal_strdup
(
ctx
,
"hello world!"
)),
take
(
a
),
&
b
,
invalid
)
==
true
);
ok1
(
streq
(
b
,
"hello"
));
ok1
(
tal_parent
(
b
)
==
ctx
);
tal_free
(
b
);
ok1
(
tal_first
(
ctx
)
==
NULL
);
/* ... even if we fail to match. */
a
=
tal_strdup
(
ctx
,
"([a-z]+)"
);
ok1
(
strreg
(
ctx
,
take
(
tal_strdup
(
ctx
,
"HELLO WORLD!"
)),
take
(
a
),
&
b
,
invalid
)
==
false
);
ok1
(
tal_first
(
ctx
)
==
NULL
);
tal_free
(
ctx
);
return
exit_status
();
...
...
ccan/tal/str/test/run.c
View file @
f103f73f
...
...
@@ -14,7 +14,7 @@ int main(int argc, char *argv[])
char
**
split
,
*
str
;
void
*
ctx
;
plan_tests
(
24
);
plan_tests
(
65
);
split
=
strsplit
(
NULL
,
"hello world"
,
" "
,
STR_EMPTY_OK
);
ok1
(
!
strcmp
(
split
[
0
],
"hello"
));
ok1
(
!
strcmp
(
split
[
1
],
""
));
...
...
@@ -61,5 +61,93 @@ int main(int argc, char *argv[])
ok1
(
tal_parent
(
str
)
==
ctx
);
tal_free
(
ctx
);
ctx
=
tal_strdup
(
NULL
,
"context"
);
/* Pass through NULLs from take. */
ok1
(
strsplit
(
NULL
,
take
(
NULL
),
" "
,
STR_EMPTY_OK
)
==
NULL
);
ok1
(
strsplit
(
NULL
,
"foo"
,
take
(
NULL
),
STR_EMPTY_OK
)
==
NULL
);
/* strsplit take string. It reallocs it to same size, but
* that sometimes causes a move, so we can't directly check
* that split[0] == str. */
str
=
tal_strdup
(
ctx
,
"hello world"
);
ok1
(
tal_check
(
ctx
,
NULL
));
ok1
(
tal_check
(
str
,
NULL
));
split
=
strsplit
(
ctx
,
take
(
str
),
" "
,
STR_EMPTY_OK
);
ok1
(
tal_parent
(
split
)
==
ctx
);
ok1
(
!
strcmp
(
split
[
0
],
"hello"
));
ok1
(
!
strcmp
(
split
[
1
],
"world"
));
ok1
(
split
[
2
]
==
NULL
);
ok1
(
tal_check
(
split
,
NULL
));
ok1
(
tal_check
(
ctx
,
NULL
));
tal_free
(
split
);
/* Previous free should get rid of str */
ok1
(
!
tal_first
(
ctx
));
/* strsplit take delims */
str
=
tal_strdup
(
ctx
,
" "
);
split
=
strsplit
(
ctx
,
"hello world"
,
take
(
str
),
STR_EMPTY_OK
);
ok1
(
tal_parent
(
split
)
==
ctx
);
ok1
(
!
strcmp
(
split
[
0
],
"hello"
));
ok1
(
!
strcmp
(
split
[
1
],
"world"
));
ok1
(
split
[
2
]
==
NULL
);
ok1
(
tal_check
(
split
,
NULL
));
ok1
(
tal_check
(
ctx
,
NULL
));
tal_free
(
split
);
/* str is gone... */
ok1
(
!
tal_first
(
ctx
));
/* strsplit takes both. */
split
=
strsplit
(
ctx
,
take
(
tal_strdup
(
NULL
,
"hello world"
)),
take
(
tal_strdup
(
NULL
,
" "
)),
STR_EMPTY_OK
);
ok1
(
tal_parent
(
split
)
==
ctx
);
ok1
(
!
strcmp
(
split
[
0
],
"hello"
));
ok1
(
!
strcmp
(
split
[
1
],
"world"
));
ok1
(
split
[
2
]
==
NULL
);
ok1
(
tal_check
(
split
,
NULL
));
ok1
(
tal_check
(
ctx
,
NULL
));
tal_free
(
split
);
/* temp allocs are gone... */
ok1
(
!
tal_first
(
ctx
));
/* strjoin passthrough taken NULLs OK. */
ok1
(
strjoin
(
ctx
,
take
(
NULL
),
""
,
STR_TRAIL
)
==
NULL
);
ok1
(
strjoin
(
ctx
,
take
(
NULL
),
""
,
STR_NO_TRAIL
)
==
NULL
);
ok1
(
strjoin
(
ctx
,
split
,
take
(
NULL
),
STR_TRAIL
)
==
NULL
);
ok1
(
strjoin
(
ctx
,
split
,
take
(
NULL
),
STR_NO_TRAIL
)
==
NULL
);
/* strjoin take strings[] */
split
=
strsplit
(
ctx
,
"hello world"
,
" "
,
STR_EMPTY_OK
);
str
=
strjoin
(
ctx
,
take
(
split
),
" there "
,
STR_NO_TRAIL
);
ok1
(
!
strcmp
(
str
,
"hello there world"
));
ok1
(
tal_parent
(
str
)
==
ctx
);
/* split is gone... */
ok1
(
tal_first
(
ctx
)
==
str
&&
!
tal_next
(
ctx
,
str
));
tal_free
(
str
);
ok1
(
!
tal_first
(
ctx
));
/* strjoin take delim */
split
=
strsplit
(
ctx
,
"hello world"
,
" "
,
STR_EMPTY_OK
);
str
=
strjoin
(
ctx
,
split
,
take
(
tal_strdup
(
ctx
,
" there "
)),
STR_NO_TRAIL
);
ok1
(
!
strcmp
(
str
,
"hello there world"
));
ok1
(
tal_parent
(
str
)
==
ctx
);
tal_free
(
split
);
/* tmp alloc is gone, str is only remainder. */
ok1
(
tal_first
(
ctx
)
==
str
&&
!
tal_next
(
ctx
,
str
));
tal_free
(
str
);
ok1
(
!
tal_first
(
ctx
));
/* strjoin take both. */
str
=
strjoin
(
ctx
,
take
(
strsplit
(
ctx
,
"hello world"
,
" "
,
STR_EMPTY_OK
)),
take
(
tal_strdup
(
ctx
,
" there "
)),
STR_NO_TRAIL
);
ok1
(
!
strcmp
(
str
,
"hello there world"
));
ok1
(
tal_parent
(
str
)
==
ctx
);
/* tmp allocs are gone, str is only remainder. */
ok1
(
tal_first
(
ctx
)
==
str
&&
!
tal_next
(
ctx
,
str
));
tal_free
(
str
);
ok1
(
!
tal_first
(
ctx
));
tal_free
(
ctx
);
return
exit_status
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment