dir.c

Go to the documentation of this file.
00001 
00006 #ifndef CTL_UNIT
00007 
00008 #include "ctl/ctldef.h"
00009 #include "ctl/dir.h"
00010 #ifdef WIN32
00011 #include <Windows.h>
00012 #include <io.h>
00013 #include <fcntl.h>
00014 #else
00015 #include <unistd.h>
00016 #include <fcntl.h>
00017 #include <dirent.h>
00018 #include <sys/stat.h>
00019 #endif
00020 #include <stdio.h>
00021 
00022 #ifndef _MAX_PATH
00023 #define _MAX_PATH 256
00024 #endif
00025 
00026 #ifndef O_BINARY
00027 #define O_BINARY 0
00028 #endif
00029 
00035 char* ctl_cwd( char* buffer, size_t cMax )
00036 {
00037     char* result;
00038     assertptr(buffer,cMax);
00039 #ifdef WIN32
00040     GetCurrentDirectory( (DWORD)cMax, buffer );
00041 #else
00042     result = getcwd( buffer, cMax );
00043 #endif
00044     if( NULL != result )
00045     {
00046         char* p = ctl_eattrailingslash( buffer );
00047 #ifdef WIN32
00048         if( (size_t)(p - buffer) < cMax )
00049             *p++ = '\\';
00050 #else
00051         if( (size_t)(p - buffer) < cMax )
00052             *p++ = '/';
00053 #endif
00054         if( (size_t)(p - buffer) < cMax )
00055             *p = 0;
00056     }
00057     return result;
00058 }
00059 
00060 
00065 bool ctl_chdir( const char* path )
00066 {
00067     assertconst(path,1);
00068 #ifdef WIN32
00069     return (bool)SetCurrentDirectory(path);
00070 #else
00071     return (bool)(0 != chdir(path));
00072 #endif
00073 }
00074 
00075 
00081 void ctl_move( const char* src, const char* dst )
00082 {
00083     assertconst(src,1);
00084     assertconst(dst,1);
00085 #ifdef WIN32
00086     MoveFileEx( src, dst, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING );
00087 #else
00088     rename( src, dst );
00089 #endif
00090 }
00091 
00092 
00098 void ctl_copy( const char* src, const char* dst )
00099 {
00100     assertconst(src,1);
00101     assertconst(dst,1);
00102 #ifdef WIN32
00103     CopyFile( src, dst, FALSE );
00104 #else
00105     int srcfd = open ( src, O_RDONLY|O_BINARY );
00106     if (srcfd >= 0)
00107     {
00108         int destfd = open( dst, O_CREAT|O_TRUNC|O_RDWR|O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
00109         if (destfd >= 0)
00110         {
00111             char buff[32768];
00112             ssize_t nread = read(srcfd, buff, sizeof (buff));
00113             ssize_t nwrote;
00114             while (nread > 0)
00115             {
00116                 nwrote = write(destfd, buff, nread);
00117                 if( nwrote != nread )
00118                     break;
00119                 nread = read(srcfd, buff, sizeof (buff));
00120             }
00121             close(destfd);
00122         }
00123         close(srcfd);
00124     }
00125 #endif
00126 }
00127 
00128 
00133 void ctl_unlink( const char* path )
00134 {
00135     assertconst(path,1);
00136 #ifdef WIN32
00137     DeleteFile( path );
00138 #else
00139     unlink( path );
00140 #endif
00141 }
00142 
00143 
00148 void ctl_rmdir( const char* path )
00149 {
00150     assertconst(path,1);
00151 #ifdef WIN32
00152     RemoveDirectory(path);
00153 #else
00154     rmdir(path);
00155 #endif
00156 }
00157 
00158 
00163 void ctl_mkdir( const char* path )
00164 {
00165     assertconst(path,1);
00166 #ifdef WIN32
00167     CreateDirectory(path,NULL);
00168 #else
00169     /* Let this user and his whole group play with it (assuming umask permits it) */
00170     mkdir( path, S_IRWXU | S_IRWXG );
00171 #endif
00172 }
00173 
00174 
00185 void ctl_iterate( const char* path, const char* szmatch, ctl_dircallback callback, void* instance )
00186 {
00187 #ifdef WIN32
00188     WIN32_FIND_DATA FileData;
00189     char szPath[_MAX_PATH];
00190     HANDLE hFind;
00191     assertconst(path,1);
00192     assertconst(szmatch,1);
00193     assertcodeptr(callback);
00194     strncpy( szPath, path, _MAX_PATH );
00195     ctl_eattrailingslash( szPath );
00196     if( !*szPath )
00197         strcat( szPath, "." );
00198     strncat( szPath, "/*.*", _MAX_PATH );
00199     szPath[_MAX_PATH-1] = 0;
00200     hFind = FindFirstFile( szPath, &FileData );
00201     if ( INVALID_HANDLE_VALUE != hFind )
00202     {
00203         do
00204         {
00205             if( *FileData.cFileName != '.' && (!szmatch || strwild( FileData.cFileName, sizeof FileData.cFileName, szmatch )) )
00206             {
00207                 char szCBPath[_MAX_PATH];
00208                 strncpy( szCBPath, path, countof(szCBPath) );
00209                 if( *szCBPath )
00210                 {
00211                     ctl_eattrailingslash( szCBPath );
00212                     strncat( szCBPath, "/", countof(szCBPath) );
00213                 }
00214                 strncat( szCBPath, FileData.cFileName, countof(szCBPath) );
00215                 if ( (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  )
00216                 {
00217                     if ( callback( szCBPath, true, instance ) )
00218                         break;
00219                 }
00220                 else
00221                 {
00222                     if ( 0 != (FileData.dwFileAttributes & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE)) && callback( szCBPath, 0 != (FileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY), instance ) )
00223                         break;
00224                 }
00225             }
00226         }
00227         while ( FindNextFile( hFind, &FileData ) );
00228         FindClose( hFind );
00229     }
00230 #else
00231     DIR* dir;
00232     assertconst(path,1);
00233     assertconst(szmatch,1);
00234     assertcodeptr(callback);
00235     dir = opendir( path );
00236     if ( dir )
00237     {
00238         struct dirent* dp;
00239         while ( NULL != (dp = readdir(dir) ) )
00240         {
00241             if ( *dp->d_name != '.' && (!szmatch || strwild( dp->d_name, sizeof dp->d_name, szmatch )) )
00242             {
00243                 char szCBPath[256];
00244                 struct stat status;
00245                 strncpy( szCBPath, path, countof(szCBPath) );
00246                 ctl_eattrailingslash( szCBPath );
00247                 strncat( szCBPath, "/", countof(szCBPath) );
00248                 strncat( szCBPath, dp->d_name, countof(szCBPath)-1 );
00249                 stat( szCBPath, &status );
00250                 if ( S_ISDIR(status.st_mode) )
00251                 {
00252                     if ( callback( szCBPath, true, instance ) )
00253                         break;
00254                 }
00255                 else
00256                 {
00257                     if ( S_ISREG(status.st_mode) && callback( szCBPath, false, instance ) )
00258                         break;
00259                 }
00260             }
00261         }
00262         closedir(dir);
00263     }
00264 #endif
00265 }
00266 
00275 void ctl_iterate_path( const char* path, ctl_dircallback callback, void* instance )
00276 {
00277     char szPath[256];
00278     const char* fileMatch;
00279     size_t len;
00280     assertconst(path,1);
00281     assertcodeptr(callback);
00282     fileMatch = ctl_filename( path );
00283     len = fileMatch - path;
00284     memcpy( szPath, path, len );
00285     szPath[len] = 0;
00286     ctl_iterate( szPath, fileMatch, callback, instance );
00287 }
00288 
00289 
00297 void ctl_fullpath( const char* basePath, const char* relPath, char* buff, size_t length )
00298 {
00299     assertconst( basePath, 1 );
00300     assertconst( relPath, 1 );
00301     assertptr( buff, length );
00302     assert( length <= _MAX_PATH );
00303     {
00304         size_t baseLength = strlen( basePath );
00305         size_t relLength = strlen( relPath );
00306         size_t totalLength = baseLength + relLength + 1;
00307         char lastBase;
00308         char firstRel = relPath[0];
00309         bool addSlash = false;
00310 
00311         /* To be linux compatible, use '/' for directories, not backslash - preferably throughout the code */
00312         assert( !strchr( basePath, '\\' ) && !strchr( relPath, '\\' ) );
00313 
00314         if( baseLength != 0 )
00315         {
00316             lastBase = basePath[baseLength-1]; 
00317             /* Determine what the final length will be and determine if a backslash must be added */
00318             if( lastBase == '/' && firstRel == '/' )
00319             {
00320                 /*skip the leading '/' of relPath */
00321                 totalLength--;
00322                 relPath++;
00323             } 
00324             else if( lastBase != '/' && firstRel != '/' )
00325             {
00326                 /*We will need to put a '/' between basePath and RelPath */
00327                 addSlash = true;
00328                 totalLength++;
00329             }
00330         }
00331 
00332         if( totalLength > length )
00333         {
00334             throwassert("Target buffer too small");
00335             *buff = 0;
00336         }
00337         else
00338         {
00339             /* Do the deed */
00340             memcpy( buff, basePath, baseLength );
00341             if( true == addSlash )
00342                 buff[baseLength++] = '/';
00343             strcpy( buff+baseLength, relPath );
00344         }
00345     }
00346 }
00347 
00353 char* ctl_eattrailingslash( char* szPath )
00354 {
00355     size_t len;
00356     assertptr( szPath, 1 );
00357     len = cstrlen(char)(szPath);
00358     if( 0 != len && ('/' == szPath[len-1] || '\\' == szPath[len-1]) )
00359     {
00360         char* ret = szPath + len-1;
00361         *ret = 0;
00362         return ret;
00363     }
00364     return szPath + len;
00365 }
00366 
00372 char* ctl_eatextension( char* szPath )
00373 {
00374     char* found;
00375     assertptr(szPath,1);
00376     found = (char*)ctl_extension( szPath );
00377     *found = 0;
00378     return found;
00379 }
00380 
00381 
00387 char* ctl_eatfilename( char* szPath )
00388 {
00389     char* found;
00390     assertptr(szPath,1);
00391     found = (char*)ctl_filename( szPath );
00392     *found = 0;
00393     return found;
00394 }
00395 
00401 const char* ctl_filename( const char* szPath )
00402 {
00403     size_t len;
00404     assertconst(szPath,1);
00405     len = cstrlen(char)(szPath);
00406     if( len )
00407     {
00408         const char* p = szPath + len-1;
00409         while( p > szPath && *p != '/' && *p != '\\' )
00410             p--;
00411         if( *p == '/' || *p == '\\' )
00412             return p+1;
00413     }
00414     return szPath;
00415 }
00416 
00422 const char* ctl_extension( const char* szPath )
00423 {
00424     size_t len;
00425     assertconst(szPath,1);
00426     len = cstrlen(char)(szPath);
00427     if( len )
00428     {
00429         const char* p = szPath + len-1;
00430         while( *p != '.' && p > szPath && *p != '/' && *p != '\\' )
00431             p--;
00432         if( *p == '.' )
00433             return p;
00434     }
00435     return szPath+len;
00436 }
00437 
00448 bool ctl_pathsearch( char* pathbuff, size_t buffmax, const char* searchpath, const char* filename )
00449 {
00450     size_t filelen;
00451     assertptr( pathbuff, buffmax );
00452     assertconst( searchpath, 1 );
00453     assertconst( filename, 1 );
00454     filename = ctl_filename( filename );
00455     filelen = strlen(filename);
00456     while( *searchpath )
00457     {
00458         const char* scan = searchpath;
00459         while( *scan && *scan != ';' )
00460             ++scan;
00461         if( filelen + (scan-searchpath) < buffmax )
00462         {
00463             size_t pathlen = scan-searchpath;
00464             memcpy( pathbuff, searchpath, pathlen );
00465             if( pathbuff[pathlen-1] != '/' && pathbuff[pathlen-1] != '\\' )
00466             {
00467                 pathbuff[pathlen++] = '/';
00468             }
00469             memcpy( pathbuff+pathlen, filename, filelen );
00470             pathbuff[pathlen+filelen] = 0;
00471 #ifdef WIN32
00472             {
00473                 int fd = _open ( pathbuff, O_RDONLY|O_BINARY );
00474                 if( fd >= 0 )
00475                 {
00476                     _close(fd);
00477                     return true;
00478                 }
00479             }
00480 #else
00481             {
00482                 int fd = open ( pathbuff, O_RDONLY|O_BINARY );
00483                 if( fd >= 0 )
00484                 {
00485                     close(fd);
00486                     return true;
00487                 }
00488             }
00489 #endif
00490             if( *scan )
00491             {
00492                 searchpath = scan + 1;
00493             }
00494             else
00495             {
00496                 break;
00497             }
00498         }
00499     }
00500     *pathbuff = 0;
00501     return false;
00502 }
00503 
00513 bool strwild( const char* sz, size_t maxsz, const char* szmatch )
00514 {
00515     const char* strend;
00516     assertconst( sz, 1 );
00517     assertconst( szmatch, 1 );
00518     strend = sz+cstrnlen(char)(sz,maxsz);
00519     while( *szmatch && sz < strend )
00520     {
00521         switch( *szmatch )
00522         {
00523         case chconst(char,'*'): /* Match any range of characters */
00524             ++szmatch;
00525             if( *szmatch )
00526             {
00527                 const char* smatch = szmatch;
00528                 size_t matchlen;
00529                 {
00530                     /* Find length of current match */
00531                     const char* smatchend = smatch;
00532                     while( *smatchend && *smatchend != chconst(char,'?') && *smatchend != chconst(char,'*') )
00533                         smatchend++;
00534                     matchlen = smatchend - smatch;
00535                 }
00536                 /* Now scan string until we find match after '*' */
00537                 while( sz + matchlen <= strend )
00538                 {
00539                     if( !cstrncmp(char)( sz, smatch, matchlen ) )
00540                     {
00541                         sz += matchlen;
00542                         szmatch += matchlen;
00543                         break;
00544                     }
00545                     sz++;
00546                 }
00547             }
00548             else
00549             {
00550                 /* Ended with '*', so whatever's left of str 'matches' */
00551                 return true;
00552             }
00553             break;
00554         case chconst(char,'?'): /* Match any single character */
00555             sz++;
00556             szmatch++;
00557             break;
00558         default:    /* Characters must match */
00559             if( *sz++ != *szmatch++ )
00560                 return false;
00561             break;
00562         }
00563     }
00564     /* Should have reached the end of both */
00565     return sz == strend && !*szmatch;
00566 }
00574 bool wcswild( const wchar_t* sz, size_t maxsz, const wchar_t* szmatch )
00575 {
00576     const wchar_t* strend;
00577     assertconst( sz, sizeof(wchar_t) );
00578     assertconst( szmatch, sizeof(wchar_t) );
00579     strend = sz+cstrnlen(wchar_t)(sz,maxsz);
00580     while( *szmatch && sz < strend )
00581     {
00582         switch( *szmatch )
00583         {
00584         case chconst(wchar_t,'*'):  /* Match any range of wchar_tacters */
00585             ++szmatch;
00586             if( *szmatch )
00587             {
00588                 const wchar_t* smatch = szmatch;
00589                 size_t matchlen;
00590                 {
00591                     /* Find length of current match */
00592                     const wchar_t* smatchend = smatch;
00593                     while( *smatchend && *smatchend != chconst(wchar_t,'?') && *smatchend != chconst(wchar_t,'*') )
00594                         smatchend++;
00595                     matchlen = smatchend - smatch;
00596                 }
00597                 /* Now scan string until we find match after '*' */
00598                 while( sz + matchlen <= strend )
00599                 {
00600                     if( !cstrncmp(wchar_t)( sz, smatch, matchlen ) )
00601                     {
00602                         sz += matchlen;
00603                         szmatch += matchlen;
00604                         break;
00605                     }
00606                     sz++;
00607                 }
00608             }
00609             else
00610             {
00611                 /* Ended with '*', so whatever's left of str 'matches' */
00612                 return true;
00613             }
00614             break;
00615         case chconst(wchar_t,'?'):  /* Match any single wchar_tacter */
00616             sz++;
00617             szmatch++;
00618             break;
00619         default:    /* Characters must match */
00620             if( *sz++ != *szmatch++ )
00621                 return false;
00622             break;
00623         }
00624     }
00625     /* Should have reached the end of both */
00626     return sz == strend && !*szmatch;
00627 }
00628 
00629 
00630 #else /* CTL_UNIT */
00631 
00632 #include "ctl/ctldef.h"
00633 #include "ctl/ctlstring.h"
00634 #include "unit/unit.h"
00635 #include "dir.h"
00636 
00637 void Test_Dir(void)
00638 {
00639     const char* szPath = "/foo/bar/baz.c";
00640     const char* szPathW = "C:\\foo\\bar\\baz.c";
00641     /* Parse up unix-like path */
00642     Test_Error( !strcmp( ctl_filename( szPath ), "baz.c" ) );
00643     Test_Error( !strcmp( ctl_extension( szPath ), ".c" ) );
00644     /* Parse up windows-like path */
00645     Test_Error( !strcmp( ctl_filename( szPathW ), "baz.c" ) );
00646     Test_Error( !strcmp( ctl_extension( szPathW ), ".c" ) );
00647     {
00648         char buff[256];
00649         /* Parse up unix-like path */
00650         strcpy( buff, szPath );
00651         ctl_eatextension( buff );
00652         Test_Error( !strcmp( buff, "/foo/bar/baz" ) );;
00653         ctl_eatfilename( buff );
00654         Test_Error( !strcmp( buff, "/foo/bar/" ) );
00655         ctl_eattrailingslash( buff );
00656         Test_Error( !strcmp( buff, "/foo/bar" ) );
00657         /* Parse up windows-like path */
00658         strcpy( buff, szPathW );
00659         ctl_eatextension( buff );
00660         Test_Error( !strcmp( buff, "C:\\foo\\bar\\baz" ) );;
00661         ctl_eatfilename( buff );
00662         Test_Error( !strcmp( buff, "C:\\foo\\bar\\" ) );
00663         ctl_eattrailingslash( buff );
00664         Test_Error( !strcmp( buff, "C:\\foo\\bar" ) );
00665     }
00666     {
00667         /* Test wildcard compare */
00668         #define MFG_TestStrings(tchar)\
00669         {\
00670             const tchar* const sz = szconst(tchar,"I could have been your daddy.");\
00671             Test_Error( cstrwild(tchar)( sz, ~0u, szconst(tchar,"I could*") ) );\
00672             Test_Error( cstrwild(tchar)( sz, ~0u, szconst(tchar,"I cou?d*been*.") ) );\
00673             Test_Error( cstrwild(tchar)( sz, ~0u, szconst(tchar,"*daddy.") ) );\
00674             Test_Error( cstrwild(tchar)( sz, 7, szconst(tchar,"I could") ) );\
00675             Test_Error( !cstrwild(tchar)( sz, 7, szconst(tchar,"I would") ) );\
00676         }
00677         MFG_TestStrings(char);
00678         MFG_TestStrings(wchar_t);
00679     }
00680 }
00681 
00682 #endif /* CTL_UNIT */

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6