X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fdirname.c;h=94f8c8936ed6744b235b03aa97d4772d529f0b68;hb=e1a15e1dd928decc9477834db7cc744072da297d;hp=e01fa42ac558a0da42965380d0cdf3ae33529ff7;hpb=4d2ba1df0fd6135c58ce1dc16e8e28ba510e700e;p=gnulib.git diff --git a/lib/dirname.c b/lib/dirname.c index e01fa42ac..94f8c8936 100644 --- a/lib/dirname.c +++ b/lib/dirname.c @@ -43,28 +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 leading directories part of PATH, - allocated with malloc. If out of memory, return 0. - Works properly even if there are trailing slashes - (by effectively ignoring them). */ - -char * -dir_name (const char *path) +/* 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 *newpath; - char *slash; - int length; /* Length of result, not including NUL. */ + 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; } @@ -80,10 +84,11 @@ dir_name (const char *path) 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; } @@ -93,35 +98,49 @@ dir_name (const char *path) 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; } - newpath = (char *) malloc (length + 1); + *result = path; + return length; +} + +/* Return the leading directories part of PATH, + allocated with malloc. If out of memory, return 0. + Works properly even if there are trailing slashes + (by effectively ignoring them). */ + +char * +dir_name (char const *path) +{ + char const *result; + size_t length = dir_name_r (path, &result); + int append_dot = (length && length == FILESYSTEM_PREFIX_LEN (newpath)); + char *newpath = (char *) malloc (length + append_dot + 1); if (newpath == 0) return 0; - strncpy (newpath, path, length); + 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; } @@ -158,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))