NMD
nmdcat.c
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include "string.h"
00003 #include "nmd.h"
00004 #include "nmd_impl.h"
00005 
00006 #define CMPCHUNK 30
00007 
00008 /*! \page categoryfunctions Metadata category manipulation
00009 
00010   A metadata object contains a number of categories, each containing
00011   multiple component which store the actual metadata. Here are the
00012   routines for manipulation the categories.
00013 
00014   See NMDObjectTryGetCategory(), NMDObjectGetCategory(),
00015   NMDAllocateCategory(), NMDObjectAllocateNewCategory(),
00016   NMDObjectGetOrCreateCategory(),
00017   NMDRemoveCategory(), NMDGetCategories(), NMDCopyCategory().
00018  */
00019 
00020 #undef __FUNCT__
00021 #define __FUNCT__ "NMDObjectTryGetCategory"
00022 /*! Test whether a metadata object has a certain category, if so
00023  yield up its pointer. 
00024 
00025  The category pointer parameter can be null, in which case only existence 
00026  is tested.
00027 */
00028 NMDErrorCode NMDObjectTryGetCategory
00029 (NMD_metadata obj,const char *cat,NMD_metadata_category *rctg,NMDTruth *f)
00030 {
00031   int icat;
00032   CHECKHASNMDCOOKIE(obj);
00033   *f = NMDFalse;
00034   for (icat=0; icat<obj->ncat; icat++) {
00035     NMD_metadata_category ctg = obj->cats[icat];
00036     CHECKHASNMDCOOKIE(ctg);
00037     if (strcmp(cat,ctg->name)==0) {
00038       if (rctg) *rctg = ctg; *f = NMDTrue; break;
00039     }
00040   }
00041   return 0;
00042 }
00043 
00044 #undef __FUNCT__
00045 #define __FUNCT__ "NMDObjectGetCategory"
00046 /*! Retrieve a category from a metadata object. The category has to exist.
00047 */
00048 NMDErrorCode NMDObjectGetCategory
00049 (NMD_metadata obj,const char *cat,NMD_metadata_category *ctg)
00050 {
00051   NMDTruth flg; NMDErrorCode ierr;
00052   CHECKHASNMDCOOKIE(obj);
00053   ierr = NMDObjectTryGetCategory(obj,cat,ctg,&flg); NMD_ERR_RETURN(ierr);
00054   if (!flg) NMD_ERR_REPORTs("Category not found",cat);
00055   return 0;
00056 }
00057 
00058 #undef __FUNCT__
00059 #define __FUNCT__ "NMDAllocateCategory"
00060 /*! This is an internal routine that merely allocates
00061   the data structure for storing a category.
00062 */
00063 static NMDErrorCode NMDAllocateCategory(NMD_metadata_category *rcat)
00064 {
00065   NMD_metadata_category cat;
00066   NMD_MALLOC(cat,1,struct NMD_metadata_category_,"category");
00067   cat->cookie = NMDCOOKIE;
00068   cat->alloc = CMPCHUNK; cat->ncmp = 0;
00069   NMD_MALLOC(cat->cmps,cat->alloc,NMD_metadata_item,"items array");
00070   *rcat = cat;  
00071   CHKMEMQ
00072   return 0;
00073 }
00074 
00075 #undef __FUNCT__
00076 #define __FUNCT__ "NMDObjectAllocateNewCategory"
00077 /*! Allocate a category in a metadata object.
00078   There is no testing whether the category name is already in use.
00079 
00080   If a category pointer is supplied, the category is returned,
00081   but this pointer is allowed to be null.
00082 */
00083 NMDErrorCode NMDObjectAllocateNewCategory
00084 (NMD_metadata obj,const char *cat,NMD_metadata_category *rctg)
00085 {
00086   NMD_metadata_category ctg; int idx; NMDErrorCode ierr;
00087   /*
00088    * if we are about to overflow, reallocate 
00089    */
00090   if (obj->ncat >= obj->alloc) {
00091     NMD_metadata_category* newcats; int newalloc;
00092     newalloc = 2*obj->alloc;
00093     ierr = PetscMalloc
00094       (newalloc*sizeof(struct NMD_metadata_category_),&newcats); CHKERRQ(ierr);
00095     for (idx=0; idx<obj->ncat; idx++)
00096       newcats[idx] = obj->cats[idx];
00097     ierr = PetscFree(obj->cats); CHKERRQ(ierr);
00098     obj->cats = newcats; obj->alloc = newalloc;
00099   }
00100   /*
00101    * with space guaranteed, create the category
00102    */
00103   idx = obj->ncat++;
00104   ierr = NMDAllocateCategory(&ctg); NMD_ERR_RETURN(ierr);
00105   NMD_STRDUP(cat,ctg->name);
00106   obj->cats[idx] = ctg;
00107   if (rctg) *rctg = ctg;
00108   CHKMEMQ
00109   return 0;
00110 }
00111 
00112 #undef __FUNCT__
00113 #define __FUNCT__ "NMDObjectGetOrCreateCategory"
00114 /*! Retrieve a category from a metadata object, or create it
00115   if it doesn't exist yet.
00116 */
00117 NMDErrorCode NMDObjectGetOrCreateCategory
00118 (NMD_metadata obj,const char *cat,NMD_metadata_category *ctg)
00119 {
00120   NMDTruth flg; NMDErrorCode ierr;
00121   CHECKHASNMDCOOKIE(obj);
00122   ierr = NMDObjectTryGetCategory(obj,cat,ctg,&flg); NMD_ERR_RETURN(ierr);
00123   if (!flg) {
00124     ierr = NMDObjectAllocateNewCategory(obj,cat,ctg); NMD_ERR_RETURN(ierr);
00125   }
00126   CHKMEMQ
00127   return 0;
00128 }
00129 
00130 #undef __FUNCT__
00131 #define __FUNCT__ "NMDGetCategories"
00132 /*! Get the number of categories and their names. Both arguments can be NULL.
00133   The names array is allocated; the user needs to free it. The names themselves
00134   are pointers to the strings in the metadata object, so they do not need to
00135   be freed.
00136 */
00137 NMDErrorCode NMDGetCategories(NMD_metadata obj,int *ncat,char ***cats)
00138 {
00139   CHECKHASNMDCOOKIE(obj);
00140   if (ncat) *ncat = obj->ncat;
00141   if (obj->ncat && cats) {
00142     char **names; int icat;
00143     NMD_MALLOC(names,obj->ncat,char*,"name array");
00144     for (icat=0; icat<obj->ncat; icat++)
00145       names[icat] = obj->cats[icat]->name;
00146     *cats = names;
00147   }
00148   CHKMEMQ
00149   return 0;
00150 }
00151 
00152 #undef __FUNCT__
00153 #define __FUNCT__ "NMDRemoveCategory"
00154 /* Remove a category from an NMD object. This is done through setting its
00155    name to \c "invalid". Later we will do real deallocation.
00156 
00157    The removed category still counts towards the number reported
00158    in NMDGetCategories().
00159 */
00160 NMDErrorCode NMDRemoveCategory(NMD_metadata obj,const char *cat)
00161 {
00162   NMD_metadata_category ctg; NMDErrorCode ierr;
00163 
00164   CHECKHASNMDCOOKIE(obj);
00165   ierr = NMDObjectGetCategory(obj,(char*)cat,&ctg); NMD_ERR_RETURN(ierr);
00166   NMD_FREE(ctg->name);
00167   NMD_STRDUP("invalid",ctg->name);
00168   CHKMEMQ
00169 
00170   return 0;
00171 }
00172 
00173 #undef __FUNCT__
00174 #define __FUNCT__ "NMDCopyCategory"
00175 /*! Copy category data from one metadata structure into another.
00176   This assumes that the category already exists in the target; 
00177   see for instance NMDHasCategory(), NMDCloneObject(),
00178   NMDCloneObjectStructure().
00179 */
00180 NMDErrorCode NMDCopyCategory(NMD_metadata_category incat,NMD_metadata_category outcat)
00181 {
00182   int icmp; NMDErrorCode ierr;
00183 
00184   CHECKHASNMDCOOKIE(incat);
00185   CHECKHASNMDCOOKIE(outcat);
00186 
00187   for (icmp=0; icmp<incat->ncmp; icmp++) {
00188     NMD_metadata_item src = incat->cmps[icmp],tar;
00189     ierr = NMDCategoryGetOrCreateComponent
00190       (outcat,src->name,src->t,&tar); NMD_ERR_RETURN(ierr);
00191     ierr = NMDCopyItemValues(src,tar); NMD_ERR_RETURN(ierr);
00192   }
00193   CHKMEMQ
00194 
00195   return 0;
00196 }
00197