Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/pathunix.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 11.5 KB
Line 
1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*  This file is ALSO:
8 *  Copyright 2001-2004 David Abrahams.
9 *  Copyright 2005 Rene Rivera.
10 *  Distributed under the Boost Software License, Version 1.0.
11 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
12 */
13
14# include "jam.h"
15# include "pathsys.h"
16# include "strings.h"
17# include "newstr.h"
18# include "filesys.h"
19# include <time.h>
20# include <stdlib.h>
21# ifndef OS_NT
22# include <unistd.h>
23# endif
24
25# ifdef USE_PATHUNIX
26
27/*
28 * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
29 *
30 * External routines:
31 *
32 *      path_parse() - split a file name into dir/base/suffix/member
33 *      path_build() - build a filename given dir/base/suffix/member
34 *      path_parent() - make a PATHNAME point to its parent dir
35 *
36 * File_parse() and path_build() just manipuate a string and a structure;
37 * they do not make system calls.
38 *
39 * 04/08/94 (seiwald) - Coherent/386 support added.
40 * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
41 * 12/19/94 (mikem) - solaris string table insanity support
42 * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
43 * 02/14/95 (seiwald) - parse and build /xxx properly
44 * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
45 *                    should expect hdr searches to come up with strings
46 *                    like "thing/thing.h". So we need to test for "/" as
47 *                    well as "\" when parsing pathnames.
48 * 03/16/95 (seiwald) - fixed accursed typo on line 69.
49 * 05/03/96 (seiwald) - split from filent.c, fileunix.c
50 * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
51 *                    don't include the archive member name.
52 * 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident
53 */
54
55/*
56 * path_parse() - split a file name into dir/base/suffix/member
57 */
58
59void
60path_parse( 
61        char    *file,
62        PATHNAME *f )
63{
64        char *p, *q;
65        char *end;
66       
67        memset( (char *)f, 0, sizeof( *f ) );
68
69        /* Look for <grist> */
70
71        if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
72        {
73            f->f_grist.ptr = file;
74            f->f_grist.len = p - file;
75            file = p + 1;
76        }
77
78        /* Look for dir/ */
79
80        p = strrchr( file, '/' );
81
82# if PATH_DELIM == '\\'
83        /* On NT, look for dir\ as well */
84        {
85            char *p1 = strrchr( file, '\\' );
86            p = p1 > p ? p1 : p;
87        }
88# endif
89
90        if( p )
91        {
92            f->f_dir.ptr = file;
93            f->f_dir.len = p - file;
94       
95            /* Special case for / - dirname is /, not "" */
96
97            if( !f->f_dir.len )
98                f->f_dir.len = 1;
99
100# if PATH_DELIM == '\\'
101            /* Special case for D:/ - dirname is D:/, not "D:" */
102
103            if( f->f_dir.len == 2 && file[1] == ':' )
104                f->f_dir.len = 3;
105# endif
106
107            file = p + 1;
108        }
109
110        end = file + strlen( file );
111
112        /* Look for (member) */
113
114        if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
115        {
116            f->f_member.ptr = p + 1;
117            f->f_member.len = end - p - 2;
118            end = p;
119        } 
120
121        /* Look for .suffix */
122        /* This would be memrchr() */
123
124        p = 0;
125        q = file;
126
127        while( q = (char *)memchr( q, '.', end - q ) )
128            p = q++;
129
130        if( p )
131        {
132            f->f_suffix.ptr = p;
133            f->f_suffix.len = end - p;
134            end = p;
135        }
136
137        /* Leaves base */
138
139        f->f_base.ptr = file;
140        f->f_base.len = end - file;
141}
142
143/*
144 * path_delims - the string of legal path delimiters
145 */
146static char path_delims[] = {
147    PATH_DELIM,
148#  if PATH_DELIM == '\\'
149    '/',
150#  endif
151    0
152};
153
154/*
155 * is_path_delim() - true iff c is a path delimiter
156 */
157static int is_path_delim( char c )
158{
159    char* p = strchr( path_delims, c );
160    return p && *p;
161}
162
163/*
164 * as_path_delim() - convert c to a path delimiter if it isn't one
165 * already
166 */
167static char as_path_delim( char c )
168{
169    return is_path_delim( c ) ? c : PATH_DELIM;
170}
171
172/*
173 * path_build() - build a filename given dir/base/suffix/member
174 *
175 * To avoid changing slash direction on NT when reconstituting paths,
176 * instead of unconditionally appending PATH_DELIM we check the
177 * past-the-end character of the previous path element.  If it is in
178 * path_delims, we append that, and only append PATH_DELIM as a last
179 * resort.  This heuristic is based on the fact that PATHNAME objects
180 * are usually the result of calling path_parse, which leaves the
181 * original slashes in the past-the-end position. Correctness depends
182 * on the assumption that all strings are zero terminated, so a
183 * past-the-end character will always be available.
184 *
185 * As an attendant patch, we had to ensure that backslashes are used
186 * explicitly in timestamp.c
187 */
188
189void
190path_build(
191        PATHNAME *f,
192        string  *file,
193        int     binding )
194{
195    file_build1( f, file );
196   
197    /* Don't prepend root if it's . or directory is rooted */
198# if PATH_DELIM == '/'
199
200    if( f->f_root.len
201        && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
202        && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )
203
204# else /* unix */
205
206    if( f->f_root.len
207        && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
208        && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
209        && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
210        && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
211
212# endif /* unix */
213
214    {
215        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
216        /* If 'root' already ends with path delimeter,
217           don't add yet another one. */
218        if( ! is_path_delim( f->f_root.ptr[f->f_root.len-1] ) )
219            string_push_back( file, as_path_delim( f->f_root.ptr[f->f_root.len] ) );
220    }
221
222    if( f->f_dir.len )
223    {
224        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
225    }
226
227    /* UNIX: Put / between dir and file */
228    /* NT:   Put \ between dir and file */
229
230    if( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
231    {
232        /* UNIX: Special case for dir \ : don't add another \ */
233        /* NT:   Special case for dir / : don't add another / */
234
235# if PATH_DELIM == '\\'
236        if( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
237# endif
238            if( !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[0] ) ) )
239                string_push_back( file, as_path_delim( f->f_dir.ptr[f->f_dir.len] ) );
240    }
241
242    if( f->f_base.len )
243    {
244        string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
245    }
246
247    if( f->f_suffix.len )
248    {
249        string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
250    }
251
252    if( f->f_member.len )
253    {
254        string_push_back( file, '(' );
255        string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
256        string_push_back( file, ')' );
257    }
258}
259
260/*
261 *      path_parent() - make a PATHNAME point to its parent dir
262 */
263
264void
265path_parent( PATHNAME *f )
266{
267        /* just set everything else to nothing */
268
269        f->f_base.ptr =
270        f->f_suffix.ptr =
271        f->f_member.ptr = "";
272
273        f->f_base.len = 
274        f->f_suffix.len = 
275        f->f_member.len = 0;
276}
277
278#ifdef NT
279#include <windows.h>
280#include <tchar.h>
281
282/* The definition of this in winnt.h is not ANSI-C compatible. */
283#undef INVALID_FILE_ATTRIBUTES
284#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
285
286
287DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
288                          cchBuffer)
289{
290    LONG i=0;
291    TCHAR path[_MAX_PATH]={0};
292    TCHAR ret[_MAX_PATH]={0};
293    LONG pos=0, prev_pos=0;
294    LONG len=_tcslen(lpszShortPath);
295
296    /* Is the string valid? */
297    if (!lpszShortPath) {
298        SetLastError(ERROR_INVALID_PARAMETER);
299        return 0; 
300    }
301
302    /* Is the path valid? */
303    if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
304        return 0;
305
306    /* Convert "/" to "\" */
307    for (i=0;i<len;++i) {
308        if (lpszShortPath[i]==_T('/')) 
309            path[i]=_T('\\');
310        else
311            path[i]=lpszShortPath[i];
312    }
313
314    /* UNC path? */
315    if (path[0]==_T('\\') && path[1]==_T('\\')) {
316        pos=2;
317        for (i=0;i<2;++i) {
318            while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
319                ++pos;
320            ++pos;
321        }
322        _tcsncpy(ret,path,pos-1);
323    } /* Drive letter? */
324    else if (path[1]==_T(':')) {
325        if (path[2]==_T('\\'))
326            pos=3;
327        if (len==3) {
328            if (cchBuffer>3)
329                _tcscpy(lpszLongPath,lpszShortPath);
330            return len;
331        }
332        _tcsncpy(ret,path,2);
333    }
334   
335    /* Expand the path for each subpath, and strip trailing backslashes */
336    for (prev_pos = pos-1;pos<=len;++pos) {
337        if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
338                                    path[pos-1]!=_T('\\'))) {
339            WIN32_FIND_DATA fd;
340            HANDLE hf=0;
341            TCHAR c=path[pos];
342            char* new_element;
343            path[pos]=_T('\0');
344
345            /* the path[prev_pos+1]... path[pos] range is the part of
346               path we're handling right now. We need to find long
347               name for that element and add it. */
348            new_element = path + prev_pos + 1;
349
350            /* First add separator, but only if there's something in result already. */
351            if (ret[0] != _T('\0'))
352            {
353                _tcscat(ret,_T("\\"));
354            }
355
356            /* If it's ".." element, we need to append it, not
357               the name in parent that FindFirstFile will return.
358               Same goes for "." */
359           
360            if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
361                new_element[0] == _T('.') && new_element[1] == _T('.') 
362                && new_element[2] == _T('\0'))
363            {
364                _tcscat(ret, new_element);
365            }
366            else
367            {
368                hf=FindFirstFile(path, &fd);
369                if (hf==INVALID_HANDLE_VALUE)
370                    return 0;
371
372                _tcscat(ret,fd.cFileName);
373                FindClose(hf);
374            }
375
376            path[pos]=c;
377
378            prev_pos = pos;
379        }
380    }
381 
382    len=_tcslen(ret)+1;
383    if (cchBuffer>=len)
384        _tcscpy(lpszLongPath,ret);
385   
386    return len;
387}
388
389char* short_path_to_long_path(char* short_path)
390{ 
391    char buffer2[_MAX_PATH];
392    int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH);
393
394    if (ret)
395        return newstr(buffer2);
396    else
397      return newstr(short_path);
398}
399
400#endif
401
402static string path_tmpdir_buffer[1];
403static const char * path_tmpdir_result = 0;
404
405const char * path_tmpdir()
406{
407    if (!path_tmpdir_result)
408    {
409        # ifdef OS_NT
410        DWORD pathLength = 0;
411        pathLength = GetTempPath(pathLength,NULL);
412        string_new(path_tmpdir_buffer);
413        string_reserve(path_tmpdir_buffer,pathLength);
414        pathLength = GetTempPathA(pathLength,path_tmpdir_buffer[0].value);
415        path_tmpdir_buffer[0].value[pathLength-1] = '\0';
416        path_tmpdir_buffer[0].size = pathLength-1;
417        # else
418        const char * t = getenv("TMPDIR");
419        if (!t)
420        {
421            t = "/tmp";
422        }
423        string_new(path_tmpdir_buffer);
424        string_append(path_tmpdir_buffer,t);
425        # endif
426        path_tmpdir_result = path_tmpdir_buffer[0].value;
427    }
428    return path_tmpdir_result;
429}
430
431const char * path_tmpnam(void)
432{
433    char name_buffer[64];
434    # ifdef OS_NT
435    unsigned long c0 = GetCurrentProcessId();
436    # else
437    unsigned long c0 = getpid();
438    # endif
439    static unsigned long c1 = 0;
440    if (0 == c1) c1 = time(0)&0xffff;
441    c1 += 1;
442    sprintf(name_buffer,"jam%lx%lx.000",c0,c1);
443    return newstr(name_buffer);
444}
445
446const char * path_tmpfile(void)
447{
448    const char * result = 0;
449   
450    string file_path;
451    string_copy(&file_path,path_tmpdir());
452    string_push_back(&file_path,PATH_DELIM);
453    string_append(&file_path,path_tmpnam());
454    result = newstr(file_path.value);
455    string_free(&file_path);
456   
457    return result;
458}
459
460
461# endif /* unix, NT, OS/2, AmigaOS */
Note: See TracBrowser for help on using the repository browser.