xref: /inferno-os/lib9/cleanname.c (revision 7ded4a527bdfd0e8b3a9049955f2af89e5f039ee)
1*7ded4a52SCharles Forsyth #include "lib9.h"
237da2899SCharles.Forsyth 
337da2899SCharles.Forsyth /*
437da2899SCharles.Forsyth  * In place, rewrite name to compress multiple /, eliminate ., and process ..
537da2899SCharles.Forsyth  */
637da2899SCharles.Forsyth #define SEP(x)	((x)=='/' || (x) == 0)
737da2899SCharles.Forsyth char*
cleanname(char * name)837da2899SCharles.Forsyth cleanname(char *name)
937da2899SCharles.Forsyth {
1037da2899SCharles.Forsyth 	char *p, *q, *dotdot;
11*7ded4a52SCharles Forsyth 	int rooted, erasedprefix;
1237da2899SCharles.Forsyth 
1337da2899SCharles.Forsyth 	rooted = name[0] == '/';
14*7ded4a52SCharles Forsyth 	erasedprefix = 0;
1537da2899SCharles.Forsyth 
1637da2899SCharles.Forsyth 	/*
1737da2899SCharles.Forsyth 	 * invariants:
1837da2899SCharles.Forsyth 	 *	p points at beginning of path element we're considering.
1937da2899SCharles.Forsyth 	 *	q points just past the last path element we wrote (no slash).
2037da2899SCharles.Forsyth 	 *	dotdot points just past the point where .. cannot backtrack
2137da2899SCharles.Forsyth 	 *		any further (no slash).
2237da2899SCharles.Forsyth 	 */
2337da2899SCharles.Forsyth 	p = q = dotdot = name+rooted;
2437da2899SCharles.Forsyth 	while(*p) {
2537da2899SCharles.Forsyth 		if(p[0] == '/')	/* null element */
2637da2899SCharles.Forsyth 			p++;
27*7ded4a52SCharles Forsyth 		else if(p[0] == '.' && SEP(p[1])) {
28*7ded4a52SCharles Forsyth 			if(p == name)
29*7ded4a52SCharles Forsyth 				erasedprefix = 1;
3037da2899SCharles.Forsyth 			p += 1;	/* don't count the separator in case it is nul */
31*7ded4a52SCharles Forsyth 		} else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
3237da2899SCharles.Forsyth 			p += 2;
3337da2899SCharles.Forsyth 			if(q > dotdot) {	/* can backtrack */
3437da2899SCharles.Forsyth 				while(--q > dotdot && *q != '/')
3537da2899SCharles.Forsyth 					;
3637da2899SCharles.Forsyth 			} else if(!rooted) {	/* /.. is / but ./../ is .. */
3737da2899SCharles.Forsyth 				if(q != name)
3837da2899SCharles.Forsyth 					*q++ = '/';
3937da2899SCharles.Forsyth 				*q++ = '.';
4037da2899SCharles.Forsyth 				*q++ = '.';
4137da2899SCharles.Forsyth 				dotdot = q;
4237da2899SCharles.Forsyth 			}
43*7ded4a52SCharles Forsyth 			if(q == name)
44*7ded4a52SCharles Forsyth 				erasedprefix = 1;	/* erased entire path via dotdot */
4537da2899SCharles.Forsyth 		} else {	/* real path element */
4637da2899SCharles.Forsyth 			if(q != name+rooted)
4737da2899SCharles.Forsyth 				*q++ = '/';
4837da2899SCharles.Forsyth 			while((*q = *p) != '/' && *q != 0)
4937da2899SCharles.Forsyth 				p++, q++;
5037da2899SCharles.Forsyth 		}
5137da2899SCharles.Forsyth 	}
5237da2899SCharles.Forsyth 	if(q == name)	/* empty string is really ``.'' */
5337da2899SCharles.Forsyth 		*q++ = '.';
5437da2899SCharles.Forsyth 	*q = '\0';
55*7ded4a52SCharles Forsyth 	if(erasedprefix && name[0] == '#'){
56*7ded4a52SCharles Forsyth 		/* this was not a #x device path originally - make it not one now */
57*7ded4a52SCharles Forsyth 		memmove(name+2, name, strlen(name)+1);
58*7ded4a52SCharles Forsyth 		name[0] = '.';
59*7ded4a52SCharles Forsyth 		name[1] = '/';
60*7ded4a52SCharles Forsyth 	}
6137da2899SCharles.Forsyth 	return name;
6237da2899SCharles.Forsyth }
63