source: trunk/src/gmake/w32/pathstuff.c@ 520

Last change on this file since 520 was 520, checked in by bird, 19 years ago

Cleaning up the modifications. Changes are now either configurable or marked, and dead stuff has been removed (dll shell).

  • Property svn:eol-style set to native
File size: 11.4 KB
Line 
1/* Path conversion for Windows pathnames.
2Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
32006 Free Software Foundation, Inc.
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify it under the
7terms of the GNU General Public License as published by the Free Software
8Foundation; either version 2, or (at your option) any later version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15GNU Make; see the file COPYING. If not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
17
18#include <Windows.h> /* bird */
19#include <stdio.h> /* bird */
20#include <string.h>
21#include <stdlib.h>
22#include "make.h"
23#include "pathstuff.h"
24
25/*
26 * Convert delimiter separated vpath to Canonical format.
27 */
28char *
29convert_vpath_to_windows32(char *Path, char to_delim)
30{
31 char *etok; /* token separator for old Path */
32
33 /*
34 * Convert all spaces to delimiters. Note that pathnames which
35 * contain blanks get trounced here. Use 8.3 format as a workaround.
36 */
37 for (etok = Path; etok && *etok; etok++)
38 if (isblank ((unsigned char) *etok))
39 *etok = to_delim;
40
41 return (convert_Path_to_windows32(Path, to_delim));
42}
43
44/*
45 * Convert delimiter separated path to Canonical format.
46 */
47char *
48convert_Path_to_windows32(char *Path, char to_delim)
49{
50 char *etok; /* token separator for old Path */
51 char *p; /* points to element of old Path */
52
53 /* is this a multi-element Path ? */
54 for (p = Path, etok = strpbrk(p, ":;");
55 etok;
56 etok = strpbrk(p, ":;"))
57 if ((etok - p) == 1) {
58 if (*(etok - 1) == ';' ||
59 *(etok - 1) == ':') {
60 etok[-1] = to_delim;
61 etok[0] = to_delim;
62 p = ++etok;
63 continue; /* ignore empty bucket */
64 } else if (!isalpha ((unsigned char) *p)) {
65 /* found one to count, handle things like '.' */
66 *etok = to_delim;
67 p = ++etok;
68 } else if ((*etok == ':') && (etok = strpbrk(etok+1, ":;"))) {
69 /* found one to count, handle drive letter */
70 *etok = to_delim;
71 p = ++etok;
72 } else
73 /* all finished, force abort */
74 p += strlen(p);
75 } else {
76 /* found another one, no drive letter */
77 *etok = to_delim;
78 p = ++etok;
79 }
80
81 return Path;
82}
83
84/*
85 * Corrects the case of a path.
86 * Expects a fullpath!
87 * Added by bird for the $(abspath ) function and w32ify
88 */
89void
90w32_fixcase(char *pszPath)
91{
92#define my_assert(expr) \
93 do { \
94 if (!(expr)) { \
95 printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \
96 #expr, __FILE__, __LINE__, pszPath, psz); \
97 __asm { __asm int 3 } \
98 exit(1); \
99 } \
100 } while (0)
101
102 char *psz = pszPath;
103 if (*psz == '/' || *psz == '\\')
104 {
105 if (psz[1] == '/' || psz[1] == '\\')
106 {
107 /* UNC */
108 my_assert(psz[1] == '/' || psz[1] == '\\');
109 my_assert(psz[2] != '/' && psz[2] != '\\');
110
111 /* skip server name */
112 psz += 2;
113 while (*psz != '\\' && *psz != '/')
114 {
115 if (!*psz)
116 return;
117 *psz++ = toupper(*psz);
118 }
119
120 /* skip the share name */
121 psz++;
122 my_assert(*psz != '/' && *psz != '\\');
123 while (*psz != '\\' && *psz != '/')
124 {
125 if (!*psz)
126 return;
127 *psz++ = toupper(*psz);
128 }
129 my_assert(*psz == '/' || *psz == '\\');
130 psz++;
131 }
132 else
133 {
134 /* Unix spec */
135 psz++;
136 }
137 }
138 else
139 {
140 /* Drive letter */
141 my_assert(psz[1] == ':');
142 *psz = toupper(*psz);
143 my_assert(psz[0] >= 'A' && psz[0] <= 'Z');
144 my_assert(psz[2] == '/' || psz[2] == '\\');
145 psz += 3;
146 }
147
148 /*
149 * Pointing to the first char after the unc or drive specifier.
150 */
151 while (*psz)
152 {
153 WIN32_FIND_DATA FindFileData;
154 HANDLE hDir;
155 char chSaved0;
156 char chSaved1;
157 char *pszEnd;
158
159
160 /* find the end of the component. */
161 pszEnd = psz;
162 while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\')
163 pszEnd++;
164
165 /* replace the end with "?\0" */
166 chSaved0 = pszEnd[0];
167 chSaved1 = pszEnd[1];
168 pszEnd[0] = '?';
169 pszEnd[1] = '\0';
170
171 /* find the right filename. */
172 hDir = FindFirstFile(pszPath, &FindFileData);
173 pszEnd[1] = chSaved1;
174 if (!hDir)
175 {
176 pszEnd[0] = chSaved0;
177 return;
178 }
179 pszEnd[0] = '\0';
180 while (stricmp(FindFileData.cFileName, psz))
181 {
182 if (!FindNextFile(hDir, &FindFileData))
183 {
184 pszEnd[0] = chSaved0;
185 return;
186 }
187 }
188 strcpy(psz, FindFileData.cFileName);
189 pszEnd[0] = chSaved0;
190
191 /* advance to the next component */
192 if (!chSaved0)
193 return;
194 psz = pszEnd + 1;
195 my_assert(*psz != '/' && *psz != '\\');
196 }
197#undef my_assert
198}
199
200/*
201 * Convert to forward slashes. Resolve to full pathname optionally
202 */
203char *
204w32ify(char *filename, int resolve)
205{
206 static char w32_path[FILENAME_MAX];
207 char *p;
208
209 if (resolve)
210 _fullpath(w32_path, filename, sizeof (w32_path));
211 else
212 strncpy(w32_path, filename, sizeof (w32_path));
213
214 w32_fixcase(w32_path); /* bird */
215
216 for (p = w32_path; p && *p; p++)
217 if (*p == '\\')
218 *p = '/';
219
220 return w32_path;
221}
222
223char *
224getcwd_fs(char* buf, int len)
225{
226 char *p = getcwd(buf, len);
227
228 if (p) {
229 char *q = w32ify(buf, 0);
230 strncpy(buf, q, len);
231 }
232
233 return p;
234}
235
236/*
237 * Workaround for directory names with trailing slashes.
238 * Added by bird reasons stated.
239 */
240int
241stat(const char *path, struct stat *st)
242{
243 int rc = _stat(path, (struct _stat *)st);
244 if ( rc != 0
245 && errno == ENOENT
246 && *path != '\0')
247 {
248 char *slash = strchr(path, '\0') - 1;
249 if (*slash == '/' || *slash == '\\')
250 {
251 size_t len_path = slash - path + 1;
252 char *tmp = alloca(len_path + 4);
253 memcpy(tmp, path, len_path);
254 tmp[len_path] = '.';
255 tmp[len_path + 1] = '\0';
256 errno = 0;
257 rc = _stat(tmp, (struct _stat *)st);
258 if ( rc == 0
259 && !S_ISDIR(st->st_mode))
260 {
261 errno = ENOTDIR;
262 rc = -1;
263 }
264 }
265 }
266 return rc;
267}
268
269#ifdef unused
270/*
271 * Convert delimiter separated pathnames (e.g. PATH) or single file pathname
272 * (e.g. c:/foo, c:\bar) to NutC format. If we are handed a string that
273 * _NutPathToNutc() fails to convert, just return the path we were handed
274 * and assume the caller will know what to do with it (It was probably
275 * a mistake to try and convert it anyway due to some of the bizarre things
276 * that might look like pathnames in makefiles).
277 */
278char *
279convert_path_to_nutc(char *path)
280{
281 int count; /* count of path elements */
282 char *nutc_path; /* new NutC path */
283 int nutc_path_len; /* length of buffer to allocate for new path */
284 char *pathp; /* pointer to nutc_path used to build it */
285 char *etok; /* token separator for old path */
286 char *p; /* points to element of old path */
287 char sep; /* what flavor of separator used in old path */
288 char *rval;
289
290 /* is this a multi-element path ? */
291 for (p = path, etok = strpbrk(p, ":;"), count = 0;
292 etok;
293 etok = strpbrk(p, ":;"))
294 if ((etok - p) == 1) {
295 if (*(etok - 1) == ';' ||
296 *(etok - 1) == ':') {
297 p = ++etok;
298 continue; /* ignore empty bucket */
299 } else if (etok = strpbrk(etok+1, ":;"))
300 /* found one to count, handle drive letter */
301 p = ++etok, count++;
302 else
303 /* all finished, force abort */
304 p += strlen(p);
305 } else
306 /* found another one, no drive letter */
307 p = ++etok, count++;
308
309 if (count) {
310 count++; /* x1;x2;x3 <- need to count x3 */
311
312 /*
313 * Hazard a guess on how big the buffer needs to be.
314 * We have to convert things like c:/foo to /c=/foo.
315 */
316 nutc_path_len = strlen(path) + (count*2) + 1;
317 nutc_path = xmalloc(nutc_path_len);
318 pathp = nutc_path;
319 *pathp = '\0';
320
321 /*
322 * Loop through PATH and convert one elemnt of the path at at
323 * a time. Single file pathnames will fail this and fall
324 * to the logic below loop.
325 */
326 for (p = path, etok = strpbrk(p, ":;");
327 etok;
328 etok = strpbrk(p, ":;")) {
329
330 /* don't trip up on device specifiers or empty path slots */
331 if ((etok - p) == 1)
332 if (*(etok - 1) == ';' ||
333 *(etok - 1) == ':') {
334 p = ++etok;
335 continue;
336 } else if ((etok = strpbrk(etok+1, ":;")) == NULL)
337 break; /* thing found was a WINDOWS32 pathname */
338
339 /* save separator */
340 sep = *etok;
341
342 /* terminate the current path element -- temporarily */
343 *etok = '\0';
344
345#ifdef __NUTC__
346 /* convert to NutC format */
347 if (_NutPathToNutc(p, pathp, 0) == FALSE) {
348 free(nutc_path);
349 rval = savestring(path, strlen(path));
350 return rval;
351 }
352#else
353 *pathp++ = '/';
354 *pathp++ = p[0];
355 *pathp++ = '=';
356 *pathp++ = '/';
357 strcpy(pathp, &p[2]);
358#endif
359
360 pathp += strlen(pathp);
361 *pathp++ = ':'; /* use Unix style path separtor for new path */
362 *pathp = '\0'; /* make sure we are null terminaed */
363
364 /* restore path separator */
365 *etok = sep;
366
367 /* point p to first char of next path element */
368 p = ++etok;
369
370 }
371 } else {
372 nutc_path_len = strlen(path) + 3;
373 nutc_path = xmalloc(nutc_path_len);
374 pathp = nutc_path;
375 *pathp = '\0';
376 p = path;
377 }
378
379 /*
380 * OK, here we handle the last element in PATH (e.g. c of a;b;c)
381 * or the path was a single filename and will be converted
382 * here. Note, testing p here assures that we don't trip up
383 * on paths like a;b; which have trailing delimiter followed by
384 * nothing.
385 */
386 if (*p != '\0') {
387#ifdef __NUTC__
388 if (_NutPathToNutc(p, pathp, 0) == FALSE) {
389 free(nutc_path);
390 rval = savestring(path, strlen(path));
391 return rval;
392 }
393#else
394 *pathp++ = '/';
395 *pathp++ = p[0];
396 *pathp++ = '=';
397 *pathp++ = '/';
398 strcpy(pathp, &p[2]);
399#endif
400 } else
401 *(pathp-1) = '\0'; /* we're already done, don't leave trailing : */
402
403 rval = savestring(nutc_path, strlen(nutc_path));
404 free(nutc_path);
405 return rval;
406}
407
408#endif
Note: See TracBrowser for help on using the repository browser.