// 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. |