从相对路径获取绝对路径

安库什

我知道之前曾有人问过这个问题(答案是realpath()),但是我的要求有些不同。realpath()是非标准功能。我需要一个符合ANSI的函数才能将完整路径从相对路径返回。本身的功能不必一定是的一部分c89,但是代码必须100%c89兼容。

感谢您的任何帮助。

编辑:应该放在UNIX之类的系统上。我现在并不真的在乎Windows。

chqrlie

没有C语言标准定义用于处理目录或路径的函数。如果没有操作系统的知识,并且操作系统特定的系统调用或库函数,您将无法完成目标。

您指定您的程序针对Unix操作系统。Unix有数百种风格(请参阅http://www.levenez.com/unix/,以及这34页的时间表:http//www.levenez.com/unix/unix_a4.pdf)。处理unix目标目录的最可移植的方法是使用Posix标准化系统调用。

Posix不是对该语言的扩展,它是操作系统结构和接口的规范。它在标准头文件和库中实现。您的程序可以符合c89,c90,c99或c11标准并使用Posix系统调用。gcc将在Posix系统上启用glibc的Posix部分,除非您指示它限制对Standard C库的支持。

Posixrealpath于2001年进行了标准化,几乎所有当前的类unix系统都可以使用它。如果你不能用这个,你要重写与功能getcwd()stat()readlink(),和其他系统调用和您的代码将被移植性较差。

手册页在这里:http : //man7.org/linux/man-pages/man3/realpath.3.html

编辑:有一个扭曲的解决方案,不使用显式的Posix支持,而是隐式依赖于Posix shell的可用性。这不是推荐的生产代码解决方案,但它可能适合您的特定约束。步骤如下:

  • 使用strrchr,提取文件名的初始路径部分。
  • 创建一个命令,将当前目录更改为该命令,并将当前目录打印到一个临时文件
  • 打开并读取该临时文件的内容。
  • 删除临时文件。
  • /分隔符连接路径和文件名

请注意,在子外壳程序中更改当前目录不会影响程序自己的当前目录。

编辑:实施上述有点棘手。您需要处理一些特殊情况。这是一个例子:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *my_realpath(const char *path) {
    const char *lastsep, *fname;
    char *cmd, *dir, *newdir;
    int pathlen, fnamelen, rc, size, pos, len;
    char buf[256];
    char tmpfile[L_tmpnam];
    FILE *fp;

    if (!tmpnam(tmpfile))
        return NULL;

    pathlen = 0;
    lastsep = strrchr(path, '/');
    if (lastsep) {
        pathlen = lastsep - path;
        if (pathlen == 0) {
            /* special case the root directory */
            pathlen = 1;
        }
    }
    fname = path + pathlen;
    fnamelen = strlen(fname);
    if (!strcmp(fname, ".")
    ||  !strcmp(fname, "/.")
    ||  !strcmp(fname, "..")
    ||  !strcmp(fname, "/..")) {
        pathlen += fnamelen;
        fname += fnamelen;
        fnamelen = 0;
    }
    if (*fname == '/') {
        fname++;
        fnamelen--;
    }
    if (pathlen > 0) {
        size = strlen("cd ") + pathlen + strlen("; pwd > ") + strlen(tmpfile) + 1;
        cmd = malloc(size);
        if (!cmd)
            return NULL;
        sprintf(cmd, "cd %.*s; pwd > %s", pathlen, path, tmpfile);
    } else {
        size = strlen("pwd > ") + strlen(tmpfile) + 1;
        cmd = malloc(size);
        if (!cmd)
            return NULL;
        sprintf(cmd, "pwd > %s", tmpfile);
    }
    rc = system(cmd);
    free(cmd);
    if (rc != 0)
        return NULL;

    fp = fopen(tmpfile, "r");
    size = pos = 0;
    dir = NULL;
    while (fgets(buf, sizeof buf, fp)) {
        len = strcspn(buf, "\n");
        size += len + 1;
        newdir = realloc(dir, size + fnamelen + 1);
        if (!newdir) {
            free(dir);
            dir = NULL;
            break;
        }
        dir = newdir;
        memcpy(dir + pos, buf, len);
        pos += len;
        dir[pos] = '\0';
        if (buf[len] == '\n')
            break;
    }
    fclose(fp);
    remove(tmpfile);
    if (dir != NULL) {
        if (pos > 0 && dir[pos - 1] != '/' && fnamelen > 0) {
            dir[pos++] = '/';
        }
        strcpy(dir + pos, fname);
    }
    return dir;
}

int main(int argc, const char *argv[]) {
    int i;
    char *absolute_path;

    for (i = 1; i < argc; i++) {
        errno = 0;
        absolute_path = my_realpath(argv[i]);
        if (absolute_path == NULL) {
            printf("my_realpath(\"%s\") -> NULL: %s\n", argv[i], strerror(errno));
        } else {
            printf("my_realpath(\"%s\") -> \"%s\"\n", argv[i], absolute_path);
            free(absolute_path);
        }
    }
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章