summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stream.c32
-rw-r--r--tests/018/path.tl26
-rw-r--r--txr.146
3 files changed, 96 insertions, 8 deletions
diff --git a/stream.c b/stream.c
index 00b4f8d8..6c6a6e65 100644
--- a/stream.c
+++ b/stream.c
@@ -5016,16 +5016,44 @@ val dir_name(val path)
val short_suffix(val name, val alt_in)
{
+ const wchar_t *psc = coerce(const wchar_t *, path_sep_chars);
const wchar_t *str = c_str(name);
const wchar_t *dot = wcsrchr(str, '.');
- return if3(dot, string(dot + 1), default_null_arg(alt_in));
+ const wchar_t *sl = if3(dot, wcspbrk(dot + 1, psc), 0);
+
+ if (!dot || (sl && sl[1])) {
+ return default_null_arg(alt_in);
+ } else {
+ wchar_t *suff = chk_strdup(dot + 1);
+ if (sl)
+ suff[sl - (dot + 1)] = 0;
+ return string_own(suff);
+ }
}
val long_suffix(val name, val alt_in)
{
+ const wchar_t *psc = coerce(const wchar_t *, path_sep_chars);
const wchar_t *str = c_str(name);
const wchar_t *dot = wcschr(str, '.');
- return if3(dot, string(dot + 1), default_null_arg(alt_in));
+
+ {
+ const wchar_t *sl;
+
+ while (dot && (sl = wcspbrk(dot, psc)) && sl[1]) {
+ dot = wcschr(sl + 1, '.');
+ sl = wcspbrk(dot, psc);
+ }
+
+ if (!dot || (sl && sl[1])) {
+ return default_null_arg(alt_in);
+ } else {
+ wchar_t *suff = chk_strdup(dot + 1);
+ if (sl)
+ suff[sl - (dot + 1)] = 0;
+ return string_own(suff);
+ }
+ }
}
val path_cat(val dir_name, val base_name)
diff --git a/tests/018/path.tl b/tests/018/path.tl
index be95d6c1..3dcb5eb3 100644
--- a/tests/018/path.tl
+++ b/tests/018/path.tl
@@ -32,3 +32,29 @@
(long-suffix "foo.txt.gz") "txt.gz"
(long-suffix ".gz") "gz"
(long-suffix ".txt.gz") "txt.gz")
+
+(mtest
+ (short-suffix "/") nil
+ (short-suffix "a/") nil
+ (short-suffix ".a/") "a"
+ (short-suffix ".a/b") nil
+ (short-suffix ".a/b/") nil
+ (short-suffix ".a/b/.b") "b"
+ (short-suffix ".a/b/.b/") "b"
+ (short-suffix ".a/b/c.b") "b"
+ (short-suffix ".a/b/c.b/") "b"
+ (short-suffix ".a/b/c.b//") nil)
+
+(mtest
+ (long-suffix "/") nil
+ (long-suffix "a/") nil
+ (long-suffix ".a/") "a"
+ (long-suffix ".a/b") nil
+ (long-suffix ".a/b/") nil
+ (long-suffix ".a/b/.b") "b"
+ (long-suffix ".a/b/.b/") "b"
+ (long-suffix ".a/b/c.b") "b"
+ (long-suffix ".a/b/c.b/") "b"
+ (long-suffix "a.b/c.d.e") "d.e"
+ (long-suffix "a.b/c.d.e/") "d.e"
+ (long-suffix "a.b/c.d.e//") nil)
diff --git a/txr.1 b/txr.1
index f358e423..cdd9df69 100644
--- a/txr.1
+++ b/txr.1
@@ -57073,26 +57073,55 @@ If
.meta path
does not contain any occurrences of the character
.code .
-(period) then it does not have a suffix. In this situation, both
+(period) in the role of a suffix delimiter, then
+.meta path
+does not have a suffix. In this situation, both
functions return the
.meta alt
argument, which defaults to
.code nil
if it is omitted.
-Otherwise the long and short suffix is the substring of
+What it means for
+.meta path
+to have a suffix delimiter is that the
+.code .
+character occurs somewhere in the last component of
+.metn path .
+What constitutes the last component is specified
+in more detail below.
+
+If a suffix delimiter is present, then the long or short suffix is the
+substring of
.meta path
-consisting of all the characters which follow the delimiting period.
-The delimiting period for the long suffix is the leftmost period;
-the delimiting period for the short suffix is the rightmost period.
+consisting of all the characters which follow the delimiting period,
+exclusive of
+.metn path 's
+trailing path separator, if any.
+
+If multiple periods occur in the last component of the path,
+the delimiter for the long suffix is the leftmost period;
+the delimiter for the short suffix is the rightmost period.
If the delimiting period is the rightmost character of
.metn path ,
+or occurs immediately before a trailing path separator,
then the suffix delimited by that period is the empty string.
If
.meta path
-contains only one period, then its long and short suffix coincide.
+contains only one suffix delimiter, then its long and short suffix coincide.
+
+For the purpose of identifying the last component of
+.meta path
+if
+.meta path
+ends in a path separating character, that character is removed.
+If the remaining string contains path-separating characters, then
+the last component consists of that portion of it which follows
+the rightmost path-separating character. Otherwise, the last component
+is the entire string. The suffix, if present, is identified and
+extracted from this last component.
.TP* Examples:
@@ -57104,6 +57133,9 @@ contains only one period, then its long and short suffix coincide.
(short-suffix "abc.") -> ""
(short-suffix "abc.tar") -> "tar"
(short-suffix "abc.tar.gz") -> "gz"
+ (short-suffix "abc.tar.gz/") -> "gz"
+ (short-suffix "x.y.z/abc.tar.gz/") -> "gz"
+ (short-suffix "x.y.z/abc.tar.gz//") -> nil
(long-suffix "") -> nil
(long-suffix ".") -> ""
@@ -57111,6 +57143,8 @@ contains only one period, then its long and short suffix coincide.
(long-suffix "abc.") -> ""
(long-suffix "abc.tar") -> "txt"
(long-suffix "abc.tar.gz") -> "tar.gz"
+ (long-suffix "abc.tar.gz/") -> "tar.gz"
+ (long-suffix "x.y.z/abc.tar.gz/") -> "tar.gz"
.brev
.coNP Function @ path-cat