Add dirname function

This commit is contained in:
Erik van der Kouwe 2010-01-25 18:12:28 +00:00
parent a89d141e90
commit 3ec29ae85e
3 changed files with 109 additions and 0 deletions

29
lib/other/dirname.c Executable file
View File

@ -0,0 +1,29 @@
#include <libgen.h>
#include <string.h>
/* based on http://www.opengroup.org/onlinepubs/009695399/functions/dirname.html */
char *dirname(char *path)
{
char *pathend;
/* remove leading slash(es) except root */
pathend = path + strlen(path) - 1;
while (pathend > path && *pathend == '/')
pathend--;
/* remove last path component */
while (pathend >= path && *pathend != '/')
pathend--;
/* remove slash(es) before last path component except root */
while (pathend > path && *pathend == '/')
pathend--;
/* special case: no slashes */
if (pathend < path)
return ".";
/* truncate and return string */
pathend[1] = 0;
return path;
}

19
man/man3/dirname.3 Executable file
View File

@ -0,0 +1,19 @@
.TH DIRNAME 3
.SH NAME
dirname \- determine name of containing directory
.SH SYNOPSIS
.nf
.ft B
#include <libgen.h>
char *dirname(char *\fIpath\fP);
.SH DESCRIPTION
The dirname function returns the name of the directory containing \fIpath\fP.
If the path does not contain slashes, the string "." is returned. Trailing
slashes are ignored.
.SH "SEE ALSO"
.BR basename (3).
.SH NOTES
This function may, but need not, overwrite the buffer passed to it.
Although MINIX' implementation of this function is re-entrant, POSIX does not
guarantee this property and portable programs should not rely on it.

View File

@ -3,6 +3,7 @@
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@ -328,6 +329,36 @@ static void cleanup(const char *path)
if (rmdir(path) < 0) ERR;
}
static void test_dirname(const char *path, const char *exp)
{
char buffer[PATH_MAX];
int i, j;
size_t pathlen = strlen(path);
char *pathout;
assert(pathlen + 3 < PATH_MAX);
/* try with no, one or two trailing slashes */
for (i = 0; i < 3; i++)
{
/* no trailing slashes for empty string */
if (pathlen < 1 && i > 0)
continue;
/* prepare buffer */
strcpy(buffer, path);
for (j = 0; j < i; j++)
buffer[pathlen + j] = '/';
buffer[pathlen + i] = 0;
/* perform test */
pathout = dirname(buffer);
if (strcmp(pathout, exp) != 0)
ERR;
}
}
int main(int argc, char **argv)
{
char buffer1[PATH_MAX + 1], buffer2[PATH_MAX + 1];
@ -358,6 +389,36 @@ int main(int argc, char **argv)
/* delete the symlinks */
cleanup(addbasepath(buffer1, PATH_BASE));
/* also test dirname */
test_dirname("", ".");
test_dirname(".", ".");
test_dirname("..", ".");
test_dirname("x", ".");
test_dirname("xy", ".");
test_dirname("x/y", "x");
test_dirname("xy/z", "xy");
test_dirname("x/yz", "x");
test_dirname("ab/cd", "ab");
test_dirname("x//y", "x");
test_dirname("xy//z", "xy");
test_dirname("x//yz", "x");
test_dirname("ab//cd", "ab");
test_dirname("/", "/");
test_dirname("/x", "/");
test_dirname("/xy", "/");
test_dirname("/x/y", "/x");
test_dirname("/xy/z", "/xy");
test_dirname("/x/yz", "/x");
test_dirname("/ab/cd", "/ab");
test_dirname("/x//y", "/x");
test_dirname("/xy//z", "/xy");
test_dirname("/x//yz", "/x");
test_dirname("/ab//cd", "/ab");
test_dirname("/usr/src", "/usr");
test_dirname("/usr/src/test", "/usr/src");
test_dirname("usr/src", "usr");
test_dirname("usr/src/test", "usr/src");
/* done */
quit();
return(-1); /* impossible */