summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stream.c83
-rw-r--r--stream.h4
-rw-r--r--txr.179
-rw-r--r--txr.c8
4 files changed, 166 insertions, 8 deletions
diff --git a/stream.c b/stream.c
index a7ff92c8..021dd2f1 100644
--- a/stream.c
+++ b/stream.c
@@ -89,6 +89,8 @@ val stdio_stream_s;
val socket_error_s;
#endif
+const wchli_t *path_sep_chars = wli("/");
+
val shell, shell_arg;
void strm_base_init(struct strm_base *s)
@@ -4158,12 +4160,89 @@ val pure_rel_path_p(val path)
return t;
}
+static void detect_path_separators(void)
+{
+#ifdef __CYGWIN__
+ struct utsname un;
+
+ if (uname(&un) >= 0) {
+ if (strncmp(un.sysname, "CYGNAL", 6) == 0)
+ path_sep_chars = wli("\\/");
+ return;
+ }
+#endif
+}
+
+val base_name(val path)
+{
+ const wchar_t *wpath = c_str(path);
+ const wchar_t *end = wpath + c_num(length_str(path));
+ const wchar_t *rsep;
+ const wchar_t *psc = wref(coerce(const wchar_t *, path_sep_chars));
+
+ if (end == wpath)
+ return null_string;
+
+ while (wpath < end && wcschr(psc, end[-1]))
+ end--;
+
+ if (end == wpath)
+ return lit("/");
+
+ for (rsep = end;
+ wpath < rsep && wcschr(psc, rsep[-1]) == 0;
+ rsep--)
+ ; /* *empty */
+
+
+ {
+ val base = mkustring(num_fast(end - rsep));
+ return init_str(base, rsep);
+ }
+}
+
+val dir_name(val path)
+{
+ const wchar_t *wpath = c_str(path);
+ const wchar_t *rsep = wpath + c_num(length_str(path));
+ const wchar_t *psc = wref(coerce(const wchar_t *, path_sep_chars));
+
+ if (rsep == wpath)
+ return lit(".");
+
+ if (wcschr(psc, rsep[-1]))
+ rsep--;
+
+ if (rsep == wpath) {
+ wchar_t root[2] = { psc[0] };
+ return string(root);
+ }
+
+ for (; rsep > wpath && wcschr(psc, rsep[-1]) == 0; rsep--)
+ ; /* *empty */
+
+ if (rsep == wpath + 1) {
+ wchar_t root[2] = { psc[0] };
+ return string(root);
+ }
+
+ if (rsep == wpath)
+ return lit(".");
+
+
+ {
+ val base = mkustring(num_fast(rsep - wpath - 1));
+ return init_str(base, wpath);
+ }
+}
+
void stream_init(void)
{
prot1(&ap_regex);
prot1(&plp_regex);
detect_format_string();
+ detect_path_separators();
from_start_k = intern(lit("from-start"), keyword_package);
from_current_k = intern(lit("from-current"), keyword_package);
@@ -4270,7 +4349,9 @@ void stream_init(void)
reg_fun(intern(lit("open-files*"), user_package), func_n2o(open_files_star, 1));
reg_fun(intern(lit("abs-path-p"), user_package), func_n1(abs_path_p));
reg_fun(intern(lit("pure-rel-path-p"), user_package), func_n1(pure_rel_path_p));
-
+ reg_fun(intern(lit("base-name"), user_package), func_n1(base_name));
+ reg_fun(intern(lit("dir-name"), user_package), func_n1(dir_name));
+ reg_varl(intern(lit("path-sep-chars"), user_package), static_str(path_sep_chars));
reg_fun(intern(lit("get-indent-mode"), user_package), func_n1(get_indent_mode));
reg_fun(intern(lit("test-set-indent-mode"), user_package), func_n3(test_set_indent_mode));
reg_fun(intern(lit("set-indent-mode"), user_package), func_n2(set_indent_mode));
diff --git a/stream.h b/stream.h
index 1985cb42..290af343 100644
--- a/stream.h
+++ b/stream.h
@@ -129,6 +129,8 @@ extern val pprint_flo_format_s, print_base_s, print_circle_s;
extern val socket_error_s;
#endif
+extern const wchli_t *path_sep_chars;
+
void strm_base_init(struct strm_base *s);
void strm_base_cleanup(struct strm_base *s);
void strm_base_mark(struct strm_base *s);
@@ -213,5 +215,7 @@ val remove_path(val path, val throw_on_error);
val rename_path(val from, val to);
val abs_path_p(val path);
val pure_rel_path_p(val path);
+val base_name(val path);
+val dir_name(val path);
void stream_init(void);
diff --git a/txr.1 b/txr.1
index 6a29f53d..ae73c821 100644
--- a/txr.1
+++ b/txr.1
@@ -41445,6 +41445,85 @@ Examples of strings which are not pure relative paths:
$:\eabc
.cble
+.coNP Functions @ dir-name and @ base-name
+.synb
+.mets (dir-name << path )
+.mets (base-name << path )
+.syne
+.desc
+The
+.code dir-name
+and
+.code base-name
+functions calculate, respective, the directory part and
+base name part of a path name.
+
+The calculation is performed in a platform-dependent way, using the
+characters in the variable
+.code path-sep-chars
+as path component separators.
+
+Both functions first remove from any further consideration all superfluous
+trailing occurrences of the directory separator characters from
+.codn path .
+Thus input such as
+.str "a////"
+is reduced to just
+.strn "a" ,
+and
+.str "///"
+is reduced to
+.strn "/" .
+
+The resulting trimmed path is the
+.I "effective path" .
+
+If the effective path is an empty string, then
+.code dir-name
+returns
+.str "."
+and
+.code base-name
+returns the empty string.
+
+If the effective path is not empty, and contains no path separator
+characters, then
+.code dir-name
+returns
+.str "."
+and
+.code base-name
+returns the effective path.
+
+Otherwise, the effective path is divided into two parts: the
+.I "raw directory prefix"
+and the remainder.
+
+The raw directory path is the maximally long prefix of the effective
+path which ends in a separator character.
+
+The
+.code dir-name
+function returns the raw directory prefix, if that prefix consists of
+nothing but a single directory separator character. Otherwise it
+returns the raw directory prefix, with the trailing path separator
+removed.
+
+The
+.code base-name
+function returns the remaining part of the effective path, after
+the raw directory prefix.
+
+.coNP Variable @ path-sep-chars
+.desc
+The
+.code path-sep-chars
+variable holds a string consisting of the characters which the underlying
+operating system recognizes as path name separators.
+
+Altering the value of this variable has no effect on any \*(TL library
+function.
+
.coNP Functions @ read and @ iread
.synb
.mets (read >> [ source >> [ error-stream >> [ error-retval <> [ name ]]]])
diff --git a/txr.c b/txr.c
index 5b0ade21..743530c3 100644
--- a/txr.c
+++ b/txr.c
@@ -273,12 +273,6 @@ static val maybe_sysroot(val exepart)
sysroot_path = sub_str(prog_path, 0, neg(length(exepart))));
}
-static val dirname(val path)
-{
- val rslash = rpos(chr('/'), path, nil, nil);
- return if3(rslash, sub_str(path, zero, succ(rslash)), path);
-}
-
static val substitute_basename(val edited_path, val source_path)
{
val lslash = rpos(chr('/'), edited_path, nil, nil);
@@ -311,7 +305,7 @@ static void sysroot_init(void)
#if HAVE_WINDOWS_H
prog_path = regsub(slash, lit("/"), prog_path);
#endif
- prog_dir = dirname(prog_path);
+ prog_dir = dir_name(prog_path);
if (!(maybe_sysroot(lit(TXR_REL_PATH)) ||
maybe_sysroot(lit(TXR_REL_PATH EXE_SUFF)) ||