Plan 9 from Bell Labs’s /usr/web/sources/plan9/sys/src/libc/port/cleanname.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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 */
	char *d0;	/* start of path afer the root name */
	Rune r;
	int rooted;

	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);
		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)
		strcpy(name, ".");
	return name;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.