cleanname.c (1199B)
1 #include <u.h> 2 #include <libc.h> 3 4 /* 5 * In place, rewrite name to compress multiple /, eliminate ., and process .. 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 considering. 19 * q points just past the last path element we wrote (no slash). 20 * dotdot points just past the point where .. cannot backtrack 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 case it is nul */ 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 ./../ is .. */ 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 }