diff options
author | Steve Bennett <steveb@workware.net.au> | 2019-10-17 22:04:49 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2019-10-18 07:59:35 +1000 |
commit | 058d07b597ce088b86e7e8a070bcfa07509f26e1 (patch) | |
tree | e7e6af728d0eecbf8b9c39fbe8c9f9bfa8cdf8e5 /jim-file.c | |
parent | ca4fa3865a730857b385e6e34af67db3471e0089 (diff) | |
download | jimtcl-058d07b597ce088b86e7e8a070bcfa07509f26e1.zip jimtcl-058d07b597ce088b86e7e8a070bcfa07509f26e1.tar.gz jimtcl-058d07b597ce088b86e7e8a070bcfa07509f26e1.tar.bz2 |
file: Better support for trailing slashes in pathnames
e.g. file tail /abc/def/ => def
Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'jim-file.c')
-rw-r--r-- | jim-file.c | 57 |
1 files changed, 50 insertions, 7 deletions
@@ -215,9 +215,43 @@ static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat return JIM_OK; } +/** + * Give a path of length 'len', returns the length of the path + * with any trailing slashes removed. + */ +static int JimPathLenNoTrailingSlashes(const char *path, int len) +{ + int i; + for (i = len; i > 1 && path[i - 1] == '/'; i--) { + /* Trailing slash, so remove it */ + if (ISWINDOWS && path[i - 2] == ':') { + /* But on windows, we won't remove the trailing slash from c:/ */ + break; + } + } + return i; +} + +/** + * Give a path in objPtr, returns a new path with any trailing slash removed. + * Use Jim_DecrRefCount() on the returned object (which may be identical to objPtr). + */ +static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr) +{ + int len = Jim_Length(objPtr); + const char *path = Jim_String(objPtr); + int i = JimPathLenNoTrailingSlashes(path, len); + if (i != len) { + objPtr = Jim_NewStringObj(interp, path, i); + } + Jim_IncrRefCount(objPtr); + return objPtr; +} + static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *path = Jim_String(argv[0]); + Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); + const char *path = Jim_String(objPtr); const char *p = strrchr(path, '/'); if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') { @@ -233,29 +267,35 @@ static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_SetResultString(interp, path, p - path + 1); } else { - Jim_SetResultString(interp, path, p - path); + /* Strip any trailing slashes from the result */ + int len = JimPathLenNoTrailingSlashes(path, p - path); + Jim_SetResultString(interp, path, len); } + Jim_DecrRefCount(interp, objPtr); return JIM_OK; } static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *path = Jim_String(argv[0]); + Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); + const char *path = Jim_String(objPtr); const char *lastSlash = strrchr(path, '/'); const char *p = strrchr(path, '.'); if (p == NULL || (lastSlash != NULL && lastSlash > p)) { - Jim_SetResult(interp, argv[0]); + Jim_SetResult(interp, objPtr); } else { Jim_SetResultString(interp, path, p - path); } + Jim_DecrRefCount(interp, objPtr); return JIM_OK; } static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *path = Jim_String(argv[0]); + Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); + const char *path = Jim_String(objPtr); const char *lastSlash = strrchr(path, '/'); const char *p = strrchr(path, '.'); @@ -263,20 +303,23 @@ static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv p = ""; } Jim_SetResultString(interp, p, -1); + Jim_DecrRefCount(interp, objPtr); return JIM_OK; } static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *path = Jim_String(argv[0]); + Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); + const char *path = Jim_String(objPtr); const char *lastSlash = strrchr(path, '/'); if (lastSlash) { Jim_SetResultString(interp, lastSlash + 1, -1); } else { - Jim_SetResult(interp, argv[0]); + Jim_SetResult(interp, objPtr); } + Jim_DecrRefCount(interp, objPtr); return JIM_OK; } |