/* ** 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 */ /* * ImportFilter.cpp : filter the imported files before importing */ #include "stdafx.h" #ifdef WIN32 # include "resource.h" #endif /* WIN32 */ #ifdef macintosh # include "GUSIInternal.h" # include "GUSIFileSpec.h" # include "MacMisc.h" #endif /* macintosh */ #include "ImportFilter.h" #include "AppConsole.h" // // MN - Apply $HOME/.cvsignore to import filter // // list_add_type function uses ignore filter to decided whether // a file should be ignored in importing (user can change this // in import dialogbox, but this is a default). If user imports // a whole subdirectory instead of a file then this will // eliminate ignored files. // #include "CvsIgnore.h" #if qCvsDebug # include "CvsAlert.h" #endif /* qCvsDebug */ #ifdef macintosh static const char *lf = "\r"; #elif defined(WIN32) static const char *lf = "\r\n"; #else static const char *lf = "\n"; #endif #ifdef WIN32 # ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; # endif #endif /* WIN32 */ #ifndef NEW #define NEW new #endif ReportConflict::ReportConflict(int mac_type, int mac_creator) { next = 0L; status = noConflict; ftype = mac_type; fcreator = mac_creator; } void ReportConflict::PrintOut(CStr & out) const { out = ""; if(HasConflict()) { out << "Text/Binary conflict, at least these files :"; out << lf; if(!sample1.empty() && !sample2.empty()) { out << " "; out << sample1; out << " and "; out << sample2; out << lf; } } else if(HasTypeCreatorConflict()) { out << "Mac signature mismatch for this type, at least these files :"; out << lf; if(!sample1.empty() && !sample2.empty()) { out << " "; out << sample1; out << " and "; out << sample2; out << lf; } } } #if qCvsDebug void ReportConflict::PrintOut(void) const { if(pattern.empty()) return; cvs_out(" New type : %s%s (%s)\n", (status & hasExtension) ? "*" : "", (const char *)pattern, (status & isBinary) ? "BINARY" : "TEXT" ); if(!sample1.empty() && !sample2.empty()) { if(HasConflict()) cvs_out(" Text/Binary CONFLICT ! %s and %s\n", (const char *)sample1, (const char *)sample2); else if(HasTypeCreatorConflict()) cvs_out(" Mac signature mismatch ! %s and %s\n", (const char *)sample1, (const char *)sample2); } } #endif /* qCvsDebug */ ReportConflict::~ReportConflict() { } void ReportConflict::AddPattern(const char *newpat, kFileType fileType, bool isExt, const char *sample) { pattern = newpat; sample1 = sample; switch( fileType ) { case kFileTypeBin: status |= isBinary; break; case kFileTypeUnicode: status |= isUnicode; break; default: // nothing to do break; } if(isExt) status |= hasExtension; } bool ReportConflict::Match(const char *pat) { if(pat == 0L || pattern.empty()) return false; int len = strlen(pat); int patlen = pattern.length(); if(status & hasExtension) { if(len < patlen) return false; // since it is the server who compares against the pattern, // that might be a case compare #if 0 //def WIN32 return stricmp(pattern, pat + len - patlen) == 0; #else /* !WIN32 */ return strcmp(pattern, pat + len - patlen) == 0; #endif /* !WIN32 */ } #if 0 //def WIN32 return stricmp(pattern, pat) == 0; #else /* !WIN32 */ return strcmp(pattern, pat) == 0; #endif /* !WIN32 */ } void ReportConflict::SetConflict(const char *sample) { // one is enough ! if(HasConflict()) return; sample2 = sample; status |= hasConflict; } void ReportConflict::SetTypeCreatorConflict(const char *sample) { // one is enough ! if(HasTypeCreatorConflict() || HasConflict()) return; sample2 = sample; status |= hasTypeCreatorConflict; } const size_t ReportWarning::maxWarnings = 10; ReportWarning::ReportWarning(kTextBinTYPE akind) { kind = akind; next = 0L; tooMuchWarnings = false; } ReportWarning::~ReportWarning() { } void ReportWarning::PrintOut(CStr & out) const { out = ""; if(samples.size() == 0) return; out = "Warning : "; switch(kind) { default: case kFileIsOK: out << "Files are OK"; break; case kFileMissing: out << "Files are missing or unreadable"; break; case kFileIsAlias: out << "Files are aliases"; break; case kFileInvalidName: out << "Files have invalid name"; break; case kTextWrongLF: out << "Files have the wrong line feed"; break; case kTextIsBinary: out << "Files are binary"; break; case kTextEscapeChar: out << "Files have escape characters in it"; break; case kTextWrongSig: out << "Text files have the wrong signature"; break; case kBinIsText: out << "Files are text, should be binary"; break; case kBinWrongSig: out << "Binary files have the wrong signature"; break; case kTextIsUnicode: out << "Files are unicode, should be text"; break; case kBinIsUnicode: out << "Files are unicode, should be binary"; break; } out << lf; std::vector::const_iterator i; for(i = samples.begin(); i != samples.end(); ++i) { out << " "; out << *i; out << lf; } if(tooMuchWarnings) { out << " More files follow"; out << lf; } } #if qCvsDebug void ReportWarning::PrintOut(void) const { if(samples.size() == 0) return; cvs_out(" Warning : "); switch(kind) { default: case kFileIsOK: cvs_out("Files are OK\n"); break; case kFileMissing: cvs_out("Files are missing or unreadable\n"); break; case kFileIsAlias: cvs_out("Files are aliases\n"); break; case kFileInvalidName: cvs_out("Files have invalid name\n"); break; case kTextWrongLF: cvs_out("Files have the wrong line feed\n"); break; case kTextIsBinary: cvs_out("Files are binary\n"); break; case kTextEscapeChar: cvs_out("Files have escape characters in it\n"); break; case kTextWrongSig: cvs_out("Text files have the wrong signature\n"); break; case kBinIsText: cvs_out("Files are text, should be binary\n"); break; case kBinWrongSig: cvs_out("Binary files have the wrong signature\n"); break; case kTextIsUnicode: cvs_out("Files are unicode, should be text\n"); break; case kBinIsUnicode: cvs_out("Files are unicode, should be binary\n"); break; } std::vector::const_iterator i; for(i = samples.begin(); i != samples.end(); ++i) { cvs_out(" %s\n", (const char *)(*i)); } if(tooMuchWarnings) cvs_out(" More files follow\n"); } #endif /* qCvsDebug */ void ReportWarning::AddWarning(const char *sample) { // it's enough ! if(samples.size() >= maxWarnings) { tooMuchWarnings = true; return; } samples.push_back(CStr(sample)); } static void list_add_warning(ReportWarning *& warnings, kTextBinTYPE warn, const char *sample) { // find if it exists already a same kind of warning ReportWarning *tmp = warnings; while(tmp != 0L) { if(tmp->Kind() == warn) break; tmp = tmp->next; } if(tmp != 0L && tmp->Kind() == warn) { tmp->AddWarning(sample); return; } // insert new one tmp = NEW ReportWarning(warn); if(tmp == 0L) { cvs_err("Impossible to allocate %d bytes !\n", sizeof(ReportWarning)); return; } tmp->AddWarning(sample); if(warnings == 0L) { warnings = tmp; } else { tmp->next = warnings; warnings = tmp; } } class ImportReport; static void list_add_type(ImportReport *impReport, ReportConflict *& conflicts, kFileType fileType, const char *sample, const char *fullname, int mac_type, int mac_creator); class ImportReport : public TraversalReport { public: ImportReport(const char *path, ReportWarning *& w, ReportConflict *& c) : warnings(w), conflicts(c) { // MN - Apply ignore filter to import file list BuildIgnoredList(m_Ignlist, path); } virtual ~ImportReport() {} ReportWarning *& warnings; ReportConflict *& conflicts; std::vector m_Ignlist; // MN - Ignore list virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const UFSSpec * macspec) { cvs_out("Filtering \'%s\'...\n", fullpath); return kContinueTraversal; } virtual kTraversal ExitDirectory(const char *fullpath) { return kContinueTraversal; } virtual kTraversal OnError(const char *err, int errcode) { list_add_warning(warnings, kFileMissing, err); return kContinueTraversal; } virtual kTraversal OnIdle(const char *fullpath) { return kContinueTraversal; } virtual kTraversal OnDirectory(const char *fullpath, const char *fullname, const char *name, const struct stat & dir, const UFSSpec * macspec) { #if defined(WIN32) || defined(macintosh) if(stricmp(name, "CVS") == 0) #else if(strcmp(name, "CVS") == 0) #endif return kSkipFile; return kContinueTraversal; } virtual kTraversal OnFile(const char *fullpath, const char *fullname, const char *name, const struct stat & dir, const UFSSpec * macspec) { int mac_type = 0; int mac_creator = 0; #ifdef macintosh # define MACSPEC , &fsSpec GUSIFileSpec inspec(fullname); # if TARGET_RT_MAC_CFM mac_type = inspec.CatInfo()->FileInfo().ioFlFndrInfo.fdType; mac_creator = inspec.CatInfo()->FileInfo().ioFlFndrInfo.fdCreator; # else FInfo finfo; memcpy(&finfo, inspec.CatInfo()->Info().finderInfo, 2 * sizeof(OSType)); mac_type = finfo.fdType; mac_creator = finfo.fdCreator; # endif UFSSpec fsSpec = inspec; #else /* !macintosh */ # define MACSPEC #endif /* !macintosh */ kFileType newType = kFileTypeText; kTextBinTYPE filetype = FileIsText(name, fullpath MACSPEC); if( kTextIsBinary == filetype || kTextWrongSig == filetype ) { kTextBinTYPE bintype = FileIsBinary(name, fullpath MACSPEC); if( kFileIsOK != bintype ) { list_add_warning(warnings, bintype, fullname); } else if( kTextWrongSig == filetype ) { list_add_warning(warnings, filetype, fullname); filetype = kTextIsBinary; newType = kFileTypeBin; } if( kFileIsOK == bintype ) { newType = kFileTypeBin; } } else if( kTextIsUnicode == filetype ) { newType = kFileTypeUnicode; } else if( kFileIsOK != filetype ) { list_add_warning(warnings, filetype, fullname); } // add the type list_add_type(this, conflicts, newType, name, fullname, mac_type, mac_creator); return kContinueTraversal; } virtual kTraversal OnAlias(const char *fullpath, const char *fullname, const char *name, const struct stat & dir, const UFSSpec * macspec) { list_add_warning(warnings, kFileIsAlias, fullname); return kContinueTraversal; } }; // // MN - Had to move this function after class ImportReport, because // this function uses a variable of that type. // // When a file is added to warning/conflict list, it is also // processed through ignore filter. If file should be ignored // then the initial state is "IGNORE" in import dialogbox. // static void list_add_type(ImportReport *impReport, ReportConflict *& conflicts, kFileType fileType, const char *sample, const char *fullname, int mac_type, int mac_creator) { // look for a matching entry ReportConflict *entry = conflicts; while(entry != 0L) { if(entry->Match(sample)) { if(entry->HasConflict()) return; if(entry->IsBinary() ^ (kFileTypeBin == fileType)) entry->SetConflict(fullname); if(entry->IsUnicode() ^ (kFileTypeUnicode == fileType)) entry->SetConflict(fullname); // mac only if(entry->GetMacType() != mac_type || entry->GetMacCreator() != mac_creator) entry->SetTypeCreatorConflict(fullname); // it matches perfectly return; } entry = entry->next; } // find the extension const char *tmp = sample, *ext = 0L; while((tmp = strchr(tmp, '.')) != 0L) { ext = tmp++; } // add a new entry ReportConflict *newc = NEW ReportConflict(mac_type, mac_creator); if(newc == 0L) { cvs_err("Impossible to allocate %d bytes !\n", sizeof(ReportConflict)); return; } newc->AddPattern(ext != 0L ? ext : sample, fileType, ext != 0L, fullname); if(conflicts == 0L) conflicts = newc; else { newc->next = conflicts; conflicts = newc; } // MN - Apply ignore filter. If $HOME/.cvsignore tells that // file should be ignored then set object to ignored state. if(MatchIgnoredList(sample, impReport->m_Ignlist)) newc->Ignore(); } kTraversal list_all_types_recur(const char *path, ReportWarning *& warnings, ReportConflict *& conflicts) { ImportReport report(path, warnings, conflicts); return FileTraverse(path, report); } void free_list_types(ReportWarning * warnings, ReportConflict * conflicts) { ReportWarning *tmpwarn; ReportWarning *warn = warnings; while(warn != 0L) { tmpwarn = warn; warn = warn->next; delete tmpwarn; } ReportConflict *tmpconf; ReportConflict *conf = conflicts; while(conf != 0L) { tmpconf = conf; conf = conf->next; delete tmpconf; } } #if qCvsDebug bool list_all_types(const char *path) { ReportWarning * warnings = 0L; ReportConflict * conflicts = 0L; list_all_types_recur(path, warnings, conflicts); cvs_out("Reporting warnings :\n"); ReportWarning *warn = warnings; while(warn != 0L) { warn->PrintOut(); warn = warn->next; } cvs_out("Reporting types :\n"); ReportConflict *conf = conflicts; while(conf != 0L) { conf->PrintOut(); conf = conf->next; } free_list_types(warnings, conflicts); return !CvsAlert("Continue importing ?", "Cancel", "Continue"); } #endif /* qCvsDebug */