int
saf_find_categories(SAF_ParMode pmode,
SAF_Db *db, /* Database on which to restrict the search. */
SAF_Set *containing_set, /* The set upon which to restrict the search. The special macro SAF_UNIVERSE(db)
* (which takes a database handle as an argument) allows the search to span
* all categories of the specified database. */
const char *name, /* The name of the categories upon which to restrict the search. The constant
* SAF_ANY_NAME allows the search to span categories with any name. */
SAF_Role *role, /* The role of the categories upon which to restrict the search. A null pointer
* allows the search to span categories with any role (see
* Collection Roles). */
int tdim, /* The topological dimension of the categories upon which to restrict the
* search. The constant SAF_ANY_TOPODIM allows the search to span categories
* with any topological dimension. */
int *num, /* For this and the succeeding argument [see Returned Handles]. */
SAF_Cat **found /* For this and the preceding argument [see Returned Handles]. */
)
{
SAF_ENTER(saf_find_categories, SAF_PRECONDITION_ERROR);
SAF_KEYMASK(SAF_Cat, key, mask);
size_t nfound=SS_NOSIZE;
ss_scope_t scope=SS_SCOPE_NULL;
size_t i, j;
ss_collection_t coll;
SAF_Cat *cats=NULL;
SAF_REQUIRE(_saf_valid_pmode(pmode), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
_saf_errmsg("PMODE must be valid"));
if (!_saf_is_participating_proc(pmode)) SAF_RETURN(-1);
SAF_REQUIRE(ss_file_isopen(db, NULL)>0, SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
_saf_errmsg("DB must be a valid database"));
SAF_REQUIRE(_saf_valid_memhints(num, (void**)found), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
_saf_errmsg("NUM and FOUND must be compatible for return value allocation"));
SAF_REQUIRE(!role || SS_ROLE(role), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
_saf_errmsg("ROLE must be a valid role handle or NULL"));
SAF_REQUIRE(!containing_set || SS_SET(containing_set), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
_saf_errmsg("CONTAINING_SET must be a valid set handle or NULL"));
/* fill in appropriate members for the find call */
if (name)
SAF_SEARCH_S(SAF_Cat, key, mask, name, name);
if (tdim != SAF_ANY_TOPODIM)
SAF_SEARCH(SAF_Cat, key, mask, tdim, tdim);
if (role)
SAF_SEARCH_LINK(SAF_Cat, key, mask, role, *role); /*search with `equal' not `eq', thus SAF_SEARCH_LINK() not SAF_SEARCH() */
/* Get all categories that match (do not limit the results) because we'll need to prune that list against the CONTAINING_SET
* if there was one. */
ss_file_topscope(db, &scope);
cats = (ss_cat_t*)ss_pers_find(&scope, (ss_pers_t*)key, mask_count?(ss_persobj_t*)&mask:NULL, 0, &nfound, NULL, NULL);
if (!cats) SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("find failed"));
/*If containing_set is an actual set (and not SAF_UNIVERSE(db)), then remove all
categories from the list that are not in collections on the set*/
if (containing_set && !_saf_is_universe(containing_set)) {
for (i=j=0; i<nfound; i++) {
if (_saf_getCollection_set(containing_set, cats+i, &coll)) {
if (i!=j) cats[j] = cats[i];
j++;
}
}
nfound = j;
}
/* Return only what the caller asked for...
*/
if (!found) {
/* Count the matches */
assert(num);
*num = nfound;
} else if (!*found) {
/* Library allocates results */
*found = cats;
cats = NULL;
if (num) *num = nfound;
} else {
/* Find limited matches; client allocates result buffer */
assert(num);
if (nfound>(size_t)*num)
SAF_ERROR(SAF_CONSTRAINT_ERROR, _saf_errmsg("found too many matching objects"));
memcpy(*found, cats, nfound*sizeof(*cats));
*num = nfound;
}
/* Cleanup...
* ...file handles if they wern't passed back
*/
cats = SS_FREE(cats);
SAF_LEAVE(SAF_SUCCESS);
}