// FileHead.cpp: implementation of the FileHead class. // ////////////////////////////////////////////////////////////////////// #include "FileHead.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// /* When a FileHead is constructed, it immediately populates itself with * all the necessary FileRev objects to make it a complete representation * of this file. Integration records are not evaluated at this time. */ FileHead::FileHead(StrBuf path, FileLogCache* newparent) { file = path; //This is the path to the file. next = NULL; head = NULL; tail = NULL; parent = newparent; //The FileLogCache that created this FileHead. ClientLogUser ui; ui.working = this; //Tell the ClientLogUser to add revisions to this FileHead. ClientApi client; Error e; StrBuf msg; /* Initialize the client/server connection. Any error at this point is the * result of a bad connection between client and server. */ client.Init(&e); if (e.GetSeverity()) { e.Fmt(&msg); ALERT(at_console, msg.Text()); return; } char* args[1]; //An array that will hold the arguments to the p4 command. args[0] = path.Text(); //Path to the file - this will be the arg to p4 filelog. client.SetArgv(1, args); //Set the argument list to be the file path. client.Run( "filelog", &ui ); //Run "p4 filelog <file>". /* At this point, the ClientLogUser takes care of creating FileRevs and * arranging them. By the time the filelog command finishes executing, it's * all done. */ /* Close the connection and report errors to the console. */ client.Final (&e); if (e.GetSeverity()) { e.Fmt(&msg); ALERT(at_console, msg.Text()); } } /* The destructor - deletes all of its FileRevs as well as its neighboring FileHeads. */ FileHead::~FileHead() { if (head != NULL) { delete head; //deleting the head FileRev deletes them all. } if (next != NULL) { delete next; //pass the deletion message on to the next FileHead. } } /* addRev is called from within ClientLogUser each time a new revision is given in * the filelog. It adds a revision to the tail of the chain of FileRevs. */ void FileHead::addRev(StrBuf newrev, StrBuf newchange, short type) { if (head != NULL) //if we already have one or more FileRevs here { tail->next = new FileRev(newrev, this, newchange, type); //tack this on the end tail = tail->next; //update the tail pointer to reflect the addition } else //this is the first revision we're adding { head = new FileRev(newrev, this, newchange, type); //make it the head tail = head; //and make it the tail also } } /* See the header file - scanInto is called when another FileHead has determined that * this one is its descendant. The first argument indicates at what point this FileHead * received content from the donor FileHead, and the second argument indicates what specific * revision that integration was from. * Note that scanInto operates on all the revisions from startrev-head. Note also that * a FileHead's revisions start with the head and work backwards, so we'll be starting with * the head revision and working down until we hit startrev - when we hit startrev, we point it * at the "caller" FileRev and return. */ void FileHead::scanInto(StrBuf startrev, FileRev* caller) { StrBuf filename; //This is the path to the file we'll be calling scanInto on next. StrBuf filerev; //This is the startrev for that file (the rev created by the integ). FileRev* foo = head; //foo is the FileRev we're looking at. Start with head. FileHead* tocheck; //tocheck is the FileHead corresponding to file 'filename'. while (foo != NULL) //Unless we hit the end of the line... { if (foo->intocheck) { //Have we already checked this rev? If so, don't do it again. if (foo->rev == startrev) return; //If this is startrev, we're done. foo = foo->next; //otherwise, move on to the next FileRev. continue; //Next loop. } /* If we reach this point, this rev hasn't been checked yet. */ filename = foo->intofiles.SPop(); filerev = foo->intorevs.SPop(); /* If foo doesn't have any integ children, these will be empty StrBufs. */ while (filename.Length()) //If length > zero, it must be a filename. { /* Here we find the FileHead representing the file from the "into" * integ record. We then scanInto it, giving the file that we're * looking at right now as the "caller" arg, and the revision from * the integ record as the startrev. */ tocheck = parent->Get(filename, false); //get the FileHead tocheck->scanInto(filerev, foo); //scanInto it filename = foo->intofiles.SPop(); //next file filerev = foo->intorevs.SPop(); //rev of that file } foo->intocheck = true; //Record the fact that this FileRev has been checked. parent->changes->AddChange(foo->change); //add this change to the sorted list if (foo->rev == startrev) //Is this the startrev? { foo->from = caller; //Set its from pointer to the caller FileRev. return; //We're done. } foo = foo->next; //Otherwise, move on to the next FileRev. } } /* scanFrom returns a FileRev* , which is then used to fill the "from" pointer * of its caller. The endrev argument indicates the end of the revision range - * in scanFrom, we start at that rev and then work our way down to the earliest * revision. */ FileRev* FileHead::scanFrom(StrBuf endrev) { StrBuf filename; StrBuf filerev; bool credit = true; //If no endrev is given, scan all revs. if (endrev.Length()) credit = false; //default - don't scan till the endrev. FileRev* foo = head; //foo is the rev we're currently looking at. FileRev* bar = NULL; //bar is what we'll ultimately return. FileHead* tocheck; //tocheck is what we'll call scanFrom on next. while (foo != NULL) //for each FileRev... { if (foo->rev == endrev) { //if this is the endrev credit = true; //begin doing scanFroms bar = foo; //this is the rev to return } if (credit) //If we've started scanning { if (foo->fromcheck) //If this rev has already been checked { foo = foo->next; //Skip over it and continue. continue; } filename = foo->fromfile; //get the fromfile if any filerev = foo->fromrev; //get the fromrev if any if (filename.Length()) //If it's there and contains something { tocheck = parent->Get(filename, true); //get the associated FileHead foo->from = tocheck->scanFrom(filerev); //call its scanFrom method } foo->fromcheck = true; //mark this FileRev as having been scanned parent->changes->AddChange(foo->change); //add this change to the list } foo = foo->next; //next FileRev } return bar; //return the value we stored earlier }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 937 | Sam Stafford |
Renaming my guest directory to the more conventional sam_stafford. |
||
#1 | 936 | Sam Stafford |
Adding P4HL to the public depot. See relnotes.txt for installation instructions; all relevant files are under p4hl/dist. Source code is under p4hl/src in the form of a VC++ project. |