// clientloguser.cpp: implementation of the clientloguser class.
//
//////////////////////////////////////////////////////////////////////
#include "clientloguser.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
ClientLogUser::ClientLogUser()
{
}
ClientLogUser::~ClientLogUser()
{
}
/* This is where the magic happens.
* Lines of filelog output will have a level of '0', '1', or '2'.
* Level '0' is the file name - we can ignore this.
* Level '1' is a revision record, looking like this:
* #2 change 767 edit on 2001/09/25 by samwise@samwise-luey (binary+k) 'description'
* Level '2' is an integ record, looking like this:
* branch from //depot/foo/bar#1,#2
*/
void ClientLogUser::OutputInfo(char level, const_char *data)
{
/* Ignore level '0'. */
/* If this is a rev record, create a new FileRev object for it. */
if (level == '1')
{
StrBuf rev = StrBuf(); //this will be the rev number
StrBuf change = StrBuf(); //this will be the change number
short type; //this will be the revision type
char* ptr = data+1; //skip over '#' - we're now pointing at the rev number
while (*ptr != ' ') //go until we see the first space
{
rev.Append(ptr, 1);
ptr++;
} //rev now contains the rev number.
ptr += 8; //skip over ' change ' - we're now pointing at the change number
while (*ptr != ' ')
{
change.Append(ptr, 1);
ptr++;
} //change now contains the change number.
ptr++; //skip the space - now looking at the rev type.
switch (*ptr) //We can determine the rev type from the first letter alone unless it's an i.
{
default:
case 'e': type = TYPE_EDIT; break; // 'edit'
case 'a': type = TYPE_ADD; break; // 'add'
case 'b': type = TYPE_BRANCH; break; // 'branch'
case 'd': type = TYPE_DEL; break; // 'delete'
case 'i': type = 0; break; //indeterminate from first character
}
if (type == 0) //Was it an 'i'?
{
ptr++;
if (*ptr == 'm') type = TYPE_ADD; // 'import'
else type = TYPE_INTEG; // 'integ'
}
working->addRev(rev, change, type); //Tell the FileHead to create a new FileRev.
return; //All done with this line of output!
}
/* Here's where we handle integ records.*/
if (level == '2')
{
short type; //This will be the integ type - different from rev type!
char* ptr = data; //ptr is pointing at the first character of the integ type.
switch (*ptr)
{
default:
case 'm': type = TYPE_MERGE; break; // 'merge'
case 'b': type = TYPE_BRANCH; break; // 'branch'
case 'e': type = TYPE_DIRTY; break; // 'edit'
case 'a': type = TYPE_DIRTY; break; // 'add'
case 'c': type = TYPE_COPY; break; // 'copy'
case 'i': type = TYPE_IGNORE; break; // 'ignored'
}
/* If the rev type is an "add", this is an "add into/from", even if the integ type
* is given as "branch". The following line takes care of that. It also takes
* care of the fact that older servers didn't have "edit from/into" records. */
if (working->tail->type == TYPE_ADD ||
working->tail->type == TYPE_EDIT ) type = TYPE_DIRTY;
while (*ptr != ' ') {ptr++;} //Skip past the rest of that word to the next space.
ptr++; //Skip the space - the current word is either 'from' or 'into'.
/* A "from" integ record will be indicated by the word "from" in most cases.
* For example, "merge from" or "branch from". The exception is the word
* "ignored". If this is the case, we'll be looking at a filespec rather
* than a "from" or "into". */
if (*ptr == 'f' || *ptr == '/') // 'from' or the beginning of a filespec.
{ //This is a "from" record, so note this in the appropriate FileRev.
working->tail->fromtype = type; //This is the integ type.
StrBuf filepath = StrBuf(); //This will be the "fromfile".
StrBuf rev = StrBuf(); //This will be the "fromrev".
if (*ptr == 'f') //If this word is "from", skip past it to the file.
{
while (*ptr != ' ') {ptr++;}
ptr++; //now we're at the start of the "from" filespec
}
//If it wasn't, it was an "ignored" and we're there anyway.
while (*ptr != '#') //scan up to the '#' revision marker.
{
filepath.Append(ptr, 1);
ptr++;
}
working->tail->fromfile = filepath; //The fromfile has been set.
ptr ++; //Skip over the '#'. Now looking at a revision number.
/* At this point we'll either see a single revision or a revision
* range. If it's a revision range it'll be of the form:
* #12,#15
* whereas a single revision will just be
* #15
* If it's a range, we want to look at the last number in that range. */
while ((*ptr != ',') && (*ptr != '\0'))
{
rev.Append(ptr, 1);
ptr++;
} //rev now contains either the single revision, or the first rev in a range.
if (*ptr == '\0') //Single revision - use it.
{
working->tail->fromrev = rev;
return; //All done with this line.
}
rev = StrBuf(); //This isn't the end of the line, so there must be another rev.
ptr+=2; //skip over ",#" to get to the start of the end rev.
while (*ptr != '\0')
{
rev.Append(ptr, 1);
ptr++;
} //Now rev contains the end rev of the range.
working->tail->fromrev = rev;
return; //Done.
}
else // This line is an "into".
{
StrBuf filepath = StrBuf();
StrBuf rev = StrBuf();
while (*ptr != ' ') {ptr++;} //Skip over this word, be it "into" or "by".
ptr++; //Skip the space - now we're at the start of an "into" filespec.
while (*ptr != '#') //Go up to the '#' marker.
{
filepath.Append(ptr, 1);
ptr++;
} // We now have the "into" file.
working->tail->intofiles.Append(filepath); //Store it in the FileRev.
ptr++; //Skip the '#' and get to the revision. This is not a range.
while (*ptr != '\0')
{
rev.Append(ptr, 1);
ptr++;
}
working->tail->intorevs.Append(rev); //Store the rev.
return; //Done!
}
}
}
| # | 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. |