xref: /inferno-os/appl/lib/names.b (revision 66f5808b81b1df84bc57c4f7b9d487201bc162fb)
1implement Names;
2
3include "sys.m";
4
5include "names.m";
6
7# return name rewritten to compress /+, eliminate ., and interpret ..
8
9cleanname(name: string): string
10{
11	if(name == nil)
12		return ".";
13
14	p := rooted := name[0]=='/';
15	if(name[0] == '#'){	# special
16		if(len name < 2)
17			return name;
18		p += 2;	# character after # whatever it is, is the name (including /)
19		for(; p < len name; p++)
20			if(name[p] == '/')
21				break;
22		rooted = p;
23	}
24	dotdot := rooted;
25
26	#
27	# invariants:
28	#	p points at beginning of path element we're considering.
29	#	out records up to the last path element (no trailing slash unless root or #/).
30	#	dotdot points in out just past the point where .. cannot backtrack
31	#		any further (no slash).
32	#
33	out := name[0:rooted];
34	while(p < len name){
35		for(q := p; p < len name && name[p] != '/'; p++){
36			# skip
37		}
38		n := name[q:p];	# path element
39		p++;
40		case n {
41		"" or "." =>
42			;	# null effect
43		".." =>
44			if(len out > dotdot){	# can backtrack
45				for(q = len out; --q > dotdot && out[q] != '/';)
46					;
47				out = out[:q];
48			}else if(!rooted){	# /.. is / but ./../ is ..
49				if(out != nil)
50					out += "/..";
51				else
52					out += "..";
53				dotdot = len out;
54			}
55		* =>
56			if(rooted > 1 || len out > rooted)
57				out[len out] = '/';
58			out += n;
59		}
60	}
61	if(out == nil)
62		return ".";
63	return out;
64}
65
66dirname(name: string): string
67{
68	for(i := len name; --i >= 0;)
69		if(name[i] == '/')
70			break;
71	if(i < 0)
72		return nil;
73	d := name[0:i];
74	if(d != nil)
75		return d;
76	if(name[0] == '/')
77		return "/";
78	return nil;
79}
80
81basename(name: string, suffix: string): string
82{
83	for(i := len name; --i >= 0;)
84		if(name[i] == '/')
85			break;
86	if(i >= 0)
87		name = name[i+1:];
88	if(suffix != nil){
89		o := len name - len suffix;
90		if(o >= 0 && name[o:] == suffix)
91			return name[0:o];
92	}
93	return name;
94}
95
96relative(name: string, root: string): string
97{
98	if(root == nil || name == nil)
99		return name;
100	if(isprefix(root, name)){
101		name = name[len root:];
102		while(name != nil && name[0] == '/')
103			name = name[1:];
104	}
105	return name;
106}
107
108rooted(root: string, name: string): string
109{
110	if(name == nil)
111		return root;
112	if(root == nil || name[0] == '/' || name[0] == '#')
113		return name;
114	if(root[len root-1] != '/' && name[0] != '/')
115		return root+"/"+name;
116	return root+name;
117}
118
119isprefix(a: string, b: string): int
120{
121	la := len a;
122	if(la == 0)
123		return 0;	# "" isn't a pathname
124	while(la > 1 && a[la-1] == '/')
125		a = a[0:--la];
126	lb := len b;
127	if(la > lb)
128		return 0;
129	if(la == lb)
130		return a == b;
131	return a == b[0:la] && (a == "/" || b[la] == '/');
132}
133
134elements(name: string): list of string
135{
136	sys := load Sys Sys->PATH;
137	(nil, fld) := sys->tokenize(name, "/");
138	if(name != nil && name[0] == '/')
139		fld = "/" :: fld;
140	return fld;
141}
142
143pathname(els: list of string): string
144{
145	name: string;
146	sl := els != nil && hd els == "/";
147	for(; els != nil; els = tl els){
148		if(!sl)
149			name += "/";
150		name += hd els;
151		sl = 0;
152	}
153	return name;
154}
155