1 /*
2  * -= Copyright 2005 Tim Baker (treectrl@hotmail.com) =-
3  *
4  * This file is part of depslib.
5  *
6  * License is hereby granted to use this software and distribute it
7  * freely, as long as this copyright notice is retained and modifications
8  * are clearly marked.
9  *
10  * ALL WARRANTIES ARE HEREBY DISCLAIMED.
11  */
12 #include "jam.h"
13 #include "pathsys.h"
14 #include "pathsplit.h"
15 #include "newstr.h"
16 #include <stdio.h>
17 
18 static const char *_dot = ".";
19 static const char *_dotdot = "..";
20 #ifdef DEPSLIB_UNIX
21 static const char *_home = "~";
22 #endif
23 static const char *_cwd = 0;
24 static PATHSPLIT _fcwd;
25 
path_setcwd(const char * cwd)26 void path_setcwd(const char *cwd)
27 {
28 	if (cwd)
29 	{
30 		_cwd = newstr(cwd);
31 		path_split(_cwd, &_fcwd);
32 	}
33 	else /* TODO: get cwd */
34 		cwd = 0;
35 }
36 
path_print(PATHSPLIT * f)37 void path_print(PATHSPLIT *f)
38 {
39 	int i;
40 
41 	for (i = 0; i < f->count; i++)
42 		printf("'%.*s'[%d] ", f->part[i].len, f->part[i].ptr, f->part[i].len);
43 	printf("\n");
44 }
45 
path_tostring(PATHSPLIT * f,char * buf)46 char *path_tostring(PATHSPLIT *f, char *buf)
47 {
48 	char *p = buf;
49 	int i;
50 
51 	for (i = 0; i < f->count; i++)
52 	{
53 		memcpy(p, f->part[i].ptr, f->part[i].len);
54 		p += f->part[i].len;
55 		if (i + 1 < f->count)
56 		{
57 			*p++ = SEP1;
58 		}
59 	}
60 	*p = '\0';
61 #ifdef DOWNSHIFT_PATHS
62 	p = buf;
63 	do *p = tolower(*p);
64 	while (*p++);
65 #endif
66 	return buf;
67 }
68 
path_split(const char * path,PATHSPLIT * f)69 void path_split(const char *path, PATHSPLIT *f)
70 {
71 	const char *p = path;
72 #ifdef DEPSLIB_WINDOWS
73 	/* support UNC filename in windows: ignore leading slashes */
74 	while ((*p == '/') || (*p == '\\'))
75         ++p;
76 #endif
77 	PATHPART *part;
78 
79 	f->count = 1;
80 	f->part[0].ptr = path;
81 
82 	while (*p)
83 	{
84 		if ((*p == SEP1) || (*p == SEP2))
85 		{
86 			part = &f->part[f->count - 1];
87 
88 			f->part[f->count].ptr = p + 1;
89 			part->len = p - part->ptr;
90 
91 			if ((part->len == 1) && (part->ptr[0] == '.'))
92 				part->ptr = _dot;
93 			if ((part->len == 2) && (part->ptr[0] == '.') &&
94 				(part->ptr[1] == '.'))
95 				part->ptr = _dotdot;
96 #ifdef DEPSLIB_UNIX
97 			if ((part->len == 1) && (part->ptr[0] == '~'))
98 				part->ptr = _home;
99 #endif
100 			++f->count;
101 		}
102 		++p;
103 	}
104 
105 	f->part[f->count - 1].len = p - f->part[f->count - 1].ptr;
106 }
107 
108 /*
109 Windows:
110  C:/foo/bar is absolute
111  C:/./foo/bar is absolute
112  C:/../foo/bar is absolute (but invalid)
113  ./foo/bar is relative
114  ../foo/bar is relative
115  foo/bar is relative
116 Unix:
117  /foo/bar is absolute
118  /./foo/bar is absolute
119  /../foo/bar is absolute (but invalid)
120  ~/./foo/bar is absolute
121  ~/../foo/bar is absolute
122  ~/foo/bar is absolute
123  ./foo/bar is relative
124  ../foo/bar is relative
125  foo/bar is relative
126  */
is_relative(PATHSPLIT * f)127 int is_relative(PATHSPLIT *f)
128 {
129 #ifdef DEPSLIB_WINDOWS
130 	/* Volume C: D: etc is present, or is a UNC filename */
131 	if (((f->part[0].len == 2) && (f->part[0].ptr[1] == ':')) ||
132 		((f->part[0].len > 2) && (f->part[0].ptr[0] == '\\' && f->part[0].ptr[1] == '\\')))
133 	{
134 		return 0;
135 	}
136 #endif
137 #ifdef DEPSLIB_UNIX
138 	/* / or ~ is present */
139 	if ((f->part[0].len == 0) || (f->part[0].ptr == _home))
140 	{
141 		return 0;
142 	}
143 #endif
144 	return 1;
145 }
146 
path_normalize(PATHSPLIT * f,PATHSPLIT * cwd)147 int path_normalize(PATHSPLIT *f, PATHSPLIT *cwd)
148 {
149 	PATHSPLIT f2;
150 	int i;
151 
152 	if (is_relative(f) && (cwd || _cwd))
153 		f2 = cwd ? *cwd : _fcwd;
154 	else
155 		f2.count = 0;
156 
157 	for (i = 0; i < f->count; i++)
158 	{
159 		PATHPART *part = &f->part[i];
160 
161 		if (part->ptr == _dot)
162 			continue;
163 
164 		if (part->ptr == _dotdot)
165 		{
166 			if (f2.count == 0)
167 				return 1;
168 			--f2.count;
169 			continue;
170 		}
171 
172 		f2.part[f2.count].ptr = part->ptr;
173 		f2.part[f2.count].len = part->len;
174 		++f2.count;
175 	}
176 
177 	*f = f2;
178 	return 0;
179 }
180 
donepath(void)181 void donepath(void)
182 {
183 	_cwd = 0; /* freed in donestr() */
184 }
185