开发中一部分工作是编写服务端的功能库,经常需要用到类似于Linux上dirname的功能。
先贴出第一个版本:
#define IS_SLASH_P(c) (*(c) == '/' || *(c) == '\\')
//对于合法的路径输入,返回其上一级目录,不包含目录分隔符
//返回值为pcDir的长度
int lib_iDirName(const char *path, char *pcDir)
{
int len = 0;
const char *endp = NULL;
const char *runp = NULL;
*pcDir = '\0';
if(path == NULL || *path == '\0')
{
return len;
}
runp = path+strlen(path)-1;
while(runp > path && IS_SLASH_P(runp))--runp;
if(runp == path)
{
endp = path;
}
else
{
while(runp > path && !IS_SLASH_P(runp))--runp;
if(runp == path)
{
endp = path;
}
else
{
while(runp > path && IS_SLASH_P(runp))--runp;
endp = runp;
}
}
if (endp != path)
{
len = endp-path+1;
memcpy(pcDir, path, len);
pcDir[len] = '\0';
}
else
{
if(*path == '/')//for Linux
{
strcpy(pcDir, "/");
len = 1;
}
else if(path[1] == ':')//for Windows
{
memcpy(pcDir, path, 2);
pcDir[2] = '\0';
len = 2;
}
else
{
strcpy(pcDir, ".");
len = 1;
}
}
return len;
}
实现上涉及到对目录分割符的处理,若对这一块内容有疑问,可以参考我另外一篇短文:细说目录分隔符
测试结果:
这个结果已经符合我的预期了,但是里面3个while(runp > path ...)感觉是可以合在一块儿的,于是有了下一个“增强”版本:
int lib_iDirNameEx(const char *path, char *pcDir)
{
int len = 0;
int count = 0;
const char *runp = NULL;
*pcDir = '\0';
if(path == NULL || *path == '\0')
{
return len;
}
runp = path+strlen(path)-1;
while(runp > path)
{
if(IS_SLASH_P(runp))
{
--runp;
continue;
}
if(count >= 1)break;
if(!IS_SLASH_P(runp))
{
--runp;
}
if(IS_SLASH_P(runp))
{
count++;
}
}
if (runp != path)
{
len = runp-path+1;
memcpy(pcDir, path, len);
pcDir[len] = '\0';
}
else
{
if(*path == '/')//for Linux
{
strcpy(pcDir, "/");
len = 1;
}
else if(path[1] == ':')//for Windows
{
memcpy(pcDir, path, 2);
pcDir[2] = '\0';
len = 2;
}
else
{
strcpy(pcDir, ".");
len = 1;
}
}
return len;
}
如果
if(count >= 1)break;
这一行改成
if(count >= 2)break;
可以实现回退两级目录,以此类推。暂时就这样定版了!