rpm 5.3.12
lib/rpmal.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>         /* XXX fnpyKey */
00009 
00010 #include <rpmtag.h>
00011 #include <rpmtypes.h>
00012 
00013 #define _RPMDS_INTERNAL
00014 #include <rpmds.h>
00015 #include <rpmal.h>
00016 
00017 #include "debug.h"
00018 
00019 typedef /*@abstract@*/ struct availablePackage_s * availablePackage;
00020 
00021 /*@access alKey @*/
00022 /*@access alNum @*/
00023 /*@access rpmal @*/
00024 /*@access rpmds @*/
00025 /*@access availablePackage @*/
00026 
00027 /*@access fnpyKey @*/   /* XXX suggestedKeys array */
00028 
00032 struct availablePackage_s {
00033 /*@refcounted@*/ /*@null@*/
00034     rpmds provides;             
00035 /*@refcounted@*/ /*@null@*/
00036     rpmfi fi;                   
00038     rpmuint32_t tscolor;        
00040 /*@exposed@*/ /*@dependent@*/ /*@null@*/
00041     fnpyKey key;                
00043 };
00044 
00045 typedef /*@abstract@*/ struct availableIndexEntry_s *   availableIndexEntry;
00046 /*@access availableIndexEntry@*/
00047 
00051 struct availableIndexEntry_s {
00052 /*@exposed@*/ /*@dependent@*/ /*@null@*/
00053     alKey pkgKey;               
00054 /*@observer@*/
00055     const char * entry;         
00056     unsigned short entryLen;    
00057     unsigned short entryIx;     
00058     enum indexEntryType {
00059         IET_PROVIDES=1                  
00060     } type;                     
00061 };
00062 
00063 typedef /*@abstract@*/ struct availableIndex_s *        availableIndex;
00064 /*@access availableIndex@*/
00065 
00069 struct availableIndex_s {
00070 /*@null@*/
00071     availableIndexEntry index;  
00072     int size;                   
00073     int k;                      
00074 };
00075 
00076 typedef /*@abstract@*/ struct fileIndexEntry_s *        fileIndexEntry;
00077 /*@access fileIndexEntry@*/
00078 
00082 struct fileIndexEntry_s {
00083 /*@dependent@*/ /*@relnull@*/
00084     const char * baseName;      
00085     size_t baseNameLen;
00086     alNum pkgNum;               
00087     rpmuint32_t ficolor;
00088 };
00089 
00090 typedef /*@abstract@*/ struct dirInfo_s *               dirInfo;
00091 /*@access dirInfo@*/
00092 
00096 struct dirInfo_s {
00097 /*@owned@*/ /*@relnull@*/
00098     const char * dirName;       
00099     size_t dirNameLen;          
00100 /*@owned@*/
00101     fileIndexEntry files;       
00102     int numFiles;               
00103 };
00104 
00108 struct rpmal_s {
00109 /*@owned@*/ /*@null@*/
00110     availablePackage list;      
00111     struct availableIndex_s index;      
00112     int delta;                  
00113     int size;                   
00114     int alloced;                
00115     rpmuint32_t tscolor;        
00116     int numDirs;                
00117 /*@owned@*/ /*@null@*/
00118     dirInfo dirs;               
00119 };
00120 
00125 static void rpmalFreeIndex(rpmal al)
00126         /*@modifies al @*/
00127 {
00128     availableIndex ai = &al->index;
00129     if (ai->size > 0) {
00130         ai->index = _free(ai->index);
00131         ai->size = 0;
00132     }
00133 }
00134 
00135 static inline alNum alKey2Num(/*@unused@*/ /*@null@*/ const rpmal al,
00136                 /*@null@*/ alKey pkgKey)
00137         /*@*/
00138 {
00139     /*@-nullret -temptrans -retalias @*/
00140     union { alKey key; alNum num; } u;
00141     u.num = 0;
00142     u.key = pkgKey;
00143     return u.num;
00144     /*@=nullret =temptrans =retalias @*/
00145 }
00146 
00147 static inline alKey alNum2Key(/*@unused@*/ /*@null@*/ const rpmal al,
00148                 /*@null@*/ alNum pkgNum)
00149         /*@*/
00150 {
00151     /*@-nullret -temptrans -retalias @*/
00152     union { alKey key; alNum num; } u;
00153     u.key = 0;
00154     u.num = pkgNum;
00155     return u.key;
00156     /*@=nullret =temptrans =retalias @*/
00157 }
00158 
00159 rpmal rpmalCreate(int delta)
00160 {
00161     rpmal al = xcalloc(1, sizeof(*al));
00162     availableIndex ai = &al->index;
00163 
00164     al->delta = delta;
00165     al->size = 0;
00166     al->list = xcalloc(al->delta, sizeof(*al->list));
00167     al->alloced = al->delta;
00168 
00169     ai->index = NULL;
00170     ai->size = 0;
00171 
00172     al->numDirs = 0;
00173     al->dirs = NULL;
00174     return al;
00175 }
00176 
00177 rpmal rpmalFree(rpmal al)
00178 {
00179     availablePackage alp;
00180     dirInfo die;
00181     int i;
00182 
00183     if (al == NULL)
00184         return NULL;
00185 
00186     if ((alp = al->list) != NULL)
00187     for (i = 0; i < al->size; i++, alp++) {
00188         (void)rpmdsFree(alp->provides);
00189         alp->provides = NULL;
00190         (void)rpmfiFree(alp->fi);
00191         alp->fi = NULL;
00192     }
00193 
00194     if ((die = al->dirs) != NULL)
00195     for (i = 0; i < al->numDirs; i++, die++) {
00196         die->dirName = _free(die->dirName);
00197         die->files = _free(die->files);
00198     }
00199     al->dirs = _free(al->dirs);
00200     al->numDirs = 0;
00201 
00202     al->list = _free(al->list);
00203     al->alloced = 0;
00204     rpmalFreeIndex(al);
00205     al = _free(al);
00206     return NULL;
00207 }
00208 
00215 static int dieCompare(const void * one, const void * two)
00216         /*@*/
00217 {
00218     /*@-castexpose@*/
00219     const dirInfo a = (const dirInfo) one;
00220     const dirInfo b = (const dirInfo) two;
00221     /*@=castexpose@*/
00222     int lenchk = (int)a->dirNameLen - (int)b->dirNameLen;
00223 
00224     if (lenchk || a->dirNameLen == 0)
00225         return lenchk;
00226 
00227     if (a->dirName == NULL || b->dirName == NULL)
00228         return lenchk;
00229 
00230     /* XXX FIXME: this might do "backward" strcmp for speed */
00231     return strcmp(a->dirName, b->dirName);
00232 }
00233 
00240 static int fieCompare(const void * one, const void * two)
00241         /*@*/
00242 {
00243     /*@-castexpose@*/
00244     const fileIndexEntry a = (const fileIndexEntry) one;
00245     const fileIndexEntry b = (const fileIndexEntry) two;
00246     /*@=castexpose@*/
00247     int lenchk = (int)a->baseNameLen - (int)b->baseNameLen;
00248 
00249     if (lenchk)
00250         return lenchk;
00251 
00252     if (a->baseName == NULL || b->baseName == NULL)
00253         return lenchk;
00254 
00255     return strcmp(a->baseName, b->baseName);
00256 }
00257 
00258 void rpmalDel(rpmal al, alKey pkgKey)
00259 {
00260     alNum pkgNum = alKey2Num(al, pkgKey);
00261     availablePackage alp;
00262     rpmfi fi;
00263 
00264     if (al == NULL || al->list == NULL)
00265         return;         /* XXX can't happen */
00266 
00267     alp = al->list + pkgNum;
00268 
00269     /* Delete directory/file info entries from added package list. */
00270     if ((fi = alp->fi) != NULL)
00271     if (rpmfiFC(fi) > 0) {
00272         int origNumDirs = al->numDirs;
00273         int dx;
00274         dirInfo dieNeedle =
00275                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00276         dirInfo die;
00277         int last;
00278         int i;
00279 
00280         /* XXX FIXME: We ought to relocate the directory list here */
00281 
00282         if (al->dirs != NULL)
00283         for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
00284         {
00285             fileIndexEntry fie;
00286 
00287             (void) rpmfiSetDX(fi, dx);
00288 
00289             /*@-assignexpose -dependenttrans -observertrans@*/
00290             dieNeedle->dirName = (char *) rpmfiDN(fi);
00291             /*@=assignexpose =dependenttrans =observertrans@*/
00292             dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00293                         ? strlen(dieNeedle->dirName) : 0);
00294             die = bsearch(dieNeedle, al->dirs, al->numDirs,
00295                                sizeof(*dieNeedle), dieCompare);
00296             if (die == NULL)
00297                 continue;
00298 
00299             last = die->numFiles;
00300             fie = die->files + last - 1;
00301             for (i = last - 1; i >= 0; i--, fie--) {
00302                 if (fie->pkgNum != pkgNum)
00303                     /*@innercontinue@*/ continue;
00304                 die->numFiles--;
00305 
00306                 if (i < die->numFiles)
00307                     memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
00308                 memset(die->files + die->numFiles, 0, sizeof(*fie)); /* overkill */
00309 
00310             }
00311             if (die->numFiles > 0) {
00312                 if (last > i)
00313                     die->files = xrealloc(die->files,
00314                                         die->numFiles * sizeof(*die->files));
00315                 continue;
00316             }
00317             die->files = _free(die->files);
00318             die->dirName = _free(die->dirName);
00319             al->numDirs--;
00320             if ((die - al->dirs) < al->numDirs)
00321                 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
00322 
00323             memset(al->dirs + al->numDirs, 0, sizeof(*al->dirs)); /* overkill */
00324         }
00325 
00326         if (origNumDirs > al->numDirs) {
00327             if (al->numDirs > 0)
00328                 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00329             else
00330                 al->dirs = _free(al->dirs);
00331         }
00332     }
00333 
00334     (void)rpmdsFree(alp->provides);
00335     alp->provides = NULL;
00336     (void)rpmfiFree(alp->fi);
00337     alp->fi = NULL;
00338 
00339     memset(alp, 0, sizeof(*alp));       /* XXX trash and burn */
00340     return;
00341 }
00342 
00343 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
00344                 rpmds provides, rpmfi fi, rpmuint32_t tscolor)
00345 {
00346     alNum pkgNum;
00347     rpmal al;
00348     availablePackage alp;
00349 
00350     /* If list doesn't exist yet, create. */
00351     if (*alistp == NULL)
00352         *alistp = rpmalCreate(5);
00353     al = *alistp;
00354     pkgNum = alKey2Num(al, pkgKey);
00355 
00356     if (pkgNum >= 0 && pkgNum < al->size) {
00357         rpmalDel(al, pkgKey);
00358     } else {
00359         if (al->size == al->alloced) {
00360             al->alloced += al->delta;
00361             al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00362         }
00363         pkgNum = al->size++;
00364     }
00365 
00366     if (al->list == NULL)
00367         return RPMAL_NOMATCH;           /* XXX can't happen */
00368 
00369     alp = al->list + pkgNum;
00370 
00371     alp->key = key;
00372     alp->tscolor = tscolor;
00373 
00374 /*@-assignexpose -castexpose @*/
00375     alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
00376     alp->fi = rpmfiLink(fi, "Files (rpmalAdd)");
00377 /*@=assignexpose =castexpose @*/
00378 
00379 /*@-castexpose@*/
00380     fi = rpmfiLink(alp->fi, "Files index (rpmalAdd)");
00381 /*@=castexpose@*/
00382     fi = rpmfiInit(fi, 0);
00383     if (rpmfiFC(fi) > 0) {
00384         dirInfo dieNeedle =
00385                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00386         dirInfo die;
00387         int dc = rpmfiDC(fi);
00388         int dx;
00389         int * dirMapping = alloca(sizeof(*dirMapping) * dc);
00390         int * dirUnique = alloca(sizeof(*dirUnique) * dc);
00391         const char * DN;
00392         int origNumDirs;
00393         int first;
00394 
00395         /* XXX FIXME: We ought to relocate the directory list here */
00396 
00397         /* XXX enough space for all directories, late realloc to truncate. */
00398         al->dirs = xrealloc(al->dirs, (al->numDirs + dc) * sizeof(*al->dirs));
00399 
00400         /* Only previously allocated dirInfo is sorted and bsearch'able. */
00401         origNumDirs = al->numDirs;
00402 
00403         /* Package dirnames are not currently unique. Create unique mapping. */
00404         for (dx = 0; dx < dc; dx++) {
00405             int i = 0;
00406             (void) rpmfiSetDX(fi, dx);
00407             DN = rpmfiDN(fi);
00408             if (DN != NULL)
00409             for (i = 0; i < dx; i++) {
00410                 const char * iDN;
00411                 (void) rpmfiSetDX(fi, i);
00412                 iDN = rpmfiDN(fi);
00413                 if (iDN != NULL && !strcmp(DN, iDN))
00414                     /*@innerbreak@*/ break;
00415             }
00416             dirUnique[dx] = i;
00417         }
00418 
00419         /* Map package dirs into transaction dirInfo index. */
00420         for (dx = 0; dx < dc; dx++) {
00421 
00422             /* Non-unique package dirs use the 1st entry mapping. */
00423             if (dirUnique[dx] < dx) {
00424                 dirMapping[dx] = dirMapping[dirUnique[dx]];
00425                 continue;
00426             }
00427 
00428             /* Find global dirInfo mapping for first encounter. */
00429             (void) rpmfiSetDX(fi, dx);
00430 
00431             /*@-assignexpose -dependenttrans -observertrans@*/
00432             dieNeedle->dirName = rpmfiDN(fi);
00433             /*@=assignexpose =dependenttrans =observertrans@*/
00434 
00435             dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00436                         ? strlen(dieNeedle->dirName) : 0);
00437             die = bsearch(dieNeedle, al->dirs, origNumDirs,
00438                                sizeof(*dieNeedle), dieCompare);
00439             if (die) {
00440                 dirMapping[dx] = die - al->dirs;
00441             } else {
00442                 dirMapping[dx] = al->numDirs;
00443                 die = al->dirs + al->numDirs;
00444                 if (dieNeedle->dirName != NULL)
00445                     die->dirName = xstrdup(dieNeedle->dirName);
00446                 die->dirNameLen = dieNeedle->dirNameLen;
00447                 die->files = NULL;
00448                 die->numFiles = 0;
00449 
00450                 al->numDirs++;
00451             }
00452         }
00453 
00454         for (first = rpmfiNext(fi); first >= 0;) {
00455             fileIndexEntry fie;
00456             int next;
00457 
00458             /* Find the first file of the next directory. */
00459             dx = rpmfiDX(fi);
00460             while ((next = rpmfiNext(fi)) >= 0) {
00461                 if (dx != rpmfiDX(fi))
00462                     /*@innerbreak@*/ break;
00463             }
00464             if (next < 0) next = rpmfiFC(fi);   /* XXX reset end-of-list */
00465 
00466             die = al->dirs + dirMapping[dx];
00467             die->files = xrealloc(die->files,
00468                         (die->numFiles + next - first) * sizeof(*die->files));
00469 
00470             fie = die->files + die->numFiles;
00471 
00472             /* Rewind to first file, generate file index entry for each file. */
00473             fi = rpmfiInit(fi, first);
00474             while ((first = rpmfiNext(fi)) >= 0 && first < next) {
00475                 /*@-assignexpose -dependenttrans -observertrans @*/
00476                 fie->baseName = rpmfiBN(fi);
00477                 /*@=assignexpose =dependenttrans =observertrans @*/
00478                 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
00479                 fie->pkgNum = pkgNum;
00480                 fie->ficolor = rpmfiFColor(fi);
00481 
00482                 die->numFiles++;
00483                 fie++;
00484             }
00485             qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
00486         }
00487 
00488         /* Resize the directory list. If any directories were added, resort. */
00489         al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00490         if (origNumDirs != al->numDirs)
00491             qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
00492     }
00493     fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
00494 
00495     rpmalFreeIndex(al);
00496 
00497 assert(((alNum)(alp - al->list)) == pkgNum);
00498     return ((alKey)(alp - al->list));
00499 }
00500 
00507 static int indexcmp(const void * one, const void * two)
00508         /*@*/
00509 {
00510     /*@-castexpose@*/
00511     const availableIndexEntry a = (const availableIndexEntry) one;
00512     const availableIndexEntry b = (const availableIndexEntry) two;
00513     /*@=castexpose@*/
00514     int lenchk;
00515 
00516     lenchk = a->entryLen - b->entryLen;
00517     if (lenchk)
00518         return lenchk;
00519 
00520     return strcmp(a->entry, b->entry);
00521 }
00522 
00523 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides, rpmuint32_t tscolor)
00524 {
00525     rpmuint32_t dscolor;
00526     const char * Name;
00527     alNum pkgNum = alKey2Num(al, pkgKey);
00528     availableIndex ai = &al->index;
00529     availableIndexEntry aie;
00530     int ix;
00531 
00532     if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
00533         return;
00534     if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
00535         return;
00536 
00537     if (rpmdsInit(provides) != NULL)
00538     while (rpmdsNext(provides) >= 0) {
00539 
00540         if ((Name = provides->N[provides->i]) == NULL)
00541             continue;   /* XXX can't happen */
00542 
00543         /* Ignore colored provides not in our rainbow. */
00544         dscolor = rpmdsColor(provides);
00545         if (tscolor && dscolor && !(tscolor & dscolor))
00546             continue;
00547 
00548         aie = ai->index + ai->k;
00549         ai->k++;
00550 
00551         aie->pkgKey = pkgKey;
00552 /*@-assignexpose@*/
00553         aie->entry = Name;
00554 /*@=assignexpose@*/
00555         aie->entryLen = (unsigned short)strlen(Name);
00556         ix = rpmdsIx(provides);
00557 
00558 /* XXX make sure that element index fits in unsigned short */
00559 assert(ix < 0x10000);
00560 
00561         aie->entryIx = ix;
00562         aie->type = IET_PROVIDES;
00563     }
00564 }
00565 
00566 void rpmalMakeIndex(rpmal al)
00567 {
00568     availableIndex ai;
00569     availablePackage alp;
00570     int i;
00571 
00572     if (al == NULL || al->list == NULL) return;
00573     ai = &al->index;
00574 
00575     ai->size = 0;
00576     for (i = 0; i < al->size; i++) {
00577         alp = al->list + i;
00578         if (alp->provides != NULL)
00579             ai->size += rpmdsCount(alp->provides);
00580     }
00581     if (ai->size == 0) return;
00582 
00583     ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
00584     ai->k = 0;
00585     for (i = 0; i < al->size; i++) {
00586         alp = al->list + i;
00587         rpmalAddProvides(al, alNum2Key(NULL, (alNum)i), alp->provides, alp->tscolor);
00588     }
00589 
00590     /* Reset size to the no. of provides added. */
00591     ai->size = ai->k;
00592     qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00593 }
00594 
00595 fnpyKey *
00596 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00597 {
00598     rpmuint32_t tscolor;
00599     rpmuint32_t ficolor;
00600     int found = 0;
00601     const char * dirName;
00602     const char * baseName;
00603     dirInfo dieNeedle =
00604                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00605     dirInfo die;
00606     fileIndexEntry fieNeedle =
00607                 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
00608     fileIndexEntry fie;
00609     availablePackage alp;
00610     fnpyKey * ret = NULL;
00611     const char * fileName;
00612 
00613     if (keyp) *keyp = RPMAL_NOMATCH;
00614 
00615     if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
00616         return NULL;
00617 
00618     /* Solaris 2.6 bsearch sucks down on this. */
00619     if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00620         return NULL;
00621 
00622     {   char * t;
00623         dirName = t = xstrdup(fileName);
00624         if ((t = strrchr(t, '/')) != NULL) {
00625             t++;                /* leave the trailing '/' */
00626             *t = '\0';
00627         }
00628     }
00629 
00630     dieNeedle->dirName = (char *) dirName;
00631     dieNeedle->dirNameLen = strlen(dirName);
00632     die = bsearch(dieNeedle, al->dirs, al->numDirs,
00633                        sizeof(*dieNeedle), dieCompare);
00634     if (die == NULL)
00635         goto exit;
00636 
00637     /* rewind to the first match */
00638     while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
00639         die--;
00640 
00641     if ((baseName = strrchr(fileName, '/')) == NULL)
00642         goto exit;
00643     baseName++;
00644 
00645     for (found = 0, ret = NULL;
00646          die < al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
00647          die++)
00648     {
00649 
00650 /*@-observertrans@*/
00651         fieNeedle->baseName = baseName;
00652 /*@=observertrans@*/
00653         fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
00654         fie = bsearch(fieNeedle, die->files, die->numFiles,
00655                        sizeof(*fieNeedle), fieCompare);
00656         if (fie == NULL)
00657             continue;   /* XXX shouldn't happen */
00658 
00659         alp = al->list + fie->pkgNum;
00660 
00661         /* Ignore colored files not in our rainbow. */
00662         tscolor = alp->tscolor;
00663         ficolor = fie->ficolor;
00664         if (tscolor && ficolor && !(tscolor & ficolor))
00665             continue;
00666 
00667         rpmdsNotify(ds, _("(added files)"), 0);
00668 
00669         ret = xrealloc(ret, (found+2) * sizeof(*ret));
00670         if (ret)        /* can't happen */
00671             ret[found] = alp->key;
00672         if (keyp)
00673             *keyp = alNum2Key(al, fie->pkgNum);
00674         found++;
00675     }
00676 
00677 exit:
00678     dirName = _free(dirName);
00679     if (ret)
00680         ret[found] = NULL;
00681     return ret;
00682 }
00683 
00684 fnpyKey *
00685 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00686 {
00687     availableIndex ai;
00688     availableIndexEntry needle;
00689     availableIndexEntry match;
00690     fnpyKey * ret = NULL;
00691     int found = 0;
00692     const char * KName;
00693     availablePackage alp;
00694     int rc;
00695 
00696     if (keyp) *keyp = RPMAL_NOMATCH;
00697 
00698     if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00699         return ret;
00700 
00701     if (*KName == '/') {
00702         /* First, look for files "contained" in package ... */
00703         ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00704         if (ret != NULL && *ret != NULL)
00705             return ret;
00706         ret = _free(ret);
00707         /* ... then, look for files "provided" by package. */
00708     }
00709 
00710     ai = &al->index;
00711     if (ai->index == NULL || ai->size <= 0)
00712         return NULL;
00713 
00714     needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00715     /*@-assignexpose -temptrans@*/
00716     needle->entry = KName;
00717     /*@=assignexpose =temptrans@*/
00718     needle->entryLen = (unsigned short)strlen(needle->entry);
00719 
00720     match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
00721     if (match == NULL)
00722         return NULL;
00723 
00724     /* rewind to the first match */
00725     while (match > ai->index && indexcmp(match-1, needle) == 0)
00726         match--;
00727 
00728     if (al->list != NULL)       /* XXX always true */
00729     for (ret = NULL, found = 0;
00730          match < ai->index + ai->size && indexcmp(match, needle) == 0;
00731          match++)
00732     {
00733         alp = al->list + alKey2Num(al, match->pkgKey);
00734 
00735         rc = 0;
00736         if (alp->provides != NULL)      /* XXX can't happen */
00737         switch (match->type) {
00738         case IET_PROVIDES:
00739             /* XXX single step on rpmdsNext to regenerate DNEVR string */
00740             (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
00741             if (rpmdsNext(alp->provides) >= 0)
00742                 rc = rpmdsCompare(alp->provides, ds);
00743 
00744             if (rc)
00745                 rpmdsNotify(ds, _("(added provide)"), 0);
00746 
00747             /*@switchbreak@*/ break;
00748         }
00749 
00750         if (rc) {
00751             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00752             if (ret)    /* can't happen */
00753                 ret[found] = alp->key;
00754 /*@-dependenttrans@*/
00755             if (keyp)
00756                 *keyp = match->pkgKey;
00757 /*@=dependenttrans@*/
00758             found++;
00759         }
00760     }
00761 
00762     if (ret)
00763         ret[found] = NULL;
00764 
00765 /*@-nullstate@*/ /* FIX: *keyp may be NULL */
00766     return ret;
00767 /*@=nullstate@*/
00768 }
00769 
00770 fnpyKey
00771 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00772 {
00773     fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00774 
00775     if (tmp) {
00776         fnpyKey ret = tmp[0];
00777         free(tmp);
00778         return ret;
00779     }
00780     return NULL;
00781 }