The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

pathunix.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
00003  *
00004  * This file is part of Jam - see jam.c for Copyright information.
00005  */
00006 
00007 /*  This file is ALSO:
00008  *  (C) Copyright David Abrahams 2001. Permission to copy, use,
00009  *  modify, sell and distribute this software is granted provided this
00010  *  copyright notice appears in all copies. This software is provided
00011  *  "as is" without express or implied warranty, and with no claim as
00012  *  to its suitability for any purpose.
00013  */
00014 
00015 # include "jam.h"
00016 # include "pathsys.h"
00017 # include "strings.h"
00018 # include "newstr.h"
00019 # include "filesys.h"
00020 
00021 # ifdef USE_PATHUNIX
00022 
00023 /*
00024  * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
00025  *
00026  * External routines:
00027  *
00028  *      path_parse() - split a file name into dir/base/suffix/member
00029  *      path_build() - build a filename given dir/base/suffix/member
00030  *      path_parent() - make a PATHNAME point to its parent dir
00031  *
00032  * File_parse() and path_build() just manipuate a string and a structure;
00033  * they do not make system calls.
00034  *
00035  * 04/08/94 (seiwald) - Coherent/386 support added.
00036  * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
00037  * 12/19/94 (mikem) - solaris string table insanity support
00038  * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
00039  * 02/14/95 (seiwald) - parse and build /xxx properly
00040  * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
00041  *                    should expect hdr searches to come up with strings
00042  *                    like "thing/thing.h". So we need to test for "/" as
00043  *                    well as "\" when parsing pathnames.
00044  * 03/16/95 (seiwald) - fixed accursed typo on line 69.
00045  * 05/03/96 (seiwald) - split from filent.c, fileunix.c
00046  * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
00047  *                    don't include the archive member name.
00048  * 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident
00049  */
00050 
00051 /*
00052  * path_parse() - split a file name into dir/base/suffix/member
00053  */
00054 
00055 void
00056 path_parse( 
00057         char    *file,
00058         PATHNAME *f )
00059 {
00060         char *p, *q;
00061         char *end;
00062         
00063         memset( (char *)f, 0, sizeof( *f ) );
00064 
00065         /* Look for <grist> */
00066 
00067         if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
00068         {
00069             f->f_grist.ptr = file;
00070             f->f_grist.len = p - file;
00071             file = p + 1;
00072         }
00073 
00074         /* Look for dir/ */
00075 
00076         p = strrchr( file, '/' );
00077 
00078 # if PATH_DELIM == '\\'
00079         /* On NT, look for dir\ as well */
00080         {
00081             char *p1 = strrchr( file, '\\' );
00082             p = p1 > p ? p1 : p;
00083         }
00084 # endif
00085 
00086         if( p )
00087         {
00088             f->f_dir.ptr = file;
00089             f->f_dir.len = p - file;
00090         
00091             /* Special case for / - dirname is /, not "" */
00092 
00093             if( !f->f_dir.len )
00094                 f->f_dir.len = 1;
00095 
00096 # if PATH_DELIM == '\\'
00097             /* Special case for D:/ - dirname is D:/, not "D:" */
00098 
00099             if( f->f_dir.len == 2 && file[1] == ':' )
00100                 f->f_dir.len = 3;
00101 # endif
00102 
00103             file = p + 1;
00104         }
00105 
00106         end = file + strlen( file );
00107 
00108         /* Look for (member) */
00109 
00110         if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
00111         {
00112             f->f_member.ptr = p + 1;
00113             f->f_member.len = end - p - 2;
00114             end = p;
00115         } 
00116 
00117         /* Look for .suffix */
00118         /* This would be memrchr() */
00119 
00120         p = 0;
00121         q = file;
00122 
00123         while( q = (char *)memchr( q, '.', end - q ) )
00124             p = q++;
00125 
00126         if( p )
00127         {
00128             f->f_suffix.ptr = p;
00129             f->f_suffix.len = end - p;
00130             end = p;
00131         }
00132 
00133         /* Leaves base */
00134 
00135         f->f_base.ptr = file;
00136         f->f_base.len = end - file;
00137 }
00138 
00139 /*
00140  * path_delims - the string of legal path delimiters
00141  */
00142 static char path_delims[] = {
00143     PATH_DELIM,
00144 #  if PATH_DELIM == '\\'
00145     '/',
00146 #  endif
00147     0
00148 };
00149 
00150 /*
00151  * is_path_delim() - true iff c is a path delimiter
00152  */
00153 static int is_path_delim( char c )
00154 {
00155     char* p = strchr( path_delims, c );
00156     return p && *p;
00157 }
00158 
00159 /*
00160  * as_path_delim() - convert c to a path delimiter if it isn't one
00161  * already
00162  */
00163 static char as_path_delim( char c )
00164 {
00165     return is_path_delim( c ) ? c : PATH_DELIM;
00166 }
00167 
00168 /*
00169  * path_build() - build a filename given dir/base/suffix/member
00170  *
00171  * To avoid changing slash direction on NT when reconstituting paths,
00172  * instead of unconditionally appending PATH_DELIM we check the
00173  * past-the-end character of the previous path element.  If it is in
00174  * path_delims, we append that, and only append PATH_DELIM as a last
00175  * resort.  This heuristic is based on the fact that PATHNAME objects
00176  * are usually the result of calling path_parse, which leaves the
00177  * original slashes in the past-the-end position. Correctness depends
00178  * on the assumption that all strings are zero terminated, so a
00179  * past-the-end character will always be available.
00180  *
00181  * As an attendant patch, we had to ensure that backslashes are used
00182  * explicitly in timestamp.c
00183  */
00184 
00185 void
00186 path_build(
00187         PATHNAME *f,
00188         string  *file,
00189         int     binding )
00190 {
00191     file_build1( f, file );
00192     
00193     /* Don't prepend root if it's . or directory is rooted */
00194 # if PATH_DELIM == '/'
00195 
00196     if( f->f_root.len 
00197         && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
00198         && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )
00199 
00200 # else /* unix */
00201 
00202     if( f->f_root.len 
00203         && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
00204         && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
00205         && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
00206         && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
00207 
00208 # endif /* unix */
00209 
00210     {
00211         string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
00212         string_push_back( file, as_path_delim( f->f_root.ptr[f->f_root.len] ) );
00213     }
00214 
00215     if( f->f_dir.len )
00216     {
00217         string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
00218     }
00219 
00220     /* UNIX: Put / between dir and file */
00221     /* NT:   Put \ between dir and file */
00222 
00223     if( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
00224     {
00225         /* UNIX: Special case for dir \ : don't add another \ */
00226         /* NT:   Special case for dir / : don't add another / */
00227 
00228 # if PATH_DELIM == '\\'
00229         if( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
00230 # endif
00231             if( !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[0] ) ) )
00232                 string_push_back( file, as_path_delim( f->f_dir.ptr[f->f_dir.len] ) );
00233     }
00234 
00235     if( f->f_base.len )
00236     {
00237         string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
00238     }
00239 
00240     if( f->f_suffix.len )
00241     {
00242         string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
00243     }
00244 
00245     if( f->f_member.len )
00246     {
00247         string_push_back( file, '(' );
00248         string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
00249         string_push_back( file, ')' );
00250     }
00251 }
00252 
00253 /*
00254  *      path_parent() - make a PATHNAME point to its parent dir
00255  */
00256 
00257 void
00258 path_parent( PATHNAME *f )
00259 {
00260         /* just set everything else to nothing */
00261 
00262         f->f_base.ptr =
00263         f->f_suffix.ptr =
00264         f->f_member.ptr = "";
00265 
00266         f->f_base.len = 
00267         f->f_suffix.len = 
00268         f->f_member.len = 0;
00269 }
00270 
00271 #ifdef NT
00272 #include <windows.h>
00273 #include <tchar.h>
00274 
00275 #ifndef INVALID_FILE_ATTRIBUTES
00276 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
00277 #endif
00278 
00279 
00280 DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
00281                           cchBuffer)
00282 {
00283     DWORD i=0;
00284     TCHAR path[_MAX_PATH]={0};
00285     TCHAR ret[_MAX_PATH]={0};
00286     DWORD pos=0, prev_pos=0;
00287     DWORD len=_tcslen(lpszShortPath);
00288 
00289     // Is the string valid?
00290     if (!lpszShortPath) {
00291         SetLastError(ERROR_INVALID_PARAMETER);
00292         return 0;  
00293     }
00294 
00295     // Is the path valid?
00296     if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
00297         return 0;
00298 
00299     // Convert "/" to "\"
00300     for (i=0;i<len;++i) {
00301         if (lpszShortPath[i]==_T('/')) 
00302             path[i]=_T('\\');
00303         else
00304             path[i]=lpszShortPath[i];
00305     }
00306 
00307     // UNC path?
00308     if (path[0]==_T('\\') && path[1]==_T('\\')) {
00309         pos=2;
00310         for (i=0;i<2;++i) {
00311             while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
00312                 ++pos;
00313             ++pos;
00314         }
00315         _tcsncpy(ret,path,pos-1);
00316     } // Drive letter?
00317     else if (path[1]==_T(':')) {
00318         if (path[2]==_T('\\'))
00319             pos=3;
00320         if (len==3) {
00321             if (cchBuffer>3)
00322                 _tcscpy(lpszLongPath,lpszShortPath);
00323             return len;
00324         }
00325         _tcsncpy(ret,path,2);
00326     }
00327     
00328     // Expand the path for each subpath, and strip trailing backslashes
00329     for (prev_pos = pos-1;pos<=len;++pos) {
00330         if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
00331                                     path[pos-1]!=_T('\\'))) {
00332             WIN32_FIND_DATA fd;
00333             HANDLE hf=0;
00334             TCHAR c=path[pos];
00335             char* new_element;
00336             path[pos]=_T('\0');
00337 
00338             // the path[prev_pos+1]... path[pos] range is the part of
00339             // path we're handling right now. We need to find long
00340             // name for that element and add it.
00341             new_element = path + prev_pos + 1;
00342 
00343             // First add separator, but only if there's something in result already.
00344             if (ret[0] != _T('\0'))
00345             {
00346                 _tcscat(ret,_T("\\"));
00347             }
00348 
00349             // If it's ".." element, we need to append it, not
00350             // the name in parent that FindFirstFile will return.
00351             // Same goes for "."
00352             
00353             if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
00354                 new_element[0] == _T('.') && new_element[1] == _T('.') 
00355                 && new_element[2] == _T('\0'))
00356             {
00357                 _tcscat(ret, new_element);
00358             }
00359             else
00360             {
00361                 hf=FindFirstFile(path, &fd);
00362                 if (hf==INVALID_HANDLE_VALUE)
00363                     return 0;
00364 
00365                 _tcscat(ret,fd.cFileName);
00366                 FindClose(hf);
00367             }
00368 
00369             path[pos]=c;
00370 
00371             prev_pos = pos;
00372         }
00373     }
00374  
00375     len=_tcslen(ret)+1;
00376     if (cchBuffer>=len)
00377         _tcscpy(lpszLongPath,ret);
00378     
00379     return len;
00380 }
00381 
00382 char* short_path_to_long_path(char* short_path)
00383 {  
00384     char buffer2[_MAX_PATH];
00385     int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH);
00386 
00387     if (ret)
00388         return newstr(buffer2);
00389     else
00390       return newstr(short_path);
00391 }
00392 
00393 #endif
00394 
00395 
00396 # endif /* unix, NT, OS/2, AmigaOS */

Generated on Mon Nov 8 17:07:46 2004 for MPT by  doxygen 1.3.9.1