#include #include #include #include "managerpm.h" enum REQOPER { REQOPER_NONE, // No version dependence REQOPER_EQUAL, // Version must be equal REQOPER_GREATER,// Version must be greater REQOPER_GEQUAL, // Must be greater or equal }; /* This pool is used to collect a lot of strings and to locate them fast. */ struct LOOKUP{ PACKAGE *pkg; LOOKUP *next; REQOPER oper; char *version; char *md5; }; static LOOKUP *tblookup=NULL; static int maxlookup=0; static int nblookup=0; static LOOKUP *freelist=NULL; static void growlookup() { if (nblookup == maxlookup){ maxlookup += 10000; tblookup = (LOOKUP*)realloc(tblookup,maxlookup*sizeof(LOOKUP)); assert (tblookup != NULL); } } /* Get a empty LOOKUP record */ static LOOKUP *getlookup() { LOOKUP *ret = NULL; if (freelist != NULL){ ret = freelist; freelist = freelist->next; }else{ growlookup(); ret = tblookup + nblookup++; } ret->version = NULL; ret->md5 = NULL; return ret; } static void freelookup (LOOKUP *pt) { free (pt->version); pt->version = NULL; free (pt->md5); pt->md5 = NULL; pt->next = freelist; freelist = pt; } PUBLIC STRENTRY::STRENTRY(const char *s) { val = strdup(s); next = NULL; provides = NULL; requires = NULL; } PUBLIC STRENTRY::~STRENTRY() { free ((char*)val); } static void poolstr_initlk( LOOKUP *pt, const char *oper, // operator > >= = const char *ver) // version { if (strcmp(oper,"=")==0){ pt->oper = REQOPER_EQUAL; }else if (strcmp(oper,">")==0){ pt->oper = REQOPER_GREATER; }else if (strcmp(oper,">=")==0){ pt->oper = REQOPER_GEQUAL; }else{ pt->oper = REQOPER_NONE; } pt->version = NULL; if (ver[0] != '\0') pt->version = strdup(ver); } PUBLIC void STRENTRY::addprovide( PACKAGE *p, const char *oper, // operator > >= = const char *ver, // version const char *md5) // MD5 signature if the "provide" is a file { LOOKUP *pt = getlookup(); pt->next = provides; pt->pkg = p; pt->md5 = md5 == NULL ? NULL : strdup(md5); provides = pt; poolstr_initlk (pt,oper,ver); } PUBLIC void STRENTRY::addrequire ( PACKAGE *p, const char *oper, // operator > >= = const char *ver) // version { LOOKUP *pt = getlookup(); pt->next = requires; pt->pkg = p; requires = pt; poolstr_initlk (pt,oper,ver); } PUBLIC STRENTRY *STRENTRIES::getitem (int no) const { return (STRENTRY*)ARRAY::getitem(no); } static void poolstr_freelookups ( LOOKUP **first, PACKAGE *pkg) { while (*first != NULL){ LOOKUP *pt = *first; if (pt->pkg == pkg){ LOOKUP *next = pt->next; freelookup (pt); *first = next; }else{ first = &(*first)->next; } } } PUBLIC void STRENTRY::forgetpkg(PACKAGE *pkg) { poolstr_freelookups (&provides,pkg); poolstr_freelookups (&requires,pkg); } PUBLIC void STRENTRIES::forgetpkg(PACKAGE *pkg) { int n = getnb(); for (int i=0; iforgetpkg (pkg); } } /* Check the requirement for a STRENTRY. Assume that the STRENTRY is required by one package. Check if one package is providing it. */ PUBLIC bool STRENTRY::testinstall( PACKAGES &needs) { bool ret = true; LOOKUP *pro = provides; if (pro == NULL){ // No package provides this string ret = false; }else{ bool once = false; PACKAGE *needed = NULL; while (pro != NULL){ if (pro->pkg->is_installed()){ once = true; break; }else{ needed = pro->pkg; } pro = pro->next; } if (!once){ // No installed package provide the string // so we require an uninstalled one if (needs.lookup(needed)==-1) needs.add (needed); } } return ret; } /* Check the requirement for a STRENTRY. Assume that the STRENTRY is provided by one package. Check if one installed package needs it. Return true if no installed package do need it. */ PUBLIC bool STRENTRY::testuninstall( PACKAGES &needs) { bool ret = true; LOOKUP *req = requires; // printf ("test val :%s:\n",val); while (req != NULL){ // printf ("poolstr unintall :%s: :%s:\n",val,req->pkg->name.get()); PACKAGE *pkg = req->pkg; if (pkg->is_installed()){ // printf ("Failed poolstr unintall :%s: :%s:\n",val,req->pkg->name.get()); if (needs.lookup(pkg)==-1) needs.add (pkg); ret = false; } req = req->next; } return ret; } /* Check if one installed package supply this symbol. Return true if at least one installed supply it. */ PUBLIC bool STRENTRY::testconflicts( const char *name, // Package which is currently tested // (not in conflict with itself) PACKAGES &conflicts) { bool ret = false; LOOKUP *pro = provides; // printf ("test val :%s:\n",val); while (pro != NULL){ // printf ("poolstr unintall :%s: :%s:\n",val,req->pkg->name.get()); PACKAGE *pkg = pro->pkg; if (pkg->is_installed() && pkg->name.cmp(name) != 0){ // printf ("Failed poolstr conflicts :%s: :%s:\n",val,pkg->name.get()); if (conflicts.lookup(pkg)==-1) conflicts.add (pkg); ret = true; } pro = pro->next; } return ret; } static STRENTRY *tbhash[1024]; static STRENTRY *poolstr_locate (const char *s, int &hash) { int h = 0; // Naive hashing function. const char *pt = s; while (*pt != '\0'){ int n = *pt++; h = (h<<1) ^ n; } h &= 1023; hash = h; STRENTRY *ret = tbhash[h]; while (ret != NULL){ if (strcmp(ret->val,s)==0) break; ret = ret->next; } return ret; } static STRENTRY *poolstr_add (const char *s, int hash) { STRENTRY *ret = new STRENTRY (s); ret->next = tbhash[hash]; tbhash[hash] = ret; return ret; } /* Locate a string. Add it if missing */ STRENTRY *poolstr_locate_add (const char *s) { int hash; STRENTRY *ret = poolstr_locate (s,hash); if (ret == NULL){ ret = poolstr_add (s,hash); } return ret; } static void poolstr_parse ( const char *s, char req[200], char oper[200], char ver[200]) { const char *pt = str_copyword (req,s,200-1); pt = str_copyword (oper,pt,200-1); str_copyword (ver,pt,200-1); } STRENTRY *poolstr_addprovide (PACKAGE *p, const char *s, const char *md5) { char req[200],oper[200],ver[200]; poolstr_parse (s,req,oper,ver); STRENTRY *ret = poolstr_locate_add (req); ret->addprovide (p,oper,ver,md5); return ret; } STRENTRY *poolstr_addrequire (PACKAGE *p, const char *s) { char req[200],oper[200],ver[200]; poolstr_parse (s,req,oper,ver); STRENTRY *ret = poolstr_locate_add (req); ret->addrequire (p,oper,ver); return ret; }