#include "ET++.ph" #ifdef __GNUG__ #pragma implementation #endif #include "FileData.h" #include "Class.h" #include "OrdColl.h" #include "FileBuf.h" #include "String.h" #include "System.h" #include "Directory.h" #include "Converter.h" #include "TypeMatcher.h" #include "CType.h" #include "File.h" #include "ProgressFilter.h" #include "ListSelectorDialog.h" extern Converter *gEtConverter; extern OrdCollection *gConverters; enum ePathInfoFlags { ePiExec = 1, ePiDir = 2, ePiSpecial = 4 }; const Symbol cDocTypeCPlusPlus("C++"), cDocTypeDirectory("DIRECTORY"), cDocTypeExec("EXEC"), cDocTypeOFile("OFILE"); #include "exec.xpm3" SmartBitmap gExecIcon(exec); #include "directory.xpm3" SmartBitmap gDirectoryIcon(directory); //---- CFileTypeMatcher -------------------------------------------------------- class CFileTypeMatcher: public TypeMatcher { public: CFileTypeMatcher() : TypeMatcher(cDocTypeCPlusPlus, 0, 0, TRUE) { } bool MatchExtension(Data *data, const char *ext); bool MatchNameAndContents(Data *data, const char *path, const char *buf, int len); }; static CFileTypeMatcher cmatcher; bool CFileTypeMatcher::MatchExtension(Data*, const char *ext) { if (ext[1] == '\0' && strchr("cChH", ext[0])) return TRUE; if (strcmp(ext, "cp") == 0) return TRUE; if (strcmp(ext, "cxx") == 0) return TRUE; return FALSE; } bool CFileTypeMatcher::MatchNameAndContents(Data *data, const char *pathname, const char*, int) { return MatchPathName(data, pathname, strlen(pathname)); } //---- OFileTypeMatcher -------------------------------------------------------- class OFileTypeMatcher: public TypeMatcher { public: OFileTypeMatcher() : TypeMatcher(cDocTypeOFile, 0, 0, FALSE) { } bool MatchExtension(Data *data, const char *ext); bool MatchNameAndContents(Data *data, const char *path, const char *buf, int len); }; static OFileTypeMatcher omatcher; bool OFileTypeMatcher::MatchExtension(Data*, const char *ext) { return (ext[0] == 'o' && ext[1] == '\0'); } bool OFileTypeMatcher::MatchNameAndContents(Data *data, const char *pathname, const char*, int) { return MatchPathName(data, pathname, strlen(pathname)); } //---- DirectoryMatcher -------------------------------------------------------- class DirectoryMatcher: public TypeMatcher { public: DirectoryMatcher() : TypeMatcher(cDocTypeDirectory, 0, 0, FALSE, 10000) { } bool MatchNameAndContents(Data*, const char *pathname, const char*, int); Bitmap *GetBitmap() { return gDirectoryIcon; } bool MatchPathName(Data*, const char *pathname, int len); }; static DirectoryMatcher directorymatcher; bool DirectoryMatcher::MatchPathName(Data *data, const char *pathname, int) { return MatchNameAndContents(data, pathname, 0, 0); } bool DirectoryMatcher::MatchNameAndContents(Data*, const char *pathname, const char*, int) { u_long flgs= 0; if (strcmp(pathname, ".") == 0 || strcmp(pathname, "..") == 0) return TRUE; if (gSystem->GetPathInfo(pathname, 0, 0, &flgs, 0) == 0) { if (flgs & ePiDir) return TRUE; } return FALSE; } //---- ExecMatcher ------------------------------------------------------------- class ExecMatcher: public TypeMatcher { public: ExecMatcher() : TypeMatcher(cDocTypeExec, 0, 0, FALSE, 10001) { } bool MatchNameAndContents(Data*, const char *pathname, const char*, int); Bitmap *GetBitmap() { return gExecIcon; } }; static ExecMatcher execmatcher; bool ExecMatcher::MatchNameAndContents(Data*, const char *pathname, const char*, int) { u_long flgs= 0; if (gSystem->GetPathInfo(pathname, 0, 0, &flgs, 0) == 0) { if ((flgs & ePiExec) && !(flgs & ePiDir)) return TRUE; } return FALSE; } //---- FileData ---------------------------------------------------------------- NewMetaImpl(FileData, Data, (TP(converter), TB(lookDeep))); static int untitledCnt; FileData::FileData(const char *nm, bool deep) : Data(nm) { lookDeep= deep; converter= 0; if (nm) { UpdateBit(eDataNew, FALSE); } else { strfreplace(&name, "untitled.%d", untitledCnt++); UpdateBit(eDataNew, TRUE); } } FileData::~FileData() { converter= 0; } void FileData::SetName(const char *nm) { flags= 0; if (nm) { strreplace(&name, nm); UpdateBit(eDataNew, FALSE); } else { strfreplace(&name, "untitled.%d", untitledCnt++); UpdateBit(eDataNew, TRUE); } } const char *FileData::FullName() { if (!IsUntitled() && name[0] != '/') { const char *wd= gSystem->WorkingDirectory(); if (strcmp(name, ".") == 0) strreplace(&name, wd); else { if (wd && strcmp(wd, "/")) strfreplace(&name, "%s/%s", wd, name); else strfreplace(&name, "/%s", name); } } return name; } const char *FileData::ShortName() { return (char*) BaseName(FullName()); } const char *FileData::GetLoadDir() { return gSystem->DirName(FullName()); } Converter *FileData::GetConverter() { if (converter == 0) converter= gEtConverter; return converter; } void FileData::SetConverter(Converter *cv) { converter= cv; } u_long FileData::UpdateFields(u_long f) { if (!TESTBIT(flags, f)) { switch (f) { case eDataId: case eDataSize: case eDataTime: case eDataExec: case eDataValid: u_long ff; bool valid= gSystem->GetPathInfo(FullName(), &uniqueid, (u_long*)&sizehint, &ff, &modtime) == 0; SETBIT(flags, eDataId); SETBIT(flags, eDataSize); SETBIT(flags, eDataTime); UpdateBit(eDataExec, (u_int)(ff & ePiExec)); UpdateBit(eDataValid, valid); break; case eDataType: if (lookDeep) { Data::UpdateFields(f); } else { typematcher= TypeMatcher::MatchByName(this); if (typematcher && type == cDocTypeUndef) type= typematcher->GetType(); SETBIT(flags, eDataType); if (type == cDocTypeDirectory) SETBIT(flags, eDataDeepType); // no need to look deeper } break; case eDataDeepType: case eDataCreator: Data::UpdateFields(f); break; case eDataRead: UpdateBit(eDataRead, !gSystem->AccessPathName(FullName(), 4)); break; case eDataWrite: { const char *nm= FullName(); if (gSystem->AccessPathName(nm, 0)) { char *p= strrchr(nm, '/'), buf[1000]; if (p) { strcpy(buf, nm); p= strrchr(buf, '/'); *p= 0; } else strcpy(buf, "."); nm= buf; } UpdateBit(eDataWrite, !gSystem->AccessPathName(nm, 2)); } break; case eDataNew: //UpdateBit(eDataNew, *FullName() != '/'); break; } } return 0; } Object *FileData::MakeObject(Class *want) { if (converter == 0) { if (gConverters == 0 || gConverters->Size() <= 0) { if (gConverters == 0) gConverters= new OrdCollection; Converter::FindConverter(this, want, gConverters); } if (gConverters->Size() > 1) converter= (Converter*) ListSelectorDialog::Select(gConverters, "Select Converter"); else if (gConverters->Size() == 1) converter= (Converter*) gConverters->At(0); else converter= 0; } SafeDelete(gConverters); if (converter && converter->CanConvert(this, want)) return converter->Convert(this, want); return 0; } void FileData::StartUpdate() { if (!IsUntitled() && IsReadable()) gSystem->Exec(form("cp %s %s%s", FullName(), FullName(), "%")); } void FileData::EndUpdate(bool isok, bool removebackup) { if (!isok) gSystem->Exec(form("cp %s%s %s", FullName(), "%", FullName())); if (isok && removebackup) File::Unlink(form("%s%s", FullName(), "%")); } StreamBuf *FileData::GetStreamBuf(bool forwriting) { if (forwriting) { return new Filebuf(FullName(), output); } else { StreamBuf *osb= new Filebuf(FullName(), input); //StreamBuf *sb= new ProgressFilter; //sb->SetBaseStream(osb); //return sb; return osb; } } SeqCollection *FileData::GetContents() { const char *nm, *fname= FullName(); Directory dir(fname); OrdCollection *files= new OrdCollection; for (int i= 0; nm= dir(); i++) if (strcmp(nm, ".") != 0) files->Add(new FileData(form("%s/%s", fname, nm), lookDeep)); return files; } Data *FileData::GetParent() { char buf[200], *cp; const char *fname= FullName(); if (strcmp(fname, "/") == 0) return 0; strcpy(buf, fname); if (cp= strrchr(buf, '/')) *cp= 0; if (cp == buf) return new FileData("/", lookDeep); return new FileData(buf, lookDeep); } OStream& FileData::PrintOn(OStream &s) { Data::PrintOn(s); return s << lookDeep SP << (long)converter SP; } IStream& FileData::ReadFrom(IStream &s) { long cv; Data::ReadFrom(s); s >> lookDeep >> cv; converter= (Converter*) cv; return s; }