//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Contains the Implementations of the OS Interfaces // // $Workfile: $ // $Date: $ // //------------------------------------------------------------------------------------------------------ // $Log: $ // // $NoKeywords: $ //=============================================================================// #include "TFStatsOSInterface.h" #include "util.h" //------------------------------------------------------------------------------------------------------ // Function: getNextDirectory // Purpose: a wrapper for strtok, to return the next directory name out of a path // Input: path - the path (will be modified by the call to strtok) // Output: char* //------------------------------------------------------------------------------------------------------ char* CTFStatsOSInterface::getNextDirectory(char* path) { char seps[3]; seps[0]=pathSeperator(); seps[1]=0; return strtok( path, seps ); } //------------------------------------------------------------------------------------------------------ // Function: makeDirectory // Purpose: makes a directory hierarchy. because mkdir can't make nested dirs // Input: dir - the string of the path to make // Output: Returns true on success, false on failure. // Note: Notice how easy the linux part of this function is... no drive letters. :) //------------------------------------------------------------------------------------------------------ bool CTFStatsOSInterface::makeHier(string dir) { errno=0; //printf("TRYING TO MAKE %s\n",dir.c_str()); char startingDir[500]; this->getcwd(startingDir,500); bool retval=true; const char* nextDir=NULL; char path[500]; char* dirs=path; strcpy(path,dir.c_str()); //have to parse out directories one at a time. because mkdir just can't handle making nested directories that don't exist (just like md.) //in otherwords, it's lame. #ifdef WIN32 //get drive out of path change to it. //if it's only one character, then interpret it as a path, make it and return; //only do this test because the tests below rely on at least 2 characters in the path if (strlen(path)<2) { this->mkdir(path); return true; } //what should we do with remote machines? //hmm, let's force users to use mapped drives. if (path[0]=='\\' && path[1]=='\\') { Util::debug_dir_printf("Cannot make a directory on a remote machine.\nMap the share to a drive and specify that drive instead.\n"); retval=false; goto end; } //if it's a drive specification if (path[0]=='\\') { if (this->chdir("\\")!=0) Util::debug_dir_printf("Could not change to root on drive %c\n",this->getdrive() + 'a' - 1); dirs=&path[1]; } else if (path[1]==':') { //this little formula turns a drive number into the drive letter int drive=path[0]+1 - 'a'; if (this->chdrive(drive)!=0) { Util::debug_dir_printf("Drive \"%c:\" does not exist\n",path[0]); retval=false; goto end; } if (path[2]=='\\') { if (this->chdir("\\")!=0) { Util::debug_dir_printf("Could not change to root on drive %c\n",path[0]); retval=false; goto end; } dirs=&path[3]; } else { dirs=&path[2]; } } #else // if linux if (path[0]=='/') { this->chdir("/"); dirs=&path[1]; char temp[100]; this->getcwd(temp,100); Util::debug_dir_printf("switched to root. current dir is %s\n",temp); } #endif if (dirs[0]==0) { retval=true; goto end; } //parse out directories. keep trying to changedir into them one by one // when one fails, make it, and continue. nextDir=getNextDirectory(path); do { if (this->chdir(nextDir)!=0) { if (this->mkdir(nextDir)!=0) { char buf[500]; Util::debug_dir_printf("Could not create directory (current directory is %s) (failed on %s)\n",getcwd(buf,500),nextDir); retval=false; goto end; } else Util::debug_dir_printf("created %s\n",nextDir); //try one more time if (this->chdir(nextDir)!=0) { char buf[500]; Util::debug_dir_printf("Could not create directory (current directory is %s) failed on second attempt to change to %s\n",getcwd(buf,500),nextDir); retval=false; goto end; } char temp[200]; this->getcwd(temp,200); Util::debug_dir_printf("Now in %s\n",temp); } nextDir=getNextDirectory(NULL); }while(nextDir); retval=true; end: this->chdir(startingDir); Util::debug_dir_printf("changingDirectory to %s\n",startingDir); return retval; } string& CTFStatsOSInterface::addDirSlash(string& tempbuf) { if (tempbuf!="") { int buflen=tempbuf.length(); if (tempbuf.at(buflen-1) != pathSeperator()) tempbuf+= pathSeperator(); } return tempbuf; } string& CTFStatsOSInterface::removeDirSlash(string& tempbuf) { int buflen=tempbuf.length(); if (buflen > 0 && tempbuf.at(buflen-1) == pathSeperator()) tempbuf.erase(tempbuf.length()-1,1); return tempbuf; } #ifdef WIN32 #include bool CTFStatsWin32Interface::findfirstfile(char* filemask,string& filename) { if (hFindFile!=-1) return false; _finddata_t fd; hFindFile=_findfirst(filemask,&fd); filename=fd.name; return hFindFile != -1; } bool CTFStatsWin32Interface::findnextfile(string& filename) { filename=""; if (hFindFile==-1) return false; _finddata_t fd; int result=_findnext(hFindFile,&fd); filename=fd.name; return result!=-1; } bool CTFStatsWin32Interface::findfileclose() { if (hFindFile==-1) return false; int result = _findclose(hFindFile); return result != -1; } #endif #ifndef WIN32 #include string CTFStatsLinuxInterface::filemask; bool CTFStatsLinuxInterface::findfirstfile(char* filemask,string& filename) { if (foundFileIterator >= 0) findfileclose(); foundFileIterator=-1; numFiles=0; foundFiles=NULL; struct dirent** namelist; int n; CTFStatsLinuxInterface::filemask=filemask; n=scandir(".",&namelist,CTFStatsLinuxInterface::filenameCompare,alphasort); if (n<0) return false; foundFileIterator=0; numFiles=n; foundFiles=namelist; return findnextfile(filename); } bool CTFStatsLinuxInterface::findnextfile(string& filename) { if (foundFileIterator == -1 || foundFiles == NULL || numFiles == 0) return false; if (foundFileIterator >= numFiles) return false; filename=foundFiles[foundFileIterator]->d_name; free(foundFiles[foundFileIterator]); foundFileIterator++; return true; } bool CTFStatsLinuxInterface::findfileclose() { free(foundFiles); return true; } void CTFStatsLinuxInterface::filemask2RegExp(char* buf) { char* read=filemask.c_str(); char* write=buf; while (*read) { if (*read=='?') { *write='.'; } else if (*read=='*') { *write='.'; write++; *write='*'; } else if (*read=='.' || *read=='*' || *read=='?' || *read=='+' || *read=='(' || *read==')' || *read=='{' || *read=='}' || *read=='[' || *read==']' || *read=='^' || *read=='$' ) { *write='\\'; write++; *write=*read; } else *write=*read; read++; write++; } *write=0; } #include int CTFStatsLinuxInterface::filenameCompare(dirent* file) { //scan the filemask, turn it into a regular expression //then fire up the regex engine and scan the filename; char buf[5000]; filemask2RegExp(buf); //printf("trying to match %s against %s\n",buf,file->d_name); string sbuf=buf; regex expression(sbuf); cmatch what; bool result=query_match((const char*)file->d_name, (const char*)(file->d_name + strlen(file->d_name)), what, expression); //if (result) // printf("\tsuccessful\n"); // else //printf("\tno dice\n"); return result?1:0; } char* CTFStatsLinuxInterface::ultoa(unsigned long theNum, char* buf,int radix) { { char ascii[]={"0123456789abcdefghijklmnopqrstuvwxyz"}; if (radix > 36) { buf[0]=0; return NULL; } string holder; while (theNum) { char next; int i=theNum % radix; next=ascii[i]; holder+=next; theNum/=radix; } int i=0; string::reverse_iterator it; for (it=holder.rbegin();it!=holder.rend();++it) { buf[i++]=*it; } buf[i]=0; return buf; } } #endif