Last active
July 7, 2024 13:05
-
-
Save starwing/2761647 to your computer and use it in GitHub Desktop.
a path normalize algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#define COMP_MAX 50 | |
#define ispathsep(ch) ((ch) == '/' || (ch) == '\\') | |
#define iseos(ch) ((ch) == '\0') | |
#define ispathend(ch) (ispathsep(ch) || iseos(ch)) | |
char *normpath(char *out, const char *in) { | |
char *pos[COMP_MAX], **top = pos, *head = out; | |
int isabs = ispathsep(*in); | |
if (isabs) *out++ = '/'; | |
*top++ = out; | |
while (!iseos(*in)) { | |
while (ispathsep(*in)) ++in; | |
if (iseos(*in)) | |
break; | |
if (memcmp(in, ".", 1) == 0 && ispathend(in[1])) { | |
++in; | |
continue; | |
} | |
if (memcmp(in, "..", 2) == 0 && ispathend(in[2])) { | |
in += 2; | |
if (top != pos + 1) | |
out = *--top; | |
else if (isabs) | |
out = top[-1]; | |
else { | |
strcpy(out, "../"); | |
out += 3; | |
} | |
continue; | |
} | |
if (top - pos >= COMP_MAX) | |
return NULL; /* path to complicate */ | |
*top++ = out; | |
while (!ispathend(*in)) | |
*out++ = *in++; | |
if (ispathsep(*in)) | |
*out++ = '/'; | |
} | |
*out = '\0'; | |
if (*head == '\0') | |
strcpy(head, "./"); | |
return head; | |
} | |
int main(void) { | |
char a[][2][260] = { | |
{ "", "./" }, | |
{ "/..", "/" }, | |
{ "/../", "/" }, | |
{ ".", "./" }, | |
{ "./", "./" }, | |
{ "..", "../" }, | |
{ "../", "../" }, | |
{ "../abc/def", "../abc/def" }, | |
{ "../abc/def/..", "../abc/" }, | |
{ "../abc/././././def/..", "../abc/" }, | |
{ "////../abc/def", "/abc/def" }, | |
{ "/../def", "/def" }, | |
{ "../def", "../def" }, | |
{ "/abc////../def", "/def" }, | |
{ "abc/../def/ghi", "def/ghi" }, | |
{ "/abc/def/../ghi", "/abc/ghi" }, | |
{ "/abc/..abc////../def", "/abc/def" }, | |
{ "/abc/..abc/../def", "/abc/def" }, | |
{ "abc/../def", "def" }, | |
{ "abc/../../def", "../def" }, | |
{ "././", "./" }, | |
{ "abc/..", "./" }, | |
{ "abc/../", "./" }, | |
{ "abc/../..", "../" }, | |
{ "abc/../../", "../" }, | |
{ "a/..", "./" }, | |
{ "a/../", "./" }, | |
{ "a/../..", "../" }, | |
{ "a/../../", "../" }, | |
{ "../../../a", "../../../a" }, | |
{ "../a../../a", "../a" }, | |
{ "cccc/abc////..////.//../", "./" }, | |
{ "aaaa/cccc/abc////..////.//../", "aaaa/" }, | |
{ "..//////.///..////..////.//////abc////.////..////def//abc/..", "../../../def/" }, | |
{ "////////////..//////.///..////..////.//////abc////.////..////def//abc/..", "/def/" }, | |
}; | |
int i; | |
int pass = 0; | |
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { | |
char buff[260]; | |
printf("[%d] in> %s\n", i+1, a[i][0]); | |
normpath(buff, a[i][0]); | |
if (strcmp(buff, a[i][1])) { | |
printf("--> %s\n", buff); | |
printf("expected: %s\n", a[i][1]); | |
} | |
else ++pass; | |
} | |
printf("-----------\nPASS: %d/%d\n", pass, sizeof(a) / sizeof(a[0])); | |
return 0; | |
} | |
/* cc: flags+='-O2 -Wall -pedantic -ansi' */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <assert.h> | |
#include <stddef.h> | |
#define NORMPATH_METHOD 1 | |
#define ALT_SEP '/' | |
int debug = 0; | |
static size_t trimpath(char *s, int *isabs, int pathsep, int altsep) { | |
char *wp = s, *rp = s; | |
for (; *rp != '\0'; ++rp) { | |
if (*rp == altsep || *rp == pathsep) { | |
while (rp[1] == altsep || rp[1] == pathsep) ++rp; | |
if (rp[1] == '.' | |
&& (rp[2] == altsep || rp[2] == pathsep || rp[2] == '\0')) | |
++rp; | |
else *wp++ = pathsep; | |
} | |
else *wp++ = *rp; | |
} | |
if (s < wp && wp[-1] == '.' && wp[-2] == '.' && | |
(wp - 2 == s || wp[-3] == pathsep)) | |
*wp++ = pathsep; | |
*wp = '\0'; | |
if (isabs != NULL) *isabs = *s == pathsep; | |
return wp - s; | |
} | |
#if NORMPATH_METHOD == 1 | |
static size_t normpath_inplace(char *s, int pathsep) { | |
int isabs; | |
char *wp = s, *rp = s; | |
trimpath(s, &isabs, pathsep, ALT_SEP); | |
for (; *rp != '\0'; ++rp) { | |
/*while (*rp != '\0' && *rp != pathsep) *wp++ = *rp++;*/ | |
/*if (*rp == '\0') break;*/ | |
if (rp[0] == pathsep && rp[1] == '.' && rp[2] == '.' | |
&& (rp[3] == pathsep || rp[3] == '\0')) { | |
char *lastwp = wp; | |
while (s < lastwp && *--lastwp != pathsep) | |
; | |
if (lastwp != wp && (wp[-1] != '.' || wp[-2] != '.' || | |
(s < wp - 3 && wp[-3] != pathsep))) { | |
wp = lastwp; | |
rp += 2; | |
continue; | |
} | |
else if (lastwp == s && isabs) { | |
rp += 2; | |
continue; | |
} | |
} | |
if (rp[0] != pathsep || wp != s || isabs) | |
*wp++ = *rp; | |
} | |
if (wp == s) | |
*wp++ = isabs ? pathsep : '.'; | |
if (wp == s + 1 && s[0] == '.') | |
*wp++ = pathsep; | |
*wp = '\0'; | |
return wp - s; | |
} | |
#endif | |
#if NORMPATH_METHOD == 2 | |
static size_t normpath_inplace(char *s, int pathsep) { | |
int isabs; | |
char *lastwp = s, *wp = s, *rp = s; | |
trimpath(s, &isabs, pathsep, ALT_SEP); | |
for (; *rp != '\0'; ++rp) { | |
if (rp[0] == pathsep) { | |
if (rp[1] == '.' && rp[2] == '.' | |
&& (rp[3] == pathsep || rp[3] == '\0')) { | |
if (lastwp != wp && (wp[-1] != '.' || wp[-2] != '.' || | |
(s < wp - 3 && wp[-3] != pathsep))) { | |
wp = lastwp; | |
while (s < lastwp && *--lastwp != pathsep) | |
; | |
rp += 2; | |
continue; | |
} | |
else if (isabs && lastwp == s) { | |
rp += 2; | |
continue; | |
} | |
} | |
if (wp != s || isabs) { | |
lastwp = wp; | |
*wp++ = *rp; | |
} | |
} | |
else *wp++ = *rp; | |
} | |
if (wp == s) | |
*wp++ = isabs ? pathsep : '.'; | |
if (wp == s + 1 && s[0] == '.') | |
*wp++ = pathsep; | |
*wp = '\0'; | |
return wp - s; | |
} | |
#endif | |
#if NORMPATH_METHOD == 3 | |
static size_t normpath_inplace(char *s, int pathsep) { | |
int isabs; | |
char *lastp = s, *p = s; | |
trimpath(s, &isabs, pathsep, ALT_SEP); | |
while (*p != '\0') { | |
if (*p++ != pathsep) continue; | |
if (p[0] == '.' && p[1] == '.' && | |
(p[2] == pathsep || p[2] == '\0')) { | |
if (*lastp != pathsep && (lastp[0] != '.' || lastp[1] != '.' || | |
lastp[2] != pathsep)) { | |
char *pi = lastp; | |
while (pi < p + 2) *pi++ = pathsep; | |
while (s < lastp && *lastp == pathsep) --lastp; | |
while (s < lastp && lastp[-1] != pathsep) --lastp; | |
p += 2; | |
} | |
else if (lastp == s && isabs) { | |
p[0] = p[1] = pathsep; | |
p += 2; | |
} | |
} | |
else lastp = p; | |
} | |
p = s + trimpath(s, pathsep, ALT_SEP); | |
if (!isabs && *s == pathsep) { | |
char *pi = s; | |
while ((pi[0] = pi[1])) ++pi; | |
--p; | |
} | |
if (p == s) | |
*p++ = isabs ? pathsep : '.'; | |
if (p == s + 1 && s[0] == '.') | |
*p++ = pathsep; | |
*p = '\0'; | |
return p - s; | |
} | |
#endif | |
#include <stdio.h> | |
#include <string.h> | |
int main(void) { | |
char a[][2][260] = { | |
{ "", "./" }, | |
{ "/..", "/" }, | |
{ "/../", "/" }, | |
{ ".", "./" }, | |
{ "./", "./" }, | |
{ "..", "../" }, | |
{ "../", "../" }, | |
{ "../abc/def", "../abc/def" }, | |
{ "../abc/def/..", "../abc/" }, | |
{ "../abc/././././def/..", "../abc/" }, | |
{ "////../abc/def", "/abc/def" }, | |
{ "/../def", "/def" }, | |
{ "../def", "../def" }, | |
{ "/abc////../def", "/def" }, | |
{ "abc/../def/ghi", "def/ghi" }, | |
{ "/abc/def/../ghi", "/abc/ghi" }, | |
{ "/abc/..abc////../def", "/abc/def" }, | |
{ "/abc/..abc/../def", "/abc/def" }, | |
{ "abc/../def", "def" }, | |
{ "abc/../../def", "../def" }, | |
{ "././", "./" }, | |
{ "abc/..", "./" }, | |
{ "abc/../", "./" }, | |
{ "abc/../..", "../" }, | |
{ "abc/../../", "../" }, | |
{ "a/..", "./" }, | |
{ "a/../", "./" }, | |
{ "a/../..", "../" }, | |
{ "a/../../", "../" }, | |
{ "../../../a", "../../../a" }, | |
{ "../a../../a", "../a" }, | |
{ "cccc/abc////..////.//../", "./" }, | |
{ "aaaa/cccc/abc////..////.//../", "aaaa/" }, | |
{ "..//////.///..////..////.//////abc////.////..////def//abc/..", "../../../def/" }, | |
{ "////////////..//////.///..////..////.//////abc////.////..////def//abc/..", "/def/" }, | |
}; | |
int i; | |
int pass = 0; | |
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { | |
char buff[260]; | |
strcpy(buff, a[i][0]); | |
normpath_inplace(buff, '\\'); | |
trimpath(a[i][1], NULL, '\\', '/'); | |
if (strcmp(buff, a[i][1])) { | |
printf("in> %s\n", a[i][0]); | |
printf("--> %s\n", buff); | |
printf("expected: %s\n", a[i][1]); | |
printf("trace:\n"); | |
debug = 1; | |
strcpy(buff, a[i][0]); | |
normpath_inplace(buff, '\\'); | |
debug = 0; | |
printf("\n"); | |
} | |
else ++pass; | |
} | |
printf("-----------\nPASS: %d/%d\n", pass, sizeof(a) / sizeof(a[0])); | |
return 0; | |
} | |
/* cc: flags+='-Wall -pedantic -ansi' */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you kind person 🤝