diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | sysif.c | 64 | ||||
-rw-r--r-- | txr.1 | 10 |
3 files changed, 81 insertions, 1 deletions
@@ -1,3 +1,11 @@ +2015-03-10 Kaz Kylheku <kaz@kylheku.com> + + * sysif.c (mkdir_nothrow_exists): New static function. + (ensure_dir): New function. + (sysif_init): ensure_dir registered as intrinsic. + + * txr.1: ensure_dir documented. + 2015-02-25 Kaz Kylheku <kaz@kylheku.com> * parser.c (open_txr_file, regex_parse, lisp_parse): Functions @@ -58,6 +58,7 @@ #include "signal.h" #include "utf8.h" #include "unwind.h" +#include "gc.h" #include "eval.h" #include "sysif.h" @@ -180,6 +181,68 @@ static val mkdir_wrap(val path, val mode) } #endif +#if HAVE_MKDIR || HAVE_WINDOWS_H +static val mkdir_nothrow_exists(val path, val mode) +{ + val ret = t; + + uw_catch_begin(cons(file_error_s, nil), esym, eobj); + + ret = mkdir_wrap(path, mode); + + uw_catch (esym, eobj) { + switch (errno) { + case EACCES: + case EPERM: + ret = num(errno); + break; + case EEXIST: + break; + default: + uw_throw(esym, eobj); + } + } + + uw_unwind; + + uw_catch_end; + + return ret; +} + +static val ensure_dir(val path, val mode) +{ +#if HAVE_WINDOWS_H + val sep = lit("\\"); + val sep_set = lit("\\/"); +#else + val sep = lit("/"); + val sep_set = lit("/"); +#endif + val split_path = split_str_set(path, sep_set); + val partial_path = pop(&split_path); + val ret = t; + + for (;;) { + if (length(partial_path) != zero) + ret = mkdir_nothrow_exists(partial_path, mode); + + if (!split_path) + break; + + partial_path = format(nil, lit("~a~a~a"), + partial_path, sep, pop(&split_path), nao); + } + + if (ret != t) + uw_throwf(file_error_s, + lit("ensure-dir: ~a: ~a/~s"), path, ret, + string_utf8(strerror(c_num(ret))), nao); + + return ret; +} +#endif + #if HAVE_UNISTD_H static val chdir_wrap(val path) { @@ -388,6 +451,7 @@ void sysif_init(void) #if HAVE_MKDIR || HAVE_WINDOWS_H reg_fun(intern(lit("mkdir"), user_package), func_n2o(mkdir_wrap, 1)); + reg_fun(intern(lit("ensure-dir"), user_package), func_n2o(ensure_dir, 1)); #endif #if HAVE_UNISTD_H @@ -23989,9 +23989,10 @@ of the system timer. Actual sleep times may be rounded up to the nearest 10 millisecond multiple on a system where timed suspensions are triggered by a 100 Hz tick. -.coNP Function @ mkdir +.coNP Functions @ mkdir and @ ensure-dir .synb .mets (mkdir < path <> [ mode ]) +.mets (ensure-dir < path <> [ mode ]) .syne .desc .code mkdir @@ -24015,6 +24016,13 @@ for the newly created directory. If omitted, the requested permissions are are subject to the system .codn umask . +The function +.code ensure-dir +is similar to +.code mkdir +except that it attempts to create all the missing parent directories +as necessary, and does not throw an error if the directory exists. + .coNP Function @ chdir .synb .mets (chdir << path ) |