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