IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Mar 7, 2005, 10:58:51 AM (21 years ago)
Author:
desonia
Message:

modified psMetadata to use a special psMetadataType to signify duplicate
entries and added a flag to signify that duplicate entries are OK.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/astronomy/psMetadata.c

    r3341 r3381  
    1212*  @author Ross Harman, MHPCC
    1313*
    14 *  @version $Revision: 1.53 $ $Name: not supported by cvs2svn $
    15 *  @date $Date: 2005-02-28 23:34:10 $
     14*  @version $Revision: 1.54 $ $Name: not supported by cvs2svn $
     15*  @date $Date: 2005-03-07 20:58:50 $
    1616*
    1717*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    8585}
    8686
     87static void metadataIteratorFree(psMetadataIterator* iter)
     88{
     89    if (iter == NULL) {
     90        return;
     91    }
     92    psFree(iter->iter);
     93    regfree(iter->preg);
     94}
     95
    8796static void metadataFree(psMetadata* metadata)
    8897{
     
    158167
    159168    // Set metadata item type
    160     metadataItem->type = type;
     169    metadataItem->type = type & PS_METADATA_TYPE_MASK;
    161170
    162171    // Allocate and set metadata item name
     
    165174
    166175    // Set metadata item value
    167     switch(type) {
     176    switch(metadataItem->type) {
    168177    case PS_META_BOOL:
    169178        metadataItem->data.B = (psBool)va_arg(argPtr, psS32);
     
    190199    case PS_META_ASTROM:
    191200    case PS_META_UNKNOWN:
     201    case PS_META_MULTI:
    192202        // Copy of input data not performed due to variability of data types
    193203        metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPtr));
     
    223233}
    224234
    225 psBool psMetadataAddItem(psMetadata *md, psMetadataItem *metadataItem, psS32 location)
     235psBool psMetadataAddItem(psMetadata *md, psMetadataItem *metadataItem, psS32 location, psS32 flags)
    226236{
    227237    char * key = NULL;
     
    229239    psList *mdList = NULL;
    230240    psMetadataItem *existingEntry = NULL;
    231     psMetadataItem *newFolderEntry = NULL;
    232     psMetadataType newType;
    233241
    234242    PS_PTR_CHECK_NULL(md,NULL);
     
    238246    PS_PTR_CHECK_NULL(metadataItem->name,NULL);
    239247
    240     newType = metadataItem->type;
    241248    mdTable = md->table;
    242249    mdList = md->list;
     
    245252    // See if key is already in table
    246253    existingEntry = (psMetadataItem*)psHashLookup(mdTable, key);
     254
     255    // how the item is added to the hash depends on flags & prior existence
    247256    if(existingEntry != NULL) {
    248 
    249         if(existingEntry->type == PS_META_LIST) {
    250 
    251             if(existingEntry->data.list == NULL) {
    252                 existingEntry->data.list = psListAlloc(NULL);
     257        if ((flags & PS_META_DUPLICATE_OK) != 0) {
     258            // duplicate entries allowed - add another entry.
     259            if (existingEntry->type != PS_META_MULTI) {
     260                // first duplicate, transfer the hash's old entry into a
     261                // list of entries with the type PS_META_MULTI.
     262
     263                // add entry to a list and dereference the local pointer
     264                psList* newList = psListAlloc(existingEntry);
     265
     266                existingEntry = psMetadataItemAlloc(key,
     267                                                    PS_META_MULTI,
     268                                                    "",
     269                                                    newList);
     270                psHashRemove(mdTable,key); // take out the old entry
     271                psHashAdd(mdTable, key, existingEntry); // put in the new entry
     272
     273                // free local references of newly allocated items.
     274                psFree(newList);
     275                psFree(existingEntry);
     276
    253277            }
    254278
    255             // Add leaf node to existing folder node
    256             if(!psListAdd(existingEntry->data.list, PS_LIST_TAIL, metadataItem)) {
    257                 psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED, metadataItem->name);
     279            // add to the hash's list of duplicate entries
     280            if (! psListAdd(existingEntry->data.list, PS_LIST_TAIL, metadataItem) ) {
     281                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
    258282                return false;
    259283            }
    260         } else if(existingEntry->type != PS_META_LIST && newType!= PS_META_LIST) {
    261 
    262             // Leaf node replaces another leaf. Make new folder node and add leaves.
    263             newFolderEntry = psMetadataItemAlloc(key, PS_META_LIST, NULL, NULL);
    264             newFolderEntry->data.list = psListAlloc(NULL);
    265 
    266             if(!psListAdd(newFolderEntry->data.list, PS_LIST_TAIL, existingEntry)) {
    267                 psError(PS_ERR_UNKNOWN,false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
    268                 psFree(newFolderEntry);
    269                 return false;
    270             }
    271 
    272             if(!psListAdd(newFolderEntry->data.list, PS_LIST_TAIL, metadataItem)) {
    273                 psError(PS_ERR_UNKNOWN,false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
    274                 psFree(newFolderEntry);
    275                 return false;
    276             }
    277 
    278             if(!psHashRemove(mdTable, key)) {
    279                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED,key);
    280                 psFree(newFolderEntry);
    281                 return false;
    282             }
    283 
    284             if(!psHashAdd(mdTable, key, newFolderEntry)) {
    285                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
    286                 psFree(newFolderEntry);
    287                 return false;
    288             }
    289 
    290             // Remove local reference to new folder node
    291             psMemDecrRefCounter(newFolderEntry);
    292         } else {
    293 
    294             // Folder node replaces leaf or folder node - Put old node into new folder and remove from table
    295             if(metadataItem->data.list == NULL) {
    296                 metadataItem->data.list = psListAlloc(NULL);
    297             }
    298 
    299             if(!psListAdd(metadataItem->data.list, PS_LIST_TAIL, existingEntry)) {
    300                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
    301                 return false;
    302             }
    303 
    304             if(!psHashRemove(mdTable, key)) {
    305                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED,key);
    306                 return false;
    307             }
    308 
     284            // (added to list below)
     285
     286        } else if ((flags & PS_META_REPLACE) != 0) {
     287            // replace entry instead of creating a duplicate entry.
     288
     289            // remove the existing entry from metadata
     290            psListRemoveData(mdList, existingEntry);
     291            psHashRemove(mdTable, key);
     292
     293            // treat as if new (added to list below)
    309294            if(!psHashAdd(mdTable, key, metadataItem)) {
    310295                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
    311296                return false;
    312297            }
     298        } else {
     299            // default is to error on duplicate entry.
     300            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     301                    PS_ERRORTEXT_psMetadata_DUPLICATE_NOT_ALLOWED);
     302            return false;
    313303        }
    314304    } else {
     305        // OK, this is a new item.
    315306
    316307        // Node doesn't exist - Add new metadata item to metadata collection's hash
     
    321312    }
    322313
    323     // Add items to metadata collection's list, even if they have the same metadata item names. Folder nodes
    324     // (PS_META_LIST metadata items) are not added, since the metadata list is flat.
    325     if(metadataItem->type != PS_META_LIST) {
    326         if(!psListAdd(mdList, location, metadataItem)) {
    327             psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
    328             return false;
    329         }
     314    if(!psListAdd(mdList, location, metadataItem)) {
     315        psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
     316        return false;
    330317    }
    331318
     
    333320}
    334321
    335 psBool psMetadataAdd(psMetadata *md, psS32 where, const char *name,
    336                      psMetadataType type, const char *comment, ...)
     322psBool psMetadataAdd(psMetadata *md, psS32 location, const char *name,
     323                     psS32 type, const char *comment, ...)
    337324{
    338325    va_list argPtr;
     326
     327    va_start(argPtr, comment);
     328    psBool result = psMetadataAddV(md,location,name,type,comment,argPtr);
     329    va_end(argPtr);
     330
     331    return result;
     332}
     333
     334psBool psMetadataAddV(psMetadata *md, psS32 location, const char *name,
     335                      psS32 type, const char *comment, va_list list)
     336{
    339337    psMetadataItem* metadataItem = NULL;
    340338
    341     va_start(argPtr, comment);
    342     metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
    343     va_end(argPtr);
    344 
    345     if (!psMetadataAddItem(md, metadataItem, where)) {
     339    metadataItem = psMetadataItemAllocV(name, type & PS_METADATA_TYPE_MASK, comment, list);
     340
     341    if (!psMetadataAddItem(md, metadataItem, location, type & PS_METADATA_FLAGS_MASK)) {
    346342        psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_FAILED);
    347343        psFree(metadataItem);
     
    373369psBool psMetadataRemove(psMetadata *md, psS32 where, const char *key)
    374370{
    375     psList* mdList = NULL;
    376     psHash* mdTable = NULL;
    377     psMetadataItem* entry = NULL;
    378 
    379 
    380371    PS_PTR_CHECK_NULL(md,NULL);
     372
     373    PS_PTR_CHECK_NULL(md->list,NULL);
     374    psList* mdList = md->list;
     375
    381376    PS_PTR_CHECK_NULL(md->table,NULL);
    382     PS_PTR_CHECK_NULL(md->list,NULL);
    383 
    384     mdList = md->list;
    385     mdTable = md->table;
     377    psHash* mdTable = md->table;
    386378
    387379    // Select removal by key or index
    388380    if (key != NULL) {
    389 
    390381        // Remove by key name
    391         entry = (psMetadataItem*)psHashLookup(mdTable, key);
     382        psMetadataItem* entry = psHashLookup(mdTable,key);
    392383        if (entry == NULL) {
    393             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_FIND_FAILED, key);
     384            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
    394385            return false;
    395386        }
    396 
     387        if (entry->type == PS_META_MULTI) {
     388            psMetadataItem* listItem;
     389            psListIterator* iter = psListIteratorAlloc(
     390                                       entry->data.list,
     391                                       PS_LIST_HEAD,true);
     392            while ((listItem=psListGetAndIncrement(iter)) != NULL) {
     393                psListRemoveData(mdList, listItem);
     394            }
     395            psFree(iter);
     396            psHashRemove(mdTable,key);
     397
     398        } else {
     399            psListRemoveData(mdList, entry);
     400            psHashRemove(mdTable, key);
     401        }
    397402    } else {
    398 
    399403        // Remove by index
    400         entry = psListGet(mdList, where);
     404        psMetadataItem* entry = psListGet(mdList, where);
    401405        if (entry == NULL) {
    402406            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_FIND_INDEX_FAILED, where);
    403407            return false;
    404408        }
    405 
    406409        key = entry->name;
    407         if(key == NULL) {
     410
     411        if (key == NULL) {
    408412            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_REMOVE_LIST_INDEX_FAILED, where);
    409413            return false;
    410414        }
    411     }
    412 
    413     if (!psListRemoveData(mdList, entry)) {
    414         psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_LIST_FAILED, key);
    415         return false;
    416     }
    417 
    418     // Remove entry from metadata collection's table
    419     if (!psHashRemove(mdTable, key)) {
    420         psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
    421         return false;
     415
     416        psMetadataItem* tableItem = psHashLookup(mdTable, key);
     417        if (tableItem == NULL) {
     418            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
     419            return false;
     420        }
     421
     422        if (tableItem->type == PS_META_MULTI) {
     423            // multiple entries with same key, remove just the specified one
     424            psListRemoveData(tableItem->data.list, entry);
     425            if (psListGet(tableItem->data.list,PS_LIST_HEAD) == NULL) {
     426                // list is empty, so let's clear the whole entry now.
     427                if (!psHashRemove(mdTable, key)) {
     428                    psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
     429                    return false;
     430                }
     431            }
     432        } else {
     433            if (!psHashRemove(mdTable, key)) {
     434                psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
     435                return false;
     436            }
     437        }
     438        psListRemove(mdList, where);
    422439    }
    423440
     
    455472        }
    456473        return NULL;
     474    }
     475    if (metadataItem->type == PS_META_MULTI) {
     476        // if multiple keys found, use the first.
     477        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head);
    457478    }
    458479
     
    486507        } \
    487508        return 0; \
     509    } \
     510    if (metadataItem->type == PS_META_MULTI) { \
     511        /* if multiple keys found, use the first. */ \
     512        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head); \
    488513    } \
    489514    \
     
    535560    return entry;
    536561}
     562
     563psMetadataIterator* psMetadataIteratorAlloc(psMetadata* md,
     564        int location,
     565        const char* regex)
     566{
     567    PS_PTR_CHECK_NULL(md,NULL);
     568    PS_PTR_CHECK_NULL(md->list,NULL);
     569
     570    psMetadataIterator* newIter = psAlloc(sizeof(psMetadataIterator));
     571    newIter->preg = NULL;
     572    newIter->iter = NULL;
     573
     574    // Set deallocator
     575    p_psMemSetDeallocator(newIter, (psFreeFcn) metadataIteratorFree);
     576
     577    if (regex == NULL) {
     578        newIter->iter = psListIteratorAlloc(md->list, location, false);
     579        return newIter;
     580    } else {
     581        int regRtn = regcomp(newIter->preg,regex,0);
     582        if (regRtn != 0) {
     583            char errMsg[256];
     584            regerror(regRtn, newIter->preg, errMsg, 256);
     585            regfree(newIter->preg);
     586            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     587                    PS_ERRORTEXT_psMetadata_REGEX_INVALID,
     588                    errMsg);
     589            psFree(newIter);
     590            return NULL;
     591        }
     592    }
     593
     594    psMetadataIteratorSet(newIter, location); // XXX: do we error if no match is found?
     595
     596    return newIter;
     597}
     598
     599psBool psMetadataIteratorSet(psMetadataIterator* iterator,
     600                             int location)
     601{
     602    int match;
     603    psMetadataItem* cursor;
     604
     605    PS_PTR_CHECK_NULL(iterator,NULL);
     606
     607    psListIterator* iter = iterator->iter;
     608    PS_PTR_CHECK_NULL(iterator->iter,NULL);
     609
     610    regex_t* preg = iterator->preg;
     611
     612    // handle trivial case where no regex subsetting is required.
     613    if (preg == NULL) {
     614        return psListIteratorSet(iter,location);
     615    }
     616
     617    if (location < 0) {
     618        // match from the tail
     619        match = 0;
     620        psListIteratorSet(iter,PS_LIST_TAIL);
     621        while ( (cursor=(psMetadataItem*)iter->cursor) != NULL) {
     622            if (regexec(preg, cursor->name, 0, NULL, 0) == 0) {
     623                // this key is a match
     624                match--;
     625                if (match == location) {
     626                    break;
     627                }
     628            }
     629            (void)psListGetAndDecrement(iter);
     630        }
     631        return (match == location);
     632    }
     633
     634    // find the n-th match from the head
     635    match = -1;
     636    psListIteratorSet(iter,PS_LIST_HEAD);
     637    while ( (cursor=(psMetadataItem*)iter->cursor) != NULL) {
     638        if (regexec(preg, cursor->name, 0, NULL, 0) == 0) {
     639            // this key is a match
     640            match++;
     641            if (match == location) {
     642                break;
     643            }
     644        }
     645        (void)psListGetAndIncrement(iter);
     646    }
     647    return (match == location);
     648}
     649
     650psMetadataItem* psMetadataGetAndIncrement(psMetadataIterator* iterator)
     651{
     652    psMetadataItem* oldValue;
     653
     654    PS_PTR_CHECK_NULL(iterator,NULL);
     655
     656    psListIterator* iter = iterator->iter;
     657    PS_PTR_CHECK_NULL(iterator->iter,NULL);
     658
     659    regex_t* preg = iterator->preg;
     660
     661    // handle trivial case where no regex subsetting is required.
     662    if (preg == NULL) {
     663        return (psMetadataItem*)psListGetAndIncrement(iter);
     664    }
     665
     666    oldValue = (psMetadataItem*)iter->cursor;
     667
     668    while (psListGetAndIncrement(iter) != NULL) {
     669        if (iter->cursor != NULL &&
     670                regexec(preg, ((psMetadataItem*)iter->cursor)->name, 0, NULL, 0) == 0) {
     671            // this key is a match
     672            break;
     673        }
     674    }
     675    return oldValue;
     676}
     677
     678psMetadataItem* psMetadataGetAndDecrement(psMetadataIterator* iterator)
     679{
     680    psMetadataItem* oldValue;
     681
     682    PS_PTR_CHECK_NULL(iterator,NULL);
     683
     684    psListIterator* iter = iterator->iter;
     685    PS_PTR_CHECK_NULL(iterator->iter,NULL);
     686
     687    regex_t* preg = iterator->preg;
     688
     689    // handle trivial case where no regex subsetting is required.
     690    if (preg == NULL) {
     691        return (psMetadataItem*)psListGetAndDecrement(iter);
     692    }
     693
     694    oldValue = (psMetadataItem*)iter->cursor;
     695
     696    while (psListGetAndDecrement(iter) != NULL) {
     697        if (iter->cursor != NULL &&
     698                regexec(preg, ((psMetadataItem*)iter->cursor)->name, 0, NULL, 0) == 0) {
     699            // this key is a match
     700            break;
     701        }
     702    }
     703    return oldValue;
     704}
Note: See TracChangeset for help on using the changeset viewer.