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 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 }