IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 156


Ignore:
Timestamp:
Mar 9, 2004, 12:50:03 PM (22 years ago)
Author:
rhl
Message:

Changes to support non-unique keys

Location:
trunk/archive/pslib/src/Metadata
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/archive/pslib/src/Metadata/metadata.c

    r141 r156  
    88#include "psUtils.h"
    99#include "psMetaData.h"
    10 /*
    11  * Return a properly filled-out psMetaData
     10
     11/*****************************************************************************/
     12/*
     13 * Handle sets of metadata
     14 */
     15psMetaDataSet *psMetaDataSetNew(void)   // make a new set of metadata
     16{
     17    psMetaDataSet *ms = psAlloc(sizeof(psMetaDataSet));
     18
     19    ms->list = psDlistNew(NULL);        // list of metadata
     20    ms->table = psHashNew(128);         // hash table
     21
     22    return ms;
     23}
     24
     25void psMetaDataSetDel(psMetaDataSet *ms) // destroy a set of metadata
     26{
     27    if (ms == NULL) {
     28        return;
     29    }
     30   
     31    psDlistDel(ms->list, (void (*)(void *))NULL);
     32    psHashDel(ms->table, (void (*)(void *))psMetaDataItemDel);
     33
     34    psFree(ms);
     35}
     36
     37/*****************************************************************************/
     38/*
     39 * Return a properly filled-out psMetaDataItem
    1240 *
    1341 * N.b. For types PS_META_FLOAT, PS_META_INT, and PS_META_STR, a COPY
    1442 * of the data will be kept. In all other cases, only a POINTER
    1543 * to the data will be kept.
    16  *
    17  * An unused argument, copy, is provided to handle this better
    18  * once we have copy constructors available.
    19  */
    20 psMetaData *psMetaDataNew(
    21     const char *name,                   // name of new item of metadata
    22     psMetaDataType type,                // type of this piece of metadata
     44 */
     45psMetaDataItem *psMetaDataItemNew(
     46    int typeFlags,                      // type of this piece of metadata + flags
    2347    const void *data,                   // value of new item
    24     const char *comment,                // comment associated with item;
    25                                         // may be NULL
    26     int copy)                           // always copy data; NOTUSED
    27 {
     48    const char *comment,                // comment associated with item; may be NULL
     49    const char *name,                   // name of new item of metadata (may be an sprintf format)
     50    ...                                 // possible arguments for name format
     51    )
     52{
     53    const psMetaDataType type = typeFlags & PS_META_TYPE_MASK; // the type part of typeFlags
     54    const long flags = typeFlags & ~PS_META_TYPE_MASK;         // the flags part of typeFlags
    2855    static int id = 0;                  // unique ID for an item of metadata
    29     psMetaData *ms = psAlloc(sizeof(psMetaData));
     56    psMetaDataItem *ms = psAlloc(sizeof(psMetaDataItem));
    3057
    3158    *(int *)&ms->id = id++;             // need to cast away const
     59
     60    assert ((PS_META_NTYPE & PS_META_TYPE_MASK) == PS_META_NTYPE); // we have enough type names available
     61    if (flags & PS_META_NON_UNIQUE) {
     62        if (flags & PS_META_UNIQUE) {
     63            psTrace("metadata.name", 1,
     64                    "Keyword \"%s\" was specified as both UNIQUE and NON_UNIQUE; adopting UNIQUE\n", name);
     65            flags &= ~PS_META_NON_UNIQUE;
     66        }
     67    } else {
     68        flags |= PS_META_UNIQUE;
     69    }
     70   
    3271    ms->type = type;
     72    ms->flags = flags;
     73    ms->items = NULL;
    3374
    3475    assert (name != NULL);
    35     ms->name = psAlloc(strlen(name) + 1);
    36     strcpy(ms->name, name);
    37 
    38     if(comment == NULL) {
    39         comment = "";
    40     }
    41     ms->comment = psAlloc(strlen(comment) + 1);
    42     strcpy(ms->comment, comment);
     76    if (strchr(name, '%') != NULL) {
     77        static char tmp[201];           // should be enough; we won't overflow even if it isn't
     78
     79        va_list ap;
     80        va_start(ap, name);
     81        if(vsnprintf(tmp, sizeof(tmp), name, ap) > sizeof(tmp) - 1) {
     82            psTrace("metadata.name", 1, "Keyword \"%s\" was truncated to \"%s\" upon expansion\n", name, tmp);
     83        }
     84        va_end(ap);
     85
     86        name = tmp;         
     87    }
     88    ms->name = psStringCopy(name);
     89
     90    ms->comment = psStringCopy(comment == NULL ? "" : comment);
    4391
    4492    assert (type >= 0 && type < PS_META_NTYPE);
    4593    switch (type) {
     94      case PS_META_ITEM_SET:
     95        *(void **)&ms->val.v = NULL;
     96        ms->items = psDlistNew(NULL);
     97        break;
     98
    4699      case PS_META_FLOAT:
    47100        *(float *)&ms->val.f = *(float *)data;
     
    62115      case PS_META_ASTROM:
    63116      case PS_META_UNKNOWN:
    64         *(void **)ms->val.v = (void *)data;
     117        *(void **)&ms->val.v = (void *)data;
    65118        break;
    66119      case PS_META_NTYPE:
     
    72125}
    73126
    74 void psMetaDataDel(psMetaData *ms)      // piece of metadata to destroy
     127void psMetaDataItemDel(psMetaDataItem *ms)      // piece of metadata to destroy
    75128{
    76129    if(ms == NULL) {
     
    83136    assert (ms->type >= 0 && ms->type < PS_META_NTYPE);
    84137    switch (ms->type) {
     138      case PS_META_ITEM_SET:
     139        psDlistDel(ms->items, (void (*)(void *))NULL); // they're still in the hash table
     140        ms->items = NULL;
     141        break;
    85142      case PS_META_FLOAT:
    86143      case PS_META_INT:
    87144        break;                          // nothing to do
    88        
    89145      case PS_META_STR:
    90146        psFree(ms->val.v);
     
    107163
    108164/*****************************************************************************/
    109 
    110 void psMetaDataPrint(FILE *fd,          // file descriptor to write to
    111                      const psMetaData *ms) // item of metadata to print
     165/*
     166 * Add an new psMetaDataItem to a psMetaDataSet
     167 */
     168psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item)
     169{
     170    psMetaDataItem *meta = NULL;        // an item of metadata
     171    assert (ms != NULL && ms->list != NULL && ms->table != NULL);
     172
     173    // Have we already seen this item?
     174    meta = psHashLookup(ms->table, item->name);
     175   
     176    if (item->flags & PS_META_NON_UNIQUE) {
     177        psMetaDataItem *head = meta;
     178        if (head == NULL) {             // this is the first item of this name
     179            head = psMetaDataAppend(ms, psMetaDataItemNew(PS_META_ITEM_SET, NULL, NULL, item->name));
     180        }           
     181
     182        psDlistSetIterator(head->items, PS_DLIST_TAIL, 0);
     183        meta = psDlistGetPrev(head->items, 0);
     184
     185        int i = 0;                      // index of this instance of name
     186        if (meta != NULL) {             // no items of this name
     187            char *ptr = strrchr(meta->name, '.');
     188            assert (ptr != NULL);
     189            i = atoi(ptr + 1) + 1;      // next value
     190        }
     191
     192        char newname[strlen(item->name) + 2 + 1];
     193        sprintf(newname, "%s.%d", item->name, i);
     194
     195        assert (psHashLookup(ms->table, newname) == NULL); // name isn't in use
     196
     197        psFree(item->name);
     198        item->name = psStringCopy(newname);
     199
     200        psDlistAppend(head->items, item);
     201        psHashInsert(ms->table, item->name, item, (void (*)(void *))psMetaDataItemDel);
     202
     203        return item;
     204    } else if (meta != NULL) {
     205        psError(__func__, "Key \"%s\" is already present in the metaDataSet 0x%x", item->name, ms);
     206        //psMetaDataItemDel(item);
     207
     208        return NULL;
     209    }
     210
     211    psDlistAppend(ms->list, item);
     212    psHashInsert(ms->table, item->name, item, (void (*)(void *))psMetaDataItemDel);
     213
     214    return item;
     215}
     216
     217/*****************************************************************************/
     218/*
     219 * Remove and return an item of metadata from a set
     220 */
     221psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key)
     222{
     223    assert (ms != NULL && ms->list != NULL && ms->table != NULL);
     224
     225    void *data = psHashRemove(ms->table, key);
     226
     227    if (data == NULL) {
     228        return NULL;
     229    } else {
     230        return psDlistRemove(ms->list, data, PS_DLIST_UNKNOWN);
     231    }
     232}
     233
     234/*****************************************************************************/
     235/*
     236 * Iterators for the psDlist representation of the metadata
     237 */
     238void psMetaDataSetIterator(psMetaDataSet *ms)
     239{
     240    assert (ms != NULL);
     241    psDlistSetIterator(ms->list, PS_DLIST_HEAD, 0);
     242}
     243
     244psMetaDataItem *psMetaDataGetNext(psMetaDataSet *restrict ms,
     245                                  const char *restrict match)
     246{
     247    assert (ms != NULL);
     248    psMetaDataItem *meta = psDlistGetNext(ms->list, 0);
     249
     250    if (match == NULL || meta == NULL) {
     251        return meta;
     252    } else {
     253        if (strncmp(meta->name, match, strlen(match)) == 0) { // a match
     254            return meta;
     255        } else {
     256            return psMetaDataGetNext(ms, match);
     257        }
     258    }
     259}
     260
     261/*****************************************************************************/
     262/*
     263 * Access using the hash table
     264 */
     265psMetaDataItem *psMetaDataLookup(const psMetaDataSet *restrict ms,
     266                                 const char *restrict key)
     267{
     268    assert (ms != NULL);
     269
     270    return psHashLookup(ms->table, key);
     271}
     272
     273/*****************************************************************************/
     274void psMetaDataItemPrint(FILE *fd,              // file descriptor to write to
     275                         const psMetaDataItem *restrict ms, // item of metadata to print
     276                         const char *prefix)       // print this at the beginning of each line
    112277{
    113278    if(ms == NULL) {
     
    115280    }
    116281
    117     fprintf(fd, "Name:     %-40s (ID: %d)\n", ms->name, ms->id);
     282    fprintf(fd, "%sName:     %-40s (ID: %d)\n", prefix, ms->name, ms->id);
    118283    if (*ms->comment != '\0') {
    119         fprintf(fd, "Comment:  %s\n", ms->comment);
    120     }
    121     fprintf(fd, "Value:    ");
     284        fprintf(fd, "%sComment:  %s\n", prefix, ms->comment);
     285    }
     286    fprintf(fd, "%sValue:    ", prefix);
    122287
    123288    assert (ms->type >= 0 && ms->type < PS_META_NTYPE);
     289    fprintf(fd, "%s", prefix);
    124290    switch (ms->type) {
     291      case PS_META_ITEM_SET:
     292        {                               // gcc 3.3 doesn't allow a declaration here
     293            psMetaDataItem *meta = NULL;
     294
     295            fprintf(fd, "\n");
     296            psDlistSetIterator(ms->items, PS_DLIST_HEAD, 0);
     297            while ((meta = psDlistGetNext(ms->items, 0)) != NULL) {
     298                psMetaDataItemPrint(fd, meta, "\t");
     299            }
     300        }
     301       
     302        break;
    125303      case PS_META_FLOAT:
    126304        fprintf(fd, "%g\n", ms->val.f);
    127305        break;
    128 
    129306      case PS_META_INT:
    130307        fprintf(fd, "%d\n", ms->val.i);
    131308        break;
    132        
    133309      case PS_META_STR:
    134310        fprintf(fd, "%s\n", (char *)ms->val.v);
    135311        break;
    136        
    137312      case PS_META_IMG:
    138313        fprintf(fd, "(IMG)\n");
    139314        break;
    140        
    141315      case PS_META_JPEG:
    142316        fprintf(fd, "(JPG)\n");
    143317        break;
    144        
    145318      case PS_META_PNG:
    146319        fprintf(fd, "(PNG)\n");
    147320        break;
    148        
    149321      case PS_META_ASTROM:
    150322        fprintf(fd, "(ASTROM)\n");
    151323        break;
    152        
    153324      case PS_META_UNKNOWN:
    154325        fprintf(fd, "(UNKNOWN)\n");
    155326        break;
    156 
    157327      case PS_META_NTYPE:
    158328        psAbort(__FILE__, "You cannot get here (%d)\n", __LINE__);
     
    170340int main(void)
    171341{
    172     psDlist *list = psDlistNew(NULL);   // list of metadata
    173 
    174     const int ten = 10;
    175     psDlistAppend(list, psMetaDataNew("const.ten", PS_META_INT, &ten, NULL,0));
    176     const float sqrt2 = sqrt(2);
    177     psDlistAppend(list, psMetaDataNew("const.sqrt2", PS_META_FLOAT, &sqrt2,
    178                                       "square root of two", 0));
    179     psDlistAppend(list, psMetaDataNew("lang.hello", PS_META_STR, "Bonjour",
    180                                       "French", 0));
    181     /*
    182      * Print that data
    183      */
    184     for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next) {
    185         psMetaDataPrint(stdout, ptr->data);
    186     }
    187 
     342    psSetTraceLevel("metadata", 1);     // turn on tracing
     343    psSetLogFormat("NM");               // suppress some of the psLogMsg verbosity
     344
     345    psMetaDataSet *ms = psMetaDataSetNew(); // set of metadata
     346    psMetaDataItem *meta = NULL;            // used to traverse a set of metadata
     347
     348    for (int i = 0; i < 10; i += 5) {
     349        float sqrti = sqrt(i);
     350        psMetaDataAppend(ms, psMetaDataItemNew(PS_META_INT, &i, NULL, "const.%d", i));
     351        psMetaDataAppend(ms, psMetaDataItemNew(PS_META_FLOAT, &sqrti, "square root", "const.sqrt%d", i));
     352    }
     353    psMetaDataAppend(ms, psMetaDataItemNew(PS_META_STR | PS_META_NON_UNIQUE,
     354                                           "Bonjour", "French", "lang.hello"));
     355    psMetaDataAppend(ms, psMetaDataItemNew(PS_META_STR | PS_META_NON_UNIQUE,
     356                                           "Aloha", "Hawaiian", "lang.hello"));
     357    psMetaDataAppend(ms, psMetaDataItemNew(PS_META_STR | PS_META_NON_UNIQUE,
     358                                           "Good Morning", "English", "lang.hello"));
     359    /*
     360     * Print all metadata starting "lang"
     361     */
     362    psMetaDataSetIterator(ms);
     363    while ((meta = psMetaDataGetNext(ms, "lang")) != NULL) {
     364        psMetaDataItemPrint(stdout, meta, "");
     365    }
     366    /*
     367     * Remove a key
     368     */
     369    psMetaDataItemDel(psMetaDataRemove(ms, "lang.hello"));
     370    /*
     371     * Print all metadata
     372     */
    188373    fprintf(stdout, "------\n");
    189     /*
    190      * Print it again
    191      */
    192     (void)psDlistGet(list, PS_DLIST_TAIL); // initialise iterator
    193     psMetaData *ms = NULL;
    194     while ((ms = psDlistGet(list, PS_DLIST_PREV)) != NULL) {
    195         psMetaDataPrint(stdout, ms);
     374    psMetaDataSetIterator(ms);
     375    while ((meta = psMetaDataGetNext(ms, NULL)) != NULL) {
     376        psMetaDataItemPrint(stdout, meta, "");
     377    }
     378    /*
     379     * Look up a key by name
     380     */
     381    fprintf(stdout, "------\n");
     382    fprintf(stdout, "Looking up by name:\n");
     383    meta = psMetaDataLookup(ms, "const.5");
     384    if (meta != NULL) {
     385        psMetaDataItemPrint(stdout, meta, "");
    196386    }
    197387    /*
    198388     * Clean up
    199389     */
    200     psDlistDel(list, (void (*)(void *))psMetaDataDel);
     390    psMetaDataSetDel(ms);
    201391    /*
    202392     * Check for memory leaks
    203393     */
    204394    fprintf(stderr,"Checking for memory leaks:\n");
     395    psTraceReset();
    205396    psMemCheckLeaks(0, NULL, stderr);
    206397   
  • trunk/archive/pslib/src/Metadata/psMetaData.h

    r141 r156  
    88 */
    99typedef enum {                          // type of val is:
    10     PS_META_FLOAT = 0,                  // float (.f)
     10    PS_META_ITEM_SET = 0,               // NULL; metadata is in psMetaDataType.items
     11    PS_META_FLOAT,                      // float (.f)
    1112    PS_META_INT,                        // int (.i)
    1213    PS_META_STR,                        // string (.v)
     
    1920} psMetaDataType;
    2021
     22enum {
     23    PS_META_TYPE_MASK =     0xffff,     // the type enum must fit in this mask
     24    PS_META_UNIQUE =       0x10000,     // the name must be unique (default)
     25    PS_META_NON_UNIQUE =   0x20000,     // the name may be repeated, and should be disambiguated for us
     26};
     27
    2128/*
    2229 * A struct to define a single item of metadata
     
    2532    const int id;                       // unique ID for this item
    2633   
    27     char *name;                         // Name of item
     34    char *restrict name;                // Name of item
    2835    psMetaDataType type;                // type of this item
     36    int flags;                          // flags associated with this item
    2937    const union {
    3038        float f;                        // floating value
     
    3341    } val;                              // value of metadata
    3442    char *comment;                      // optional comment ("", not NULL)
    35 } psMetaData;
     43    psDlist *restrict items;            // list of psMetaDataItems with the same name
     44} psMetaDataItem;
     45
     46/*
     47 * A set of metadata
     48 */
     49typedef struct {
     50    psDlist *restrict list;             // list of psMetaDataItem
     51    psHash *restrict table;             // hash table of the same metadata
     52} psMetaDataSet;
    3653
    3754/*****************************************************************************/
     
    3956 * Constructors and destructors
    4057 */
    41 psMetaData *psMetaDataNew(
    42     const char *name,                   // name of new item of metadata
    43     psMetaDataType type,                // type of this piece of metadata
     58psMetaDataItem *psMetaDataItemNew(
     59    int typeFlags,                      // type of this piece of metadata + flags
    4460    const void *val,                    // value of new item
    4561                                        // N.b. a pointer even if the item
    4662                                        // is of type e.g. int
    4763    const char *comment,                // comment associated with item
    48     int copy);                          // always copy data; NOTUSED
     64    const char *name,                   // name of new item of metadata (may be an sprintf format)
     65    ...);                               // possible arguments for name format
    4966
    50 void psMetaDataDel(psMetaData *ms);     // piece of metadata to destroy
     67void psMetaDataItemDel(psMetaDataItem *ms); // piece of metadata to destroy
     68
     69psMetaDataSet *psMetaDataSetNew(void);    // make a new set of metadata
     70void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata
    5171
    5272/*****************************************************************************/
     
    5474 * Utilities
    5575 */
    56 void psMetaDataPrint(FILE *fd,          // file descriptor to write to
    57                      const psMetaData *ms); // item of metadata to print
     76psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item);
     77psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key);
    5878
     79void psMetaDataSetIterator(psMetaDataSet *ms);
     80psMetaDataItem *psMetaDataGetNext(psMetaDataSet *restrict ms, const char *restrict match);
     81psMetaDataItem *psMetaDataLookup(const psMetaDataSet *restrict ms, const char *restrict key);
    5982
     83void psMetaDataItemPrint(FILE *fd,              // file descriptor to write to
     84                         const psMetaDataItem *restrict ms, // item of metadata to print
     85                         const char *prefix);      // print this at the beginning of each line
    6086#endif
Note: See TracChangeset for help on using the changeset viewer.