[code h=300]
#pragma once
#include <string>
#include <vector>
using namespace std;
struct strpair {string n; string a;};
enum PacketType { //тип пакета
UndefinedType, Empty, Main, Utility };
const char UndefinedVersion [] = "Undefined";
class Packet //базовый класс
{
protected:
string name; //имя программы
string author; //автор
vector<Packet*> deps; //зависимости
bool installed; //флаг установки
int clients; //сколько других программ нуждаются в данной
public:
Packet () : installed (false), clients (0) {}; //конструктор по умолчанию
Packet (const Packet& ep):name(ep.name),author(ep.author),deps(ep.deps),installed(ep.installed),clients(ep.clients){}; //конструктор копирования
Packet (string n, string a, vector<Packet*> d) : name(n), author(a), deps (d), installed(false),clients(0) {}; //конструктор с инициализацией
~Packet () {};
bool IsInstalled () {return installed;}; //проверка на установку
void GetDependencyCount (int &emptyps, int &mainps, int &utilityps); //число зависимостей по типам пакетов
void Uninstall (bool automat); //удаление
bool CanDelete (); //можно ли удалять
virtual PacketType GetPacketType () {return UndefinedType;}; //тип пакета
virtual const const char* GetLastVersion () {return UndefinedVersion;}; //версии
virtual const const char* GetInstalledVersion () {return UndefinedVersion;};
virtual void Install (const char* version, bool automat); //установить
virtual void Update () {}; //обновить до последней версии
virtual bool Save (FILE* f); //сохранение базовых данных
virtual bool Load (FILE* f, vector<strpair>& dps); //загрузка базовых данных
protected:
bool NeedYou (); //вызывается при установке пакета, зависящего от данного
void DontNeedYouAnymore (); //вызывается при удалении пакета, зависящего от данного
friend class PacketManager; //дружественные классы для доступа к закрытым полям
friend class EmptyPacket;
friend class MainPacket;
friend class UtilityPacket;
};
class EmptyPacket : public Packet
{
Packet* linked; //связанный пакет
int lds;
public:
EmptyPacket () : linked(NULL), Packet() {};
EmptyPacket (Packet* l) : linked(l), Packet() {};
EmptyPacket (const EmptyPacket& ep);
EmptyPacket (string n, string a, vector<Packet*> d, Packet* l) : Packet(n, a, d), linked(l) {};
~EmptyPacket () {};
virtual PacketType GetPacketType () {return Empty;};
virtual bool Save (FILE* f); //сохранение всех данных пустого пакета
virtual bool Load (FILE* f, vector<strpair>& dps); //загрузка
friend class PacketManager; //дружественные классы для доступа к закрытым полям
};
class MainPacket : public Packet
{
string lastVersion; //последняя версия
string installedVersion; //установленная версия
public:
MainPacket():Packet() {};
MainPacket (const MainPacket& mp):Packet(mp),lastVersion(mp.lastVersion),installedVersion(mp.installedVersion) {};
MainPacket (string n, string a, vector<Packet*> d, string lv):Packet(n,a,d),lastVersion(lv){};
~MainPacket() {};
bool Merge (Packet* ep); //объединение с другим пакетом
virtual void Update ();
virtual PacketType GetPacketType () {return Main;};
virtual const const char* GetLastVersion () {return lastVersion.c_str();};
virtual const const char* GetInstalledVersion () {return installedVersion.c_str();};
virtual bool Save (FILE* f); //сохранение
virtual bool Load (FILE* f, vector<strpair>& dps); //загрузка
virtual void Install (const char* version, bool automat);
friend class PacketManager; //дружественные классы для доступа к закрытым полям
};
class UtilityPacket : public MainPacket
{
public:
UtilityPacket():MainPacket() {};
UtilityPacket(const UtilityPacket& up) : MainPacket (up) {};
UtilityPacket (string n, string a, vector<Packet*> d, string lv):MainPacket(n,a,d,lv){};
~UtilityPacket ();
Packet** Divide (int count); //разделение на заданное число пакетов
virtual PacketType GetPacketType () {return Utility;};
};
class PacketManager
{
Packet system; //вся система (корень дерева)
public:
PacketManager ();
~PacketManager ();
void Init (vector<Packet*> &ep); //инициализация системы
bool Install (string name, string author, string version, bool automat); //установка пакета
bool Uninstall (string name, string autor, bool automat); //удаление пакета
void Divide (string name, string author, int count); //деление пакета
void Merge (string name1, string author1, string name2, string author2); //объединение пакетов
void ClearSystem (); //очистка системы
void Update (); //обновление системы
bool Save (string filename); //сохранение
bool Load (string filename); //загрузка
private:
Packet* Find (string &name, string &author, Packet* begin); //поиск по дереву
void Replace (Packet* p, Packet** ps, Packet* begin, int n = 1); //замена по дереву
void ListofPackets (vector<Packet*> & res, Packet* begin); //получение всех пакетов списком
void Delete (Packet* w, Packet* begin);
};
#include "StdAfx.h"
#include "Packets.h"
#include <algorithm>
#include <iostream>
void Packet::GetDependencyCount (int &emptyps, int &mainps, int &utilityps)
{//проходим по зависимостям и считаем по типам
emptyps = mainps = utilityps = 0;
for (int i=0; i<deps.size(); i++)
switch (deps[i]->GetPacketType()) {
case Empty:
emptyps++;
break;
case Main:
mainps++;
break;
case Utility:
utilityps++;
break;
}
}
bool Packet::CanDelete ()
{//проверяем наличие программ, использующих данную
return (clients==0);
}
void Packet::Uninstall (bool automat)
{//освобождаем все зависимые и удаляем освободившиеся
installed = false;
for (int i=0; i<deps.size(); i++) {
deps[i]->DontNeedYouAnymore();
if (deps[i]->CanDelete()) {
if (automat)
deps[i]->Uninstall (true);
else {
cout << "Uninstall " << deps[i]->name << "? (y/n)";
char c;
cin >> c;
if (c=='y') deps[i]->Install (NULL, true);
else cout << "Ok, but program may be not needed anymore.";
}
}
}
}
void Packet::Install (const char* version, bool automat)
{//занимаем зависимости и устанавливаем их при необходимости
for (int i=0; i<deps.size(); i++) {
if (deps[i]->installed == false) {
if (automat)
deps[i]->Install (NULL, true);
else {
cout << "Install " << deps[i]->name << "? (y/n)";
char c;
cin >> c;
if (c=='y') deps[i]->Install (NULL, true);
else cout << "Ok, but program may not work correctly.";
}
}
deps[i]->NeedYou();
}
}
bool Packet::NeedYou ()
{
clients++;
return installed;
}
void Packet::DontNeedYouAnymore ()
{
clients--;
}
bool Packet::Save (FILE* f)
{
if (!f) return false; //проверяем на открытие файл
int er; //пишем все данные в файл текстом
er = fprintf (f, "%s\n%s\n%d\n%d\n%d\n", name.c_str(), author.c_str(), installed, clients, deps.size());
for (int i=0; i<deps.size(); i++) //пишем зависимости в виде имён пакетов
er = fprintf (f, "%s\n%s\n", deps[i]->name.c_str(), deps[i]->author.c_str());
return er>0;
}
bool Packet::Load (FILE* f, vector<strpair>& dps)
{//возвращает список зависимостей в виде имён пакетов
if (!f) return false;
int er1, sz;
char* er;
char s[256]; //считываем данные
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
name = s;
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
author = s;
er1 = fscanf (f, "%d\n%d\n%d\n", &installed, &clients, &sz);
dps.resize (sz);
for (int i=0; i<sz; i++) { //считываем имена зависимостей
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
dps[i].n = s;
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
dps[i].a = s;
}
return (er1>0 && er!=NULL);
}
bool EmptyPacket::Save (FILE* f)
{
if (!f) return false;
int er = fprintf (f, "%s\n%s\n", linked->name.c_str(), linked->author.c_str());
bool fl2 = Packet::Save (f);
return (er>0 && fl2);
}
bool EmptyPacket::Load (FILE* f, vector<strpair>& dps)
{
if (!f) return false;
strpair t;
char s[256]; //считываем данные
char* er = fgets (s, 255, f);//дополнительно загружаем связанный пакет
s[strlen(s)-1] = '\0';
t.n = s;
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
t.a = s;
bool fl2 = Packet::Load (f, dps);
dps.push_back (t); //кладём связанный пакет в конец списка зависимостей
return (er!=NULL && fl2);
}
bool MainPacket::Merge (Packet* ep)
{//объединяем в новый пакет, заменяем им текущий
name = name + "+" + ep->name;
author = author + "&" + ep->author;
installed = installed||ep->installed;
installedVersion = "1.0";
lastVersion = "1.0";
deps.insert (deps.end(), ep->deps.begin(), ep->deps.end());
unique (deps.begin(), deps.end());
clients+=ep->clients;
delete ep;
ep = NULL;
return true;
}
void MainPacket::Update ()
{
installedVersion = lastVersion;
}
void MainPacket::Install (const char* version, bool automat)
{
if (version!=NULL)
installedVersion = version;
else installedVersion = lastVersion;
Packet::Install (version, automat);
}
bool MainPacket::Save (FILE* f)
{
if (!f) return false;
int er; //сохраняем дополнительно версии
er = fprintf (f, "%s\n%s\n", lastVersion.c_str(), installedVersion.c_str());
bool fl = Packet::Save (f);
return (er>0 && fl);
}
bool MainPacket::Load (FILE* f, vector<strpair>& dps)
{
if (!f) return false;
int sz;
char *er;
char s[256]; //загружаем дополнительно версии
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
lastVersion = s;
er = fgets (s, 255, f);
s[strlen(s)-1] = '\0';
installedVersion = s;
bool fl = Packet::Load (f, dps);
return (er!=NULL && fl);
}
Packet** UtilityPacket::Divide (int count)
{ //делим пакет на несколько, текущий оставляем одним их них
Packet** ps = new Packet* [count];
ps[0] = this;
for (int i=1; i<count; i++)
ps[i] = new Packet (*this);
return ps;
}
PacketManager::PacketManager ()
{ //устанавливаем систему
system.Install (NULL, true);
}
PacketManager::~PacketManager ()
{ //получаем список всех пакетов и удаляем их
vector<Packet*> ps;
ListofPackets (ps, &system);
for (int i=0; i<ps.size(); i++)
delete ps[i];
}
void PacketManager::Init (vector<Packet*> &ep)
{ //заполняем систему зависимостями
system.deps.assign (ep.begin(), ep.end());
}
bool PacketManager::Install (string name, string author, string version, bool automat)
{//ищем пакет и устанавливаем, если нашли
Packet* p = Find (name, author, &system);
if (p!=NULL)
p->Install (version.c_str(), automat);
return p!=NULL;
}
bool PacketManager::Uninstall (string name, string autor, bool automat)
{//ищем пакет и удаляем
Packet* p = Find (name, autor, &system);
if (p!=NULL)
p->Uninstall (automat);
return p!=NULL;
}
void PacketManager::Divide (string name, string author, int count)
{//ищем пакет, делим и заменяем его вхождения массивом новых пакетов
Packet* p = Find (name, author, &system);
if (p->GetPacketType()!=Utility) {
cout << "Cannot divide packet of this type";
return;
}
Replace (p, ((UtilityPacket*)p)->Divide (count), &system, count);
}
void PacketManager::Merge (string name1, string author1, string name2, string author2)
{//ищем пакеты, объединяем и заменяем второй первым (т.к. он теперь его содержит)
Packet* p1 = Find (name1, author1, &system);
Packet* p2 = Find (name2, author2, &system);
if (p1->GetPacketType()==Empty || p1->GetPacketType()==UndefinedType) {
cout << "Cannot merge packet of this type";
return;
}
((MainPacket*)p1)->Merge (p2);
Packet** s = new Packet*[1];
s[0] = p1;
Replace (p2, s, &system);
delete [] s;
}
void PacketManager::ClearSystem ()
{//удаляем пакеты, которые можно удалить
vector<Packet*> ps;
ListofPackets (ps, &system);
for (int i=0; i<ps.size(); i++)
if (ps[i]->CanDelete()) {
ps[i]->Uninstall (true);
Delete (ps[i], &system);
delete ps[i];
}
}
void PacketManager::Update ()
{//получаем список пакетов и обновляем каждый
vector<Packet*> ps;
ListofPackets (ps, &system);
for (int i=0; i<ps.size(); i++) {
ps[i]->Update();
cout << ps[i]->name << " updated succesfully\n";
}
}
Packet* PacketManager::Find (string &name, string &author, Packet* begin)
{//рекурсивный поиск по дереву системы
if (begin->name == name && begin->author == author) return begin;
for (int i = 0; i<begin->deps.size(); i++) {
Packet* p = Find (name, author, begin->deps[i]);
if (p!=NULL) return p;
}
return NULL;
}
void PacketManager::Replace (Packet* p, Packet** ps, Packet* begin, int n)
{//рекурсивная замена по дереву системы
for (int i=0; i<begin->deps.size(); i++) {
Replace (p, ps, begin->deps[i], n);
for (vector<Packet*>::iterator j=begin->deps[i]->deps.begin(); j!=begin->deps[i]->deps.end(); j++)
if (*j == p) {
for (int k = 0; k<n; k++)
begin->deps[i]->deps.insert (j, ps[k]);
break;
}
}
}
void PacketManager::Delete (Packet* w, Packet* begin)
{
vector<Packet*>::iterator del = begin->deps.end();
for (vector<Packet*>::iterator i=begin->deps.begin(); i!=begin->deps.end(); i++) {
if (*i==w) {
del = i;
}
else Delete (w, *i);
}
if (del!=begin->deps.end()) begin->deps.erase (del);
}
void PacketManager::ListofPackets (vector<Packet*> & res, Packet* begin)
{//рекурсивное составление списка всех пакетов
for (int i=0; i<begin->deps.size(); i++) {
if (find (res.begin(), res.end(), begin->deps[i])==res.end()) res.push_back (begin->deps[i]);
ListofPackets (res, begin->deps[i]);
}
}
bool PacketManager::Save (string filename)
{
FILE* f = fopen (filename.c_str(), "wt");
if (!f) return false;
vector<Packet*> ps; //получаем список всех пакетов
ListofPackets (ps, &system);
fprintf (f, "%d\n", ps.size()); //сохраняем число пакетов
for (int i=0; i<ps.size(); i++) { //сохраняем каждый пакет последовательно в файле
fprintf (f, "%d\n", ps[i]->GetPacketType());
ps[i]->Save (f);
}
fclose (f); //закрываем файл
return true;
}
bool PacketManager::Load (string filename)
{
FILE* f = fopen (filename.c_str(), "rt");
if (!f) return false;
vector<Packet*> ps; //очищаем систему
ListofPackets (ps, &system);
for (int i=0; i<ps.size(); i++)
delete ps[i];
system.deps.clear();
int sz, type;
fscanf (f, "%d\n", &sz); //получаем число пакетов
system.deps.resize (sz);
vector<strpair> *sp = new vector<strpair> [sz]; //подготавливаем массив для имён зависимостей каждого пакета системы
for (int i=0; i<sz; i++) {
fscanf (f, "%d\n", &type); //получаем тип
switch (type) { //в зависимости от типа выделяем память под пакет
case Empty:
system.deps[i] = new EmptyPacket();
break;
case Utility:
system.deps[i] = new UtilityPacket();
break;
case Main:
system.deps[i] = new MainPacket();
break;
default:
system.deps[i] = new Packet();
break;
}
system.deps[i]->Load (f,sp[i]); //грузим данные пакета (вызовется виртуальная функция нужного типа)
}
for (int i=0; i<sz; i++) //ищем ссылки на зависимости для каждого пакета
if (system.deps[i]->deps.size()==0) { //если ссылки ещё не найдены
if (system.deps[i]->GetPacketType()==Empty) { //если пустой пакет
((EmptyPacket*)system.deps[i])->linked = Find (sp[i][sp[i].size()-1].n, sp[i][sp[i].size()-1].a, &system);
sp[i].pop_back(); //грузим связанный и удаляем из списка зависимостей
}
for (int j=0; j<sp[i].size(); j++) { //ищем для каждого имени реальный пакет
Packet* p = Find (sp[i][j].n, sp[i][j].a, &system);
if (p) system.deps[i]->deps.push_back (p); //грузим в список зависимостей ссылку
}
}
return true;
}
[/code]
[code h=200]
#include "Packets.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
setlocale (LC_ALL, "russian");
PacketManager pm;
vector<Packet*>p(5),d;
bool e = true;
while (e) {
system ("cls");
cout << "1.инициализация списком пакетов, требуемых для первоначальной установки\n";
cout << "2.установка требуемого пользовательского или "пустого" пакета ( с автоматической установкой всех требуемых пакетов)\n";
cout << "3. установка требуемого пользовательского или "пустого" пакета ( с запросом пользователя на установку каждого требуемого пакета)\n";
cout << "4. удаление указанного пользовательского пакета с автоматическим удалением ненужных пакетов со вспомогательным ПО или без него\n";
cout << "5.очистка системы от неиспользуемых вспомогательных пакетов\n";
cout << "6. глобальное обновление системы с выводом данных о каждом обновленном пакете\n";
cout << "7.Выход\nВыбор: ";
int c;
cin >> c;
switch (c) {
case 1:
p[0] = new UtilityPacket ("a", "aa", d, "1.2");
p[1] = new EmptyPacket ("e", "ae", d, p[0]);
d.push_back (p[0]);
p[2] = new MainPacket ("b", "ab", d, "2.3");
p[3] = new UtilityPacket ("c", "ac", d, "1.2");
d.push_back (p[3]);
p[4] = new MainPacket ("d", "ad", d, "2.3");
pm.Init (p);
break;
case 2:
pm.Install ("b", "ab", "2.3", true);
break;
case 3:
pm.Install ("d", "ad", "2.3", false);
break;
case 4:
cout << "С/без (c/b)? ";
char ch;
cin >> ch;
pm.Uninstall ("d", "ad", ch=='c');
break;
case 5:
pm.ClearSystem ();
break;
case 6:
pm.Update ();
break;
case 7:
e = false;
break;
}
}
return 0;
}
[/code]