summaryrefslogtreecommitdiff
path: root/lib/rpmal.c
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2001-10-29 20:12:35 +0000
committerjbj <devnull@localhost>2001-10-29 20:12:35 +0000
commite62f50c8a585566d68bbfdbaf1eead46630e3ca9 (patch)
tree9872586e4c0974865f078e52ce1c4132e06d2883 /lib/rpmal.c
parent89c1ce1325ed7391e3253aab3eb8c176af38781d (diff)
downloadlibrpm-tizen-e62f50c8a585566d68bbfdbaf1eead46630e3ca9.tar.gz
librpm-tizen-e62f50c8a585566d68bbfdbaf1eead46630e3ca9.tar.bz2
librpm-tizen-e62f50c8a585566d68bbfdbaf1eead46630e3ca9.zip
- start hiding availablePackage data/methods in rpmal.c/rpmal.h.
CVS patchset: 5140 CVS date: 2001/10/29 20:12:35
Diffstat (limited to 'lib/rpmal.c')
-rw-r--r--lib/rpmal.c666
1 files changed, 666 insertions, 0 deletions
diff --git a/lib/rpmal.c b/lib/rpmal.c
new file mode 100644
index 000000000..8b727c76a
--- /dev/null
+++ b/lib/rpmal.c
@@ -0,0 +1,666 @@
+/** \ingroup rpmdep
+ * \file lib/rpmal.c
+ */
+
+#include "system.h"
+
+#include <rpmlib.h>
+
+#include "depends.h"
+#include "rpmal.h"
+
+#include "debug.h"
+
+/*@access Header@*/ /* XXX compared with NULL */
+/*@access FD_t@*/ /* XXX compared with NULL */
+/*@access rpmDependencyConflict@*/
+
+/*@access availablePackage@*/
+/*@access availableIndexEntry@*/
+/*@access availableIndex@*/
+/*@access fileIndexEntry@*/
+/*@access dirInfo@*/
+/*@access availableList@*/
+
+/*@unchecked@*/
+static int _al_debug = 0;
+
+/**
+ * Destroy available item index.
+ * @param al available list
+ */
+static void alFreeIndex(availableList al)
+ /*@modifies al @*/
+{
+ if (al->index.size) {
+ al->index.index = _free(al->index.index);
+ al->index.size = 0;
+ }
+}
+
+availableList alCreate(int delta)
+{
+ availableList al = xcalloc(1, sizeof(*al));
+
+ al->delta = delta;
+ al->size = 0;
+ al->list = xcalloc(al->delta, sizeof(*al->list));
+ al->alloced = al->delta;
+
+ al->index.index = NULL;
+ al->index.size = 0;
+
+ al->numDirs = 0;
+ al->dirs = NULL;
+ return al;
+}
+
+availableList alFree(availableList al)
+{
+ HFD_t hfd = headerFreeData;
+ availablePackage p;
+ rpmRelocation * r;
+ int i;
+
+ if (al == NULL)
+ return NULL;
+
+ if ((p = al->list) != NULL)
+ for (i = 0; i < al->size; i++, p++) {
+
+ { tsortInfo tsi;
+ while ((tsi = p->tsi.tsi_next) != NULL) {
+ p->tsi.tsi_next = tsi->tsi_next;
+ tsi->tsi_next = NULL;
+ tsi = _free(tsi);
+ }
+ }
+
+ p->provides = hfd(p->provides, -1);
+ p->providesEVR = hfd(p->providesEVR, -1);
+ p->requires = hfd(p->requires, -1);
+ p->requiresEVR = hfd(p->requiresEVR, -1);
+ p->baseNames = hfd(p->baseNames, -1);
+ p->h = headerFree(p->h);
+
+ if (p->relocs) {
+ for (r = p->relocs; (r->oldPath || r->newPath); r++) {
+ r->oldPath = _free(r->oldPath);
+ r->newPath = _free(r->newPath);
+ }
+ p->relocs = _free(p->relocs);
+ }
+ /*@-type@*/ /* FIX: cast? */
+ if (p->fd != NULL)
+ p->fd = fdFree(p->fd, "alAddPackage (alFree)");
+ /*@=type@*/
+ }
+
+ if (al->dirs != NULL)
+ for (i = 0; i < al->numDirs; i++) {
+ al->dirs[i].dirName = _free(al->dirs[i].dirName);
+ al->dirs[i].files = _free(al->dirs[i].files);
+ }
+
+ al->dirs = _free(al->dirs);
+ al->numDirs = 0;
+ al->list = _free(al->list);
+ al->alloced = 0;
+ alFreeIndex(al);
+ return NULL;
+}
+
+/**
+ * Compare two directory info entries by name (qsort/bsearch).
+ * @param one 1st directory info
+ * @param two 2nd directory info
+ * @return result of comparison
+ */
+static int dirInfoCompare(const void * one, const void * two) /*@*/
+{
+ /*@-castexpose@*/
+ const dirInfo a = (const dirInfo) one;
+ const dirInfo b = (const dirInfo) two;
+ /*@=castexpose@*/
+ int lenchk = a->dirNameLen - b->dirNameLen;
+
+ if (lenchk)
+ return lenchk;
+
+ /* XXX FIXME: this might do "backward" strcmp for speed */
+ return strcmp(a->dirName, b->dirName);
+}
+
+void alDelPackage(availableList al, int pkgNum)
+{
+ HGE_t hge = (HGE_t)headerGetEntryMinMemory;
+ HFD_t hfd = headerFreeData;
+ availablePackage p;
+
+ /*@-nullptrarith@*/ /* FIX: al->list might be NULL */
+ p = al->list + pkgNum;
+ /*@=nullptrarith@*/
+
+/*@-modfilesys@*/
+if (_al_debug)
+fprintf(stderr, "*** del %p[%d] %s-%s-%s\n", al->list, pkgNum, p->name, p->version, p->release);
+/*@=modfilesys@*/
+
+ if (p->relocs) {
+ rpmRelocation * r;
+ for (r = p->relocs; r->oldPath || r->newPath; r++) {
+ r->oldPath = _free(r->oldPath);
+ r->newPath = _free(r->newPath);
+ }
+ p->relocs = _free(p->relocs);
+ }
+ if (p->fd) {
+ /*@-type@*/ /* FIX: cast? */
+ (void) fdFree(p->fd, "alDelPackage");
+ /*@=type@*/
+ p->fd = NULL;
+ }
+
+ if (p->baseNames != NULL && p->filesCount > 0) {
+ int origNumDirs = al->numDirs;
+ const char ** dirNames;
+ int_32 numDirs;
+ rpmTagType dnt;
+ int dirNum;
+ dirInfo dirNeedle =
+ memset(alloca(sizeof(*dirNeedle)), 0, sizeof(*dirNeedle));
+ dirInfo dirMatch;
+ int last;
+ int i, xx;
+
+ xx = hge(p->h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
+
+ /* XXX FIXME: We ought to relocate the directory list here */
+
+ if (al->dirs != NULL)
+ for (dirNum = al->numDirs - 1; dirNum >= 0; dirNum--) {
+ dirNeedle->dirName = (char *) dirNames[dirNum];
+ dirNeedle->dirNameLen = strlen(dirNames[dirNum]);
+ dirMatch = bsearch(dirNeedle, al->dirs, al->numDirs,
+ sizeof(*dirNeedle), dirInfoCompare);
+ if (dirMatch == NULL)
+ continue;
+ last = dirMatch->numFiles;
+ for (i = dirMatch->numFiles - 1; i >= 0; i--) {
+ if (dirMatch->files[i].pkgNum != pkgNum)
+ /*@innercontinue@*/ continue;
+ dirMatch->numFiles--;
+ if (i > dirMatch->numFiles)
+ /*@innercontinue@*/ continue;
+ memmove(dirMatch->files, dirMatch->files+1,
+ (dirMatch->numFiles - i));
+ }
+ if (dirMatch->numFiles > 0) {
+ if (last > i)
+ dirMatch->files = xrealloc(dirMatch->files,
+ dirMatch->numFiles * sizeof(*dirMatch->files));
+ continue;
+ }
+ dirMatch->files = _free(dirMatch->files);
+ dirMatch->dirName = _free(dirMatch->dirName);
+ al->numDirs--;
+ if (dirNum > al->numDirs)
+ continue;
+ memmove(dirMatch, dirMatch+1, (al->numDirs - dirNum));
+ }
+
+ if (origNumDirs > al->numDirs) {
+ if (al->numDirs > 0)
+ al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
+ else
+ al->dirs = _free(al->dirs);
+ }
+
+ dirNames = hfd(dirNames, dnt);
+ }
+ p->h = headerFree(p->h);
+ memset(p, 0, sizeof(*p));
+ /*@-nullstate@*/ /* FIX: al->list->h may be NULL */
+ return;
+ /*@=nullstate@*/
+}
+
+availablePackage
+alAddPackage(availableList al, int pkgNum,
+ Header h, /*@null@*/ /*@dependent@*/ const void * key,
+ /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs)
+ /*@modifies al, h @*/
+{
+ HGE_t hge = (HGE_t)headerGetEntryMinMemory;
+ HFD_t hfd = headerFreeData;
+ rpmTagType dnt, bnt;
+ availablePackage p;
+ int i, xx;
+ uint_32 multiLibMask = 0;
+ uint_32 * pp = NULL;
+
+ if (pkgNum >= 0 && pkgNum < al->size) {
+ alDelPackage(al, pkgNum);
+ } else {
+ if (al->size == al->alloced) {
+ al->alloced += al->delta;
+ al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
+ }
+ pkgNum = al->size++;
+ }
+
+ p = al->list + pkgNum;
+
+ p->h = headerLink(h); /* XXX reference held by transaction set */
+ p->depth = p->npreds = 0;
+ memset(&p->tsi, 0, sizeof(p->tsi));
+ p->multiLib = 0; /* MULTILIB */
+
+ xx = headerNVR(p->h, &p->name, &p->version, &p->release);
+
+/*@-modfilesys@*/
+if (_al_debug)
+fprintf(stderr, "*** add %p[%d] %s-%s-%s\n", al->list, pkgNum, p->name, p->version, p->release);
+/*@=modfilesys@*/
+
+ /* XXX This should be added always so that packages look alike.
+ * XXX However, there is logic in files.c/depends.c that checks for
+ * XXX existence (rather than value) that will need to change as well.
+ */
+ if (hge(p->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
+ multiLibMask = *pp;
+
+ if (multiLibMask) {
+ for (i = 0; i < pkgNum - 1; i++) {
+ if (!strcmp (p->name, al->list[i].name)
+ && hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
+ (void **) &pp, NULL)
+ && !rpmVersionCompare(p->h, al->list[i].h)
+ && *pp && !(*pp & multiLibMask))
+ p->multiLib = multiLibMask;
+ }
+ }
+
+ if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL))
+ p->epoch = NULL;
+
+ if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides,
+ &p->providesCount))
+ {
+ p->providesCount = 0;
+ p->provides = NULL;
+ p->providesEVR = NULL;
+ p->provideFlags = NULL;
+ } else {
+ if (!hge(h, RPMTAG_PROVIDEVERSION,
+ NULL, (void **) &p->providesEVR, NULL))
+ p->providesEVR = NULL;
+ if (!hge(h, RPMTAG_PROVIDEFLAGS,
+ NULL, (void **) &p->provideFlags, NULL))
+ p->provideFlags = NULL;
+ }
+
+ if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires,
+ &p->requiresCount)) {
+ p->requiresCount = 0;
+ p->requires = NULL;
+ p->requiresEVR = NULL;
+ p->requireFlags = NULL;
+ } else {
+ if (!hge(h, RPMTAG_REQUIREVERSION,
+ NULL, (void **) &p->requiresEVR, NULL))
+ p->requiresEVR = NULL;
+ if (!hge(h, RPMTAG_REQUIREFLAGS,
+ NULL, (void **) &p->requireFlags, NULL))
+ p->requireFlags = NULL;
+ }
+
+ if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **)&p->baseNames, &p->filesCount))
+ {
+ p->filesCount = 0;
+ p->baseNames = NULL;
+ } else {
+ int_32 * dirIndexes;
+ const char ** dirNames;
+ int_32 numDirs;
+ uint_32 * fileFlags = NULL;
+ int * dirMapping;
+ dirInfo dirNeedle =
+ memset(alloca(sizeof(*dirNeedle)), 0, sizeof(*dirNeedle));
+ dirInfo dirMatch;
+ int first, last, fileNum, dirNum;
+ int origNumDirs;
+
+ xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
+ xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
+ xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
+
+ /* XXX FIXME: We ought to relocate the directory list here */
+
+ dirMapping = alloca(sizeof(*dirMapping) * numDirs);
+
+ /* allocated enough space for all the directories we could possible
+ need to add */
+ al->dirs = xrealloc(al->dirs,
+ (al->numDirs + numDirs) * sizeof(*al->dirs));
+ origNumDirs = al->numDirs;
+
+ for (dirNum = 0; dirNum < numDirs; dirNum++) {
+ dirNeedle->dirName = (char *) dirNames[dirNum];
+ dirNeedle->dirNameLen = strlen(dirNames[dirNum]);
+ dirMatch = bsearch(dirNeedle, al->dirs, origNumDirs,
+ sizeof(*dirNeedle), dirInfoCompare);
+ if (dirMatch) {
+ dirMapping[dirNum] = dirMatch - al->dirs;
+ } else {
+ dirMapping[dirNum] = al->numDirs;
+ dirMatch = al->dirs + al->numDirs;
+ dirMatch->dirName = xstrdup(dirNames[dirNum]);
+ dirMatch->dirNameLen = strlen(dirNames[dirNum]);
+ dirMatch->files = NULL;
+ dirMatch->numFiles = 0;
+ al->numDirs++;
+ }
+ }
+
+ dirNames = hfd(dirNames, dnt);
+
+ for (first = 0; first < p->filesCount; first = last + 1) {
+ for (last = first; (last + 1) < p->filesCount; last++) {
+ if (dirIndexes[first] != dirIndexes[last + 1])
+ /*@innerbreak@*/ break;
+ }
+
+ dirMatch = al->dirs + dirMapping[dirIndexes[first]];
+ dirMatch->files = xrealloc(dirMatch->files,
+ (dirMatch->numFiles + last - first + 1) *
+ sizeof(*dirMatch->files));
+ if (p->baseNames != NULL) /* XXX can't happen */
+ for (fileNum = first; fileNum <= last; fileNum++) {
+ /*@-assignexpose@*/
+ dirMatch->files[dirMatch->numFiles].baseName =
+ p->baseNames[fileNum];
+ /*@=assignexpose@*/
+ dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum;
+ dirMatch->files[dirMatch->numFiles].fileFlags =
+ fileFlags[fileNum];
+ dirMatch->numFiles++;
+ }
+ }
+
+ /* XXX should we realloc to smaller size? */
+ if (origNumDirs + al->numDirs)
+ qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dirInfoCompare);
+
+ }
+
+ /*@-assignexpose@*/
+ p->key = key;
+ /*@=assignexpose@*/
+ /*@-type@*/ /* FIX: cast? */
+ p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL);
+ /*@=type@*/
+
+ if (relocs) {
+ rpmRelocation * r;
+
+ for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++)
+ {};
+ p->relocs = xmalloc((i + 1) * sizeof(*p->relocs));
+
+ for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
+ p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
+ p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
+ }
+ p->relocs[i].oldPath = NULL;
+ p->relocs[i].newPath = NULL;
+ } else {
+ p->relocs = NULL;
+ }
+
+ alFreeIndex(al);
+
+ return p;
+}
+
+/**
+ * Compare two available index entries by name (qsort/bsearch).
+ * @param one 1st available index entry
+ * @param two 2nd available index entry
+ * @return result of comparison
+ */
+static int indexcmp(const void * one, const void * two) /*@*/
+{
+ /*@-castexpose@*/
+ const availableIndexEntry a = (const availableIndexEntry) one;
+ const availableIndexEntry b = (const availableIndexEntry) two;
+ /*@=castexpose@*/
+ int lenchk = a->entryLen - b->entryLen;
+
+ if (lenchk)
+ return lenchk;
+
+ return strcmp(a->entry, b->entry);
+}
+
+void alMakeIndex(availableList al)
+{
+ availableIndex ai = &al->index;
+ int i, j, k;
+
+ if (ai->size || al->list == NULL) return;
+
+ for (i = 0; i < al->size; i++)
+ ai->size += al->list[i].providesCount;
+
+ if (ai->size) {
+ ai->index = xcalloc(ai->size, sizeof(*ai->index));
+
+ k = 0;
+ for (i = 0; i < al->size; i++) {
+ for (j = 0; j < al->list[i].providesCount; j++) {
+
+ /* If multilib install, skip non-multilib provides. */
+ if (al->list[i].multiLib &&
+ !isDependsMULTILIB(al->list[i].provideFlags[j])) {
+ ai->size--;
+ /*@innercontinue@*/ continue;
+ }
+
+ ai->index[k].package = al->list + i;
+ /*@-assignexpose@*/
+ ai->index[k].entry = al->list[i].provides[j];
+ /*@=assignexpose@*/
+ ai->index[k].entryLen = strlen(al->list[i].provides[j]);
+ ai->index[k].type = IET_PROVIDES;
+ k++;
+ }
+ }
+
+ qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
+ }
+}
+
+availablePackage *
+alAllFileSatisfiesDepend(const availableList al,
+ const char * keyType, const char * fileName)
+{
+ int i, found = 0;
+ const char * dirName;
+ const char * baseName;
+ dirInfo dirNeedle =
+ memset(alloca(sizeof(*dirNeedle)), 0, sizeof(*dirNeedle));
+ dirInfo dirMatch;
+ availablePackage * ret = NULL;
+
+ /* Solaris 2.6 bsearch sucks down on this. */
+ if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
+ return NULL;
+
+ { char * t;
+ dirName = t = xstrdup(fileName);
+ if ((t = strrchr(t, '/')) != NULL) {
+ t++; /* leave the trailing '/' */
+ *t = '\0';
+ }
+ }
+
+ dirNeedle->dirName = (char *) dirName;
+ dirNeedle->dirNameLen = strlen(dirName);
+ dirMatch = bsearch(dirNeedle, al->dirs, al->numDirs,
+ sizeof(*dirNeedle), dirInfoCompare);
+ if (dirMatch == NULL)
+ goto exit;
+
+ /* rewind to the first match */
+ while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, dirNeedle) == 0)
+ dirMatch--;
+
+ if ((baseName = strrchr(fileName, '/')) == NULL)
+ goto exit;
+ baseName++;
+
+ for (found = 0, ret = NULL;
+ dirMatch <= al->dirs + al->numDirs &&
+ dirInfoCompare(dirMatch, dirNeedle) == 0;
+ dirMatch++)
+ {
+ /* XXX FIXME: these file lists should be sorted and bsearched */
+ for (i = 0; i < dirMatch->numFiles; i++) {
+ if (dirMatch->files[i].baseName == NULL ||
+ strcmp(dirMatch->files[i].baseName, baseName))
+ /*@innercontinue@*/ continue;
+
+ /*
+ * If a file dependency would be satisfied by a file
+ * we are not going to install, skip it.
+ */
+ if (al->list[dirMatch->files[i].pkgNum].multiLib &&
+ !isFileMULTILIB(dirMatch->files[i].fileFlags))
+ /*@innercontinue@*/ continue;
+
+ if (keyType)
+ rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
+ keyType, fileName);
+
+ ret = xrealloc(ret, (found+2) * sizeof(*ret));
+ if (ret) /* can't happen */
+ ret[found++] = al->list + dirMatch->files[i].pkgNum;
+ /*@innerbreak@*/ break;
+ }
+ }
+
+exit:
+ dirName = _free(dirName);
+ /*@-mods@*/ /* AOK: al->list not modified through ret alias. */
+ if (ret)
+ ret[found] = NULL;
+ /*@=mods@*/
+ return ret;
+}
+
+#ifdef DYING
+/**
+ * Check added package file lists for first package that provides a file.
+ * @param al available list
+ * @param keyType type of dependency
+ * @param fileName file name to search for
+ * @return available package pointer
+ */
+/*@unused@*/ static /*@dependent@*/ /*@null@*/ availablePackage
+alFileSatisfiesDepend(const availableList al,
+ const char * keyType, const char * fileName)
+ /*@*/
+{
+ availablePackage ret;
+ availablePackage * tmp = alAllFileSatisfiesDepend(al, keyType, fileName);
+
+ if (tmp) {
+ ret = tmp[0];
+ tmp = _free(tmp);
+ return ret;
+ }
+ return NULL;
+}
+#endif /* DYING */
+
+availablePackage *
+alAllSatisfiesDepend(const availableList al,
+ const char * keyType, const char * keyDepend,
+ const char * keyName, const char * keyEVR, int keyFlags)
+{
+ availableIndexEntry needle =
+ memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
+ availableIndexEntry match;
+ availablePackage p, * ret = NULL;
+ int i, rc, found;
+
+ if (*keyName == '/') {
+ ret = alAllFileSatisfiesDepend(al, keyType, keyName);
+ /* XXX Provides: /path was broken with added packages (#52183). */
+ if (ret != NULL && *ret != NULL)
+ return ret;
+ }
+
+ if (!al->index.size || al->index.index == NULL) return NULL;
+
+ /*@-assignexpose@*/
+ /*@-temptrans@*/
+ needle->entry = keyName;
+ /*@=temptrans@*/
+ needle->entryLen = strlen(keyName);
+ match = bsearch(needle, al->index.index, al->index.size,
+ sizeof(*al->index.index), indexcmp);
+ /*@=assignexpose@*/
+
+ if (match == NULL) return NULL;
+
+ /* rewind to the first match */
+ while (match > al->index.index && indexcmp(match-1, needle) == 0)
+ match--;
+
+ for (ret = NULL, found = 0;
+ match <= al->index.index + al->index.size &&
+ indexcmp(match, needle) == 0;
+ match++)
+ {
+
+ p = match->package;
+ rc = 0;
+ switch (match->type) {
+ case IET_PROVIDES:
+ for (i = 0; i < p->providesCount; i++) {
+ const char * proEVR;
+ int proFlags;
+
+ /* Filter out provides that came along for the ride. */
+ if (strcmp(p->provides[i], keyName))
+ /*@innercontinue@*/ continue;
+
+ proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
+ proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
+ rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
+ keyName, keyEVR, keyFlags);
+ if (rc)
+ /*@innerbreak@*/ break;
+ }
+ if (keyType && keyDepend && rc)
+ rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
+ keyType, keyDepend+2);
+ /*@switchbreak@*/ break;
+ }
+
+ /*@-branchstate@*/
+ if (rc) {
+ ret = xrealloc(ret, (found + 2) * sizeof(*ret));
+ if (ret) /* can't happen */
+ ret[found++] = p;
+ }
+ /*@=branchstate@*/
+ }
+
+ if (ret)
+ ret[found] = NULL;
+
+ return ret;
+}