ss_pers_t *
ss_pers_find(ss_scope_t *scope, /* Scope to be searched */
ss_pers_t *key, /* Value for which to search. This is required even if MASK is null because
* the KEY determines the type of objects for which to search. */
ss_persobj_t *mask, /* Which elements of KEY to consider when searching. It is an error if no bits
* of MASK are set, but if MASK is the null pointer then KEY is assumed to
* match every object. If non-null then MASK and KEY must be of the same
* type. The reason MASK is an object pointer rather than an object link is
* that the memory is really only used to store one-byte flags that control
* how the matching is performed. In other words, MASK isn't truly an
* object--it just has to be the same size as an object. */
size_t nskip, /* Number of initial matched results that should be skipped. */
size_t *nfound, /* INOUT: The input value limits the matching to the specified number of
* objects, and on successful return this points to the number of objects
* actually found to match. This can be a null pointer as long as BUFFER is
* a null pointer, but if BUFFER is supplied then the incoming value of NFOUND
* indicates the number of elements in BUFFER. An incoming value of SS_NOSIZE
* indicates that the result is not to be truncated. */
ss_pers_t *buffer, /* Optional buffer to fill in with handles to items that were found. If this
* is the constant SS_PERS_TEST then this function behaves exactly as if the
* caller had supplied a buffer but does not attempt to return links to the
* matching objects. */
ss_prop_t *props /* Optional properties (See Persistent Object Properties) */
)
{
SS_ENTER(ss_pers_find, ss_pers_tP);
unsigned tableid;
ss_table_t *table=NULL;
ss_pers_find_t find_data;
ss_scope_t *reg_scope=NULL;
size_t regidx;
int noregistries=0;
ss_gfile_t *gfile=NULL;
memset(&find_data, 0, sizeof find_data); /* Necessary for error cleanup */
SS_ASSERT_MEM(scope, ss_scope_t);
SS_ASSERT_CLASS(key, ss_pers_t);
if (buffer && NULL==nfound)
SS_ERROR_FMT(USAGE, ("if BUFFER is specified then NFOUND must be non-null"));
tableid = SS_MAGIC_SEQUENCE(SS_MAGIC_OF(key));
if (NULL==(table = ss_scope_table(scope, tableid, NULL))) SS_ERROR(FAILED);
/* Initialize data to pass through ss_table_scan() */
if (NULL==(find_data.key = ss_pers_deref(key))) SS_ERROR(NOTFOUND);
find_data.mask = mask;
find_data.buffer = buffer;
find_data.nalloc = buffer ? *nfound : 0;
find_data.limit = nfound ? *nfound : SS_NOSIZE;
find_data.nskip = nskip;
find_data.overflowed = FALSE;
find_data.scope = scope;
if (NULL==ss_prop_get(props, "detect_overflow", H5T_NATIVE_INT, &(find_data.detect_overflow))) {
SS_STATUS_OK;
find_data.detect_overflow = FALSE;
}
/* Scan the entire table for matches. We could also check whether ss_table_scan() returned positive, which indicates that
* we've found more matches than the find_data.limit value. */
if (ss_table_scan(table, NULL, 0, ss_pers_find_cb, &find_data)<0) SS_ERROR(FAILED);
if (find_data.detect_overflow && find_data.overflowed) SS_ERROR(OVERFLOW);
/* Search registries until we find something. The tables that describe the file infrastructure do not need to search
* registries because doing so doesn't really make any sense: Scope, File, and Blob tables. */
if (0==find_data.nused &&
SS_MAGIC_OF(key)!=SS_MAGIC(ss_scope_t) &&
SS_MAGIC_OF(key)!=SS_MAGIC(ss_file_t) &&
SS_MAGIC_OF(key)!=SS_MAGIC(ss_blob_t) &&
(NULL==ss_prop_get(props, "noregistries", H5T_NATIVE_INT, &noregistries) || !noregistries)) {
SS_STATUS_OK; /*clean up from possible failed ss_prop_get()*/
if (NULL==(gfile = SS_GFILE_LINK(scope))) SS_ERROR(FAILED);
for (regidx=0; 0==find_data.nused && regidx<gfile->reg_nused; regidx++) {
reg_scope = gfile->reg + regidx;
if (NULL==(table = ss_scope_table(reg_scope, tableid, NULL))) SS_ERROR(FAILED);
find_data.scope = reg_scope;
if (ss_table_scan(table, reg_scope, 0, ss_pers_find_cb, &find_data)<0) SS_ERROR(FAILED);
if (find_data.detect_overflow && find_data.overflowed) SS_ERROR(OVERFLOW);
}
}
/* If no matches were found but we were otherwise successful then make sure we return a non-null value */
if (nfound) *nfound = find_data.nused;
if (0==find_data.nused && NULL==find_data.buffer) {
find_data.buffer = calloc(1, sizeof(ss_pers_t));
find_data.nalloc = 1;
}
/* If there is room then set the link after the last one to null */
if (!buffer) SS_EXTEND(find_data.buffer, find_data.nused+1, find_data.nalloc);
if (find_data.nused<find_data.nalloc && SS_PERS_TEST!=find_data.buffer)
memset(find_data.buffer + find_data.nused, 0, sizeof(find_data.buffer[0]));
SS_CLEANUP:
if (!buffer) SS_FREE(find_data.buffer);
if (nfound) *nfound = 0;
SS_LEAVE(find_data.buffer);
}