jehanne/sys/src/lib/jehanne/port/cleanname.c

110 lines
2.2 KiB
C

/*
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
*
* 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*
jehanne_cleanname(char *name)
{
char *s; /* source of copy */
char *d; /* destination of copy */
char *d0; /* start of path after the root name */
Rune r;
int rooted;
assert(name != nil);
if(name[0] == 0)
return jehanne_strcpy(name, ".");
rooted = 0;
d0 = name;
if(d0[0] == '#'){
if(d0[1] == 0)
return d0;
d0 += 1 + jehanne_chartorune(&r, d0+1); /* ignore slash: #/ */
while(!SEP(*d0))
d0 += jehanne_chartorune(&r, d0);
if(*d0 == 0)
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)
jehanne_strcpy(name, ".");
return name;
}