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