NMD
nmd.c
Go to the documentation of this file.
00001 /*! \mainpage NMD: the Numerical MetaData library
00002 
00003   The NMD library serves to store two-level data structures of
00004   numerical metadata. While this library was intended to be used with
00005   AnaMod in the Salsa project, it can be used on its own. Unlike other
00006   libraries in the Salsa project, it does not rely on Petsc.
00007 
00008   \section general General notes
00009 
00010   All routines in NMD return an error code of type \c NMDErrorCode. This
00011   is zero for success and anything else for failure. Return codes can be
00012   caught with \c NMD_ERR_RETURN(ierr) and generate with 
00013   \c NMD_ERR_REPORT(msg).
00014 
00015   \subpage objectfunctions
00016 
00017   \subpage categoryfunctions
00018 
00019   \subpage componentfunctions
00020 
00021   \subpage values
00022 
00023   \subpage viewing
00024 
00025   \subpage installation
00026 
00027   \author Victor Eijkhout
00028   \version 2.5
00029   \date unreleased
00030 
00031   \section Change history
00032   2.5 changes
00033   - added routines: NMDUnsetValue(),NMDCategoryGetComponents(),
00034   NMDTypeGetMySQLName()
00035   - NMDReportObject() now takes delimiter arguments. This is useful
00036   for generating MySQL strings and such.
00037 
00038   2.4 changes
00039   - minor
00040 
00041   2.3 changes
00042 
00043   - NMDGetValue now returns failure (instead of aborting) 
00044   if cat/cmp do not exist
00045   - removed occurrences of Petsc's CHKERRQ
00046   - introduced NMDErrorCode
00047   - new files nmdcat.c nmdcmp.c
00048   - NMDGetValue and GetArrayValue now use NMDTruth
00049   - NMDSetValue and NMDSetArrayValue are now analogous: use ampersand 
00050   for all types of data
00051   - NMDTrue and NMDFalse instead of 1 and 0
00052   - unit tests added
00053 
00054   2.3 bug fixes
00055 
00056   - NMDGetValue missing case of string value added
00057   - NMDTryGetCategory (and various other Get routines) were able to 
00058   find non-existing category names. Fixed.
00059   - lots of memory leaks plugged
00060 
00061   2.2
00062   - Completely revamped array handling; watch out for prototype changes
00063   - CFLAGS is now NMD_CFLAGS
00064  */
00065 
00066 /*! \page installation Installing NMD
00067 
00068   Installing NMD takes the following steps:
00069   - edit the Make.inc file for:
00070     - compiler options, and settings for your \c ar and \c ranlib program
00071     - add \c "-DNMD_HAVE_PETSC" to the compile line if you are using NMD
00072     with Petsc (see NMDReportObject())
00073     - \c NMD_LIB_DIR is the location where the library will be installed
00074   - do \c "make install" to generate the binaries
00075 
00076  */
00077 
00078 #include <stdlib.h>
00079 #include <stdio.h>
00080 #include <string.h>
00081 #include "nmd_impl.h"
00082 #include "nmd.h"
00083 
00084 const char *typenames[] =
00085   {"invalid","int","real","string","intarray","realarray"};
00086 const char *mysqltypenames[] =
00087   {"VARCHAR(256)","INTEGER","DOUBLE","VARCHAR(1024)",
00088    "VARCHAR(1024)","VARCHAR(1024)"};
00089 static const int nnmdtypenames = 6;
00090 
00091 #define CATCHUNK 10
00092 
00093 /*! \page objectfunctions Metadata object manipulation
00094 
00095   Top level functions for manipulation metadata objects.
00096 
00097   See NMDCreateObject(), NMDDestroyObject(), NMDBuildObjectStructure(),
00098   NMDCloneObject(), NMDCloneObjectStructure(), NMDViewObject()
00099  */
00100 
00101 #undef __FUNCT__
00102 #define __FUNCT__ "NMDCreateObject"
00103 /*!
00104   This routine create an NMD_metadata object, and allocates enough 
00105   space in it for 10 categories of 20 elements each. Currently this can not
00106   be reallocated. In the future we want to be a bit more flexible.
00107 */
00108 NMDErrorCode NMDCreateObject(NMD_metadata *obj)
00109 {
00110   NMD_metadata nnew;
00111 
00112   /* allocate the metadata object */
00113   NMD_MALLOC(nnew,1,struct NMD_metadata_,"object");
00114   nnew->cookie = NMDCOOKIE;
00115   *obj = nnew;
00116 
00117   /* give it a basic array of categories */
00118   nnew->alloc = CATCHUNK; nnew->ncat = 0;
00119   NMD_MALLOC(nnew->cats,nnew->alloc,NMD_metadata_category,"categories");
00120 
00121   CHKMEMQ
00122   return 0;
00123 }
00124 
00125 #undef __FUNCT__
00126 #define __FUNCT__ "NMDDestroyObject"
00127 /*!
00128   Deallocate all the data in a metadata object.
00129 */
00130 NMDErrorCode NMDDestroyObject(NMD_metadata obj)
00131 {
00132   int i,j; NMDErrorCode ierr;
00133 
00134   CHECKHASNMDCOOKIE(obj);
00135   for (i=0; i<obj->ncat; i++) {
00136     NMD_metadata_category cat = obj->cats[i];
00137     for (j=0; j<cat->ncmp; j++) {
00138       NMD_metadata_item cmp = cat->cmps[j];
00139       ierr = NMDComponentDestroy(cmp); NMD_ERR_RETURN(ierr);
00140     }
00141     NMD_FREE(cat->cmps);
00142     NMD_FREE(cat->name);
00143     NMD_FREE(cat);
00144     CHKMEMQ
00145   }
00146   NMD_FREE(obj->cats);
00147   NMD_FREE(obj);
00148 
00149   return 0;
00150 }
00151 
00152 #if 0
00153 #undef __FUNCT__
00154 #define __FUNCT__ "NMDBuildObjectStructure"
00155 NMDErrorCode NMDBuildObjectStructure(NMD_metadata nmd)
00156 {
00157   char **categories; int ncat,icat; NMDErrorCode ierr;
00158 
00159   ierr = NMDGetCategories(nmd,&ncat,&categories); NMD_ERR_RETURN(ierr);
00160   for (icat=0; icat<ncat; icat++) {   
00161     NMDDataType *t; char **modules; int nmod,imod;
00162     ierr = NMDObjectGetOrCreateCategory(nmd,categories[icat]); NMD_ERR_RETURN(ierr);
00163     ierr = CategoryGetModules
00164       (categories[icat],&modules,&t,PETSC_NULL,&nmod); NMD_ERR_RETURN(ierr);
00165     for (imod=0; imod<nmod; imod++) {
00166       ierr = NMDCreateComponent
00167         (nmd,categories[icat],modules[imod],t[imod]); NMD_ERR_RETURN(ierr);
00168     }
00169   }
00170   return 0;
00171 }
00172 #endif
00173 
00174 #undef __FUNCT__
00175 #define __FUNCT__ "NMDCloneObjectStructure"
00176 /*!
00177   This routine creates an NMD_metadata object, and fills it in with 
00178   the categories and components of a template object. Data is not copied; 
00179   for that, see NMDCloneObject() and NMDCopyCategory().
00180 */
00181 NMDErrorCode NMDCloneObjectStructure(NMD_metadata old,NMD_metadata *ret)
00182 {
00183   NMD_metadata nnew;
00184   int icat,icmp; NMDErrorCode ierr;
00185 
00186   CHECKHASNMDCOOKIE(old);
00187   ierr = NMDCreateObject(&nnew); NMD_ERR_RETURN(ierr);
00188   CHECKHASNMDCOOKIE(nnew);
00189   for (icat=0; icat<old->ncat; icat++) {
00190     NMD_metadata_category oldcat = old->cats[icat];
00191     CHECKHASNMDCOOKIE(oldcat);
00192     for (icmp=0; icmp<oldcat->ncmp; icmp++) {
00193       NMD_metadata_item oldcmp = oldcat->cmps[icmp];
00194       CHECKHASNMDCOOKIE(oldcmp);
00195       ierr = NMDObjectEnsureCategoryComponent
00196         (nnew,oldcat->name,oldcmp->name,oldcmp->t,NULL); NMD_ERR_RETURN(ierr);
00197     }
00198   }
00199   CHKMEMQ
00200   *ret = nnew;
00201   return 0;
00202 }
00203 
00204 #undef __FUNCT__
00205 #define __FUNCT__ "NMDCloneObject"
00206 /*!
00207   Given an already created NMD_metadata object, fill it with 
00208   the data of a template object. See also NMDCloneObjectStructure().
00209 */
00210 NMDErrorCode NMDCloneObject(NMD_metadata old,NMD_metadata nnew)
00211 {
00212   int icat; NMDErrorCode ierr;
00213 
00214   CHECKHASNMDCOOKIE(old);
00215   CHECKHASNMDCOOKIE(nnew);
00216   for (icat=0; icat<old->ncat; icat++) {
00217     /* loop over input categories by index; output categories
00218        are retrieved by label, or newly created */
00219     NMD_metadata_category oldcat = old->cats[icat],newcat; int icmp;
00220     ierr = NMDObjectGetOrCreateCategory
00221       (nnew,oldcat->name,&newcat); NMD_ERR_RETURN(ierr);
00222     CHECKHASNMDCOOKIE(oldcat);
00223     for (icmp=0; icmp<oldcat->ncmp; icmp++) {
00224       NMD_metadata_item oldcmp = oldcat->cmps[icmp],newcmp;
00225       ierr = NMDCategoryGetOrCreateComponent
00226         (newcat,oldcmp->name,oldcmp->t,&newcmp); NMD_ERR_RETURN(ierr);
00227       ierr = NMDCopyItemValues(oldcmp,newcmp); NMD_ERR_RETURN(ierr);
00228     }
00229   }
00230   CHKMEMQ
00231   return 0;
00232 }
00233 
00234 /*! \page viewing Viewing objects
00235   NMDViewObject() gives informal output; NMDReportObject() can be
00236   used for database records and such.
00237  */
00238 #undef __FUNCT__
00239 #define __FUNCT__ "NMDViewObject"
00240 /*! Print out an NMD object.
00241 
00242   Currently only int, real, string fields are displayed,
00243   others are displayed as \c "***".
00244  */
00245 NMDErrorCode NMDViewObject(NMD_metadata obj)
00246 {
00247   int icat,icmp;
00248   CHECKHASNMDCOOKIE(obj);
00249   printf("========\n");
00250   for (icat=0; icat<obj->ncat; icat++) {
00251     NMD_metadata_category cat = obj->cats[icat];
00252     CHECKHASNMDCOOKIE(cat);
00253     printf("Category: <%s>\n",cat->name);
00254     for (icmp=0; icmp<cat->ncmp; icmp++) {
00255       NMD_metadata_item cmp = cat->cmps[icmp];
00256       CHECKHASNMDCOOKIE(cmp);
00257       printf("  <%s> : ",cmp->name);
00258       if (!cmp->set) {
00259         printf("(null)\n");
00260       } else {
00261         switch (cmp->t) {
00262         case NMDInt : printf("<%d>\n",cmp->i); break;
00263         case NMDReal : printf("<%e>\n",cmp->r); break;
00264         case NMDString : printf("<<%s>>\n",cmp->cc); break;
00265         default : printf("****\n"); break;
00266         }
00267       }
00268     }
00269   }
00270   printf("========\n\n");
00271   CHKMEMQ
00272   return 0;
00273 }
00274 
00275 #undef __FUNCT__
00276 #define __FUNCT__ "NMDReportObject"
00277 /*! Generate a delimited representation of a metadata object.
00278 
00279   The returned strings are allocated in this routine and it is the user's
00280   responsibility to free them with NMD_FREE().
00281 
00282   Arguments:
00283   - obj : the metadata object
00284   - ar : boolean to indicate whether arrays need to be written out in full.
00285   If this is false, only the first and last couple of elements are given.
00286   - rkey : a string containing the names of the metadata items
00287   - rval : the metadata items
00288   - delim : delimiter character used in \c rkey and \c rval
00289   - itemdelim1 : an optional opening quote, used for both keys and values.
00290   (A NULL value will cause no delimiter to be printed, rather than a null
00291   character.)
00292   For instance, use the backquote when generating MySQL strings.
00293   - itemdelim2 : an optional closing quote
00294 
00295  */
00296 NMDErrorCode NMDReportObject
00297 (NMD_metadata obj,NMDTruth arrays,const char **rkey,const char **rval,
00298  const char delim,const char itemdelim1,const char itemdelim2)
00299 {
00300   int icat,icmp,write,keylen=0,vallen=0; char *key=NULL,*val=NULL, *scratch;
00301   CHECKHASNMDCOOKIE(obj);
00302 
00303   /*
00304    * allocate and fill in the key and value strings
00305    */
00306 #define CHKLEN 500
00307   NMD_MALLOC(scratch,CHKLEN,char,"scratch pad");
00308 #define CHKSPACEFOR(ar,arlen,fmt,str) {int nr; memset(scratch,0,CHKLEN); sprintf(scratch,fmt,str); nr=strlen(scratch); if (write==0) {arlen = arlen+nr+2; } else {int l = strlen(ar); if (l+nr<arlen) {sprintf(ar+l,fmt,str);} else SETERRQ(1,"sprintf would overflow allocated buffer");}}
00309   write = 0;
00310  writeloop:
00311   if (write==0) {
00312     keylen=vallen=0;
00313   } else {
00314     if (rkey) NMD_MALLOC(key,keylen,char,"names array");
00315     if (rval) NMD_MALLOC(val,vallen,char,"values array");
00316   }
00317   for (icat=0; icat<obj->ncat; icat++) {
00318     NMD_metadata_category cat = obj->cats[icat];
00319     CHECKHASNMDCOOKIE(cat);
00320     for (icmp=0; icmp<cat->ncmp; icmp++) {
00321       NMD_metadata_item cmp = cat->cmps[icmp];
00322       CHECKHASNMDCOOKIE(cmp);
00323       if (rkey) {
00324         if (itemdelim1) CHKSPACEFOR(key,keylen,"%c",itemdelim1);
00325         CHKSPACEFOR(key,keylen,"%s:",cat->name);
00326         CHKSPACEFOR(key,keylen,"%s",cmp->name);
00327         if (itemdelim2) CHKSPACEFOR(key,keylen,"%c",itemdelim2);
00328         CHKSPACEFOR(key,keylen,"%c",delim);
00329       }
00330       if (rval) {
00331         if (itemdelim1) CHKSPACEFOR(val,vallen,"%c",itemdelim1);
00332         if (!cmp->set) goto delimiter;
00333         switch (cmp->t) {
00334         case NMDInt : {
00335           CHKSPACEFOR(val,vallen,"%8d",cmp->i); break;}
00336         case NMDReal : {
00337           CHKSPACEFOR(val,vallen,"%15.8e",cmp->r); break;}
00338         case NMDString :
00339           if (!cmp->cc) NMD_ERR_REPORT("Null string");
00340           if (strlen(cmp->cc)>0) {
00341             if (strlen(cmp->cc)<=CHKLEN) {
00342               CHKSPACEFOR(val,vallen,"%s",cmp->cc);
00343             } else {CHKSPACEFOR(val,vallen,"%s","stringtoolong");}
00344           } else {
00345             CHKSPACEFOR(val,vallen,"%s","null"); 
00346           }
00347           break;
00348         case NMDIntarray : {
00349           struct NMD_intarray_struct *arraystruct =
00350             (struct NMD_intarray_struct *)(cmp->ii);
00351           int n = arraystruct->length,i;
00352           if (arrays || n<=4) {
00353             for (i=0; i<n; i++) {
00354               if (i<n-1) {
00355                 CHKSPACEFOR(val,vallen,"%8d,",arraystruct->data[i]);
00356               } else {
00357                 CHKSPACEFOR(val,vallen,"%8d",arraystruct->data[i]);
00358               }
00359             }
00360           } else {
00361             CHKSPACEFOR(val,vallen,"%8d,",arraystruct->data[0]);
00362             CHKSPACEFOR(val,vallen,"%8d,",arraystruct->data[1]);
00363             CHKSPACEFOR(val,vallen,"%8d,",arraystruct->data[n-2]);
00364             CHKSPACEFOR(val,vallen,"%8d",arraystruct->data[n-1]);
00365           }
00366         } ; break;
00367         case NMDRealarray : {
00368           struct NMD_realarray_struct *arraystruct =
00369             (struct NMD_realarray_struct *)(cmp->rr);
00370           int n = arraystruct->length,i;
00371           if (arrays || n<=4) {
00372             for (i=0; i<n; i++) {
00373               if (i<n-1) {
00374                 CHKSPACEFOR(val,vallen,"%11.4e,",arraystruct->data[i]);
00375               } else {
00376                 CHKSPACEFOR(val,vallen,"%11.4e",arraystruct->data[i]);
00377               }
00378             }
00379           } else {
00380             CHKSPACEFOR(val,vallen,"%11.4e,",arraystruct->data[0]);
00381             CHKSPACEFOR(val,vallen,"%11.4e,",arraystruct->data[1]);
00382             CHKSPACEFOR(val,vallen,"%11.4e,",arraystruct->data[n-2]);
00383             CHKSPACEFOR(val,vallen,"%11.4e",arraystruct->data[n-1]);
00384           }
00385         } ; break;
00386         default :
00387           CHKSPACEFOR(val,vallen,"%s","==="); break;
00388         }
00389       delimiter:
00390         if (itemdelim2) CHKSPACEFOR(val,vallen,"%c",itemdelim2);
00391         CHKSPACEFOR(val,vallen,"%c",delim);
00392       }
00393     }
00394   }
00395   write += 1;
00396   if (write<=1) goto writeloop;
00397   NMD_FREE(scratch);
00398   CHKMEMQ;
00399   /* *rkey = key; *rval = val; */
00400   if (key) {
00401     int l = strlen(key); 
00402     if (l>keylen)
00403       NMD_ERR_REPORT("key string overrun");
00404     *rkey = key;
00405   }
00406   if (val) {
00407     int l = strlen(val); 
00408     if (l>vallen)
00409       NMD_ERR_REPORTii("val string overrun; alloc/actual",vallen,l);
00410     *rval = val;
00411   }
00412 
00413   return 0;
00414 }
00415 
00416 /*! \page values Value handling
00417 
00418   NMD handles scalar and array values slightly differently.
00419   For scalar values use NMDSetValue() and NMDGetValue();
00420   for array values use NMDSetArrayValue(), NMDGetArrayValue(),
00421   NMDCopyArrayValue(). The array routines take an extra parameter 
00422   denoting the length of the array.
00423 
00424   Note that scalar values have to be passed by reference:
00425 \code
00426   int i,*ii;
00427   NMDSetValue(nmd,....,&i);        // use an ampersand here
00428   NMDSetValue(nmd,....,ii,length); // no ampersand needed here!
00429   NMDGetValue(nmd,....,&i);
00430   NMDGetValue(nmd,....,&ii,&length);
00431 \endcode
00432 
00433   Furthermore, see NMDCopyItemValues(), NMDGetDataType(),
00434   NMDIsArrayType().
00435  */
00436 
00437 #undef __FUNCT__
00438 #define __FUNCT__ "NMDSetValue"
00439 /*! Set a metadata value, indexed by category and component name.
00440 
00441   The value has to be passed by reference
00442 
00443   String values are copied. (Reason: literal strings are treated
00444   differently from allocated, and Petsc has its own way of doing strings.)
00445 
00446   This call can be used to create categories and components; there is
00447   no checking of slight misspellings.
00448 
00449   See also \ref values.
00450 */
00451 NMDErrorCode NMDSetValue(NMD_metadata obj,const char *cat,const char *cmp,NMDDataType t,void *v)
00452 {
00453   NMD_metadata_category ctg; NMD_metadata_item cpt; NMDErrorCode ierr;
00454 
00455   CHECKHASNMDCOOKIE(obj);
00456   ierr = NMDObjectGetOrCreateCategory(obj,(char*)cat,&ctg); NMD_ERR_RETURN(ierr);
00457   ierr = NMDCategoryGetOrCreateComponent(ctg,(char*)cmp,t,&cpt); NMD_ERR_RETURN(ierr);
00458   ierr = NMDComponentSetValue(cpt,t,v); NMD_ERR_RETURN(ierr);
00459   CHKMEMQ
00460 
00461   return 0;
00462 }
00463 
00464 NMDErrorCode NMDUnsetValue(NMD_metadata obj,const char *cat,const char *cmp)
00465 {
00466   NMD_metadata_category ctg; NMD_metadata_item cpt; 
00467   NMDTruth flg; NMDErrorCode ierr;
00468 
00469   CHECKHASNMDCOOKIE(obj);
00470   ierr = NMDObjectTryGetCategory(obj,cat,&ctg,&flg); NMD_ERR_RETURN(ierr);
00471   if (!flg) return 0;
00472   ierr = NMDCategoryTryGetComponent(ctg,cmp,&cpt,&flg); NMD_ERR_RETURN(ierr);
00473   if (!flg) return 0;
00474   ierr = NMDComponentUnsetValue(cpt); NMD_ERR_RETURN(ierr);
00475   CHKMEMQ
00476 
00477   return 0;
00478 }
00479 
00480 #undef __FUNCT__
00481 #define __FUNCT__ "NMDSetArrayValue"
00482 /*! Set a metadata value, if it is an array type.
00483 
00484   The arrays are not copied, so the user is responsible for freeing the array. 
00485   Use NMDCopyArrayValue() to have the array copied; NMD will then free the 
00486   array when the metadata object is freed.
00487 
00488   This call can be used to create categories and components; there is
00489   no checking of slight misspellings.
00490 
00491   See also \ref values.
00492 */
00493 NMDErrorCode NMDSetArrayValue
00494 (NMD_metadata obj,const char *cat,const char *cmp,NMDDataType t,void *v,int l)
00495 {
00496   NMD_metadata_category ctg; NMD_metadata_item cpt; NMDErrorCode ierr;
00497 
00498   CHECKHASNMDCOOKIE(obj);
00499   ierr = NMDObjectGetOrCreateCategory(obj,(char*)cat,&ctg); NMD_ERR_RETURN(ierr);
00500   ierr = NMDCategoryGetOrCreateComponent(ctg,(char*)cmp,t,&cpt); NMD_ERR_RETURN(ierr);
00501   ierr = NMDComponentSetArrayValue(cpt,t,v,l); NMD_ERR_RETURN(ierr);
00502   CHKMEMQ
00503 
00504   return 0;
00505 }
00506 
00507 #undef __FUNCT__
00508 #define __FUNCT__ "NMDCopyArrayValue"
00509 /*! Set a metadata array value; the user array is
00510   copied.
00511 
00512   This call can be used to create categories and components; there is
00513   no checking of slight misspellings.
00514 
00515   See also \ref values.
00516 */
00517 NMDErrorCode NMDCopyArrayValue
00518 (NMD_metadata obj,const char *cat,const char *cmp,NMDDataType t,void *v,int l)
00519 {
00520   NMD_metadata_category ctg; NMD_metadata_item cpt; NMDErrorCode ierr;
00521 
00522   CHECKHASNMDCOOKIE(obj);
00523   ierr = NMDObjectGetOrCreateCategory(obj,(char*)cat,&ctg); NMD_ERR_RETURN(ierr);
00524   ierr = NMDCategoryGetOrCreateComponent(ctg,(char*)cmp,t,&cpt); NMD_ERR_RETURN(ierr);
00525 
00526   CHECKHASNMDCOOKIE(cpt);
00527   cpt->set = NMDTrue;
00528   switch (cpt->t) {
00529   case NMDInt :
00530   case NMDReal :
00531   case NMDString :
00532     ierr = NMDSetValue(obj,cat,cmp,t,v); NMD_ERR_RETURN(ierr);
00533     break;
00534   case NMDIntarray : {
00535     struct NMD_intarray_struct* iistruct; int *ii,i;
00536     NMD_MALLOC(iistruct,1,struct NMD_intarray_struct,"int array struct");
00537     iistruct->unique = 1; iistruct->length = l; 
00538     NMD_MALLOC(ii,l,sizeof(int),"copied int array");
00539     for (i=0; i<l; i++) ii[i] = (*(int**)v)[i];
00540     iistruct->data = ii;
00541     cpt->ii = iistruct;
00542     break;}
00543   case NMDRealarray : {
00544     struct NMD_realarray_struct* rrstruct; NMDRealtype *rr; int i;
00545     NMD_MALLOC(rrstruct,1,struct NMD_realarray_struct,"real array struct");
00546     rrstruct->unique = 1; rrstruct->length = l;
00547     NMD_MALLOC(rr,l,NMDRealtype,"copied real array");
00548     for (i=0; i<l; i++) rr[i] = (*(NMDRealtype**)v)[i];
00549     rrstruct->data = rr;
00550     cpt->rr = rrstruct;
00551     break;}
00552   default : NMD_ERR_REPORTi("Unknown type",(int)t); break;
00553   }
00554   CHKMEMQ
00555 
00556   return 0;
00557 }
00558 
00559 #undef __FUNCT__
00560 #define __FUNCT__ "NMDGetValue"
00561 /*! Retrieve a stored scalar value.
00562    If no value has been stored under the specified category and component,
00563    a zero flag is returned. The flag parameter can be null.
00564 
00565    Null pointers can be passed for the datatype or value, for instance to
00566    test only for the existence of a set value.
00567 
00568   See also \ref values.
00569 */
00570 NMDErrorCode NMDGetValue
00571 (NMD_metadata obj,const char *cat,const char *cmp,NMDDataType *t,void *v,NMDTruth *f)
00572 {
00573   NMD_metadata_category ctg; NMD_metadata_item cpt; 
00574   NMDTruth ff; NMDErrorCode ierr;
00575 
00576   CHECKHASNMDCOOKIE(obj);
00577   ierr = NMDObjectTryGetCategory(obj,cat,&ctg,&ff); NMD_ERR_RETURN(ierr);
00578   if (!ff) {
00579     if (f) {
00580       *f = NMDFalse; return 0;
00581     } else NMD_ERR_REPORT
00582              ("Could not find category, but no flag given to report this");
00583   }
00584   CHECKHASNMDCOOKIE(ctg);
00585   ierr = NMDCategoryTryGetComponent(ctg,cmp,&cpt,&ff); NMD_ERR_RETURN(ierr);
00586   if (!ff) {
00587     if (f) {
00588       *f = NMDFalse; return 0;
00589     } else NMD_ERR_REPORT
00590              ("Could not find component, but no flag given to report this");
00591   }
00592   CHECKHASNMDCOOKIE(cpt);
00593   if (!cpt->set) {
00594     if (f) {
00595       *f = NMDFalse; return 0;
00596     } else NMD_ERR_REPORT
00597              ("Value not set, but no flag given to report this");
00598   }
00599   if (t) *t = cpt->t;
00600   switch (cpt->t) {
00601   case NMDInt :
00602     if (v) *(int*)v = cpt->i;
00603     if (f) *f = NMDTrue; break;
00604   case NMDReal :
00605     if (v) *(double*)v = cpt->r;
00606     if (f) *f = NMDTrue; break;
00607   case NMDString :
00608     if (v) *(char**)v = cpt->cc;
00609     if (f) *f = NMDTrue; break;
00610   case NMDIntarray :
00611   case NMDRealarray :
00612     NMD_ERR_REPORT("Please use NMDGetArrayValue"); break;
00613   default :
00614     if (f) *f = NMDFalse;
00615   }
00616   CHKMEMQ
00617   return 0;
00618 }
00619 
00620 #undef __FUNCT__
00621 #define __FUNCT__ "NMDGetArrayValue"
00622 /*! Retrieve a stored value.
00623    If no value has been stored under the specified category and component,
00624    a zero flag is returned. The flag parameter can be null.
00625 
00626    Null pointers can be passed for the datatype or value, for instance to
00627    test only for the existence of a set value.
00628 
00629   See also \ref values.
00630 */
00631 NMDErrorCode NMDGetArrayValue
00632 (NMD_metadata obj,const char *cat,const char *cmp,
00633  NMDDataType *t,void *v,int *len,NMDTruth *f)
00634 {
00635   NMD_metadata_category ctg; NMD_metadata_item cpt; NMDErrorCode ierr;
00636 
00637   CHECKHASNMDCOOKIE(obj);
00638   ierr = NMDObjectGetCategory(obj,cat,&ctg); NMD_ERR_RETURN(ierr);
00639   CHECKHASNMDCOOKIE(ctg);
00640   ierr = NMDCategoryGetComponent(ctg,cmp,&cpt); NMD_ERR_RETURN(ierr);
00641   CHECKHASNMDCOOKIE(cpt);
00642   if (!cpt->set) {
00643     if (f) {
00644       *f = NMDFalse; return 0;
00645     } else NMD_ERR_REPORT
00646              ("Value not set, but no flag given to report this");
00647   }
00648   if (t) *t = cpt->t;
00649   switch (cpt->t) {
00650   case NMDInt :
00651   case NMDReal :
00652   case NMDString :
00653     ierr = NMDGetValue(obj,cat,cmp,NULL,v,f); NMD_ERR_RETURN(ierr);
00654     break;
00655   case NMDIntarray :
00656     if (v || len) {
00657       struct NMD_intarray_struct *as = cpt->ii;
00658       if (v) *(int**)v = as->data;
00659       if (len) *len = as->length;
00660     }
00661     if (f) *f = NMDTrue; break;
00662   case NMDRealarray :
00663     if (v || len) {
00664       struct NMD_realarray_struct *as = cpt->rr;
00665       if (v) *(NMDRealtype**)v = as->data;
00666       if (len) *len = as->length;
00667     }
00668     if (f) *f = NMDTrue; break;
00669   default :
00670     if (f) *f = NMDFalse;
00671   }
00672   CHKMEMQ
00673   return 0;
00674 }
00675 
00676 #if 0
00677 #undef __FUNCT__
00678 #define __FUNCT__ "NMDGetValueByIndex"
00679 /*! Retrieve a stored value by index. As in NMDGetValue(), all output
00680   parameters can receive null pointers.
00681 */
00682 NMDErrorCode NMDGetValueByIndex
00683 (NMD_metadata obj,int icat,int icmp,NMDDataType *t,void *v,int *f)
00684 {
00685   NMD_metadata_category cat;
00686   NMD_metadata_item cmp;
00687   NMDErrorCode ierr;
00688 
00689   CHECKHASNMDCOOKIE(obj);
00690   if (icat<0 || icat>=obj->ncat)
00691     NMD_ERR_REPORTi("category index out of range",icat);
00692   cat = obj->cats[icat]; CHECKHASNMDCOOKIE(cat);
00693   if (icmp<0 || icmp>=obj->cats[icat]->ncmp)
00694     NMD_ERR_REPORTii("component index out of range",icat,icmp);
00695 
00696   cmp = cat->cmps[icmp]; CHECKHASNMDCOOKIE(cmp);
00697   if (t) *t = cmp->t;
00698   switch (cmp->t) {
00699   case NMDInt :
00700     if (v) *(int*)v = cmp->i;
00701     if (f) *f = NMDTrue; break;
00702   case NMDReal :
00703     if (v) *(double*)v = cmp->r;
00704     if (f) *f = NMDTrue; break;
00705   case NMDIntarray :
00706     if (v) *(int**)v = cmp->ii;
00707     if (f) *f = NMDTrue; break;
00708   case NMDRealarray :
00709     if (v) *(double**)v = cmp->rr;
00710     if (f) *f = NMDTrue; break;
00711   default :
00712     if (f) *f = NMDFalse;
00713   }
00714   return 0;
00715 }
00716 #endif
00717 
00718 #undef __FUNCT__
00719 #define __FUNCT__ "NMDGetDataType"
00720 NMDErrorCode NMDGetDataType(NMD_metadata obj,const char *cat,const char *cmp,NMDDataType *t)
00721 {
00722   NMD_metadata_category ctg; NMD_metadata_item cpt;
00723   NMDErrorCode ierr;
00724 
00725   CHECKHASNMDCOOKIE(obj);
00726   ierr = NMDObjectGetCategory(obj,cat,&ctg); NMD_ERR_RETURN(ierr);
00727   ierr = NMDCategoryGetComponent(ctg,cmp,&cpt); NMD_ERR_RETURN(ierr);
00728   CHECKHASNMDCOOKIE(cmp);
00729   *t = cpt->t;
00730   
00731   return 0;
00732 }
00733 
00734 #undef __FUNCT__
00735 #define __FUNCT__ "NMDIsArrayType"
00736 /*! Test whether a data type is an array type */
00737 NMDErrorCode NMDIsArrayType(NMDDataType type,NMDTruth *flg)
00738 {
00739   *flg = ( (type==NMDIntarray) || (type==NMDRealarray) ? NMDTrue : NMDFalse ) ;
00740   return 0;
00741 }
00742 
00743 #undef __FUNCT__
00744 #define __FUNCT__ "NMDGetTypeMySQLName"
00745 PetscErrorCode NMDGetTypeMySQLName(NMDDataType type,const char **name)
00746 {
00747   int itype = (int)(type);
00748   if (itype<0 || itype>=nnmdtypenames)
00749     NMD_ERR_REPORTi("Invalid type",itype);
00750   *name = (char*)mysqltypenames[itype];
00751   return 0;
00752 }
00753