/* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 1, or (at your option) ** any later version. ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Author : Alexandre Parenteau --- March 1998 */ /* * LogParse.cpp : parse the cvs log output */ #include "stdafx.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef WIN32 # include "wincvs.h" # include "GraphDoc.h" #endif /* WIN32 */ #ifdef macintosh # include # include "MacCvsApp.h" # include "CTreeView.h" #endif /* macintosh */ #if qUnix # include "UCvsDialogs.h" # include "UCvsGraph.h" #endif #include "LogParse.h" #include "CvsArgs.h" #include "CvsLog.h" #include "AppGlue.h" #include "AppConsole.h" #include "CPStr.h" #include "getline.h" #ifdef WIN32 # ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; # endif #endif /* WIN32 */ static void print(CColorConsole & out, const CRevFile & rev) { out << kBlue << "----------------------------" << kNormal << kNL; out << "Revision : " << kBold << kRed << rev.RevNum().c_str() << kNormal << kNL; if(!rev.Locker().empty()) out << "Locked by : '" << kBold << rev.Locker() << kNormal << '\'' << kNL; out << "Date : " << kBold << (rev.RevTime().tm_year + 1900) << '/' << rev.RevTime().tm_mon << '/' << rev.RevTime().tm_mday << ' ' << rev.RevTime().tm_hour << ':' << rev.RevTime().tm_min << ':' << rev.RevTime().tm_sec << kNormal << kNL; out << "Author : '" << kBold << rev.Author() << kNormal << '\'' << kNL; out << "State : '" << kBold << rev.State() << kNormal << '\'' << kNL; out << "Lines : +" << kBold << rev.ChgPos() << ' ' << rev.ChgNeg() << kNormal << kNL; if(!rev.BranchesList().empty()) { out << "Branches :" << kNL; std::vector::const_iterator s; for(s = rev.BranchesList().begin(); s != rev.BranchesList().end(); ++s) { const CRevNumber & branch = *s; out << '\t' << kBold << branch.c_str() << kNormal << kNL; } } out << "Description :" << kNL << kBrown << rev.DescLog() << kNormal << kNL; } static void print(CColorConsole & out, const CRcsFile & rcs, bool recurse = true) { out << "Rcs file : '" << kRed << rcs.RcsFile() << kNormal << '\'' << kNL; out << "Working file : '" << kBold << rcs.WorkingFile() << kNormal << '\'' << kNL; out << "Head revision : " << kBold << kRed << rcs.HeadRev().c_str() << kNormal << kNL; out << "Branch revision : " << kBold << rcs.BranchRev().c_str() << kNormal << kNL; out << "Locks :" << kBold << (rcs.LockStrict() ? " strict" : "") << kNormal << kNL; std::vector::const_iterator s; for(s = rcs.LocksList().begin(); s != rcs.LocksList().end(); ++s) { const CRevNumber & lock = *s; out << '\t' << kBold << lock.c_str() << " : '" << lock.Tag() << '\'' << kNormal << kNL; } out << "Access :" << kNL; std::vector::const_iterator a; for(a = rcs.AccessList().begin(); a != rcs.AccessList().end(); ++a) { out << "\t'" << kBold << *a << kNormal << '\'' << kNL; } if(!rcs.SymbolicList().empty()) { out << "Symbolic names :" << kNL; std::vector::const_iterator n; for(n = rcs.SymbolicList().begin(); n != rcs.SymbolicList().end(); ++n) { const CRevNumber & symb = *n; out << '\t' << kBold << symb.c_str() << " : '" << symb.Tag() << '\'' << kNormal << kNL; } } out << "Keyword substitution : '" << kBold << rcs.KeywordSubst() << kNormal << '\'' << kNL; out << "Total revisions : " << kBold << rcs.TotRevisions() << kNormal << kNL; out << "Selected revisions : " << kBold << rcs.SelRevisions() << kNormal << kNL; out << "Description :" << kNL << kBrown << rcs.DescLog() << kNormal << kNL; std::vector::const_iterator i; if(recurse) for(i = rcs.AllRevs().begin(); i != rcs.AllRevs().end(); ++i) { print(out, *i); } out << kGreen << "===============================================" << kNormal << kNL; } static void print(CColorConsole & out, const CLogNode * node, CStr & offset) { out << offset; switch(node->GetType()) { case kNodeHeader : { CLogNodeHeader *header = (CLogNodeHeader *)node; out << offset << "Rcs file : '" << kRed << (**header).RcsFile() << kNormal << '\'' << kNL; break; } case kNodeBranch : break; case kNodeRev : { CLogNodeRev *rev = (CLogNodeRev *)node; out << offset << kBold << (**rev).RevNum().c_str() << kNormal << kNL; break; } case kNodeTag : break; } CStr newOffset; newOffset = offset; newOffset << " "; std::vector::const_iterator i; for(i = node->Childs().begin(); i != node->Childs().end(); ++i) { print(out, *i, newOffset); newOffset << ' '; } if(node->Next() != 0L) { print(out, node->Next(), offset); } } void CvsLogOutput(CColorConsole & out, CLogNode *node) { switch(node->GetType()) { case kNodeHeader : { CRcsFile & rcs = **(CLogNodeHeader *)node; print(out, rcs, false); break; } case kNodeBranch : break; case kNodeRev : { CRevFile & rev = **(CLogNodeRev *)node; print(out, rev); break; } case kNodeTag : break; } } void CvsLogParse(const char *dir, const CvsArgs & args, bool outGraph, void *defWnd) { // make a stream of the cvs log output CStr tmpFile; FILE *output; output = launchCVS(dir, args, tmpFile); if(output == 0L) return; // parse std::vector & allRcs = CvsLogParse(output); // maybe something went wrong or may be the user // asked to print only the RCS names, so print the // output directly whithout parsing../ if(allRcs.empty()) { char *line = 0L; size_t line_chars_allocated = 0; int line_length; fseek(output, SEEK_SET, 0); while ((line_length = getline (&line, &line_chars_allocated, output)) > 0) { cvs_outstr(line, line_length); cvs_outstr("\n", 1); } if (line_length < 0 && !feof (output)) cvs_err("Cannot read output file (error %d)\n", errno); if(line != 0L) free (line); } // close the temp file fclose(output); if(unlink(tmpFile) != 0) { cvs_err("Impossible to delete the file '%s' (error %d)", (const char *)tmpFile, errno); } if(allRcs.empty()) return; // output the result CColorConsole out; std::vector::iterator i; for(i = allRcs.begin(); i != allRcs.end(); ++i) { CRcsFile & rcs = *i; if(!outGraph) print(out, rcs); else { CLogNode *node = CvsLogGraph(rcs); if(node == 0L) { cvs_err("Impossible to create a graph for %s\n", (const char *)rcs.WorkingFile()); } #ifdef WIN32 CWincvsApp* app = (CWincvsApp *)AfxGetApp(); CGraphDoc *doc; if(defWnd != 0L) doc = (CGraphDoc *)defWnd; else doc = (CGraphDoc*)app->gLogGraph->OpenDocumentFile(NULL); doc->SetNode(node, dir); #elif qMacCvsPP if(defWnd != 0L) ((CTreeView *)defWnd)->SetNode(node, dir); else CMacCvsApp::app->NewLogTree(node, dir); #elif qUnix UCvsGraph * graph = new UCvsGraph(node, dir); void *win = UCreate_GraphWindow(); UEventSendMessage(graph->GetWidID(), EV_INIT_WIDGET, kUMainWidget, win); UEventSendMessage(graph->GetWidID(), EV_SHOW_WIDGET, UMAKEINT(kUMainWidget, 1), 0L); #else CStr offset; print(out, node, offset); delete node; #endif } } // reset the parser CvsLogReset(); }