については既に読みましrealpath()
たが、シンボリックリンクを解決したり、ファイルが実際に存在するかどうかを確認したりせずに、次の結果が得られるベースディレクトリとファイル名を渡すことができる関数はありますか? または、変更されたを使用する必要がありrealpath()
ますか?
"/var/", "../etc///././/passwd" => "/etc/passwd"
については既に読みましrealpath()
たが、シンボリックリンクを解決したり、ファイルが実際に存在するかどうかを確認したりせずに、次の結果が得られるベースディレクトリとファイル名を渡すことができる関数はありますか? または、変更されたを使用する必要がありrealpath()
ますか?
"/var/", "../etc///././/passwd" => "/etc/passwd"
これが normalize_path() 関数です。
指定されたパスが相対パスの場合、関数は現在の作業ディレクトリを先頭に追加して開始します。
次に、 のような特別なパス コンポーネント..
、.
または空のコンポーネントが処理され、結果が返されます。
の場合..
、最後のコンポーネントがあれば削除されます (/..
単に を返し/
ます)。または空のコンポーネント ( double ) の
場合、これは単にスキップされます。.
/
この関数は、空のパスを返さないことを保証します (/
代わりに が返されます)。
#define _GNU_SOURCE /* memrchr() */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
char * normalize_path(const char * src, size_t src_len) {
char * res;
size_t res_len;
const char * ptr = src;
const char * end = &src[src_len];
const char * next;
if (src_len == 0 || src[0] != '/') {
// relative path
char pwd[PATH_MAX];
size_t pwd_len;
if (getcwd(pwd, sizeof(pwd)) == NULL) {
return NULL;
}
pwd_len = strlen(pwd);
res = malloc(pwd_len + 1 + src_len + 1);
memcpy(res, pwd, pwd_len);
res_len = pwd_len;
} else {
res = malloc((src_len > 0 ? src_len : 1) + 1);
res_len = 0;
}
for (ptr = src; ptr < end; ptr=next+1) {
size_t len;
next = memchr(ptr, '/', end-ptr);
if (next == NULL) {
next = end;
}
len = next-ptr;
switch(len) {
case 2:
if (ptr[0] == '.' && ptr[1] == '.') {
const char * slash = memrchr(res, '/', res_len);
if (slash != NULL) {
res_len = slash - res;
}
continue;
}
break;
case 1:
if (ptr[0] == '.') {
continue;
}
break;
case 0:
continue;
}
res[res_len++] = '/';
memcpy(&res[res_len], ptr, len);
res_len += len;
}
if (res_len == 0) {
res[res_len++] = '/';
}
res[res_len] = '\0';
return res;
}
function normalize_path($path, $pwd = '/') {
if (!isset($path[0]) || $path[0] !== '/') {
$result = explode('/', getcwd());
} else {
$result = array('');
}
$parts = explode('/', $path);
foreach($parts as $part) {
if ($part === '' || $part == '.') {
continue;
} if ($part == '..') {
array_pop($result);
} else {
$result[] = $part;
}
}
return implode('/', $result);
}
(私がこれを書いた時点で、質問にはPHPのタグが付けられていました。)
とにかく、ここに正規表現バージョンがあります:
function normalize_path($path, $pwd = '/') {
if (!isset($path[0]) || $path[0] !== '/') {
$path = "$pwd/$path";
}
return preg_replace('~
^(?P>sdotdot)?(?:(?P>sdot)*/\.\.)*
|(?<sdotdot>(?:(?P>sdot)*/(?!\.\.)(?:[^/]+)(?P>sdotdot)?(?P>sdot)*/\.\.)+)
|(?<sdot>/\.?(?=/|$))+
~sx', '', $path);
}
#include <string.h>
char * normalizePath(char* pwd, const char * src, char* res) {
size_t res_len;
size_t src_len = strlen(src);
const char * ptr = src;
const char * end = &src[src_len];
const char * next;
if (src_len == 0 || src[0] != '/') {
// relative path
size_t pwd_len;
pwd_len = strlen(pwd);
memcpy(res, pwd, pwd_len);
res_len = pwd_len;
} else {
res_len = 0;
}
for (ptr = src; ptr < end; ptr=next+1) {
size_t len;
next = (char*)memchr(ptr, '/', end-ptr);
if (next == NULL) {
next = end;
}
len = next-ptr;
switch(len) {
case 2:
if (ptr[0] == '.' && ptr[1] == '.') {
const char * slash = (char*)memrchr(res, '/', res_len);
if (slash != NULL) {
res_len = slash - res;
}
continue;
}
break;
case 1:
if (ptr[0] == '.') {
continue;
}
break;
case 0:
continue;
}
if (res_len != 1)
res[res_len++] = '/';
memcpy(&res[res_len], ptr, len);
res_len += len;
}
if (res_len == 0) {
res[res_len++] = '/';
}
res[res_len] = '\0';
return res;
}
例:
#include <stdio.h>
int main(){
char path[FILENAME_MAX+1];
printf("\n%s\n",normalizePath((char*)"/usr/share/local/apps",(char*)"./../../../",path));
return 0;
}
出力:
/usr
char*
、正規化されたパスを格納するために必要なメモリ/容量が必要な です。