xref: /plan9/sys/src/libc/port/cleanname.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier 
47dd7cddfSDavid du Colombier /*
57dd7cddfSDavid du Colombier  * In place, rewrite name to compress multiple /, eliminate ., and process ..
67dd7cddfSDavid du Colombier  */
77dd7cddfSDavid du Colombier #define SEP(x)	((x)=='/' || (x) == 0)
87dd7cddfSDavid du Colombier char*
cleanname(char * name)97dd7cddfSDavid du Colombier cleanname(char *name)
107dd7cddfSDavid du Colombier {
11*853458f3SDavid du Colombier 	char *s;	/* source of copy */
12*853458f3SDavid du Colombier 	char *d;	/* destination of copy */
13*853458f3SDavid du Colombier 	char *d0;	/* start of path afer the root name */
14*853458f3SDavid du Colombier 	Rune r;
15*853458f3SDavid du Colombier 	int rooted;
167dd7cddfSDavid du Colombier 
17*853458f3SDavid du Colombier 	if(name[0] == 0)
18*853458f3SDavid du Colombier 		return strcpy(name, ".");
19*853458f3SDavid du Colombier 	rooted = 0;
20*853458f3SDavid du Colombier 	d0 = name;
21*853458f3SDavid du Colombier 	if(d0[0] == '#'){
22*853458f3SDavid du Colombier 		if(d0[1] == 0)
23*853458f3SDavid du Colombier 			return d0;
24*853458f3SDavid du Colombier 		d0  += 1 + chartorune(&r, d0+1); /* ignore slash: #/ */
25*853458f3SDavid du Colombier 		while(!SEP(*d0))
26*853458f3SDavid du Colombier 			d0 += chartorune(&r, d0);
27*853458f3SDavid du Colombier 		if(d0 == 0)
28*853458f3SDavid du Colombier 			return name;
29*853458f3SDavid du Colombier 		d0++;	/* keep / after #<name> */
30*853458f3SDavid du Colombier 		rooted = 1;
31*853458f3SDavid du Colombier 	}else if(d0[0] == '/'){
32*853458f3SDavid du Colombier 		rooted = 1;
33*853458f3SDavid du Colombier 		d0++;
34*853458f3SDavid du Colombier 	}
357dd7cddfSDavid du Colombier 
36*853458f3SDavid du Colombier 	s = d0;
37*853458f3SDavid du Colombier 	if(rooted){
38*853458f3SDavid du Colombier 		/* skip extra '/' at root name */
39*853458f3SDavid du Colombier 		for(; *s == '/'; s++)
407dd7cddfSDavid du Colombier 			;
417dd7cddfSDavid du Colombier 	}
42*853458f3SDavid du Colombier 	/* remove dup slashes */
43*853458f3SDavid du Colombier 	for(d = d0; *s != 0; s++){
44*853458f3SDavid du Colombier 		*d++ = *s;
45*853458f3SDavid du Colombier 		if(*s == '/')
46*853458f3SDavid du Colombier 			while(s[1] == '/')
47*853458f3SDavid du Colombier 				s++;
48*853458f3SDavid du Colombier 	}
49*853458f3SDavid du Colombier 	*d = 0;
50*853458f3SDavid du Colombier 
51*853458f3SDavid du Colombier 	d = d0;
52*853458f3SDavid du Colombier 	s = d0;
53*853458f3SDavid du Colombier 	while(*s != 0){
54*853458f3SDavid du Colombier 		if(s[0] == '.' && SEP(s[1])){
55*853458f3SDavid du Colombier 			if(s[1] == 0)
56*853458f3SDavid du Colombier 				break;
57*853458f3SDavid du Colombier 			s+= 2;
58*853458f3SDavid du Colombier 			continue;
59*853458f3SDavid du Colombier 		}
60*853458f3SDavid du Colombier 		if(s[0] == '.' && s[1] == '.' && SEP(s[2])){
61*853458f3SDavid du Colombier 			if(d == d0){
62*853458f3SDavid du Colombier 				if(rooted){
63*853458f3SDavid du Colombier 					/* /../x -> /x */
64*853458f3SDavid du Colombier 					if(s[2] == 0)
65*853458f3SDavid du Colombier 						break;
66*853458f3SDavid du Colombier 					s += 3;
67*853458f3SDavid du Colombier 					continue;
68*853458f3SDavid du Colombier 				}else{
69*853458f3SDavid du Colombier 					/* ../x -> ../x; and never collect ../ */
70*853458f3SDavid du Colombier 					d0 += 3;
717dd7cddfSDavid du Colombier 				}
727dd7cddfSDavid du Colombier 			}
73*853458f3SDavid du Colombier 			if(d > d0){
74*853458f3SDavid du Colombier 				/* a/../x -> x */
75*853458f3SDavid du Colombier 				assert(d-2 >= d0 && d[-1] == '/');
76*853458f3SDavid du Colombier 				for(d -= 2; d > d0 && d[-1] != '/'; d--)
77*853458f3SDavid du Colombier 						;
78*853458f3SDavid du Colombier 				if(s[2] == 0)
79*853458f3SDavid du Colombier 					break;
80*853458f3SDavid du Colombier 				s += 3;
81*853458f3SDavid du Colombier 				continue;
82c35931e2SDavid du Colombier 			}
83*853458f3SDavid du Colombier 		}
84*853458f3SDavid du Colombier 		while(!SEP(*s))
85*853458f3SDavid du Colombier 			*d++ = *s++;
86*853458f3SDavid du Colombier 		if(*s == 0)
87*853458f3SDavid du Colombier 			break;
88*853458f3SDavid du Colombier 
89*853458f3SDavid du Colombier 		*d++ = *s++;
90*853458f3SDavid du Colombier 	}
91*853458f3SDavid du Colombier 	*d = 0;
92*853458f3SDavid du Colombier 	if(d-1 > name && d[-1] == '/')	/* thanks to #/ */
93*853458f3SDavid du Colombier 		*--d = 0;
94*853458f3SDavid du Colombier 	if(name[0] == 0)
95*853458f3SDavid du Colombier 		strcpy(name, ".");
967dd7cddfSDavid du Colombier 	return name;
977dd7cddfSDavid du Colombier }
98