00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00028
00029 #include <cxxtls/file.h>
00030 #include <cxxtls/options.h>
00031 #include <cxxtls/strtool.h>
00032 #include <portable_io.h>
00033
00034 #include <time.h>
00035 #include <errno.h>
00036 #include <algorithm>
00037 #include <fcntl.h>
00038 #include <memory.h>
00039 #include <string.h>
00040 #include <cxxtls/user.h>
00041 #include <set>
00042
00043 using namespace std;
00044
00045 namespace cxxtls
00046 {
00047
00048 #ifdef _MSC_VER
00049 # include <io.h>
00050 # include <direct.h>
00051 # define R_OK 4
00052 # define W_OK 2
00053 # define X_OK 1
00054 # define F_OK 0
00055 # define lstat stat
00056 # define S_ISLNK(x) 0
00057 # define S_IFLNK 0
00058 # include <wchar.h>
00059 # include <wtypes.h>
00060 # include <direct.h>
00061 # include <process.h>
00062
00063 # define SET_MODE(a,b) setmode(a,b)
00064
00065
00066 #ifndef NAME_MAX
00067 # define NAME_MAX 255
00068 #endif
00069
00070 #define __DIRENT_COOKIE 0xfefeabab
00071
00072
00073
00074 struct dirent
00075 {
00076 ino_t d_ino;
00077 char d_name[NAME_MAX+1];
00078 };
00079
00080 typedef struct dir_struct
00081 {
00082 ULONG dir_ulCookie;
00083 HANDLE dir_hDirHandle;
00084 DWORD dir_nNumFiles;
00085 char dir_pDirectoryName[NAME_MAX+1];
00086 struct dirent dir_sdReturn;
00087 }DIR;
00088
00089 DIR *opendir(const char *);
00090 struct dirent *readdir(DIR *);
00091 void closedir(DIR *);
00092
00093 struct passwd { char* pw_name; };
00094
00095 struct passwd* getpwuid(int) { return 0; }
00096
00097 #else
00098 # include <dirent.h>
00099 # include <unistd.h>
00100 # include <pwd.h>
00101 # include <grp.h>
00102 # define O_BINARY 0
00103 # define SET_MODE(a,b)
00104 #endif
00105
00106 #include <sys/stat.h>
00107 #include <time.h>
00108 #include <portable_io.h>
00109
00110 extern "C"
00111 {
00112 #include <fnmatch.h>
00113 };
00114
00115 typedef FileName::rep_t rep_t;
00116
00117
00118 FileTime::
00119 operator string() const
00120 {
00121 char buffer[256];
00122
00123 sprintf(buffer, "%02d/%02d/%02d %02d:%02d:%02d",
00124 year % 100,
00125 month +1,
00126 day,
00127 hour,
00128 minute,
00129 second
00130 );
00131
00132 return buffer;
00133
00134 }
00135
00136 char const *months[]=
00137 {
00138 "Jan",
00139 "Feb",
00140 "Mar",
00141 "Apr",
00142 "May",
00143 "Jun",
00144 "Jul",
00145 "Aug",
00146 "Sep",
00147 "Oct",
00148 "Nov",
00149 "Dec"
00150 };
00151
00152 string
00153 FileTime::
00154 short_string() const
00155 {
00156
00157 time_t curtime;
00158
00159 time(&curtime);
00160
00161 struct tm *p = localtime(&curtime);
00162
00163 if(p)
00164 {
00165 long operand_month = year * 12 + month;
00166
00167 long current_month = p->tm_year * 12 + p->tm_mon;
00168
00169 long delta = current_month - operand_month;
00170
00171 if(delta < -6 || delta > 6)
00172 {
00173 char buffer[256];
00174
00175 sprintf(buffer, "%s %2d %d", months[month], day, year + 1900);
00176
00177 return buffer;
00178
00179 }
00180 else
00181 {
00182 char buffer[256];
00183
00184 sprintf(buffer, "%s %2d %02d:%02d", months[month], day, hour, minute);
00185
00186 return buffer;
00187 }
00188
00189 }
00190 else
00191 {
00192 char buffer[256];
00193
00194 sprintf(buffer, "%s %2d %d", months[month], day, year + 1900);
00195
00196 return buffer;
00197
00198 }
00199 }
00200
00201
00202 bool
00203 FileTime::
00204 construct_from_string(string s)
00205 {
00206
00207
00208 char month_buf[2048];
00209 int day_buf ;
00210 char year_buf [2048];
00211
00212 if(3 != sscanf(s.c_str(), "%s %d %s", month_buf, &day_buf, year_buf))
00213 return true;
00214
00215 int i;
00216
00217 for(i=0; i < 12; ++i)
00218 {
00219 if(strcmp(month_buf, months[i]) == 0)
00220 {
00221 break;
00222 }
00223 }
00224
00225 if(i == 12)
00226 return true;
00227
00228 month = i;
00229
00230 day = day_buf;
00231
00232 if(year_buf[1] != ':' && year_buf[2] != ':')
00233 {
00234
00235
00236 if(1 != sscanf(year_buf, "%d", &day_buf) )
00237 return true;
00238
00239 hour = 0;
00240 minute = 0;
00241 second = 0;
00242
00243 year = day_buf - 1900;
00244
00245 return false;
00246
00247
00248 }
00249
00250
00251
00252 struct tm *buf;
00253
00254 time_t curtime;
00255
00256 time(&curtime);
00257
00258 if( 0 != (buf = localtime( &curtime )) )
00259 {
00260 year = buf->tm_year;
00261
00262 }
00263 else
00264 return true;
00265
00266 if(2 != sscanf(year_buf, "%d:%d", &day_buf, &i))
00267 return true;
00268
00269 second = 0;
00270 hour = day_buf;
00271 minute = i;
00272
00273 return false;
00274
00275 }
00276
00277
00278
00279 FileTime::
00280 FileTime(struct tm const *p)
00281 {
00282 if(p == 0)
00283 {
00284 year = 0;
00285 month = 0;
00286 day = 0;
00287 hour = 0;
00288 minute = 0;
00289 second = 0;
00290 }
00291 else
00292 {
00293 year = p->tm_year;
00294 month = p->tm_mon;
00295 day = p->tm_mday;
00296 hour = p->tm_hour;
00297 minute = p->tm_min;
00298 second = p->tm_sec;
00299 }
00300
00301 }
00302
00303 FileMode::
00304 operator string() const
00305 {
00306 char buffer[40];
00307
00308 char *scan = buffer;
00309
00310 *scan++ = ( (mode&FileMode::link) ? 'L' : ' ' );
00311 *scan++ = ( (mode&FileMode::directory) ? 'd' : '-' );
00312 *scan++ = ( (mode&FileMode::user_readable) ? 'r' : '-' );
00313 *scan++ = ( (mode&FileMode::user_writeable) ? 'w' : '-' );
00314 *scan++ = ( (mode&FileMode::user_executable) ? (mode &FileMode:: set_uid ? 'S' : 'x' ) : ('-') );
00315 *scan++ = ( (mode&FileMode::group_readable) ? 'r' : '-' );
00316 *scan++ = ( (mode&FileMode::group_writeable) ? 'w' : '-' );
00317 *scan++ = ( (mode&FileMode::group_executable) ? (mode &FileMode:: set_gid ? 'S' : 'x' ) : ('-') );
00318 *scan++ = ( (mode&FileMode::world_readable) ? 'r' : '-' );
00319 *scan++ = ( (mode&FileMode::world_writeable) ? 'w' : '-' );
00320 *scan++ = ( (mode&FileMode::world_executable) ? 'x' : '-' );
00321
00322 *scan = 0;
00323
00324 return buffer;
00325 }
00326
00327 void
00328 FileMode::
00329 construct_from_string(char const *permissions)
00330 {
00331 int l = strlen(permissions);
00332
00333 mode=0;
00334
00335 if(l >= 10)
00336 {
00337
00338
00339
00340
00341 if(permissions[0] == 'l' || permissions[0] == 'L' )
00342 mode = FileMode::link;
00343
00344 if(l == 10)
00345 --permissions;
00346
00347 if(permissions[1] == 'd')
00348 mode = FileMode::directory;
00349
00350
00351 if(permissions[2] == 'r') mode += FileMode::user_readable;
00352 if(permissions[3] == 'w') mode += FileMode::user_writeable;
00353 if(permissions[4] == 'x') mode += FileMode::user_executable;
00354 if(permissions[4] == 's') mode += FileMode::user_executable + FileMode::set_uid;
00355 if(permissions[4] == 'S') mode += FileMode::user_executable + FileMode::set_uid;
00356
00357 if(permissions[5] == 'r') mode += FileMode::group_readable;
00358 if(permissions[6] == 'w') mode += FileMode::group_writeable;
00359 if(permissions[7] == 'x') mode += FileMode::group_executable;
00360 if(permissions[7] == 's') mode += FileMode::group_executable + FileMode::set_gid;
00361 if(permissions[7] == 'S') mode += FileMode::group_executable + FileMode::set_gid;
00362
00363 if(permissions[8] == 'r') mode += FileMode::world_readable;
00364 if(permissions[9] == 'w') mode += FileMode::world_writeable;
00365 if(permissions[10] == 'x') mode += FileMode::world_executable;
00366 }
00367 else
00368 {
00369 while(*permissions == ' ')
00370 ++permissions;
00371
00372 if(*permissions == '0')
00373 {
00374 int value=0;
00375
00376 sscanf(permissions, "%o", &value);
00377
00378 int user = (value >> 6) & 7;
00379 int group = (value >> 3) & 7;
00380 int world = (value ) & 7;
00381
00382 if(user & 4) mode |= FileMode::user_readable;
00383 if(user & 2) mode |= FileMode::user_writeable;
00384 if(user & 1) mode |= FileMode::user_executable;
00385
00386 if(group & 4) mode |= FileMode::group_readable;
00387 if(group & 2) mode |= FileMode::group_writeable;
00388 if(group & 1) mode |= FileMode::group_executable;
00389
00390 if(world & 4) mode |= FileMode::world_readable;
00391 if(world & 2) mode |= FileMode::world_writeable;
00392 if(world & 1) mode |= FileMode::world_executable;
00393
00394 }
00395 }
00396
00397 }
00398
00399
00400 FileMode::
00401 FileMode(int m)
00402
00403 {
00404 mode = 0;
00405
00406 #if _MSC_VER
00407
00408 if(m & _S_IFDIR) mode |= directory | user_executable| group_executable | world_executable;
00409 if(m & _S_IREAD) mode |= user_readable | group_readable | world_readable;
00410 if(m & _S_IWRITE) mode |= user_writeable| group_writeable| world_writeable;
00411
00412 #else
00413 if(S_ISLNK(m)) mode |= link;
00414 if(S_ISDIR(m)) mode |= directory;
00415 if(m & S_ISUID) mode |= set_uid;
00416 if(m & S_ISGID) mode |= set_gid;
00417
00418 if(m & S_IRUSR) mode |= user_readable;
00419 if(m & S_IWUSR) mode |= user_writeable;
00420 if(m & S_IXUSR) mode |= user_executable;
00421
00422 if(m & S_IRGRP) mode |= group_readable;
00423 if(m & S_IWGRP) mode |= group_writeable;
00424 if(m & S_IXGRP) mode |= group_executable;
00425
00426 if(m & S_IROTH) mode |= world_readable;
00427 if(m & S_IWOTH) mode |= world_writeable;
00428 if(m & S_IXOTH) mode |= world_executable;
00429 #endif
00430 }
00431
00432
00433
00434 rep_t
00435 FileName::
00436 basename(bool remove_extension) const
00437
00438
00439 {
00440
00441 const_iterator first = begin();
00442 const_iterator last = end();
00443
00444 while(last != first)
00445 {
00446 --last;
00447
00448 if(*last == '/' || *last == '\\')
00449 {
00450 ++last;
00451 const_iterator tail = end();
00452
00453 if(remove_extension)
00454 {
00455
00456
00457 while(tail != last)
00458 {
00459 --tail;
00460
00461 if(*tail == '.')
00462 break;
00463
00464 }
00465
00466 if(tail == last)
00467 tail = end();
00468
00469 }
00470
00471 return rep_t(last, tail);
00472 }
00473
00474 }
00475
00476
00477
00478
00479 {
00480 if(remove_extension)
00481 {
00482
00483
00484 const_iterator last = begin();
00485 const_iterator tail = end();
00486
00487 while(tail != last)
00488 {
00489 --tail;
00490
00491 if(*tail == '.')
00492 break;
00493
00494 }
00495
00496 if(tail == last)
00497 tail = end();
00498
00499 return rep_t(last, tail);
00500
00501 }
00502
00503 }
00504
00505 return *this;
00506
00507 }
00508
00509 rep_t
00510 FileName::
00511 dirname() const
00512
00513 {
00514 const_iterator first = begin();
00515 const_iterator last = end();
00516
00517 while(last != first)
00518 {
00519 --last;
00520
00521 if(*last == '/' || *last == '\\')
00522 {
00523 return rep_t(first, ++last);
00524 }
00525
00526 }
00527
00528
00529
00530
00531 return rep_t("./");
00532
00533 }
00534
00535
00536
00537 string
00538 FileStatus::
00539 convert_to_string(bool resolve_id_names) const
00540
00544 {
00545 string rv;
00546
00547
00548 rv.append(mode);
00549 rv.append(" ");
00550 rv.append(time);
00551
00552 char buffer[256];
00553
00554
00555 if(resolve_id_names)
00556 {
00557 sprintf(buffer, " %-12.12s %-12.12s %12d",
00558 id2string(owner_id).c_str(),
00559 group2string(group_id).c_str(),
00560 (int)(size)
00561 );
00562
00563 }
00564 else
00565 {
00566 sprintf(buffer, " %12d %12d %12d", owner_id, group_id, (int)(size));
00567 }
00568
00569 rv.append(buffer);
00570
00571 return rv;
00572
00573 }
00574
00575
00576 void
00577 FileName::
00578 convert_to_absolute_path()
00579
00580
00581 {
00582
00583 iterator first;
00584 iterator last ;
00585
00586
00587
00588
00589 size_t siz = size();
00590
00591 char c = siz < 1 ? 0 : begin()[0];
00592 char d = siz < 2 ? 0 : begin()[1];
00593 char e = siz < 3 ? 0 : begin()[2];
00594
00595 bool is_full_path = (c == '/')
00596 || (c == '\\')
00597 || ( (d == ':')
00598 && ( e == '/' || (e == '\\') )
00599 );
00600
00601
00602 if( ! is_full_path )
00603 {
00604
00605
00606 char buffer[2048];
00607
00608
00609 if(0 == ::getcwd(buffer, 2048) )
00610 {
00611 buffer[0] = '.';
00612 buffer[1] = '/';
00613 buffer[2] = 0;
00614 }
00615
00616 string new_name(buffer);
00617
00618 new_name.append("/");
00619 new_name.append(*this);
00620
00621 *this = new_name;
00622
00623 }
00624
00625
00626
00627 first = begin();
00628 last = end();
00629
00630 while(first != last)
00631 {
00632 char c = *first;
00633
00634 if(c == '\\')
00635 {
00636 size_t offset = first - begin();
00637 erase(first);
00638 insert(begin() + offset, '/');
00639 first = begin() + offset;
00640 }
00641
00642 ++first;
00643 }
00644
00645
00646
00647 {
00648
00649 first = begin();
00650 last = end();
00651
00652 while(first != last)
00653 {
00654 char const *scan = "/./";
00655
00656 first = search(first, last, scan, scan + 3);
00657
00658 if(first != last)
00659 {
00660 size_t off = first - begin();
00661
00662 erase(first, first + 2);
00663
00664 first = begin() + off;
00665 last = end();
00666
00667 }
00668 }
00669
00670
00671
00672
00673
00674 first = begin();
00675 last = end();
00676
00677 while( last - first > 2 )
00678 {
00679 --last;
00680 --last;
00681
00682 if(last[0] == '/' && last[1] == '.')
00683 {
00684 erase(last, end());
00685 }
00686 else
00687 break;
00688
00689 }
00690
00691
00692 }
00693 {
00694 first = begin();
00695 last = end();
00696
00697 while(first != last)
00698 {
00699 char const *scan = "/../";
00700
00701 first = search(first, last, scan, scan + 4);
00702
00703 if(first != last)
00704 {
00705
00706
00707 iterator scan = first - 1;
00708
00709 while(scan != begin())
00710 {
00711 if(*scan == '/')
00712 break;
00713
00714 --scan;
00715 }
00716
00717 size_t off = scan - begin();
00718
00719 erase(scan, first + 3);
00720
00721 first = begin() + off;
00722 last = end();
00723
00724 }
00725 }
00726
00727
00728
00729
00730
00731 first = begin();
00732 last = end();
00733
00734 while( last - first > 3 )
00735 {
00736 --last;
00737 --last;
00738 --last;
00739
00740 if(last[0] == '/' && last[1] == '.' && last[2] == '.')
00741 {
00742 erase(last, end());
00743 *this = this->dirname();
00744 if(size())
00745 erase(begin() + size()-1);
00746 }
00747 else
00748 break;
00749
00750 }
00751 }
00752
00753 #ifdef _MSC_VER
00754
00755 if(this->operator[](0) == '/')
00756 {
00757 *this = "c:" + *this;
00758 }
00759 #endif
00760
00761
00762 }
00763
00764 bool
00765 FileName::
00766 is_syntactically_valid() const
00767
00768 {
00769 if(size() < 1)
00770 return false;
00771
00772 if(size() > 2048)
00773 return false;
00774
00775 const_iterator first = begin();
00776 const_iterator last = end();
00777
00778 while(first != last)
00779 {
00780 char c = *first++;
00781
00782 if(c < ' ' || c > 0x7e)
00783 return false;
00784
00785 }
00786
00787 return true;
00788 }
00789
00790 bool
00791 FileName::
00792 exists() const
00793
00794 {
00795 char const *name = c_str();
00796 int check_mode = F_OK;
00797 int access_code = access(name, check_mode);
00798
00799 return 0 == access_code;
00800 }
00801
00802 bool
00803 FileName::
00804 file_stat(FileStatus* s, bool read_link_info) const
00805
00806
00807
00808
00809 {
00810
00811 string fixedName = *this;
00812
00813 size_t nameLength = fixedName.size();
00814
00815 if(nameLength)
00816 {
00817 char lastChar = fixedName[nameLength-1];
00818
00819 if(lastChar == '/' || lastChar == '\\')
00820 {
00821
00822
00823 if(nameLength != 1)
00824 {
00825 char secondChar = fixedName[1];
00826
00827 if(secondChar == ':')
00828 {
00829 if(nameLength >4)
00830 {
00831 fixedName.erase(nameLength-1, 1);
00832 }
00833 }
00834 else
00835 if(nameLength > 2)
00836 {
00837 fixedName.erase(nameLength-1, 1);
00838 }
00839
00840 }
00841 }
00842 }
00843
00844 char const *p = fixedName.c_str();
00845
00846 struct stat buf;
00847
00848 memset(&buf, 0, sizeof(buf));
00849
00850
00851 s->mode.mode = 0;
00852 s->size = -1;
00853 s->owner_id = -1;
00854 s->group_id = -1;
00855
00856
00857 bool is_a_link = false;
00858
00859 if(read_link_info && lstat(p, &buf))
00860 {
00861
00862
00863 return true;
00864
00865 }
00866 else
00867 {
00868 is_a_link = S_ISLNK(buf.st_mode);
00869 }
00870
00871
00872
00873
00874 if( ( (!read_link_info)
00875 || is_a_link
00876 )
00877 && stat(p,&buf)
00878 )
00879 {
00880 return true;
00881 }
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 s->size = buf.st_size;
00898
00899 (&s->mode)->~FileMode(); new (&s->mode) FileMode(buf.st_mode);
00900 (&s->time)->~FileTime(); new (&s->time) FileTime(localtime(&buf.st_mtime));
00901
00902 s->group_id = buf.st_gid;
00903 s->owner_id = buf.st_uid;
00904
00905 if(is_a_link)
00906 s->mode.mode |= FileMode::link;
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 return false;
00919 }
00920
00921
00922 bool
00923 FileName::
00924 is_dir() const
00925
00926 {
00927 FileStatus s;
00928
00929 if(file_stat(&s))
00930 return false;
00931
00932 return s.mode.is_dir();
00933
00934 }
00935
00936
00937 bool
00938 FileName::
00939 is_executable() const
00940
00941 {
00942 return 0 == access( c_str(), X_OK);
00943
00944 }
00945
00946 bool
00947 FileName::
00948 is_writeable() const
00949
00950 {
00951 return 0 == access( c_str(), W_OK);
00952 }
00953
00954 bool
00955 FileName::
00956 is_readable() const
00957
00958 {
00959 return 0 == access( c_str(), R_OK);
00960 }
00961
00962 bool
00963 FileName::
00964 is_createable() const
00965
00966 {
00967 if( is_writeable() )
00968 return true;
00969
00970 FileName dir(dirname());
00971
00972 if(dir.is_writeable())
00973 return true;
00974
00975 return false;
00976
00977
00978 }
00979
00980 FileMode
00981 FileName::
00982 file_mode() const
00983
00984
00985
00986 {
00987 FileStatus s;
00988
00989 if(file_stat(&s))
00990 return 0;
00991
00992 return s.mode;
00993
00994 }
00995
00996 FileName::off_t
00997 FileName::
00998 file_size() const
00999
01000 {
01001 FileStatus s;
01002
01003 if(file_stat(&s))
01004 return -1;
01005
01006 return s.size;
01007
01008 }
01009
01010 bool
01011 FileName::
01012 file_time(FileTime *rv) const
01013 {
01014 FileStatus s;
01015
01016 if(file_stat(&s))
01017 return true;
01018
01019 *rv = s.time;
01020
01021 return false;
01022
01023 }
01024
01025 bool
01026 FileName::
01027 matches(char const *pattern) const
01028 {
01029 char *p = const_cast<char*>(pattern);
01030 char *s = const_cast<char*>(c_str());
01031
01032 return FNM_NOMATCH != fnmatch(p, s, FNM_PATHNAME);
01033 }
01034
01035
01036
01037 string
01038 FileStatus::id2string(int id)
01039 {
01040 passwd *p = getpwuid(id);
01041
01042 if(p)
01043 {
01044 return p->pw_name;
01045 }
01046
01047 char buffer[20];
01048
01049 sprintf(buffer, "%d", id);
01050
01051 return buffer;
01052
01053 }
01054
01055
01056 string
01057 FileStatus::group2string(int id)
01058 {
01059 #ifdef _MSC_VER
01060 return "group";
01061 #else
01062 struct group *p = getgrgid(id);
01063
01064 if(p)
01065 {
01066 return p->gr_name;
01067 }
01068
01069 char buffer[20];
01070
01071 sprintf(buffer, "%d", id);
01072
01073 return buffer;
01074 #endif
01075
01076 }
01077
01078 int
01079 FileName::
01080 find_matching(char const *pattern, sorted_names_t *l, int options)
01081 {
01082 int count=0;
01083
01084 enum flags { include_paths=1,
01085 only_dirs= 2,
01086 not_dirs= 4
01087 };
01088
01089 FileName f(pattern);
01090
01091 string dir = f.dirname();
01092 string base= f.basename();
01093
01094
01095 if(dir.size() > 1 && dir[dir.size()-1] == '/')
01096 {
01097 dir.erase( dir.begin() + dir.size() - 1 );
01098 }
01099
01100 #ifdef _MSC_VER
01101
01102 if(dir.size() == 2 && dir[dir.size()-1] == ':')
01103 {
01104 dir += '/';
01105 }
01106
01107 if(dir.size() == 0 || dir == "/")
01108 {
01109 dir = "c:/";
01110 }
01111
01112 #else
01113
01114 if(dir.size() == 0)
01115 {
01116 dir = "/";
01117 }
01118
01119 #endif
01120
01121
01122
01123 DIR *d = opendir(dir.c_str());
01124 dirent *e;
01125
01126 while(d && (e = readdir(d) ) )
01127 {
01128 char *pat = const_cast<char*>(base.c_str());
01129
01130 if( fnmatch(pat, e->d_name, FNM_PATHNAME) == 0 )
01131 {
01132 FileName rv(e->d_name);
01133 FileName path(rv);
01134
01135 if(dir.size() != 0)
01136 path = dir + string("/") + rv;
01137
01138 FileStatus fs;
01139
01140 path.file_stat(&fs);
01141
01142 if(fs.mode.is_dir())
01143 {
01144 if( options & not_dirs )
01145 {
01146 continue;
01147 }
01148
01149 if( options & include_paths )
01150 rv = path;
01151
01152
01153 }
01154 else
01155 {
01156 if( options & only_dirs )
01157 {
01158 continue;
01159 }
01160
01161 if( options & include_paths )
01162 rv = path;
01163 }
01164
01165 l->insert(rv);
01166
01167 ++count;
01168
01169 }
01170 }
01171
01172 if(d)
01173 closedir(d);
01174
01175 return count;
01176 }
01177
01178 #ifdef _MSC_VER
01179 DIR*
01180 opendir(const char* pDirName)
01181 {
01182 struct stat sb;
01183 DIR* pDir;
01184 char* pEndDirName;
01185 int nBufferLen;
01186
01187 std::string adjustedDirName(pDirName);
01188
01189 size_t dirNameLength = adjustedDirName.size();
01190
01191 if(dirNameLength)
01192 {
01193
01194
01195
01196
01197 if(adjustedDirName[dirNameLength-1] == '/' ||
01198 adjustedDirName[dirNameLength-1] == '\\'
01199 )
01200 {
01201 adjustedDirName.erase(dirNameLength-1);
01202
01203 --dirNameLength;
01204
01205 if(dirNameLength == 2 && adjustedDirName[1] == ':')
01206 {
01207 adjustedDirName += '\\';
01208 ++dirNameLength;
01209 }
01210
01211 }
01212 }
01213
01214 pDirName = adjustedDirName.c_str();
01215
01216
01217
01218 if (!pDirName) {
01219 errno = EINVAL;
01220 return NULL;
01221 }
01222 if (stat(pDirName, &sb) != 0) {
01223 errno = ENOENT;
01224 return NULL;
01225 }
01226 if ((sb.st_mode & S_IFMT) != S_IFDIR) {
01227 errno = ENOTDIR;
01228 return NULL;
01229 }
01230
01231
01232 pDir = (DIR *) malloc(sizeof (DIR));
01233
01234 if (!pDir)
01235 return NULL;
01236
01237
01238 nBufferLen = strlen(pDirName);
01239
01240
01241 strcpy(pDir->dir_pDirectoryName, pDirName);
01242
01243
01244 pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1];
01245
01246
01247 if ((*pEndDirName != '/') && (*pEndDirName != '\\')) {
01248 pEndDirName++;
01249 *pEndDirName = '/';
01250 }
01251
01252
01253 pEndDirName++;
01254 *pEndDirName = '*';
01255 pEndDirName++;
01256 *pEndDirName = '\0';
01257
01258
01259 pDir->dir_nNumFiles = 0;
01260 pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
01261 pDir->dir_ulCookie = __DIRENT_COOKIE;
01262
01263 return pDir;
01264 }
01265
01266 void
01267 closedir(DIR *pDir)
01268 {
01269
01270 if (!pDir) {
01271 errno = EINVAL;
01272 return;
01273 }
01274
01275
01276 if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
01277 errno = EINVAL;
01278 return;
01279 }
01280
01281
01282 if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
01283 FindClose(pDir->dir_hDirHandle);
01284
01285 free(pDir);
01286
01287 return;
01288 }
01289
01290 struct dirent *
01291 readdir(DIR* pDir)
01292 {
01293 WIN32_FIND_DATA wfdFindData;
01294
01295 if (!pDir) {
01296 errno = EINVAL;
01297 return NULL;
01298 }
01299
01300
01301 if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
01302 errno = EINVAL;
01303 return NULL;
01304 }
01305
01306 if (pDir->dir_nNumFiles == 0) {
01307 pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData);
01308 if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE)
01309 return NULL;
01310 } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData))
01311 return NULL;
01312
01313
01314 pDir->dir_nNumFiles++;
01315
01316
01317 pDir->dir_sdReturn.d_ino = -1;
01318 strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName);
01319
01320 return &pDir->dir_sdReturn;
01321 }
01322
01323 #endif
01324
01325 void
01326 FileName::
01327 slurp(FileContents *c) const
01328
01329 {
01330 FILE *f = fopen(c_str(), "rb");
01331
01332 if(!f)
01333 {
01334 c->set_error("fopen failed");
01335 }
01336 else
01337 {
01338 FileStatus s;
01339
01340 if(file_stat(&s))
01341 {
01342 c->set_error("couldn't get file status");
01343 }
01344 else
01345 {
01346 c->reserve(s.size);
01347
01348 long size = fread(c->begin(), 1, s.size, f);
01349
01350 if(size != s.size)
01351 {
01352 c->reserve(0);
01353
01354 c->set_error("reading file resulted in fewer bytes that the file status indicated");
01355 }
01356 else
01357 {
01358 c->clear_error();
01359 }
01360
01361 }
01362
01363 fclose(f);
01364
01365 }
01366
01367 }
01368
01369 FileName
01370 FileName::
01371 mktemp(FileName dir)
01372 {
01373 char buffer[40];
01374
01375 int count;
01376
01377 for(count=1; count < 100; ++count)
01378 {
01379 if(count > 1)
01380 sprintf(buffer, "%d.tmp.%d", getpid(), count);
01381 else
01382 sprintf(buffer, "%d.tmp", getpid());
01383
01384 FileName rv = dir + buffer;
01385
01386 if(! rv.exists() )
01387 return rv;
01388 }
01389
01390 static int badcount=0;
01391
01392 sprintf(buffer, "%d-%d", getpid(), badcount++);
01393
01394 return dir + buffer;
01395
01396 }
01397
01398 struct Is_Path_Space
01400 {
01401 bool operator() (char c) const
01402 {
01403 return c == ' ' ||
01404 c == '\t' ||
01405 c == '\n' ||
01406 c == '\r' ||
01407 c == FileName::PATH_separator
01408 ;
01409 }
01410
01411 };
01412
01413
01414 FileName
01415 FileName::
01416 find_executable(string progname, string path)
01417 {
01418
01419
01420
01421
01422 if(path.size() == 0)
01423 {
01424
01425 char const *p;
01426
01427 if(ProgramOptions::global_options_)
01428 p = ProgramOptions::global_options_->getenv("PATH").c_str();
01429 else
01430 p = getenv("PATH");
01431
01432 if(p)
01433 path = p;
01434 }
01435
01436 StrTool::stringlist_t splitpath;
01437
01438 Is_Path_Space functor;
01439
01440
01441 StrTool::parse_words(path,
01442 &splitpath,
01443 2000000000U,
01444 functor
01445 );
01446
01447 StrTool::stringlist_t::iterator f = splitpath.begin();
01448 StrTool::stringlist_t::iterator l = splitpath.end();
01449
01450 while(f != l)
01451 {
01452 #ifdef _MSC_VER
01453
01454 FileName progpath(*f++);
01455
01456 progpath += "\\";
01457 progpath += progname;
01458
01459 for(size_t i=0; i < progpath.size(); ++i)
01460 if(progpath[i] == '/')
01461 progpath[i] = '\\';
01462
01463 if(progpath.exists())
01464 {
01465 return progpath;
01466 }
01467
01468 FileName exefile(progpath + ".exe");
01469
01470 if(exefile.exists())
01471 {
01472 return exefile;
01473 }
01474
01475 FileName batfile(progpath + ".bat");
01476
01477 if(batfile.exists())
01478 {
01479 return batfile;
01480 }
01481
01482 FileName cmdfile(progpath + ".cmd");
01483
01484 if(cmdfile.exists())
01485 {
01486 return cmdfile;
01487 }
01488
01489 FileName comfile(progpath + ".com");
01490
01491 if(comfile.exists())
01492 {
01493 return comfile;
01494 }
01495
01496 #else
01497 FileName progpath(*f++);
01498
01499 progpath += "/";
01500 progpath += progname;
01501
01502 if(progpath.exists())
01503 {
01504 return progpath;
01505 }
01506 #endif
01507
01508 }
01509
01510 return "";
01511
01512 }
01513
01514
01515 FileName
01516 FileName::
01517 find_file_in_path(string progname, string path)
01518 {
01519
01520
01521
01522
01523 if(path.size() == 0)
01524 {
01525
01526
01527
01528 char const *p;
01529
01530 if(ProgramOptions::global_options_)
01531 p = ProgramOptions::global_options_->getenv("PATH").c_str();
01532 else
01533 p = getenv("PATH");
01534
01535 if(p)
01536 path = p;
01537 }
01538
01539
01540 StrTool::stringlist_t splitpath;
01541
01542 Is_Path_Space functor;
01543
01544 StrTool::parse_words(path,
01545 &splitpath,
01546 2000000000U,
01547 functor
01548 );
01549
01550 StrTool::stringlist_t::iterator f = splitpath.begin();
01551 StrTool::stringlist_t::iterator l = splitpath.end();
01552
01553 StrTool::stringlist_t expandedList;
01554
01555 {
01556
01557
01558
01559
01560
01561
01562 while(f != l)
01563 {
01564 if(f->find_first_of("*?") < f->size())
01565 {
01566 sorted_names_t matches;
01567
01568 find_matching(f->c_str(), &matches, 3);
01569
01570 sorted_names_t::iterator a = matches.begin(), b = matches.end();
01571
01572 while(a != b) expandedList.push_back(*a++);
01573
01574
01575 }
01576 else
01577 expandedList.push_back(*f);
01578
01579 ++f;
01580
01581 }
01582
01583
01584
01585
01586 f = expandedList.begin();
01587 l = expandedList.end();
01588
01589 }
01590
01591
01592 while(f != l)
01593 {
01594 FileName progpath(*f++);
01595
01596 progpath += "/";
01597 progpath += progname;
01598
01599 if(progpath.exists())
01600 {
01601 progpath.convert_to_absolute_path();
01602 return progpath;
01603 }
01604
01605 }
01606
01607 return "";
01608
01609 }
01610
01611
01612 #ifdef _MSC_VER
01613 char FileName::PATH_separator = ';';
01614 #else
01615 char FileName::PATH_separator = ':';
01616 #endif
01617
01618
01619 bool
01620 FileName::
01621 remove() const
01622 {
01623 char const *n = c_str();
01624
01625 if(access(n, W_OK) != 0)
01626 return true;
01627
01628 return 0 != unlink(n);
01629 }
01630
01631 bool
01632 FileName::
01633 rmdir() const
01634 {
01635 errno = 0;
01636 return 0 != ::rmdir(c_str()) || errno != 0;
01637 }
01638
01639 bool
01640 FileName::
01641 mkdir( FileMode permissions ) const
01642 {
01643 #ifdef _MSC_VER
01644 return 0 != ::mkdir(c_str());
01645 #else
01646 return 0 != ::mkdir(c_str(), permissions.os_mode());
01647 #endif
01648 }
01649
01650 int
01651 FileMode::
01652 os_mode() const
01653 {
01654 int rv=0;
01655
01656 #if _MSC_VER
01657
01658 if(mode & directory) rv |= _S_IFDIR;
01659 if(mode & user_readable) rv |= _S_IREAD;
01660 if(mode & user_writeable) rv |= _S_IWRITE;
01661
01662 #else
01663
01664 if(mode & link) rv |= S_IFLNK;
01665 if(mode & directory) rv |= S_IFDIR;
01666 if(mode & set_uid) rv |= S_ISUID;
01667 if(mode & set_gid) rv |= S_ISGID;
01668 if(mode & user_readable) rv |= S_IRUSR;
01669 if(mode & user_writeable) rv |= S_IWUSR;
01670 if(mode & user_executable)rv |= S_IXUSR;
01671 if(mode & group_readable) rv |= S_IRGRP;
01672 if(mode & group_writeable) rv |= S_IWGRP;
01673 if(mode & group_executable)rv |= S_IXGRP;
01674 if(mode & world_readable) rv |= S_IROTH;
01675 if(mode & world_writeable) rv |= S_IWOTH;
01676 if(mode & world_executable)rv |= S_IXOTH;
01677
01678 #endif
01679
01680 return rv;
01681
01682 }
01683
01684 bool
01685 FileName::
01686 copy(FileName const &destination) const
01687 {
01688 char buffer[32768];
01689
01690 FileStatus stat;
01691
01692 if(file_stat(&stat))
01693 return true;
01694
01695 int fh_in = open(c_str(), O_RDONLY | O_BINARY);
01696
01697 if(fh_in < 0)
01698 return true;
01699
01700 destination.remove();
01701
01702 int fh = creat(destination.c_str(), stat.mode.os_mode());
01703
01704 if(fh < 0)
01705 return true;
01706
01707 SET_MODE(fh, O_BINARY);
01708
01709 int bytes_read;
01710 int bytes_written;
01711
01712 bool rv = false;
01713
01714 for(;;)
01715 {
01716 bytes_read = read(fh_in, buffer, sizeof(buffer));
01717
01718 if(bytes_read == 0)
01719 break;
01720
01721 bytes_written = ::write(fh, buffer, bytes_read);
01722
01723 if(bytes_written != bytes_read)
01724 {
01725 rv = true;
01726 break;
01727 }
01728
01729 }
01730
01731 close(fh);
01732 close(fh_in);
01733
01734
01735 return rv;
01736 }
01737
01738 bool
01739 FileName::
01740 chmod( FileMode mode ) const
01741 {
01742 int err = ::chmod( c_str(), mode.os_mode() );
01743
01744 if(err)
01745 return true;
01746
01747 return false;
01748
01749 }
01750
01751 bool
01752 FileName::
01753 rename( FileName const &destination ) const
01754 {
01755 if(destination.exists() && !destination.is_writeable())
01756 {
01757 return true;
01758 }
01759
01760 int err = ::rename( c_str(), destination.c_str() );
01761
01762 if(err)
01763 return true;
01764
01765 return false;
01766
01767 }
01768
01769 string
01770 FileName::
01771 extension() const
01772 {
01773 const_iterator first = begin(),
01774 last = end();
01775
01776 while(last != first)
01777 {
01778 --last;
01779
01780 char c = *last;
01781
01782 if(c == '.')
01783 return string(last, end());
01784 else
01785 if(c == '/')
01786 break;
01787 else
01788 if(c == '\\')
01789 break;
01790 }
01791
01792 return "";
01793
01794 }
01795
01796 size_t
01797 FileName::
01798 slurp(list<string> *lines) const
01799 {
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824 bool incomplete_line=false;
01825
01826
01827 size_t line_count=0;
01828
01829 int fh = open(c_str(), O_RDONLY);
01830
01831 for(;;)
01832 {
01833
01834
01835
01836
01837 char buffer[32768];
01838
01839 int bytes_read = read(fh, buffer, sizeof(buffer));
01840
01841 if(bytes_read < 1)
01842 break;
01843
01844 char const *next = buffer;
01845 char const *end = buffer + bytes_read;
01846
01847 while(next < end)
01848 {
01849 char * eol = (char*)memchr(next, '\n', end - next);
01850
01851 if(eol == 0)
01852 {
01853
01854
01855
01856 if(incomplete_line)
01857 lines->back().append(next, end - next);
01858 else
01859 {
01860 lines->push_back(string(next, end-next));
01861 incomplete_line = true;
01862 }
01863
01864 break;
01865 }
01866 else
01867 {
01868 int line_fragment_length = eol - next + 1 ;
01869
01870 if(incomplete_line)
01871 {
01872 lines->back().append(next, line_fragment_length);
01873 incomplete_line = false;
01874 }
01875 else
01876 {
01877 lines->push_back(string(next, line_fragment_length));
01878 }
01879
01880 next = eol + 1;
01881
01882 ++line_count;
01883 }
01884 }
01885 }
01886
01887 return line_count;
01888
01889 }
01890
01891 bool
01892 FileName::
01893 is_absolute_path() const
01894 {
01895 string::const_iterator first = begin();
01896
01897 size_t len = size();
01898
01899 if(len < 1)
01900 return false;
01901
01902 if( first[0] == '/' || first[0] == '\\')
01903 return true;
01904
01905 if(len < 3)
01906 return false;
01907
01908 return first[1] == ':' && (first[2] == '\\' || first[2] == '/');
01909
01910 }
01911
01912 bool
01913 FileName::
01914 is_root_dir() const
01915 {
01916 string::const_iterator first = begin();
01917
01918 size_t len = size();
01919
01920 if( len == 1
01921 && (*first == '/' || *first == '\\')
01922 )
01923 {
01924 return true;
01925 }
01926
01927 if( len == 3
01928 && operator[](1) == ':'
01929 && ( operator[](2) == '/'
01930 || operator[](2) == '\\'
01931 )
01932 )
01933 {
01934 return true;
01935 }
01936
01937
01938
01939 return false;
01940
01941
01942
01943 }
01944
01945
01946 string
01947 FileName::
01948 shorten(int length) const
01950 {
01951 size_t s = size();
01952
01953
01954
01955 if( s <= (size_t) length )
01956 return *this;
01957
01958
01959
01960 string me = *this;
01961
01962 if(length < 5)
01963 {
01964 me.erase(0, me.size() - length);
01965
01966 return me;
01967 }
01968
01969
01970
01971
01972 length -= 3;
01973
01974 static string elipsis("...");
01975
01976 size_t excess = s - length;
01977
01978 size_t start = s - excess; start /= 2;
01979
01980 me.erase(start, excess);
01981
01982 me.insert(start, elipsis);
01983
01984 return me;
01985
01986 }
01987
01988
01989 string
01990 FileName::
01991 read_lines(FileName::accumulate_lines& accum, size_t* line_count_ptr, bool removeCR)
01992 {
01993 bool incomplete_line=false;
01994
01995 size_t line_count=0;
01996
01997 if(line_count_ptr) *line_count_ptr = 0;
01998
01999 int fh = open(c_str(), O_RDONLY);
02000
02001 if(fh < 0)
02002 return string(strerror(errno));
02003
02004 int partial_lines=0;
02005
02006 for(;;)
02007 {
02008 char buffer[32768];
02009
02010 int bytes_read = read(fh, buffer, sizeof(buffer));
02011
02012 if(bytes_read < 1)
02013 {
02014 if(bytes_read == 0)
02015 break;
02016
02017 string rv(strerror(errno));
02018
02019 close(fh);
02020
02021 return rv;
02022 }
02023
02024 char const *next = buffer;
02025 char const *end = buffer + bytes_read;
02026
02027 while(next < end)
02028 {
02029 char * eol = (char*)memchr(next, '\n', end - next);
02030
02031 if(eol == 0)
02032 {
02033
02034
02035
02036 ++partial_lines;
02037
02038 if(incomplete_line)
02039 accum.back().append(next, end - next);
02040 else
02041 {
02042 accum.push_back(string(next, end-next));
02043 incomplete_line = true;
02044 }
02045
02046 break;
02047 }
02048 else
02049 {
02050 int line_fragment_length = eol - next;
02051
02052 bool hasRemovedCR = false;
02053
02054 if( removeCR
02055 && line_fragment_length >= 1
02056 && eol[-1] == '\r'
02057 )
02058 {
02059 hasRemovedCR = true;
02060 --line_fragment_length;
02061 }
02062
02063
02064 if(incomplete_line)
02065 {
02066 accum.back().append(next, line_fragment_length);
02067 incomplete_line = false;
02068 }
02069 else
02070 {
02071 accum.push_back(string(next, line_fragment_length));
02072 }
02073
02074 if(hasRemovedCR)
02075 {
02076 accum.setBackHasCR(true);
02077
02078
02079
02080
02081
02082 }
02083
02084
02085 next = eol + 1;
02086
02087 ++line_count;
02088 }
02089 }
02090 }
02091
02092 if(close(fh) < 0)
02093 {
02094 return strerror(errno);
02095 }
02096
02097 if(line_count_ptr) *line_count_ptr = line_count;
02098
02099
02100 return string();
02101 }
02102
02103 FileName
02104 FileName::
02105 getcwd()
02106 {
02107 char buffer[2048];
02108
02109 if(::getcwd(buffer, sizeof(buffer)) == 0)
02110 {
02111 return ".";
02112 }
02113
02114 return buffer;
02115 }
02116
02117 bool
02118 FileName::
02119 write(string const &file_contents, bool binary_mode)
02120 {
02121 return write(file_contents.data(),
02122 file_contents.data() + file_contents.size(),
02123 binary_mode
02124 );
02125 }
02126
02127 bool
02128 FileName::
02129 write(char const* begin, char const* end, bool binary_mode)
02130 {
02131 size_t bytes = (end - begin);
02132
02133 FILE * f = fopen(c_str(), binary_mode ? "wb" : "w");
02134
02135 if(!f)
02136 return true;
02137
02138 if(1 != fwrite(begin, bytes, 1, f))
02139 return true;
02140
02141 if(fflush(f))
02142 return true;
02143
02144 fclose(f);
02145
02146 return false;
02147 }
02148
02149
02150 std::auto_ptr<FileName::Tree>
02151 FileName::
02152 tree_helper(string const &path_string, bool only_dirs, int depth) const
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162 {
02163 Tree* tree = new Tree;
02164
02165 tree->name_ = *this;
02166 tree->depth_ = depth;
02167
02168 FileName path(path_string);
02169
02170 path.file_stat(&tree->status_);
02171
02172 if(tree->status_.mode.is_dir())
02173 {
02174
02175
02176 sorted_names_t children;
02177
02178 FileName child_pattern(path); child_pattern.convertToDirectorySearchPattern();
02179
02180 find_matching(child_pattern, &children);
02181
02182 sorted_names_t::iterator f=children.begin(), l=children.end();
02183
02184 FileName me(".");
02185 FileName mommy("..");
02186
02187 while(f != l)
02188 {
02189 FileName const& curname = *f++;
02190
02191 if( (curname[0] == '.') && (curname == me || curname == mommy) )
02192 {
02193 continue;
02194 }
02195
02196 FileName child(path);
02197
02198 if(child == ".")
02199 child = "";
02200 else
02201 if(child[child.size()-1] != '/')
02202 child += "/";
02203
02204 child += curname;
02205
02206 FileStatus status;
02207
02208 if(only_dirs)
02209 child.file_stat(&status);
02210
02211 std::auto_ptr<Tree> tmp(0);
02212
02213 if(!only_dirs || status.mode.is_dir())
02214 {
02215 tmp.reset(curname.tree_helper(child, only_dirs, depth+1).release());
02216
02217 tmp->parent_ = tree;
02218
02219 tree->add_child(tmp.release());
02220 }
02221
02222 }
02223 }
02224
02225 return std::auto_ptr<Tree>(tree);
02226 }
02227
02228 std::auto_ptr<FileName::Tree>
02229 FileName::
02230 tree(bool only_dirs) const
02231 {
02232 return tree_helper(*this, only_dirs);
02233 }
02234
02235 FileName::Tree::
02236 ~Tree()
02237 {
02238 children_t::iterator f =children_.begin(), l = children_.end();
02239
02240 while(f != l)
02241 {
02242 delete *f++;
02243 }
02244 }
02245
02246 FileName::Tree::
02247 Tree(Tree const &r)
02248 : status_(r.status_),
02249 name_(r.name_),
02250 parent_(r.parent_),
02251 depth_(r.depth_)
02252 {
02253 children_t::iterator f =children_.begin(), l = children_.end();
02254
02255 while(f != l)
02256 {
02257 Tree* t = *f++;
02258 children_.push_back( new Tree(*t) );
02259 }
02260
02261 }
02262
02263
02264 void
02265 FileName::Tree::
02266 remove_child(FileName const &name)
02267 {
02268 children_t::iterator f =children_.begin(), l = children_.end();
02269
02270 while(f != l)
02271 {
02272 Tree* cur = *f;
02273
02274 if(cur->name_ == name)
02275 {
02276 delete cur;
02277
02278 children_.erase(f);
02279 return;
02280 }
02281 ++f;
02282 }
02283
02284 }
02285
02286 FileName
02287 FileName::Tree::
02288 path() const
02289 {
02290 FileName rv = name();
02291
02292 Tree const* scan = this;
02293
02294 while(scan->parent_)
02295 {
02296 string pname = scan->parent_->name();
02297
02298 char c=' ';
02299
02300 if(pname.size())
02301 c = pname[ pname.size() -1 ];
02302
02303 if(c != '/')
02304 rv.insert(0, "/");
02305
02306 rv.insert(0, pname);
02307 scan = scan->parent_;
02308 }
02309
02310 return rv;
02311
02312 }
02313
02314 using namespace std;
02315
02316 static set<string> tilde_cache;
02317
02318 static string gethomepath()
02319 {
02320 {
02321 char const *home = getenv("HOME");
02322
02323 #ifdef _MSC_VER
02324
02325 {
02326 char const *homepathp= getenv("HOMEPATH");
02327
02328 string homepath;
02329
02330 if(homepathp)
02331 {
02332 homepath = homepathp;
02333
02334 char const *homedrive= getenv("HOMEDRIVE");
02335
02336 if(homedrive)
02337 {
02338 char buffer[1024];
02339
02340 sprintf(buffer, "%s%s", homedrive, homepath.c_str());
02341
02342 set<string>::iterator f = tilde_cache.find(buffer);
02343
02344 if(f == tilde_cache.end())
02345 {
02346 tilde_cache.insert(buffer);
02347 f = tilde_cache.find(buffer);
02348 }
02349
02350 return f->c_str();
02351
02352 }
02353 else
02354 return homepath;
02355 }
02356 }
02357 #endif
02358
02359 if(home == 0)
02360 home=".";
02361
02362 return home;
02363 }
02364 }
02365
02366
02367 FileName
02368 FileName::
02369 expand_tildes() const
02370 {
02371 if(size() < 1 || *begin() != '~')
02372 return *this;
02373
02374
02375
02376
02377 FileName const &me = *this;
02378
02379 if(size() == 1 )
02380 {
02381 return gethomepath();
02382 }
02383 else
02384 {
02385
02386
02387
02388 if(me[1] == '/' || me[1] == '\\')
02389 {
02390
02391
02392 string home = gethomepath();
02393
02394 FileName prefix;
02395 FileName homevalue;
02396
02397 homevalue = home;
02398
02399 homevalue += me.substr(1,me.size());
02400
02401 return homevalue;
02402
02403 }
02404 else
02405 {
02406
02407
02408 string user;
02409
02410 size_t i;
02411
02412 for(i=1; i < me.size(); ++i)
02413 {
02414 char c = me[i];
02415
02416 if(c == '/' || c == '\\')
02417 break;
02418 else
02419 user += c;
02420 }
02421
02422 string rest = me.substr(i, me.size());
02423
02424 #ifdef _MSC_VER
02425
02426 {
02427 FileName homepath = gethomepath();
02428 FileName parent = homepath.dirname();
02429
02430 return parent + user + rest;
02431 }
02432
02433 #else
02434 UserInfo ui = UserInfo::get(user);
02435 return ui.home_dir_ + rest;
02436 #endif
02437
02438
02439
02440 }
02441 }
02442
02443 return *this;
02444
02445 }
02446
02447 void
02448 FileName::
02449 convertToDirectorySearchPattern(char const *pattern)
02450 {
02451 if(size() == 0)
02452 *this = pattern;
02453 else
02454 {
02455 char lastChar = (*this)[size()-1];
02456
02457 if(lastChar == '/' || lastChar == '\\' || is_dir())
02458 {
02459 if(lastChar != '/' && lastChar != '\\')
02460 (*this) += '/';
02461
02462 *this += pattern;
02463 }
02464
02465 }
02466 }
02467
02468
02469 FileName
02470 FileName::
02471 readlink(int *mode) const
02472 {
02473 #ifdef _MSC_VER
02474 return "";
02475 #else
02476
02477 char const *p = this->c_str();
02478
02479 char buffer[3000];
02480
02481
02482 ssize_t rv = ::readlink(p, buffer, sizeof(buffer));
02483
02484 if(rv < 1)
02485 return "";
02486
02487 if(rv == sizeof(buffer))
02488 {
02489
02490
02491 return "";
02492
02493 }
02494
02495 buffer[rv]=0;
02496
02497 FileName tmp(buffer);
02498
02499 tmp.convert_to_absolute_path();
02500
02501 if(mode)
02502 {
02503 struct stat buf;
02504
02505 if(lstat(p, &buf))
02506 {
02507 *mode=0;
02508 }
02509 else
02510 {
02511 *mode = buf.st_mode;
02512 }
02513 }
02514
02515 return tmp;
02516 #endif
02517
02518 }
02519
02520
02521
02522
02523 void
02524 FileMode::
02525 unpackPermissions(string &user, string &group, string &world)
02526 {
02527
02528
02529
02530
02531
02532 user="";
02533 group="";
02534 world="";
02535
02536 if(mode & user_readable) user += 'r';
02537 if(mode & user_writeable) user += 'w';
02538 if(mode & user_executable) user += 'x';
02539
02540 if(mode & group_readable) group += 'r';
02541 if(mode & group_writeable) group += 'w';
02542 if(mode & group_executable) group += 'x';
02543
02544 if(mode & world_readable) world += 'r';
02545 if(mode & world_writeable) world += 'w';
02546 if(mode & world_executable) world += 'x';
02547
02548 }
02549
02550
02551 static int unpackPermString(string const &s, int readable, int writeable, int executable)
02552 {
02553
02554
02555
02556 string::const_iterator begin = s.begin(), end = s.end();
02557
02558 int rv = 0;
02559
02560 while(begin != end)
02561 {
02562 char c = *begin++;
02563
02564 switch(c)
02565 {
02566 case 'r':
02567 case 'R':
02568 rv |= readable;
02569 break;
02570
02571 case 'w':
02572 case 'W':
02573 rv |= writeable;
02574 break;
02575
02576 case 'x':
02577 case 'X':
02578 rv |= executable;
02579 break;
02580 }
02581
02582 }
02583
02584 return rv;
02585
02586 }
02587
02588 void
02589 FileMode::
02590 packPermissions(string const &user, string const &group, string const &world)
02591 {
02592 int userMode = unpackPermString(user, user_readable, user_writeable, user_executable);
02593 int groupMode = unpackPermString(group, group_readable, group_writeable, group_executable);
02594 int worldMode = unpackPermString(world, world_readable, world_writeable, world_executable);
02595
02596 mode &= ~(
02597 user_readable |
02598 user_writeable |
02599 user_executable |
02600 group_readable |
02601 group_writeable |
02602 group_executable |
02603 world_readable |
02604 world_writeable |
02605 world_executable
02606 );
02607
02608 mode |= userMode | groupMode | worldMode;
02609
02610
02611 }
02612
02613
02614 bool
02615 FileMode::
02616 permStringValid(string const &s)
02617 {
02618
02619 int rcount = 0;
02620 int wcount = 0;
02621 int xcount = 0;
02622
02623 string::const_iterator begin = s.begin(), end = s.end();
02624
02625 while(begin != end)
02626 {
02627 char c = *begin++;
02628
02629 switch(c)
02630 {
02631 case 'r':
02632 case 'R':
02633 ++rcount;
02634 if(rcount > 1)
02635 return false;
02636 break;
02637
02638 case 'w':
02639 case 'W':
02640 ++wcount;
02641 if(wcount > 1)
02642 return false;
02643 break;
02644
02645 case 'x':
02646 case 'X':
02647 ++xcount;
02648 if(xcount > 1)
02649 return false;
02650 break;
02651
02652 default:
02653 return false;
02654 break;
02655
02656 }
02657
02658 }
02659
02660 return true;
02661 }
02662
02663 }