/* ** 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 --- December 1997 */ /* * CvsCommands.cpp --- set of CVS commands */ #include "stdafx.h" #include #ifdef WIN32 # include "wincvs.h" # ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; # endif #endif /* WIN32 */ #include "CvsCommands.h" #include "CvsPrefs.h" #include "Authen.h" #include "CvsArgs.h" #include "MultiFiles.h" #include "PromptFiles.h" #include "AppConsole.h" #include "AppGlue.h" #include "MoveToTrash.h" #include "LineCmd.h" #include "CvsAlert.h" #include "TextBinary.h" #include "CommitDlg.h" #include "ImportDlg.h" #include "CheckoutDlg.h" #include "TclGlue.h" #include "ImportFilterDlg.h" #include "UpdateDlg.h" #include "LogDlg.h" #include "DiffDlg.h" #include "LogParse.h" #include "RtagDlg.h" #include "TagDlg.h" #include "InitDlg.h" #include "ReleaseDlg.h" #include "AnnotateDlg.h" #include "StatusDlg.h" #ifdef qMacCvsPP # include "AppGlue.mac.h" #endif // - clean up the log message for the server. // - put the good line feeds // - TODO mac : ISO conversion char *cleanUpLogMsg(const char *msg) { static CStaticAllocT buf; size_t len = strlen(msg); buf.AdjustSize(len + 1); char *tmp = buf; char c; while((c = *msg++) != '\0') { #ifdef WIN32 if(c == '\r') continue; #endif /* WIN32 */ #ifdef macintosh if(c == '\r') c = '\n'; #endif /* macintosh */ *tmp++ = c; } *tmp++ = '\0'; return buf; } void CvsCmdUpdateFolder(const char *dir, bool queryOnly) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to update :"); if(dir == 0L) return; bool toStdout; bool noRecurs; bool resetSticky; CPStr date; CPStr rev; bool useMostRecent; CPStr rev1; CPStr rev2; bool createMissDir; bool getCleanCopy; if(!queryOnly && !CompatGetUpdate(toStdout, noRecurs, resetSticky, date, rev, useMostRecent, rev1, rev2, createMissDir, getCleanCopy)) return; CvsArgs args; if(queryOnly) args.add("-n"); args.add("update"); if(gCvsPrefs.PruneOption()) args.add("-P"); if(!queryOnly) { if(resetSticky) args.add("-A"); if(createMissDir) args.add("-d"); if(getCleanCopy) args.add("-C"); if(!date.empty()) { args.add("-D"); args.add(date); } if(useMostRecent) args.add("-f"); if(!rev1.empty()) { CPStr tmp; tmp = "-j"; tmp << rev1; args.add(tmp); } if(!rev2.empty()) { CPStr tmp; tmp = "-j"; tmp << rev2; args.add(tmp); } if(noRecurs) args.add("-l"); if(toStdout) args.add("-p"); if(!rev.empty()) { args.add("-r"); args.add(rev); } } args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdCommitFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to commit :"); if(dir == 0L) return; bool norecurs; CStr logmsg; bool forceCommit; bool forceRecurse; CPStr rev; bool noModuleProgram; bool checkValidEdits; if( !CompatGetCommit(logmsg, norecurs, forceCommit, forceRecurse, rev, noModuleProgram, checkValidEdits, dir) ) return; CvsArgs args; args.add("commit"); if(checkValidEdits) args.add("-c"); if(norecurs) args.add("-l"); if(noModuleProgram) args.add("-n"); if(forceRecurse) args.add("-R"); if(forceCommit) args.add("-f"); args.add("-m"); args.add(cleanUpLogMsg(logmsg)); if(!rev.empty()) { args.add("-r"); args.add(rev); } args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdDiffFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to diff :"); if(dir == 0L) return; bool noRecurs; bool isDate1; bool isDate2; bool useExtDiff; bool useUnifiedDiff; CPStr rev1; CPStr rev2; bool noWhiteSpace; bool noBlankLines; // will be replaced when options combobox is ready bool ignoreCase; if(!CompatGetDiff(noRecurs, isDate1, isDate2, rev1, rev2, useExtDiff, useUnifiedDiff, noWhiteSpace, noBlankLines, ignoreCase)) return; CvsArgs args; args.add("diff"); if(noRecurs) args.add("-l"); if(!rev1.empty()) { args.add(isDate1 ? "-D" : "-r"); args.add(rev1); } if(!rev2.empty()) { args.add(isDate2 ? "-D" : "-r"); args.add(rev2); } if(noWhiteSpace) args.add("-wb"); // --ignore-all-space --ignore-space-change if(noBlankLines) args.add("-B"); // --ignore-blank-lines if(ignoreCase) args.add("-i"); // --ignore-case if(useUnifiedDiff) args.add("-u"); // --unified, -u args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdAddFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to add :"); if(dir == 0L) return; CStr uppath, folder; if(!SplitPath(dir, uppath, folder)) { cvs_err("Unable to convert path name '%s'\n", dir); return; } CvsArgs args; args.add("add"); args.add(folder); args.print(uppath); launchCVS(uppath, args.Argc(), args.Argv()); } void CvsCmdInit(const char *dir) { if(gCvsPrefs.empty()) return; bool forceCvsroot; if(!CompatGetInit(forceCvsroot)) return; CvsArgs args; if(forceCvsroot) { CStr root; // extract from the cvsroot const char *ccvsroot = gCvsPrefs; ccvsroot = Authen::skiptoken(ccvsroot); root = gAuthen.token(); root << ccvsroot; args.add("-d"); args.add(root); } args.add("init"); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdImportModule(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to import :"); if(dir == 0L) return; ReportConflict * entries; ReportWarning * warnings; if(!CompatImportFilter(dir, entries, warnings)) return; CPStr modname, vendortag, reltag, path(dir); CStr logmsg; bool useDefIgnore; bool useFilesTime; if( !CompatGetImport(modname, logmsg, vendortag, reltag, path, useDefIgnore, useFilesTime) ) return; CvsArgs args; args.add("import"); if( useFilesTime ) { args.add("-d"); } // fill the wrappers ReportConflict * tmpentry = entries; if( !useDefIgnore ) { args.add("-I"); // no default (core, *.o...) args.add("!"); args.add("-I"); // but ignore the CVS folders args.add("CVS"); } while(tmpentry != 0L) { if(tmpentry->HasIgnore()) { CPStr ign; args.add("-I"); if(tmpentry->IsExtension()) ign << '*'; ign << tmpentry->GetPattern(); args.add(ign); } else if( !tmpentry->HasForceText() && (tmpentry->IsBinary() || tmpentry->HasForceBinary() || tmpentry->HasForceNoKeywords() || tmpentry->IsUnicode() || tmpentry->HasForceUnicode()) ) { CPStr wrap; const char *pattern = tmpentry->GetPattern(); bool hasSpace = strchr(pattern, ' ') != 0L; args.add("-W"); if( hasSpace ) wrap << '"'; if( tmpentry->IsExtension() ) wrap << '*'; wrap << pattern; if( hasSpace ) wrap << '"'; if( tmpentry->HasForceNoKeywords() ) wrap << " -k 'o'"; else if( tmpentry->IsUnicode() || tmpentry->HasForceUnicode() ) wrap << " -k 'u'"; else wrap << " -k 'b'"; args.add(wrap); } tmpentry = tmpentry->next; } free_list_types(warnings, entries); args.add("-m"); args.add(cleanUpLogMsg(logmsg)); args.add(modname); args.add(vendortag); args.add(reltag); args.print(path); launchCVS(path, args.Argc(), args.Argv()); } void CvsCmdCheckoutModule(const char *dir) { if(gCvsPrefs.empty()) return; #ifndef WIN32 if(dir == 0L) dir = BrowserGetDirectory("Select a directory to checkout to :"); if(dir == 0L) return; #endif bool norecurs; CPStr modname; CPStr path(dir); bool toStdout; CPStr date; CPStr rev; bool useMostRecent; CPStr rev1; CPStr rev2; bool doexport; bool forceCvsroot; bool overrideCheckoutDir; CPStr checkoutDir; if( !CompatGetCheckout(modname, path, norecurs, toStdout, date, rev, useMostRecent, rev1, rev2, doexport, forceCvsroot, overrideCheckoutDir, checkoutDir) ) { return; } CvsArgs args; if(forceCvsroot) { CStr root; // extract from the cvsroot const char *ccvsroot = gCvsPrefs; ccvsroot = Authen::skiptoken(ccvsroot); root = gAuthen.token(); root << ccvsroot; args.add("-d"); args.add(root); } args.add(doexport ? "export" : "checkout"); if(gCvsPrefs.PruneOption() && !doexport) args.add("-P"); if(norecurs) args.add("-l"); if(toStdout) args.add("-p"); if(useMostRecent) args.add("-f"); if(!rev1.empty()) { CPStr tmp; tmp = "-j"; tmp << rev1; args.add(tmp); } if(!rev2.empty()) { CPStr tmp; tmp = "-j"; tmp << rev2; args.add(tmp); } if(!date.empty()) { args.add("-D"); args.add(date); } if(!rev.empty()) { args.add("-r"); args.add(rev); } if(doexport && rev.empty() && date.empty()) { args.add("-r"); args.add("HEAD"); } if( overrideCheckoutDir ) { args.add("-d"); args.add(checkoutDir); } args.add(modname); args.print(path); launchCVS(path, args.Argc(), args.Argv()); } void CvsCmdRtagCreate(void) { if(gCvsPrefs.empty()) return; bool norecurs; bool useMostRecent; bool overwriteExisting; bool lookAttic; CPStr modname; CPStr tagname; CPStr date; CPStr rev; if(!CompatRtagCreate(norecurs, overwriteExisting, tagname, modname, date, rev, useMostRecent, lookAttic)) return; CvsArgs args; args.add("rtag"); if(norecurs) args.add("-l"); if(useMostRecent) args.add("-f"); if(overwriteExisting) args.add("-F"); if(lookAttic) args.add("-a"); if(!date.empty()) { args.add("-D"); args.add(date); } if(!rev.empty()) { args.add("-r"); args.add(rev); } args.add(tagname); args.add(modname); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdRtagDelete(void) { if(gCvsPrefs.empty()) return; bool norecurs; bool lookAttic; CPStr modname; CPStr tagname; if(!CompatRtagDelete(norecurs, lookAttic, tagname, modname)) return; CvsArgs args; args.add("rtag"); args.add("-d"); if(norecurs) args.add("-l"); if(lookAttic) args.add("-a"); args.add(tagname); args.add(modname); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdRtagBranch(void) { if(gCvsPrefs.empty()) return; bool norecurs; bool useMostRecent; bool lookAttic; CPStr modname; CPStr branchname; CPStr date; CPStr rev; if(!CompatRtagBranch(norecurs, branchname, modname, date, rev, useMostRecent, lookAttic)) return; CvsArgs args; args.add("rtag"); args.add("-b"); if(norecurs) args.add("-l"); if(useMostRecent) args.add("-f"); if(lookAttic) args.add("-a"); if(!date.empty()) { args.add("-D"); args.add(date); } if(!rev.empty()) { args.add("-r"); args.add(rev); } args.add(branchname); args.add(modname); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdLogin(void) { if(gCvsPrefs.empty()) return; if(gAuthen.kind() != pserver) { cvs_err("Logging in is only required with pserver authentication (see Preferences dialog).\n" "Please consult the CVS manual for more details.\n"); return; } if(gCvsPrefs.HasLoogedIn() && gCvsPrefs.LogoutTimeOut() > 0) { cvs_err("Making automatic logout:\n"); CvsCmdLogout(); WaitForCvs(); } gCvsPrefs.SetHasLoogedIn(true); CvsArgs args; args.add("login"); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdLogout(void) { if(gCvsPrefs.empty()) return; if(gAuthen.kind() != pserver) { cvs_err("Logging out requires pserver authentication (see Preferences dialog).\n" "Please consult the CVS manual for more details.\n"); return; } gCvsPrefs.SetHasLoogedIn(false); CvsArgs args; args.add("logout"); args.print(); launchCVS(0L, args.Argc(), args.Argv()); } void CvsCmdUpdateFiles(MultiFiles *mfarg, bool queryOnly) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to update :", mf)) return; mfarg = &mf; } bool toStdout; bool noRecurs; bool resetSticky; CPStr date; CPStr rev; bool useMostRecent; CPStr rev1; CPStr rev2; bool createMissDir; bool getCleanCopy; if(!queryOnly && !CompatGetUpdate(toStdout, noRecurs, resetSticky, date, rev, useMostRecent, rev1, rev2, createMissDir, getCleanCopy)) return; while(mfarg->next()) { CvsArgs args; if(queryOnly) args.add("-n"); args.add("update"); if(!queryOnly) { if(resetSticky) args.add("-A"); if(createMissDir) args.add("-d"); if(getCleanCopy) args.add("-C"); if(!date.empty()) { args.add("-D"); args.add(date); } if(useMostRecent) args.add("-f"); if(!rev1.empty()) { CPStr tmp; tmp = "-j"; tmp << rev1; args.add(tmp); } if(!rev2.empty()) { CPStr tmp; tmp = "-j"; tmp << rev2; args.add(tmp); } /*if(noRecurs) args.add("-l");*/ if(toStdout) args.add("-p"); if(!rev.empty()) { args.add("-r"); args.add(rev); } } const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdCommitFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to commit :", mf)) return; mfarg = &mf; } bool firstTime = true; bool norecurs; CStr logmsg; bool forceCommit; bool forceRecurse; CPStr rev; bool noModuleProgram; bool checkValidEdits; while(mfarg->next()) { if(firstTime) { // we have to give the path where the commit is done is // the user expects to fill the CVS/Template file. we just // grab the first one for this purpose. const char *tmplDir = 0L; CStr pathTmpl, dontCareFile, currRev; if(mfarg->get(0, pathTmpl, dontCareFile, currRev)) tmplDir = pathTmpl; if( !CompatGetCommit(logmsg, norecurs, forceCommit, forceRecurse, rev, noModuleProgram, checkValidEdits, tmplDir, mfarg) ) return; firstTime = false; } CvsArgs args; args.add("commit"); if(checkValidEdits) args.add("-c"); if(norecurs) args.add("-l"); if(noModuleProgram) args.add("-n"); if(forceRecurse) args.add("-R"); if(forceCommit) args.add("-f"); args.add("-m"); args.add(cleanUpLogMsg(logmsg)); if(!rev.empty()) { args.add("-r"); args.add(rev); } const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } #ifdef WIN32 // Windows client may provide file names pointing into subfolders. // The function below removes folder separators by replacing them with dots, // the reason is that temporary file could be created without creating // matching subfolders in the temporary file folder static void FlatenSubFolders(CStr& tmpf) { char* cp = (char*)tmpf; if (cp) { while(*cp) { if (*cp == kPathDelimiter) { *cp = '.'; } cp++; } } } #else #define FlatenSubFolders(tmpf) // no-op on other platforms #endif void CvsCmdDiffFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to diff :", mf)) return; mfarg = &mf; } bool noRecurs; bool isDate1; bool isDate2; bool useExtDiff; bool useUnifiedDiff; CPStr rev1; CPStr rev2; bool noWhiteSpace; bool noBlankLines; bool ignoreCase; bool extDiffResult; if(!CompatGetDiff(noRecurs, isDate1, isDate2, rev1, rev2, useExtDiff, useUnifiedDiff, noWhiteSpace, noBlankLines, ignoreCase, true)) return; while(mfarg->next()) { extDiffResult = false; if (useExtDiff) { CStr path, filename, ext, base, currRev; CStr file1, file2; for(int i = 0; ; i++) { if(!mfarg->get(i, path, filename, currRev)) break; // note that filename can contain subfolders GetExtension(filename, base, ext); CvsArgs args; CStr tmpf(base); tmpf << '_'; if(!rev1.empty()) tmpf << rev1; else tmpf << currRev; tmpf << '_'; // convert subfolder names to regular name FlatenSubFolders(tmpf); args.add("update"); args.add("-p"); if(!rev1.empty()) { args.add(isDate1 ? "-D" : "-r"); args.add(rev1); } else { args.add("-r"); args.add(currRev); } args.add(filename); args.print(path); file1 = launchCVS(path, args, (const char *)tmpf, ext); #ifdef qMacCvsPP decodeCVS (file1); #endif if(rev2.empty()) { file2 = path; if(!file2.endsWith(kPathDelimiter)) file2 << kPathDelimiter; file2 << filename; } else { CvsArgs args2; tmpf = base; tmpf << '_'; tmpf << rev2; tmpf << '_'; // convert subfolder names to regular name FlatenSubFolders(tmpf); args2.add("update"); args2.add("-p"); args2.add(isDate2 ? "-D" : "-r"); args2.add(rev2); args2.add(filename); args2.print(path); file2 = launchCVS(path, args2, (const char *)tmpf, ext); #ifdef qMacCvsPP decodeCVS (file2); #endif } if(file1.empty() || file2.empty()) continue; extDiffResult = LaunchDiff(file1, file2); } } if (!useExtDiff || !extDiffResult) { CvsArgs args; args.add("diff"); if(noRecurs) args.add("-l"); if(!rev1.empty()) { args.add(isDate1 ? "-D" : "-r"); args.add(rev1); } if(!rev2.empty()) { args.add(isDate2 ? "-D" : "-r"); args.add(rev2); } if(useUnifiedDiff) args.add("-u"); // --unified, -u if(noWhiteSpace) args.add("-wb"); //--ignore-all-space --ignore-space-change if(noBlankLines) args.add("-B"); //--ignore-blank-lines if(ignoreCase) args.add("-i"); //--ignore-case const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } } void CvsCmdLogFiles(MultiFiles *mfarg, bool outGraph, void *defWnd) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to log :", mf)) return; mfarg = &mf; } bool noRecurs; bool defBranch; CPStr date; bool headerOnly; bool noTags; bool onlyRCSfile; bool hasRev; CPStr rev; CPStr states; bool hasUser; CPStr users; if( !CompatGetLog(noRecurs, defBranch, date, headerOnly, noTags, onlyRCSfile, hasRev, rev, states, hasUser, users, outGraph) ) { return; } while(mfarg->next()) { CvsArgs args; args.add("log"); if(noRecurs) args.add("-l"); if(defBranch) args.add("-b"); if(headerOnly) args.add("-h"); if(noTags) args.add("-N"); if(onlyRCSfile) args.add("-R"); if(!date.empty()) { args.add("-d"); args.add(date); } if(!states.empty()) { args.add("-s"); args.add(states); } if(hasRev) { CPStr tmp; tmp = "-r"; tmp << rev; args.add(tmp); } if(hasUser) { CPStr tmp; tmp = "-w"; tmp << users; args.add(tmp); } const char *dir = mfarg->add(args); args.print(dir); CvsLogParse(dir, args, outGraph, defWnd); } } class ControlCvsArgs : public CvsArgs { public: ControlCvsArgs() : m_gotProblem(false) { } virtual void addfile(const char* arg, const char* dir = 0L, const UFSSpec* spec = 0L); inline bool HasProblem(void) const { return m_gotProblem; } inline void SetProblem(bool newState) { m_gotProblem = newState; } protected: virtual kTextBinTYPE FileIsType(const char* arg, const char* dir, const UFSSpec* spec = 0L) = 0; virtual const char* TypeDesc() = 0; private: bool m_gotProblem; }; void ControlCvsArgs::addfile(const char* arg, const char* dir, const UFSSpec* spec) { CvsArgs::addfile(arg, dir, spec); if(!gCvsPrefs.AddControl()) return; #if TARGET_RT_MAC_CFM // here a bug of MSL : it refuses to open a file beginning by // ".". So we skip this file out of the test and warn the user. if(arg[0] == '.') { cvs_out("Warning : \'%s\' cannot be verified due to a bug in MW MSL, please\n", arg); cvs_out(" verify manually \'%s\' *is* a %s file\n", arg, TypeDesc()); return; } #endif kTextBinTYPE state = FileIsType(arg, dir, spec); switch(state) { case kFileIsOK: break; case kFileMissing: // we can resurect a file which is missing by re-adding it break; case kFileIsAlias: cvs_err("Warning : \'%s\' is an alias\n", arg); SetProblem(true); break; case kFileInvalidName: cvs_err("Warning : \'%s\' has an invalid name\n", arg); SetProblem(true); break; case kTextWrongLF: cvs_err("Warning : \'%s\' seems to have the wrong line feed for this machine, you should correct it first\n", arg); SetProblem(true); break; case kUnicodeIsBinary: // fall thru intentional case kTextIsBinary: cvs_err("Warning : \'%s\' seems to be \'binary\', you should use the \'Add binary\' command instead...\n", arg); SetProblem(true); break; case kTextEscapeChar: #ifdef macintosh if(gCvsPrefs.IsoConvert() == ISO8559_none) { cvs_err("Warning : \'%s\' has some escape characters in it (0x00-0x20, 0x80-0xFF),\n", arg); cvs_err("Warning so you may need to have the ISO8559 translation option set in the preferences\n"); cvs_err("Warning before commiting\n"); } #else /* !macintosh */ cvs_err("Warning : \'%s\' has some escape characters in it (0x00-0x20, 0x80-0xFF), you should correct it first\n", arg); #endif /* !macintosh */ break; case kTextWrongSig: cvs_err("Warning : \'%s\' has a file type different from \'TEXT\', you should correct it first\n", arg); SetProblem(true); break; case kUnicodeIsText: // fall thru intentional case kBinIsText: cvs_err("Warning : \'%s\' seems to be a text file, you should consider to use the \'Add selection\' command instead\n", arg); SetProblem(true); break; case kBinWrongSig: cvs_err("Warning : \'%s\' has a file type of \'TEXT\', you should correct it first\n", arg); SetProblem(true); break; case kTextIsUnicode: // fall thru intentional case kBinIsUnicode: cvs_err("Warning : \'%s\' seems to be an Unicode file, you should consider to use the \'Add unicode\' command instead\n", arg); SetProblem(true); break; default: cvs_err("Warning : \'%s\' has some unknown problems\n", arg); SetProblem(true); break; } } class AddCvsArgs : public ControlCvsArgs { protected: virtual kTextBinTYPE FileIsType(const char* arg, const char* dir, const UFSSpec* spec = 0L) { return FileIsText(arg, dir, spec); } virtual const char* TypeDesc() { return "TEXT"; } }; void CvsCmdAddFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to add :", mf)) return; mfarg = &mf; } while(mfarg->next()) { AddCvsArgs args; args.add("add"); const char *dir = mfarg->add(args); if(!args.HasProblem() || !CvsAlert("Some problems have been found while adding files and should be corrected", "Cancel", "Ignore")) { args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } } class AddBinCvsArgs : public ControlCvsArgs { protected: virtual kTextBinTYPE FileIsType(const char* arg, const char* dir, const UFSSpec* spec = 0L) { return FileIsBinary(arg, dir, spec); } virtual const char* TypeDesc() { return "binary"; } }; void CvsCmdAddBinaryFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select binary files to add :", mf)) return; mfarg = &mf; } while(mfarg->next()) { AddBinCvsArgs args; args.add("add"); args.add("-kb"); const char *dir = mfarg->add(args); if(!args.HasProblem() || !CvsAlert("Some problems have been found while adding binary files and should be corrected", "Cancel", "Ignore")) { args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } } class AddUnicodeCvsArgs : public ControlCvsArgs { protected: virtual kTextBinTYPE FileIsType(const char* arg, const char* dir, const UFSSpec* spec = 0L) { return FileIsUnicode(arg, dir, spec); } virtual const char* TypeDesc() { return "Unicode"; } }; void CvsCmdAddUnicodeFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select unicode files to add :", mf)) return; mfarg = &mf; } while(mfarg->next()) { AddUnicodeCvsArgs args; args.add("add"); args.add("-ku"); const char *dir = mfarg->add(args); if(!args.HasProblem() || !CvsAlert("Some problems have been found while adding unicode files and should be corrected", "Cancel", "Ignore")) { args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } } class RemoveCvsArgs : public CvsArgs { public: virtual void addfile(const char *arg, const char *dir = 0L, const UFSSpec *spec = 0L); }; void RemoveCvsArgs::addfile(const char *arg, const char *dir, const UFSSpec *spec) { CvsArgs::addfile(arg, dir, spec); CStr fullpath(dir); if(!fullpath.endsWith(kPathDelimiter)) fullpath << kPathDelimiter; fullpath << arg; // check the file is not already deleted struct stat sb; if (stat(dir, &sb) != -1 && S_ISDIR(sb.st_mode) && stat(fullpath, &sb) == -1 && errno == ENOENT) { return; } if(!CompatMoveToTrash(arg, dir, spec)) #ifdef WIN32 cvs_err("Unable to send \'%s\' to the recycle bin\n", arg); else cvs_out("\'%s\' has been moved successfully to the recycle bin...\n", arg); #elif !defined(macintosh) cvs_err("Unable to send \'%s\' to the trash\n", arg); else cvs_out("\'%s\' has been moved successfully to trash...\n", arg); #else {} #endif } void CvsCmdRemoveFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to remove :", mf)) return; mfarg = &mf; } while(mfarg->next()) { RemoveCvsArgs args; CompatBeginMoveToTrash(); args.add("remove"); const char *dir = mfarg->add(args); args.print(dir); CompatEndMoveToTrash(); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdStatusFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to status :", mf)) return; mfarg = &mf; } bool noRecurs = false; STATUSOUTPUT_TYPE outputType = STATUSOUTPUT_VERBOSE; #ifdef WIN32 if( !CompatGetStatus(noRecurs, outputType) ) return; #endif while(mfarg->next()) { CvsArgs args; args.add("status"); if( noRecurs ) args.add("-l"); if( STATUSOUTPUT_VERBOSE == outputType ) args.add("-v"); else if( STATUSOUTPUT_QUICK == outputType ) args.add("-q"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdCancelChangesFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to cancel changes :", mf)) return; mfarg = &mf; } while(mfarg->next()) { RemoveCvsArgs args; args.add("update"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdLine(void) { CvsArgs args(false); const char *dir; if(!CompatGetCommand(args, dir)) return; args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdLogFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to log :"); if(dir == 0L) return; bool noRecurs; bool defBranch; CPStr date; bool headerOnly; bool noTags; bool onlyRCSfile; bool hasRev; CPStr rev; CPStr states; bool hasUser; CPStr users; if(!CompatGetLog(noRecurs, defBranch, date, headerOnly, noTags, onlyRCSfile, hasRev, rev, states, hasUser, users)) return; CvsArgs args; args.add("log"); if(noRecurs) args.add("-l"); if(defBranch) args.add("-b"); if(headerOnly) args.add("-h"); if(noTags) args.add("-N"); if(onlyRCSfile) args.add("-R"); if(!date.empty()) { args.add("-d"); args.add(date); } if(!states.empty()) { args.add("-s"); args.add(states); } if(hasRev) { CPStr tmp; tmp = "-r"; tmp << rev; args.add(tmp); } if(hasUser) { CPStr tmp; tmp = "-w"; tmp << users; args.add(tmp); } args.print(dir); CvsLogParse(dir, args, false, NULL); } void CvsCmdStatusFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to get status :"); if(dir == 0L) return; bool noRecurs = false; STATUSOUTPUT_TYPE outputType = STATUSOUTPUT_VERBOSE; #ifdef WIN32 if( !CompatGetStatus(noRecurs, outputType) ) return; #endif CvsArgs args; args.add("status"); if( noRecurs ) args.add("-l"); if( STATUSOUTPUT_VERBOSE == outputType ) args.add("-v"); else if( STATUSOUTPUT_QUICK == outputType ) args.add("-q"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdLockFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to lock :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("admin"); args.add("-l"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdUnlockFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to unlock :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("admin"); args.add("-u"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdTagCreateFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to tag :", mf)) return; mfarg = &mf; } bool noRecurs, overwriteExisting, checkUnmod; CPStr tagName; if(!CompatTagCreate(noRecurs, overwriteExisting, tagName, checkUnmod)) return; while(mfarg->next()) { CvsArgs args; args.add("tag"); if(noRecurs) args.add("-l"); if(overwriteExisting) args.add("-F"); if(checkUnmod) args.add("-c"); args.add(tagName); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdTagDeleteFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to untag :", mf)) return; mfarg = &mf; } bool noRecurs; CPStr tagName; if(!CompatTagDelete(noRecurs, tagName)) return; while(mfarg->next()) { CvsArgs args; args.add("tag"); args.add("-d"); if(noRecurs) args.add("-l"); args.add(tagName); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdTagBranchFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to branch :", mf)) return; mfarg = &mf; } bool noRecurs, checkUnmod; CPStr branchName; if(!CompatTagBranch(noRecurs, branchName, checkUnmod)) return; while(mfarg->next()) { CvsArgs args; args.add("tag"); args.add("-b"); if(noRecurs) args.add("-l"); if(checkUnmod) args.add("-c"); args.add(branchName); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdLockFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to lock :"); if(dir == 0L) return; CvsArgs args; args.add("admin"); args.add("-l"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdUnlockFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to unlock :"); if(dir == 0L) return; CvsArgs args; args.add("admin"); args.add("-u"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdTagCreateFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to tag :"); if(dir == 0L) return; bool noRecurs, overwriteExisting, checkUnmod; CPStr tagName; if(!CompatTagCreate(noRecurs, overwriteExisting, tagName, checkUnmod)) return; CvsArgs args; args.add("tag"); if(noRecurs) args.add("-l"); if(overwriteExisting) args.add("-F"); if(checkUnmod) args.add("-c"); args.add(tagName); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdTagDeleteFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to untag :"); if(dir == 0L) return; bool noRecurs; CPStr tagName; if(!CompatTagDelete(noRecurs, tagName)) return; CvsArgs args; args.add("tag"); args.add("-d"); if(noRecurs) args.add("-l"); args.add(tagName); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdTagBranchFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to branch :"); if(dir == 0L) return; bool noRecurs, checkUnmod; CPStr tagName; if(!CompatTagBranch(noRecurs, tagName, checkUnmod)) return; CvsArgs args; args.add("tag"); args.add("-b"); if(noRecurs) args.add("-l"); if(checkUnmod) args.add("-c"); args.add(tagName); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdEditFiles(MultiFiles *mfarg /*= 0L*/, kEditCmdType editType /*= kNormal*/) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to edit :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("edit"); switch( editType ) { default: case kEditNormal: // intentionally blank break; case kEditReserved: args.add("-c"); break; case kEditForce: args.add("-f"); break; } const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdUneditFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to unedit :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("unedit"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdWatchOnFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to watch :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("watch"); args.add("add"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdWatchOffFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to unwatch :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("watch"); args.add("remove"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdWatchersFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to get the watchers from :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("watchers"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdEditorsFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select the files to get the editors from :", mf)) return; mfarg = &mf; } while(mfarg->next()) { CvsArgs args; args.add("editors"); const char *dir = mfarg->add(args); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } } void CvsCmdEditFolder(const char *dir /*= 0L*/, kEditCmdType editType /*= kEditNormal*/) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to edit :"); if(dir == 0L) return; CvsArgs args; args.add("edit"); switch( editType ) { default: case kEditNormal: // intentionally blank break; case kEditReserved: args.add("-c"); break; case kEditForce: args.add("-f"); break; } args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdUneditFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to unedit :"); if(dir == 0L) return; CvsArgs args; args.add("unedit"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdWatchOnFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to watch :"); if(dir == 0L) return; CvsArgs args; args.add("watch"); args.add("add"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdWatchOffFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to unwatch :"); if(dir == 0L) return; CvsArgs args; args.add("watch"); args.add("remove"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdReleaseFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to release :"); if(dir == 0L) return; CStr uppath, folder; if( !SplitPath(dir, uppath, folder) ) { cvs_err("Unable to convert path name '%s'\n", dir); //even thought something didn't work we will try to continue and put all the responsibility onto the user uppath = dir; folder = "."; } bool removeDirectory = false; if( !CompatGetRelease(dir, removeDirectory) ) { return; } CvsArgs args; args.add("release"); if( removeDirectory ) args.add("-d"); args.add(folder); args.print(uppath); launchCVS(uppath, args.Argc(), args.Argv()); } void CvsCmdWatchersFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to get the watchers from :"); if(dir == 0L) return; CvsArgs args; args.add("watchers"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdEditorsFolder(const char *dir) { if(gCvsPrefs.empty()) return; if(dir == 0L) dir = BrowserGetDirectory("Select a directory to get the editors from :"); if(dir == 0L) return; CvsArgs args; args.add("editors"); args.print(dir); launchCVS(dir, args.Argc(), args.Argv()); } void CvsCmdMacrosAdmin(const char *macroName) { if(gCvsPrefs.empty() || !CTcl_Interp::IsAvail()) return; CTcl_Interp interp; CStr path = macroName; CTcl_Interp::Unixfy(path); interp.DoScriptVar("source \"%s\"", (const char *)path); } void CvsCmdAnnotateFiles(MultiFiles *mfarg) { if(gCvsPrefs.empty()) return; MultiFiles mf; if(mfarg == 0L) { if(!BrowserGetMultiFiles("Select files to annotate :", mf)) return; mfarg = &mf; } bool noRecurs; bool isDate; CPStr rev; bool force; if(!CompatGetAnnotate(noRecurs, isDate, rev, force)) return; while(mfarg->next()) { CStr path, filename, ext, base, currRev; CStr file; for(int i = 0; ; i++) { if(!mfarg->get(i, path, filename, currRev)) break; // note that filename can contain subfolders GetExtension(filename, base, ext); CvsArgs args; CStr tmpf(base); if(!rev.empty()) { tmpf << "_ann_"; tmpf << rev; tmpf << '_'; } else tmpf << "_ann_"; // convert subfolder names to regular name FlatenSubFolders(tmpf); args.add("annotate"); if(noRecurs) { args.add("-l"); } if(force) { args.add("-f"); } if(!rev.empty()) { args.add(isDate ? "-D" : "-r"); args.add(rev); } args.add(filename); args.print(path); file = launchCVS(path, args, (const char *)tmpf, ext); #ifdef qMacCvsPP decodeCVS (file); #endif if(file.empty()) continue; LaunchViewer(file, true); } } }