X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fdirname.c;h=94f8c8936ed6744b235b03aa97d4772d529f0b68;hb=e2b0b4a5bc39813736d624662b9006a645d08083;hp=3487015343dc0c890294470a7dbf4faccde2663f;hpb=bbbfa79c3f7327e1359af33e833c9d078ba52ff1;p=gnulib.git diff --git a/lib/dirname.c b/lib/dirname.c index 348701534..94f8c8936 100644 --- a/lib/dirname.c +++ b/lib/dirname.c @@ -43,26 +43,32 @@ void *memrchr (); #include "dirname.h" +#ifndef FILESYSTEM_PREFIX_LEN +# define FILESYSTEM_PREFIX_LEN(Filename) 0 +#endif + #ifndef ISSLASH # define ISSLASH(C) ((C) == '/') #endif #define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\') -/* Return the length of `dirname (PATH)' and set *RESULT - to point to PATH or to `"."', as appropriate. - Works properly even if there are trailing slashes - (by effectively ignoring them). */ -size_t -dir_name_r (const char *path, const char **result) +/* Return the length of `dirname (PATH)' and set *RESULT to point + to PATH or to `"."', as appropriate. Works properly even if + there are trailing slashes (by effectively ignoring them). + WARNING: This function doesn't work for cwd-relative names like + `a:foo' that are specified with a drive-letter prefix. That case + is handled in the caller. */ +static size_t +dir_name_r (char const *path, char const **result) { - char *slash; + char const *slash; size_t length; /* Length of result, not including NUL. */ slash = strrchr (path, '/'); if (BACKSLASH_IS_PATH_SEPARATOR) { - char *b = strrchr (path, '\\'); + char const *b = strrchr (path, '\\'); if (b && slash < b) slash = b; } @@ -78,10 +84,11 @@ dir_name_r (const char *path, const char **result) if (path < slash) { - slash = memrchr (path, '/', slash - path); + size_t len = slash - path; + slash = memrchr (path, '/', len); if (BACKSLASH_IS_PATH_SEPARATOR) { - char *b = memrchr (path, '\\', slash - path); + char const *b = memrchr (path, '\\', len); if (b && slash < b) slash = b; } @@ -91,27 +98,23 @@ dir_name_r (const char *path, const char **result) if (slash == 0) { /* File is in the current directory. */ - path = "."; - length = 1; + + length = FILESYSTEM_PREFIX_LEN (path); + + if (length == 0) + { + path = "."; + length = 1; + } } else { - /* Remove any trailing slashes from the result. */ - if (BACKSLASH_IS_PATH_SEPARATOR) - { - const char *lim = ((path[0] >= 'A' && path[0] <= 'z' - && path[1] == ':') - ? path + 2 : path); + /* Remove any trailing slashes from the result. If we have a + canonicalized "d:/path", leave alone the root case "d:/". */ + char const *lim = path + FILESYSTEM_PREFIX_LEN (path); - /* If canonicalized "d:/path", leave alone the root case "d:/". */ - while (slash > lim && ISSLASH (*slash)) - --slash; - } - else - { - while (slash > path && ISSLASH (*slash)) - --slash; - } + while (lim < slash && ISSLASH (*slash)) + --slash; length = slash - path + 1; } @@ -126,14 +129,18 @@ dir_name_r (const char *path, const char **result) (by effectively ignoring them). */ char * -dir_name (const char *path) +dir_name (char const *path) { - const char *result; + char const *result; size_t length = dir_name_r (path, &result); - char *newpath = (char *) malloc (length + 1); + int append_dot = (length && length == FILESYSTEM_PREFIX_LEN (newpath)); + char *newpath = (char *) malloc (length + append_dot + 1); if (newpath == 0) return 0; strncpy (newpath, result, length); + /* If PATH is "d:foo", return "d:.", the CWD on drive d: */ + if (append_dot) + newpath[length++] = '.'; newpath[length] = 0; return newpath; } @@ -170,7 +177,7 @@ main () { char path[MAX_BUFF_LEN]; char expected_result[MAX_BUFF_LEN]; - char *result; + char const *result; sscanf (buff, "%s %s", path, expected_result); result = dir_name (path); if (strcmp (result, expected_result))