xref: /plan9/sys/src/cmd/unix/drawterm/libc/cleanname.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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 Colombier cleanname(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