2015-12-22 12:55:44 +01:00
|
|
|
/*
|
2016-11-25 17:18:40 +01:00
|
|
|
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
|
|
*
|
2015-12-22 12:55:44 +01:00
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In place, rewrite name to compress multiple /, eliminate ., and process ..
|
|
|
|
*/
|
|
|
|
#define SEP(x) ((x)=='/' || (x) == 0)
|
|
|
|
char*
|
|
|
|
cleanname(char *name)
|
|
|
|
{
|
|
|
|
char *s; /* source of copy */
|
|
|
|
char *d; /* destination of copy */
|
2016-11-25 17:18:40 +01:00
|
|
|
char *d0; /* start of path after the root name */
|
2015-12-22 12:55:44 +01:00
|
|
|
Rune r;
|
|
|
|
int rooted;
|
|
|
|
|
2016-11-25 17:18:40 +01:00
|
|
|
assert(name != nil);
|
2015-12-22 12:55:44 +01:00
|
|
|
if(name[0] == 0)
|
|
|
|
return strcpy(name, ".");
|
|
|
|
rooted = 0;
|
|
|
|
d0 = name;
|
|
|
|
if(d0[0] == '#'){
|
|
|
|
if(d0[1] == 0)
|
|
|
|
return d0;
|
|
|
|
d0 += 1 + chartorune(&r, d0+1); /* ignore slash: #/ */
|
|
|
|
while(!SEP(*d0))
|
|
|
|
d0 += chartorune(&r, d0);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(*d0 == 0)
|
2015-12-22 12:55:44 +01:00
|
|
|
return name;
|
|
|
|
d0++; /* keep / after #<name> */
|
|
|
|
rooted = 1;
|
|
|
|
}else if(d0[0] == '/'){
|
|
|
|
rooted = 1;
|
|
|
|
d0++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = d0;
|
|
|
|
if(rooted){
|
|
|
|
/* skip extra '/' at root name */
|
|
|
|
for(; *s == '/'; s++)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
/* remove dup slashes */
|
|
|
|
for(d = d0; *s != 0; s++){
|
|
|
|
*d++ = *s;
|
|
|
|
if(*s == '/')
|
|
|
|
while(s[1] == '/')
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
*d = 0;
|
|
|
|
|
|
|
|
d = d0;
|
|
|
|
s = d0;
|
|
|
|
while(*s != 0){
|
|
|
|
if(s[0] == '.' && SEP(s[1])){
|
|
|
|
if(s[1] == 0)
|
|
|
|
break;
|
|
|
|
s+= 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(s[0] == '.' && s[1] == '.' && SEP(s[2])){
|
|
|
|
if(d == d0){
|
|
|
|
if(rooted){
|
|
|
|
/* /../x -> /x */
|
|
|
|
if(s[2] == 0)
|
|
|
|
break;
|
|
|
|
s += 3;
|
|
|
|
continue;
|
|
|
|
}else{
|
|
|
|
/* ../x -> ../x; and never collect ../ */
|
|
|
|
d0 += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(d > d0){
|
|
|
|
/* a/../x -> x */
|
|
|
|
assert(d-2 >= d0 && d[-1] == '/');
|
|
|
|
for(d -= 2; d > d0 && d[-1] != '/'; d--)
|
|
|
|
;
|
|
|
|
if(s[2] == 0)
|
|
|
|
break;
|
|
|
|
s += 3;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while(!SEP(*s))
|
|
|
|
*d++ = *s++;
|
|
|
|
if(*s == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
*d++ = *s++;
|
|
|
|
}
|
|
|
|
*d = 0;
|
|
|
|
if(d-1 > name && d[-1] == '/') /* thanks to #/ */
|
|
|
|
*--d = 0;
|
|
|
|
if(name[0] == 0)
|
|
|
|
strcpy(name, ".");
|
|
|
|
return name;
|
|
|
|
}
|