2016-03-19 13 views
-1

Я знаю, что этот вопрос задан раньше (ответ realpath()), но мои требования немного разные. realpath() - нестандартная функция. Мне нужна функция, совместимая с ANSI, чтобы вернуть форму полного пути относительным путем. Функция, которую она сама, не должна быть частью c89, но код должен быть 100% c89 совместимым.Получение абсолютного пути от относительного пути

Благодарим за помощь.

РЕДАКТИРОВАТЬ: Должен быть поставлен для UNIX-подобных систем. На данный момент меня не волнуют окна.

+1

Проблема в том, что определение абсолютного пути зависит от ОС. Таким образом, не может быть портативное решение (по крайней мере, не без кучи #ifdefs или проверки времени выполнения на основе ОС). – user3386109

+0

Спасибо за это. Я обновлю свой вопрос для систем UNIX – Ankush

+1

@Ankush: Если вы используете систему Unix (как), то вы уже являетесь POSIX и должны уже иметь «realpath()». Почему вам нужно строгое соответствие ANSI/ISO, если ваша программа будет в любом случае POSIX? – 3442

ответ

1

Ни один из стандартов языка 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.

Posix стандартизованный realpath в 2001 году, он доступен практически для каждой современной унифицированной системы. если вы не можете использовать это, вы переписываете его функциональные возможности с getcwd(), stat(), readlink() и другими системными вызовами, а ваш код будет менее переносимым.

Страница руководства здесь: http://man7.org/linux/man-pages/man3/realpath.3.html

EDIT: Существует искаженное решение, которое не использует явную поддержку Posix, но косвенно зависит от наличия оболочки Posix. Это не рекомендуемое решение для производственного кода, но оно может соответствовать вашим конкретным ограничениям. Вот шаги:

  • с strrchr, извлеките начальную часть пути в имени файла.
  • создайте команду для изменения текущей директории и распечатайте текущий каталог во временном файле.
  • открыть и прочитать содержимое этого временного файла.
  • удалите временный файл.
  • конкатенации путь и имя файла с / сепараторе

Заметим, что изменение текущего каталога в суб-оболочки не повлияет на собственный текущий каталог вашей программы.

EDIT: Выполнение вышеизложенного несколько сложнее. Вам нужно обработать некоторые особые случаи.Вот пример:

#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; 
} 
+0

Спасибо за ваш ответ! Просто интересно, если '-std = c89' или' -ansi' на моих флагах компилятора будет считаться ограничивающей поддержкой библиотеки c std? – Ankush

+0

Также мне просто интересно, не является ли 'realpath()' не расширением языка, зачем мне использовать флаг '-D' во время компиляции или использовать' #define GNU_SOURCE'. Это просто немного смущает меня – Ankush

+1

Существует различие между языковыми расширениями, такими как оператор 'typeof' gnu cc и конкретная целевая среда, для которой может потребоваться некоторая конфигурация компилятора. – chqrlie