// // Copyright 1997 Nicholas J. Irias. All rights reserved. // // // P4FileStats.cpp #include "stdafx.h" #include "P4Win.h" #include "MainFrm.h" #include "P4FileStats.h" #include "GuiClient.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // File actions, MUST match the enums in P4FileStats.h static LPCTSTR actions[]= { _T("none"), // not a Perforce type, just padding to match the enum in header _T("unknown"), _T("add"), _T("edit"), _T("delete"), _T("branch"), _T("integrate"), _T("import"), _T("no action"), 0 }; // File types, MUST match the enums in P4FileStats.h static LPCTSTR types[]= { _T("unknown"), _T("text"), _T("ctext"), _T("cxtext"), _T("ltext"), _T("ktext"), _T("ttext"), _T("xtext"), _T("xltext"), _T("kxtext"), _T("binary"), _T("tbinary"), _T("ubinary"), _T("xbinary"), _T("symlink"), _T("resource"), _T("tempobj"), _T("xtempobj"), _T("unicode"), _T("xunicode"), _T("utf16"), 0 }; IMPLEMENT_DYNCREATE(CP4FileStats, CObject) CP4FileStats::CP4FileStats() { Clear(); } void CP4FileStats::Clear() { m_MyOpenAction= m_OtherOpenAction= 0; m_MyLock= m_OtherLock= FALSE; m_OtherUserMyClient= FALSE; m_HeadRev= m_HaveRev= 0; m_HeadAction= 0; m_HeadType= m_Type= _T("unknown"); m_HeadTime=0; m_Unresolved=FALSE; m_Resolved=FALSE; m_OpenChangeNum=m_HeadChangeNum=0; m_OtherOpens=0; m_UserParam=0; m_NotInDepot=FALSE; m_FileSize=0; m_DepotPath=_T(""); m_ClientPath=_T(""); m_OtherUsers=_T(""); m_Digest=_T(""); } void CP4FileStats::Create( CP4FileStats *st ) { m_MyOpenAction= st->m_MyOpenAction; m_OtherOpenAction= st->m_OtherOpenAction; m_OtherUserMyClient= st->m_OtherUserMyClient; m_MyLock= st->m_MyLock; m_OtherLock= st->m_OtherLock; m_HeadRev= st->m_HeadRev; m_HaveRev= st->m_HaveRev; m_HeadTime= st->m_HeadTime; m_HeadAction= st->m_HeadAction; m_Type= st->m_Type; m_HeadType= st->m_HeadType; m_Unresolved= st->m_Unresolved; m_Resolved= st->m_Resolved; m_OpenChangeNum= st->m_OpenChangeNum; m_HeadChangeNum= st->m_HeadChangeNum; m_OtherOpens= st->m_OtherOpens; m_UserParam= st->m_UserParam; m_NotInDepot= st->m_NotInDepot; m_DepotPath= st->m_DepotPath; m_ClientPath= st->m_ClientPath; m_ClientPath.Replace(_T('/'), _T('\\')); m_OtherUsers= st->m_OtherUsers; m_Digest= st->m_Digest; m_FileSize= st->m_FileSize; } CP4FileStats::~CP4FileStats() { } // Create from an fstat result set. BOOL CP4FileStats::Create(StrDict *client) { int i; StrPtr *str; Error err; // Get the depot name str= client->GetVar( "depotFile", &err); // name in depot ASSERT(str || err.Test()); if(err.Test()) goto badFile; m_DepotPath = CharToCString(str->Value()); // If the client path exists, note that file is in client view str= client->GetVar( "clientFile" ); if(str) { m_ClientPath = CharToCString(str->Value()); m_ClientPath.Replace(_T('/'), _T('\\')); } else { // need to determine if the client path doesn't exist or doesn't translate // we can't handle the no translation case. CString txt = FormatError(&err); if(txt.Find(_T("No Translation")) == 0) goto badFile; // there is no client path m_ClientPath=_T(""); } // Concatenate a list of all other users with the file open { char varName[] = "otherOpen "; char varNam2[] = "otherAction "; for(m_OtherOpens=m_OtherOpenAction=0; m_OtherOpens < 100; m_OtherOpens++) { itoa(m_OtherOpens, varName+9, 10); if( (str=client->GetVar( varName )) == 0 ) break; else { if(m_OtherOpens==0) m_OtherUsers = CharToCString(str->Value()); else { m_OtherUsers+=_T("/"); m_OtherUsers+=CharToCString(str->Value()); } if (m_OtherOpenAction != F_DELETE) { itoa(m_OtherOpens, varNam2+11, 10); if ( (str=client->GetVar( varNam2 )) != 0) { for(i=F_UNKNOWNACTION; actions[i]; i++) { if(_tcscmp(actions[i], CharToCString(str->Value()))==0) { m_OtherOpenAction=(BYTE) i; break; } } } } } } } if( (str= client->GetVar( "headRev" )) != NULL) m_HeadRev=atol(str->Value()); if( (str= client->GetVar( "haveRev" )) != NULL) m_HaveRev=atol(str->Value()); if( (str= client->GetVar( "change" )) != NULL) m_OpenChangeNum=atol(str->Value()); if( (str= client->GetVar( "headChange" )) != NULL) m_HeadChangeNum=atol(str->Value()); if( (str= client->GetVar( "headTime" )) != NULL) m_HeadTime=atol(str->Value()); if( (str= client->GetVar( "ourLock" )) != NULL) m_MyLock=TRUE; if( (str= client->GetVar( "otherLock" )) != NULL) m_OtherLock=TRUE; if( (str= client->GetVar( "type" )) != NULL) m_Type= CharToCString(str->Value()); if( (str= client->GetVar( "headType" )) != NULL) m_HeadType= CharToCString(str->Value()); if( (str= client->GetVar( "headAction" )) != NULL) { for(i=F_UNKNOWNACTION; actions[i]; i++) { if(_tcscmp(actions[i], CharToCString(str->Value()))==0) { m_HeadAction=(BYTE) i; break; } } } ASSERT(client->GetVar("headAction")==NULL || m_HeadAction); if( (str= client->GetVar( "action" )) != NULL) { for(i=F_UNKNOWNACTION; actions[i]; i++) { if(_tcscmp(actions[i], CharToCString(str->Value()))==0) { m_MyOpenAction= (BYTE) i; break; } } } ASSERT(client->GetVar("action")==NULL || m_MyOpenAction); if (!m_HaveRev && !m_HeadRev && (m_MyOpenAction == F_ADD || m_MyOpenAction == F_BRANCH)) m_HaveRev = 1; if( (str= client->GetVar( "unresolved" )) != NULL) m_Unresolved=TRUE; str= client->GetVar( "actionOwner" ); if(str) { m_ActionOwner = CharToCString(str->Value()); if (Compare( m_ActionOwner, GET_P4REGPTR()->GetP4User() ) !=0) { m_OtherUserMyClient = TRUE; m_OtherUsers = m_ActionOwner + _T('@') + GET_P4REGPTR()->GetP4Client(); } } str= client->GetVar( "digest" ); if(str) m_Digest = CharToCString(str->Value()); if( (str= client->GetVar( "fileSize" )) != NULL) m_FileSize=atol(str->Value()); // In release builds, these values may be zero for an unrecognized // file type or action, which maps to F_UNKNOWNFILETYPE or F_UNKNOWNACTION // ASSERT(client->GetVar("headType")== NULL || m_HeadType); // commented out as useless and irritating in debug version - leighb 99/11/30 ASSERT(client->GetVar("headAction")==NULL || m_HeadAction); ASSERT(client->GetVar("action")==NULL || m_MyOpenAction); return TRUE; badFile: // most likely a translation failure. Nothing to do but ignore this file. return FALSE; } // This verion of Create() used to process info returned by P4 ADD // looks like : //depot/x_win32/samples/rpc/README.TXT#1 - opened for add BOOL CP4FileStats::Create(LPCTSTR depotName, long changeNumber) { CString line=depotName; int pound=m_DepotPath.ReverseFind(_T('#')); ASSERT(pound != -1); if(pound == 0) { ASSERT(0); return FALSE; } // not a line from P4 add m_DepotPath= line.Left(pound); // File revision m_HaveRev=_ttoi(depotName+pound+1); ASSERT(m_HaveRev==1); m_HeadRev=0; // Not in depot yet m_MyOpenAction=F_ADD; m_HeadAction=F_ADD; m_OpenChangeNum=changeNumber; m_HeadType=m_Type=types[F_UNKNOWNFILETYPE]; return TRUE; } // This version of Create() is only needed till open gets frobbed to // provide data in the fstat format. // // Parses a row returned by P4 opened, of the form: // "//depot/dir/subdir/fname#9 - edit change 25 (text) by user@machine *locked*" // "//depot/x_win32/samples/rpc/README.TXT#1 - add default change (text)" // "//depot/x_win32/embedded - dash/README.TXT#1 - add default change (text)" BOOL CP4FileStats::Create(LPCTSTR openRow) { // Find the revision delimiter '#', and then scan subsequent fileRow // characters for the separator, " - ". We need to look for the // rev number first, because " - " may be embedded within the filename. CString line=openRow; int pound= line.Find(_T('#')); if(pound == -1) { ASSERT(0); return FALSE; } // doesnt look like a fileRow int separator= pound+1; int len= line.GetLength(); for( ; separator < len ; separator++) { if(line[separator]==_T(' ') && line[separator+1]==_T('-') && line[separator+2]==_T(' ')) break; } if(separator == len) { ASSERT(0); return FALSE; } // doesnt look like a fileRow m_DepotPath=line.Left(pound); // File revision - note that this is stored under haveRev, no matter which user has the // file. // note, too that rev can be 0, if the opened command returns a version #null // (so remove the assert that used to be here) // long rev=_ttol(openRow+pound+1); m_HaveRev=rev; CString info=line.Mid(separator+3); CString ModeText=info.Left(info.Find(_T(" "))); // File open action int openAction=F_UNKNOWNACTION; for(int i=F_UNKNOWNACTION; actions[i]; i++) { if(_tcscmp(actions[i], ModeText)==0) { openAction=i; break; } } // File change number info=info.Mid(ModeText.GetLength()+1); if(info.Find(_T("default"))==0) { m_OpenChangeNum=0; // default change } else { if(info.Find(_T("change"))==0) { m_OpenChangeNum=_ttoi(info.Mid(7)); } } // File type info=info.Mid(info.Find(_T("("))+1); CString TypeText=info.Left(info.Find(_T(")"))); m_HeadType = m_Type = TypeText; info=info.Mid( min( info.GetLength()-1, TypeText.GetLength() + 2)); int byStart, userLen; if( (byStart=info.Find(_T("by"))) == 0) { info=info.Mid(byStart+3); // Skip over "by " userLen=info.Find(_T(" ")); if(userLen == -1) m_OtherUsers=info; else m_OtherUsers=info.Left(userLen); if( Compare( m_OtherUsers, GET_P4REGPTR()->GetMyID()) ==0 ) { m_OtherUsers.Empty(); m_OtherOpens=0; m_MyOpenAction= (BYTE) openAction; m_HaveRev= rev; if(info.Find(_T("locked")) > 0) m_MyLock=TRUE; } else { // See if its on my client int at= m_OtherUsers.Find(_T('@')); if( at != -1 && ++at < m_OtherUsers.GetLength() ) { if( Compare( m_OtherUsers.Mid(at), GET_P4REGPTR()->GetP4Client()) ==0 ) m_OtherUserMyClient= TRUE; } else // Why didnt we find client name ASSERT(0); // Update locked and open action info m_OtherOpens=1; if(info.Find(_T("locked")) > 0) m_OtherLock=TRUE; m_OtherOpenAction= (BYTE) openAction; } } else { // didnt find "by", so its my open file m_OtherOpens=0; m_MyOpenAction= (BYTE) openAction; m_HaveRev= rev; if(info.Find(_T("locked")) > 0) m_MyLock=TRUE; } return TRUE; } // This version of Create is used to create an entry // for a file that is not under Perforce control BOOL CP4FileStats::Create( LPCTSTR localsyntax, LPCTSTR depotsyntax ) { Clear(); m_DepotPath = depotsyntax; m_ClientPath= localsyntax; m_ClientPath.Replace(_T('/'), _T('\\')); m_NotInDepot= TRUE; return TRUE; } //////////////////////////////////// // Functions to allow updates to file status info void CP4FileStats::SetClosed() { SetOpenAction(0, FALSE); SetOpenAction(0, TRUE); } void CP4FileStats::SetLocked(BOOL locked, BOOL otherUser) { if(otherUser) m_OtherLock= (BYTE)locked; else m_MyLock= (BYTE)locked; } void CP4FileStats::SetOpenAction(int action, BOOL otherUser) { ASSERT(action >= 0 && action < F_MAXACTION); if(otherUser) { m_OtherOpenAction= (BYTE) action; if(action == 0) { m_Unresolved=FALSE; m_OtherLock= FALSE; m_OtherOpens=0; m_OtherUserMyClient=FALSE; } } else { m_MyOpenAction= (BYTE) action; if(action == 0) { m_Unresolved=FALSE; m_MyLock= FALSE; } } } void CP4FileStats::SetOtherOpens(int num) { m_OtherOpens=num; if(num==0) { m_OtherOpenAction=0; m_OtherUserMyClient=FALSE; SetLocked(FALSE, TRUE); } } void CP4FileStats::SetHeadAction(int action) { ASSERT(action >= 0 && action < F_MAXACTION); m_HeadAction= (BYTE) action; } void CP4FileStats::SetHeadType(int type) { ASSERT(type >= 0 && type < F_MAXTYPE); m_HeadType= types[type]; } void CP4FileStats::SetHeadType(LPCTSTR txttype) { ASSERT(txttype != NULL); ASSERT(_tcslen(txttype) > 0); m_HeadType= txttype; } void CP4FileStats::SetType(int type) { ASSERT(type >= 0 && type < F_MAXTYPE); m_Type= types[type]; } void CP4FileStats::SetType(LPCTSTR txttype) { ASSERT(txttype != NULL); ASSERT(_tcslen(txttype) > 0); m_Type= txttype; } void CP4FileStats::SetHaveRev(long rev) { ASSERT(rev >= 0); m_HaveRev=rev; if(m_HeadRev != 0 && m_HeadRev < rev) m_HeadRev= rev; } void CP4FileStats::SetDepotPath(LPCTSTR path) { ASSERT(_tcslen(path)==0 || _tcsncmp(path, _T("//"), 2) == 0 ); m_DepotPath= path; // If the depot path just got cleared, free the buffer if(path[0]==_T('\0')) m_DepotPath.FreeExtra(); } void CP4FileStats::SetClientPath(LPCTSTR path) { ASSERT(_tcslen(path)==0 || path[1]==_T(':')); m_ClientPath=path; m_ClientPath.Replace(_T('/'), _T('\\')); } // User list looks like: swine@cow/pig@vermin/spion@goon void CP4FileStats::SetOtherUsers(LPCTSTR userlist) { m_OtherUsers=userlist; m_OtherOpens=0; // If the list just got cleared, free the buffer if(userlist[0]==_T('\0')) { m_OtherUsers.FreeExtra(); return; } int hitSlash=TRUE; for(int i=0; i< m_OtherUsers.GetLength(); i++) { if(m_OtherUsers[i] == _T('/')) { ASSERT(!hitSlash); // two slashes without '@' in between hitSlash=TRUE; } if(m_OtherUsers[i] == _T('@')) { ASSERT(hitSlash); hitSlash=FALSE; m_OtherOpens++; } } } /////////////////////////////////////////////////////// // Data access members CString CP4FileStats::GetActionStr(int action) const { ASSERT(action >=0 && action < F_MAXACTION); return CString(actions[action]); } CString CP4FileStats::GetDepotDir() const { int slash=m_DepotPath.ReverseFind(_T('/')); if(slash != -1) return m_DepotPath.Left(slash+1); else { ASSERT(0); return CString(); } } CString CP4FileStats::GetClientDir() const { int slash=m_ClientPath.ReverseFind(_T('\\')); if(slash != -1) return m_ClientPath.Left(slash+1); else { ASSERT(0); return CString(); } } CString CP4FileStats::GetDepotFilename() const { int slash=m_DepotPath.ReverseFind(_T('/')); if(slash != -1) return m_DepotPath.Mid(slash+1); else { ASSERT(0); return CString(); } } CString CP4FileStats::GetClientFilename() const { int slash=m_ClientPath.ReverseFind(_T('\\')); if(slash != -1) return m_ClientPath.Mid(slash+1); else { ASSERT(0); return CString(); } } CString CP4FileStats::GetFormattedFilename(BOOL showFileType) const { CString filename = GET_P4REGPTR( )->ShowEntireDepot( ) <= SDF_DEPOT ? GetDepotFilename() : GetClientFilename(); // Format name + haveRev+headRev for display CString temp; if(m_HeadAction == F_DELETE) { // If the user has the file at < headrev, let the user know if( m_HaveRev > 0 && m_HaveRev < m_HeadRev ) temp.FormatMessage(IDS_FSTAT_s_n_n_s_HEAD_REV_DELETED, filename, m_HaveRev, m_HeadRev, m_HeadType); else if(showFileType) temp.FormatMessage(IDS_FSTAT_s_n_n_s_DELETED, filename, m_HaveRev, m_HeadRev, m_HeadType); else temp.FormatMessage(IDS_FSTAT_s_n_n_DELETED, filename, m_HaveRev, m_HeadRev); } else { if (!m_HeadRev && !m_HaveRev) temp = filename; else if(showFileType) temp.FormatMessage(IDS_FSTAT_s_n_n_s, filename, m_HaveRev, m_HeadRev, m_HeadType); else temp.FormatMessage(IDS_FSTAT_s_n_n, filename, m_HaveRev, m_HeadRev); } return temp; } CString CP4FileStats::GetFormattedChangeFile(BOOL showFileType, BOOL showOpenAction) const { // Format name + haveRev+headRev for display CString temp; int openAction= m_MyOpenAction; if(showOpenAction && m_OtherOpens && !m_MyOpenAction) { openAction= m_OtherOpenAction; } if(showFileType) { CString type = (m_Type == _T("unknown")) ? m_HeadType : m_Type; if(showOpenAction) temp.FormatMessage(IDS_FSTAT_s_n_s_s, m_DepotPath, m_HaveRev, type, actions[openAction]); else temp.FormatMessage(IDS_FSTAT_s_n_s, m_DepotPath, m_HaveRev, type); } else { if(showOpenAction) temp.FormatMessage(IDS_FSTAT_s_n_s, m_DepotPath, m_HaveRev, actions[openAction]); else temp.FormatMessage(IDS_FSTAT_s_n, m_DepotPath, m_HaveRev); } return temp; } CString CP4FileStats::GetFormattedHeadTime() { CString time; struct tm *t; if (!m_HeadTime && !m_HeadRev && !m_HaveRev) { time = _T(""); } else { if(m_HeadTime < 0) m_HeadTime = -m_HeadTime; t = localtime( (const time_t *)&m_HeadTime ); time.Format(_T("%04d/%02d/%02d %02d:%02d:%02d"), t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); } return CString(time); } BOOL CP4FileStats::IsTextFile() const { CString type = m_HeadType.Find(_T("unknown")) == -1 ? m_HeadType : m_Type; return( ((type.Find(_T("text")) != -1) || (type.Find(_T("symlink")) != -1) || (type.Find(_T("unicode")) != -1) || (type.Find(_T("utf16")) != -1)) ? TRUE : FALSE ); } BOOL CP4FileStats::IsOtherOpenExclusive() const { if (IsOtherOpen()) { int i; CString fileType = GetHeadType(); if ((i = fileType.Find(_T('+'))) != -1) { if (fileType.Find(_T('l'),i) != -1) return TRUE; } } return FALSE; } BOOL CP4FileStats::IsMyOpenExclusive() const { if (IsMyOpen()) { int i; CString fileType = GetHeadType(); if ((i = fileType.Find(_T('+'))) != -1) { if (fileType.Find(_T('l'),i) != -1) return TRUE; } } return FALSE; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
//guest/perforce_software/p4win/main/gui/P4FileStats.cpp | |||||
#1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
//guest/perforce_software/p4win/gui/P4FileStats.cpp | |||||
#1 | 8562 | Matt Attaway |
These feet never stop running. Initial commit of the P4Win source code. To the best of our knowledge this compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes as we refine the build process. Please post any build issues to the forums. |