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
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
00312 assert( !strchr( basePath, '\\' ) && !strchr( relPath, '\\' ) );
00313
00314 if( baseLength != 0 )
00315 {
00316 lastBase = basePath[baseLength-1];
00317
00318 if( lastBase == '/' && firstRel == '/' )
00319 {
00320
00321 totalLength--;
00322 relPath++;
00323 }
00324 else if( lastBase != '/' && firstRel != '/' )
00325 {
00326
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
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,'*'):
00524 ++szmatch;
00525 if( *szmatch )
00526 {
00527 const char* smatch = szmatch;
00528 size_t matchlen;
00529 {
00530
00531 const char* smatchend = smatch;
00532 while( *smatchend && *smatchend != chconst(char,'?') && *smatchend != chconst(char,'*') )
00533 smatchend++;
00534 matchlen = smatchend - smatch;
00535 }
00536
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
00551 return true;
00552 }
00553 break;
00554 case chconst(char,'?'):
00555 sz++;
00556 szmatch++;
00557 break;
00558 default:
00559 if( *sz++ != *szmatch++ )
00560 return false;
00561 break;
00562 }
00563 }
00564
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,'*'):
00585 ++szmatch;
00586 if( *szmatch )
00587 {
00588 const wchar_t* smatch = szmatch;
00589 size_t matchlen;
00590 {
00591
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
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
00612 return true;
00613 }
00614 break;
00615 case chconst(wchar_t,'?'):
00616 sz++;
00617 szmatch++;
00618 break;
00619 default:
00620 if( *sz++ != *szmatch++ )
00621 return false;
00622 break;
00623 }
00624 }
00625
00626 return sz == strend && !*szmatch;
00627 }
00628
00629
00630 #else
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
00642 Test_Error( !strcmp( ctl_filename( szPath ), "baz.c" ) );
00643 Test_Error( !strcmp( ctl_extension( szPath ), ".c" ) );
00644
00645 Test_Error( !strcmp( ctl_filename( szPathW ), "baz.c" ) );
00646 Test_Error( !strcmp( ctl_extension( szPathW ), ".c" ) );
00647 {
00648 char buff[256];
00649
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
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
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