summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-05-31 07:49:38 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-05-31 07:49:38 -0700
commitfdb8f90b22f8d4993b5937d55f5cbffc45ae940c (patch)
tree30f6c8cd4f9318010f8bbe0d8558806af7358cc8
parent93454f1fc069d7d5a0af7b2aa1c773949b59d106 (diff)
downloadtxr-fdb8f90b22f8d4993b5937d55f5cbffc45ae940c.tar.gz
txr-fdb8f90b22f8d4993b5937d55f5cbffc45ae940c.tar.bz2
txr-fdb8f90b22f8d4993b5937d55f5cbffc45ae940c.zip
New: mkdtemp and mkstemp functions.
* configure: check for mkstemp and mkdtemp. * stream.c (stdio_set_prop): Implement setting the :name property. We need this in mkstemp_wrap in order to punch in the temporary name, so that the application can retrieve it. (mkdtemp_wrap, mkstemp_wrap): New functions. (stream_init): Register mkdtemp and mkstemp intrinsics. * stream.h (mkdtemp_wrap, mkstemp_wrap): Declared. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
-rwxr-xr-xconfigure21
-rw-r--r--share/txr/stdlib/doc-syms.tl2
-rw-r--r--stream.c55
-rw-r--r--stream.h2
-rw-r--r--txr.185
5 files changed, 165 insertions, 0 deletions
diff --git a/configure b/configure
index bf5cfb82..666a238d 100755
--- a/configure
+++ b/configure
@@ -3228,6 +3228,27 @@ if [ -z "$have_winsize" ] ; then
printf "no\n"
fi
+printf "Checking for mkstemp/mkdtemp ... "
+
+cat > conftest.c <<!
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ char templ[] = "abcXXXXXX";
+ int fd = mkstemp(templ);
+ char *s = mkdtemp(templ);
+ return 0;
+}
+!
+
+if conftest ; then
+ printf "yes\n"
+ printf "#define HAVE_MKSTEMP 1\n" >> config.h
+else
+ printf "no\n"
+fi
+
printf "Checking for mkstemps ... "
cat > conftest.c <<!
diff --git a/share/txr/stdlib/doc-syms.tl b/share/txr/stdlib/doc-syms.tl
index 223eb987..177ac266 100644
--- a/share/txr/stdlib/doc-syms.tl
+++ b/share/txr/stdlib/doc-syms.tl
@@ -1222,8 +1222,10 @@
("minusp" "D-0050")
("mismatch" "N-03164F4F")
("mkdir" "N-00C543B8")
+ ("mkdtemp" "N-026E4871")
("mkfifo" "N-0091FD43")
("mknod" "N-00F93A39")
+ ("mkstemp" "N-026E0471")
("mkstring" "N-033DD796")
("mlet" "N-008216E0")
("mmakunbound" "N-02964FC0")
diff --git a/stream.c b/stream.c
index 14e1f725..34509f87 100644
--- a/stream.c
+++ b/stream.c
@@ -738,6 +738,8 @@ static val stdio_set_prop(val stream, val ind, val prop)
} else if (ind == byte_oriented_k) {
h->is_byte_oriented = prop ? 1 : 0;
return t;
+ } else if (ind == name_k) {
+ h->descr = prop;
}
return nil;
}
@@ -4952,6 +4954,55 @@ val tmpfile_wrap(void)
num(errno), errno_to_str(errno), nao);
}
+#if HAVE_MKSTEMP
+
+val mkdtemp_wrap(val template)
+{
+ char *tmpl = utf8_dup_to(c_str(scat2(template, lit("XXXXXX"))));
+
+ if (mkdtemp(tmpl) != 0) {
+ val ret = string_utf8(tmpl);
+ free(tmpl);
+ return ret;
+ }
+
+ free(tmpl);
+ uw_throwf(file_error_s, lit("mkdtemp failed: ~d/~s"),
+ num(errno), errno_to_str(errno), nao);
+}
+
+val mkstemp_wrap(val prefix, val suffix)
+{
+ val self = lit("mkstemp");
+ val suff = default_arg(suffix, null_string);
+ val template = scat3(prefix, lit("XXXXXX"), suff);
+ cnum slen = c_num(length(suffix), self);
+ char *tmpl = utf8_dup_to(c_str(template));
+ val name;
+ int fd;
+
+#if HAVE_MKSTEMPS
+ fd = mkstemps(tmpl, slen);
+#else
+ if (slen > 0) {
+ free(tmpl);
+ uw_throwf(system_error_s, lit("~a: suffix not supported"), self, nao);
+ }
+ fd = mkstemps(tmpl);
+#endif
+ name = string_utf8(tmpl);
+ free(tmpl);
+ if (fd != -1) {
+ val stream = open_fileno(num(fd), lit("w+b"));
+ stream_set_prop(stream, name_k, name);
+ return stream;
+ }
+ uw_throwf(file_error_s, lit("~a failed: ~d/~s"),
+ self, num(errno), errno_to_str(errno), nao);
+}
+
+#endif
+
static val iobuf_free_list;
val iobuf_get(void)
@@ -5145,6 +5196,10 @@ void stream_init(void)
reg_varl(intern(lit("indent-code"), user_package), num_fast(indent_code));
reg_varl(intern(lit("indent-foff"), user_package), num_fast(indent_foff));
reg_fun(intern(lit("tmpfile"), user_package), func_n0(tmpfile_wrap));
+#if HAVE_MKSTEMP
+ reg_fun(intern(lit("mkdtemp"), user_package), func_n1(mkdtemp_wrap));
+ reg_fun(intern(lit("mkstemp"), user_package), func_n2o(mkstemp_wrap, 1));
+#endif
#if HAVE_SOCKETS
uw_register_subtype(socket_error_s, error_s);
diff --git a/stream.h b/stream.h
index 8e6874dc..cdfe9d8c 100644
--- a/stream.h
+++ b/stream.h
@@ -252,4 +252,6 @@ val iobuf_get(void);
void iobuf_put(val buf);
void iobuf_list_empty(void);
val tmpfile_wrap(void);
+val mkdtemp_wrap(val template);
+val mkstemp_wrap(val prefix, val suffix);
void stream_init(void);
diff --git a/txr.1 b/txr.1
index 6da4c92e..a0d9773d 100644
--- a/txr.1
+++ b/txr.1
@@ -55048,6 +55048,14 @@ in the file system. POSIX (IEEE Std 1003.1-2017) notes that in some
implementations, "a permanent file may be left behind if the process calling
tmpfile() is killed while it is processing a call to tmpfile".
+Notes: if a unique file is required which exists in the file system under a
+known name until explicitly deleted, the
+.code mkstemp
+function may be used. If a unique directory needs to be created, the
+.code mkdtemp
+function may be used. These two functions are described in the Unix Filesystem
+Complex Operations section of the manual.
+
.coNP Function @ make-string-input-stream
.synb
.mets (make-string-input-stream << string )
@@ -65556,6 +65564,83 @@ is a symbolic link, it is dereferenced;
.code touch
operates on the target of the link.
+.coNP Function @ mkdtemp
+.synb
+.mets (mkdtemp << prefix )
+.syne
+.desc
+The
+.code mkdtemp
+function combines the
+.metn prefix ,
+which is a string, with a generated suffix to create a unique directory
+name. The directory is created, and the name is returned.
+
+If the
+.code prefix
+argument ends in with a sequence of one or more
+.code X
+characters, the behavior is unspecified.
+
+Note: this function is implemented using the same-named POSIX function.
+Whereas the POSIX function requires the template to end in a sequence of
+at least six
+.code X
+characters, which are replaced by the generated suffix, the \*(TL function
+handles this detail internally, requiring only the prefix part without those
+characters.
+
+.coNP Function @ mkstemp
+.synb
+.mets (mkstemp << prefix <> [ suffix ])
+.syne
+.desc
+The
+.code mkdtemp
+create a unique file name by adding a generated infix between the
+.meta prefix
+and
+.meta suffix
+strings.
+The file is created, and a stream open in
+.str w+b
+mode for the file is returned.
+
+If either the
+.meta prefix
+or
+.meta suffix
+contain
+.code X
+characters, the behavior is unspecified.
+
+If
+.meta suffix
+is omitted, it defaults to the empty string.
+
+The name of the file is available by interrogating the returned stream's
+.code :name
+property using the function
+.codn stream-get-prop .
+
+Notes: this function is implemented using the POSIX function
+.code mkstemp
+or, if available, using the
+.code mkstemps
+function which is not standardized, but appears in the GNU C Library
+and some other systems. If
+.code mkstemps
+is unavailable, then the suffix functionality is not available: the
+.meta suffix
+argument must either be omitted, or must be an empty string.
+
+Whereas the C library functions require the template to contain a sequence
+at least six
+.code X
+characters, which are replaced by the generated portion, the \*(TL function
+handles this detail internally, requiring no such characters in any of its
+inputs.
+
.SS* Unix Filesystem Object Existence, Type and Access Tests
Functions in this category perform various tests on the attributes of