cleanname.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
cleanname.c (1199B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 | |
4 /* | |
5 * In place, rewrite name to compress multiple /, eliminate ., and proce… | |
6 */ | |
7 #define SEP(x) ((x)=='/' || (x) == 0) | |
8 char* | |
9 cleanname(char *name) | |
10 { | |
11 char *p, *q, *dotdot; | |
12 int rooted; | |
13 | |
14 rooted = name[0] == '/'; | |
15 | |
16 /* | |
17 * invariants: | |
18 * p points at beginning of path element we're considerin… | |
19 * q points just past the last path element we wrote (no … | |
20 * dotdot points just past the point where .. cannot back… | |
21 * any further (no slash). | |
22 */ | |
23 p = q = dotdot = name+rooted; | |
24 while(*p) { | |
25 if(p[0] == '/') /* null element */ | |
26 p++; | |
27 else if(p[0] == '.' && SEP(p[1])) | |
28 p += 1; /* don't count the separator in c… | |
29 else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { | |
30 p += 2; | |
31 if(q > dotdot) { /* can backtrack */ | |
32 while(--q > dotdot && *q != '/') | |
33 ; | |
34 } else if(!rooted) { /* /.. is / but ./..… | |
35 if(q != name) | |
36 *q++ = '/'; | |
37 *q++ = '.'; | |
38 *q++ = '.'; | |
39 dotdot = q; | |
40 } | |
41 } else { /* real path element */ | |
42 if(q != name+rooted) | |
43 *q++ = '/'; | |
44 while((*q = *p) != '/' && *q != 0) | |
45 p++, q++; | |
46 } | |
47 } | |
48 if(q == name) /* empty string is really ``.'' */ | |
49 *q++ = '.'; | |
50 *q = '\0'; | |
51 return name; | |
52 } |