/*************************************************************************** params.cpp -- configuration parameters management ------------------- created : Fri Aug 13 22:27:57 CEST 1999 copyright : (C) 1999 by Eric Espie email : torcs@free.fr version : $Id: params.cpp,v 1.28 2005/02/01 15:55:54 berniw Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /** @file This is the parameters manipulation API. @author Eric Espie @version $Id: params.cpp,v 1.28 2005/02/01 15:55:54 berniw Exp $ @ingroup params */ #include #include #include #include #ifndef _WIN32 #include #endif #include #include #ifdef WIN32 #include #endif #include #include #define LINE_SZ 1024 #define PARAM_CREATE 0x01 struct within { char *val; GF_TAILQ_ENTRY (struct within) linkWithin; }; GF_TAILQ_HEAD (withinHead, struct within); #define P_NUM 0 #define P_STR 1 /** Parameter header structure */ struct param { char *name; /**< Name of the parameter */ char *fullName; /**< Name of the parameter including the full section name ('/' separated) */ char *value; /**< Value of the parameter */ tdble valnum; int type; char *unit; /* for output only */ tdble min; tdble max; struct withinHead withinList; GF_TAILQ_ENTRY (struct param) linkParam; /**< Next parameter in the same section */ }; GF_TAILQ_HEAD (paramHead, struct param); struct section; GF_TAILQ_HEAD (sectionHead, struct section); /** Section header structure */ struct section { char *fullName; /**< Name of the section including full path ('/' separated) */ struct paramHead paramList; /**< List of the parameters of this section */ GF_TAILQ_ENTRY (struct section) linkSection; /**< Next section at the same level */ struct sectionHead subSectionList; /**< List of sub-sections (linked by linkSection)*/ struct section *curSubSection; struct section *parent; /**< Upper section */ }; #define PARM_MAGIC 0x20030815 /** Configuration header structure */ struct parmHeader { char *filename; /**< Name of the configuration file */ char *name; /**< Name of the data */ char *dtd; /**< Optional DTD location */ char *header; /**< Optional header (comment, xsl...) */ int refcount; /**< Use counter (number of conf handle) */ struct section *rootSection; /**< List of sections at the first level */ void *paramHash; /**< Hash table for parameter access */ void *sectionHash; /**< Hash table for section access */ }; #define PARM_HANDLE_FLAG_PRIVATE 0x01 #define PARM_HANDLE_FLAG_PARSE_ERROR 0x02 /** Ouput control structure */ struct parmOutput { int state; struct section *curSection; struct param *curParam; char *filename; /**< Name of the output configuration file */ char *indent; }; /** Configuration handle structure */ struct parmHandle { int magic; struct parmHeader *conf; char *val; int flag; XML_Parser parser; struct section *curSection; struct parmOutput outCtrl; GF_TAILQ_ENTRY (struct parmHandle) linkHandle; /**< Next configuration handle */ }; GF_TAILQ_HEAD (parmHead, struct parmHandle); static struct parmHead parmHandleList; static char *getFullName(char *sectionName, const char *paramName); static struct param *getParamByName (struct parmHeader *conf, char *sectionName, const char *paramName, int flag); static void removeParamByName (struct parmHeader *conf, char *sectionName, char *paramName); static void removeParam (struct parmHeader *conf, struct section *section, struct param *param); static struct param *addParam (struct parmHeader *conf, struct section *section, const char *paramName, const char *value); static void removeSection (struct parmHeader *conf, struct section *section); static struct section *addSection (struct parmHeader *conf, char *sectionName); static void parmClean (struct parmHeader *conf); static void parmReleaseHandle (struct parmHandle *parmHandle); static void parmReleaseHeader (struct parmHeader *conf); static struct section *getParent (struct parmHeader *conf, char *sectionName); static void cleanUnusedSection (struct parmHeader *conf, struct section *section); /** Configuration initialization. @ingroup conf @return none. */ void gfParamInit (void) { GF_TAILQ_INIT (&parmHandleList); } /** Configuration shutdown. @ingroup conf @return none */ void GfParmShutdown (void) { struct parmHandle *parmHandle; while ((parmHandle = GF_TAILQ_FIRST (&parmHandleList)) != GF_TAILQ_END (&parmHandleList)) { parmReleaseHandle (parmHandle); } } /* Compute parameter full name */ /* Caller must release the returned name */ static char * getFullName (char *sectionName, const char *paramName) { char *fullName; fullName = (char *) malloc (strlen (sectionName) + strlen (paramName) + 2); if (!fullName) { GfError ("getFullName: malloc (%d) failed", strlen (sectionName) + strlen (paramName) + 2); return NULL; } sprintf (fullName, "%s/%s", sectionName, paramName); return fullName; } /* Get a parameter by section/param names */ static struct param * getParamByName (struct parmHeader *conf, char *sectionName, const char *paramName, int flag) { char *fullName; struct param *param; struct section *section; fullName = getFullName (sectionName, paramName); if (!fullName) { GfError ("getParamByName: getFullName failed\n"); return NULL; } param = (struct param *)GfHashGetStr (conf->paramHash, fullName); free (fullName); if (param || ((flag & PARAM_CREATE) == 0)) { return param; } /* Parameter not found CREATE it */ section = (struct section *)GfHashGetStr (conf->sectionHash, sectionName); if (!section) { section = addSection (conf, sectionName); if (!section) { GfError ("getParamByName: addSection failed\n"); return NULL; } } param = addParam (conf, section, paramName, ""); return param; } /* Remove a parameter */ static void removeParamByName (struct parmHeader *conf, char *sectionName, char *paramName) { char *fullName; struct param *param; struct section *section; section = (struct section *)GfHashGetStr (conf->sectionHash, sectionName); if (!section) { return; } fullName = getFullName (sectionName, paramName); if (!fullName) { GfError ("removeParamByName: getFullName failed\n"); return; } param = (struct param *)GfHashGetStr (conf->paramHash, fullName); freez (fullName); if (param) { removeParam (conf, section, param); } cleanUnusedSection (conf, section); } /* Clean up unused sections and parents */ static void cleanUnusedSection (struct parmHeader *conf, struct section *section) { struct section *parent; if (!section->fullName || (!GF_TAILQ_FIRST (&(section->paramList)) && !GF_TAILQ_FIRST (&(section->subSectionList)))) { parent = section->parent; removeSection (conf, section); if (parent) { /* check if the parent is unused */ cleanUnusedSection (conf, parent); } } } /* Remove a parameter */ static void removeParam (struct parmHeader *conf, struct section *section, struct param *param) { GfHashRemStr (conf->paramHash, param->fullName); GF_TAILQ_REMOVE (&(section->paramList), param, linkParam); struct within *within; while ((within = GF_TAILQ_FIRST (¶m->withinList)) != GF_TAILQ_END (¶m->withinList)) { GF_TAILQ_REMOVE (¶m->withinList, within, linkWithin); freez(within->val); free(within); } freez (param->name); freez (param->fullName); freez (param->value); freez (param->unit); freez (param); } /* Add a parameter anywhere, does not check for duplicate. */ static struct param * addParam (struct parmHeader *conf, struct section *section, const char *paramName, const char *value) { char *fullName; struct param *param = NULL; char *tmpVal = NULL; tmpVal = strdup (value); if (!tmpVal) { GfError ("addParam: strdup (%s) failed\n", value); goto bailout; } param = (struct param *) calloc (1, sizeof (struct param)); if (!param) { GfError ("addParam: calloc (1, %d) failed\n", sizeof (struct param)); goto bailout; } param->name = strdup (paramName); if (!param->name) { GfError ("addParam: strdup (%s) failed\n", paramName); goto bailout; } fullName = getFullName (section->fullName, paramName); if (!fullName) { GfError ("addParam: getFullName failed\n"); goto bailout; } param->fullName = fullName; if (GfHashAddStr (conf->paramHash, param->fullName, param)) { goto bailout; } GF_TAILQ_INIT (&(param->withinList)); /* Attach to section */ GF_TAILQ_INSERT_TAIL (&(section->paramList), param, linkParam); freez (param->value); param->value = tmpVal; return param; bailout: if (param) { freez (param->name); freez (param->fullName); freez (param->value); free (param); } freez (tmpVal); return NULL; } /* Remove a section */ static void removeSection (struct parmHeader *conf, struct section *section) { struct param *param; struct section *subSection; while ((subSection = GF_TAILQ_FIRST (&(section->subSectionList))) != NULL) { removeSection (conf, subSection); } if (section->fullName) { /* not the root section */ GfHashRemStr (conf->sectionHash, section->fullName); GF_TAILQ_REMOVE (&(section->parent->subSectionList), section, linkSection); while ((param = GF_TAILQ_FIRST (&(section->paramList))) != GF_TAILQ_END (&(section->paramList))) { removeParam (conf, section, param); } freez (section->fullName); } freez (section); } /* Get or create parent section */ static struct section * getParent (struct parmHeader *conf, char *sectionName) { struct section *section; char *tmpName; char *s; tmpName = strdup (sectionName); if (!tmpName) { GfError ("getParent: strdup (\"%s\") failed\n", sectionName); return NULL; } s = strrchr (tmpName, '/'); if (s) { *s = '\0'; section = (struct section *)GfHashGetStr (conf->sectionHash, tmpName); if (section) { goto end; } section = addSection (conf, tmpName); goto end; } else { section = conf->rootSection; goto end; } end: free (tmpName); return section; } /* Add a new section */ static struct section * addSection (struct parmHeader *conf, char *sectionName) { struct section *section; struct section *parent; if (GfHashGetStr (conf->sectionHash, sectionName)) { GfError ("addSection: duplicate section [%s]\n", sectionName); return NULL; } parent = getParent(conf, sectionName); if (!parent) { GfError ("addSection: Problem with getParent for section [%s]\n", sectionName); return NULL; } section = (struct section *) calloc (1, sizeof (struct section)); if (!section) { GfError ("addSection: calloc (1, %d) failed\n", sizeof (struct section)); return NULL; } section->fullName = strdup(sectionName); if (!section->fullName) { GfError ("addSection: strdup (%s) failed\n", sectionName); goto bailout; } if (GfHashAddStr (conf->sectionHash, sectionName, section)) { GfError ("addSection: GfHashAddStr failed\n"); goto bailout; } /* no more bailout call */ section->parent = parent; GF_TAILQ_INIT (&(section->paramList)); GF_TAILQ_INIT (&(section->subSectionList)); GF_TAILQ_INSERT_TAIL (&(parent->subSectionList), section, linkSection); return section; bailout: freez (section->fullName); freez (section); return NULL; } static struct parmHeader * getSharedHeader (const char *file, int mode) { struct parmHeader *conf = NULL; struct parmHandle *parmHandle; /* Search for existing conf */ if ((mode & GFPARM_RMODE_PRIVATE) == 0) { for (parmHandle = GF_TAILQ_FIRST (&parmHandleList); parmHandle != GF_TAILQ_END (&parmHandleList); parmHandle = GF_TAILQ_NEXT (parmHandle, linkHandle)) { if ((parmHandle->flag & PARM_HANDLE_FLAG_PRIVATE) == 0) { conf = parmHandle->conf; if (!strcmp(conf->filename, file)) { if (mode & GFPARM_RMODE_REREAD) { parmClean (conf); } conf->refcount++; return conf; } } } } return NULL; } /* Conf header creation */ static struct parmHeader * createParmHeader (const char *file) { struct parmHeader *conf = NULL; conf = (struct parmHeader *) calloc (1, sizeof (struct parmHeader)); if (!conf) { GfError ("gfParmReadFile: calloc (1, %d) failed\n", sizeof (struct parmHeader)); return NULL; } conf->refcount = 1; conf->rootSection = (struct section *) calloc (1, sizeof (struct section)); if (!conf->rootSection) { GfError ("gfParmReadFile: calloc (1, %d) failed\n", sizeof (struct section)); goto bailout; } GF_TAILQ_INIT (&(conf->rootSection->paramList)); GF_TAILQ_INIT (&(conf->rootSection->subSectionList)); conf->paramHash = GfHashCreate (GF_HASH_TYPE_STR); if (!conf->paramHash) { GfError ("gfParmReadFile: GfHashCreate (paramHash) failed\n"); goto bailout; } conf->sectionHash = GfHashCreate (GF_HASH_TYPE_STR); if (!conf->sectionHash) { GfError ("gfParmReadFile: GfHashCreate (sectionHash) failed\n"); goto bailout; } conf->filename = strdup (file); if (!conf->filename) { GfError ("gfParmReadFile: strdup (%s) failed\n", file); goto bailout; } return conf; bailout: freez (conf->rootSection); if (conf->paramHash) { GfHashRelease (conf->paramHash, NULL); } if (conf->sectionHash) { GfHashRelease (conf->sectionHash, NULL); } freez (conf->filename); freez (conf); return NULL; } static void addWithin (struct param *curParam, char *s1) { struct within *curWithin; if (!s1 || ! strlen (s1)) { return; } curWithin = (struct within *) calloc (1, sizeof (struct within)); curWithin->val = strdup (s1); GF_TAILQ_INSERT_TAIL (&(curParam->withinList), curWithin, linkWithin); } /* XML Processing */ static int myStrcmp(const void *s1, const void * s2) { return strcmp((const char *)s1, (const char *)s2); } static tdble getValNumFromStr (const char *str) { tdble val; if (!str || !strlen (str)) { return 0.0; } if (strncmp (str, "0x", 2) == 0) { return (tdble)strtol(str, NULL, 0); } sscanf (str, "%g", &val); return val; } /* XML Processing */ static void xmlStartElement (void *userData , const char *name, const char **atts) { struct parmHandle *parmHandle = (struct parmHandle *)userData; struct parmHeader *conf = parmHandle->conf; struct param *curParam; int nAtts; int len; const char **p; const char *s1, *s2; char *fullName; const char *shortName; const char *val; const char *min; const char *max; const char *unit; char *within; char *sa, *sb; if (parmHandle->flag & PARM_HANDLE_FLAG_PARSE_ERROR) { // parse error occured, ignore. return; } p = atts; while (*p) { ++p; } nAtts = (p - atts) >> 1; if (nAtts > 1) { qsort ((void *)atts, nAtts, sizeof(char *) * 2, myStrcmp); } if (!strcmp(name, "params")) { parmHandle->curSection = conf->rootSection; parmHandle->curSection->fullName = strdup (""); if (!parmHandle->curSection->fullName) { GfError ("xmlStartElement: strdup (\"\") failed\n"); goto bailout; } while (*atts) { s1 = *atts++; s2 = *atts++; if (!strcmp(s1, "name")) { FREEZ (conf->name); conf->name = strdup(s2); if (!conf->name) { GfError ("xmlStartElement: strdup (\"%s\") failed\n", s2); goto bailout; } break; } } if (!conf->name) { GfOut ("xmlStartElement: Syntax error, missing \"name\" field in params definition\n"); goto bailout; } } else if (!strcmp(name, "section")) { if (!parmHandle->curSection) { GfError ("xmlStartElement: Syntax error, missing \"params\" tag\n"); goto bailout; } shortName = NULL; while (*atts) { s1 = *atts++; s2 = *atts++; if (!strcmp(s1, "name")) { shortName = s2; break; } } if (!shortName) { GfError ("xmlStartElement: Syntax error, missing \"name\" field in section definition\n"); goto bailout; } if (strlen(parmHandle->curSection->fullName)) { len = strlen (shortName) + strlen (parmHandle->curSection->fullName) + 2; fullName = (char *) malloc (len); if (!fullName) { GfError ("xmlStartElement: malloc (%d) failed\n", len); goto bailout; } sprintf (fullName, "%s/%s", parmHandle->curSection->fullName, shortName); } else { fullName = strdup (shortName); } parmHandle->curSection = addSection(conf, fullName); free(fullName); if (!parmHandle->curSection) { GfError ("xmlStartElement: addSection failed\n"); goto bailout; } } else if (!strcmp(name, "attnum")) { if ((!parmHandle->curSection) || (!strlen (parmHandle->curSection->fullName))) { GfError ("xmlStartElement: Syntax error, missing \"section\" tag\n"); goto bailout; } shortName = NULL; val = NULL; min = max = unit = NULL; while (*atts) { s1 = *atts++; s2 = *atts++; if (!strcmp(s1, "name")) { shortName = s2; } else if (!strcmp(s1, "val")) { val = s2; } else if (!strcmp(s1, "min")) { min = s2; } else if (!strcmp(s1, "max")) { max = s2; } else if (!strcmp(s1, "unit")) { unit = s2; } } if (!shortName) { GfError ("xmlStartElement: Syntax error, missing \"name\" field in %s definition\n", name); goto bailout; } if (!val) { GfError ("xmlStartElement: Syntax error, missing \"val\" field in %s definition\n", name); goto bailout; } if (!min) { min = val; } if (!max) { max = val; } curParam = addParam (conf, parmHandle->curSection, shortName, val); if (!curParam) { GfError ("xmlStartElement: addParam failed\n"); goto bailout; } curParam->type = P_NUM; curParam->valnum = getValNumFromStr (val); curParam->min = getValNumFromStr (min); curParam->max = getValNumFromStr (max); if (curParam->min > curParam->valnum) { curParam->min = curParam->valnum; } if (curParam->max < curParam->valnum) { curParam->max = curParam->valnum; } if (unit) { curParam->unit = strdup (unit); curParam->valnum = GfParmUnit2SI ((char*)unit, curParam->valnum); curParam->min = GfParmUnit2SI ((char*)unit, curParam->min); curParam->max = GfParmUnit2SI ((char*)unit, curParam->max); } } else if (!strcmp(name, "attstr")) { if ((!parmHandle->curSection) || (!strlen (parmHandle->curSection->fullName))) { GfError ("xmlStartElement: Syntax error, missing \"section\" tag\n"); goto bailout; } shortName = NULL; val = NULL; within = NULL; while (*atts) { s1 = *atts++; s2 = *atts++; if (!strcmp(s1, "name")) { shortName = s2; } else if (!strcmp(s1, "val")) { val = s2; } else if (!strcmp(s1, "in")) { within = (char *)s2; } } if (!shortName) { GfError ("xmlStartElement: Syntax error, missing \"name\" field in %s definition\n", name); goto bailout; } if (!val) { GfError ("xmlStartElement: Syntax error, missing \"val\" field in %s definition\n", name); goto bailout; } curParam = addParam (conf, parmHandle->curSection, shortName, val); if (!curParam) { GfError ("xmlStartElement: addParam failed\n"); goto bailout; } curParam->type = P_STR; if (within) { sa = within; sb = strchr (sa, ','); while (sb) { *sb = 0; addWithin (curParam, sa); sa = sb + 1; sb = strchr (sa, ','); } addWithin (curParam, sa); } } return; bailout: parmHandle->flag |= PARM_HANDLE_FLAG_PARSE_ERROR; return; } static void xmlEndElement (void *userData, const XML_Char *name) { struct parmHandle *parmHandle = (struct parmHandle *)userData; if (parmHandle->flag & PARM_HANDLE_FLAG_PARSE_ERROR) { /* parse error occured, ignore */ return; } if (!strcmp(name, "section")) { if ((!parmHandle->curSection) || (!parmHandle->curSection->parent)) { GfError ("xmlEndElement: Syntax error in \"%s\"\n", name); return; } parmHandle->curSection = parmHandle->curSection->parent; } } static int xmlExternalEntityRefHandler (XML_Parser mainparser, const XML_Char *openEntityNames, const XML_Char * /* base */, const XML_Char *systemId, const XML_Char * /* publicId */) { FILE *in; char buf[BUFSIZ]; XML_Parser parser; int done; char fin[LINE_SZ]; char *s; struct parmHandle *parmHandle; struct parmHeader *conf; parmHandle = (struct parmHandle *)XML_GetUserData (mainparser); conf = parmHandle->conf; parser = XML_ExternalEntityParserCreate (mainparser, openEntityNames, (const XML_Char *)NULL); if (systemId[0] == '/') { strncpy (fin, systemId, sizeof (fin)); fin[LINE_SZ - 1] = 0; } else { /* relative path */ strncpy (fin, conf->filename, sizeof (fin)); fin[LINE_SZ - 1] = 0; s = strrchr (fin, '/'); if (s) { s++; } else { s = fin; } strncpy (s, systemId, sizeof (fin) - (s - fin)); fin[LINE_SZ - 1] = 0; } in = fopen (fin, "r"); if (in == NULL) { perror (fin); GfError ("GfReadParmFile: file %s has pb\n", systemId); return 0; } XML_SetElementHandler (parser, xmlStartElement, xmlEndElement); do { size_t len = fread (buf, 1, sizeof(buf), in); done = len < sizeof (buf); if (!XML_Parse (parser, buf, len, done)) { GfError ("file: %s -> %s at line %d\n", systemId, XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); fclose (in); return 0; } } while (!done); XML_ParserFree (parser); fclose(in); return 1; /* ok (0 for failure) */ } /* xml type parameters line parser */ static int parseXml (struct parmHandle *parmHandle, char *buf, int len, int done) { if (!XML_Parse(parmHandle->parser, buf, len, done)) { GfError ("parseXml: %s at line %d\n", (char*)XML_ErrorString (XML_GetErrorCode (parmHandle->parser)), XML_GetCurrentLineNumber (parmHandle->parser)); return 1; } if (done) { XML_ParserFree(parmHandle->parser); parmHandle->parser = 0; } return 0; } static int parserXmlInit (struct parmHandle *parmHandle) { parmHandle->parser = XML_ParserCreate((XML_Char*)NULL); XML_SetElementHandler(parmHandle->parser, xmlStartElement, xmlEndElement); XML_SetExternalEntityRefHandler(parmHandle->parser, xmlExternalEntityRefHandler); XML_SetUserData(parmHandle->parser, parmHandle); return 0; } /** Read a configuration buffer. @ingroup conf @param logHandle log handle @param buf input buffer. @return handle on the configuration data
0 if Error */ void * GfParmReadBuf (char *buffer) { struct parmHeader *conf; struct parmHandle *parmHandle = NULL; /* Conf Header creation */ conf = createParmHeader (""); if (!conf) { GfError ("gfParmReadBuf: conf header creation failed\n"); goto bailout; } /* Handle creation */ parmHandle = (struct parmHandle *) calloc (1, sizeof (struct parmHandle)); if (!parmHandle) { GfError ("gfParmReadBuf: calloc (1, %d) failed\n", sizeof (struct parmHandle)); goto bailout; } parmHandle->magic = PARM_MAGIC; parmHandle->conf = conf; parmHandle->val = NULL; parmHandle->flag = PARM_HANDLE_FLAG_PRIVATE; /* Parsers Initialization */ if (parserXmlInit (parmHandle)) { GfError ("gfParmReadBuf: parserInit failed\n"); goto bailout; } /* Parameters reading in buffer */ if (parseXml (parmHandle, buffer, strlen (buffer), 1)) { GfError ("gfParmReadBuf: Parse failed for buffer\n"); goto bailout; } GF_TAILQ_INSERT_HEAD (&parmHandleList, parmHandle, linkHandle); return parmHandle; bailout: freez (parmHandle); if (conf) { parmReleaseHeader (conf); } return NULL; } /** Read a configuration file. @note Called by #gfInitThread @ingroup conf @param logHandle log handle @param file name of the file to read or content if input is a buffer. @param mode openning mode is a mask of: #GF_PARM_RMODE_STD #GF_PARM_RMODE_REREAD #GF_PARM_RMODE_CREAT #GF_PARM_RMODE_PRIVATE @return handle on the configuration data
0 if Error */ void * GfParmReadFile (const char *file, int mode) { FILE *in = NULL; struct parmHeader *conf; struct parmHandle *parmHandle = NULL; char buf[LINE_SZ]; int len; int done; /* search for an already openned header & clean the conf if necessary */ conf = getSharedHeader (file, mode); /* Conf Header creation */ if (conf == NULL) { conf = createParmHeader (file); if (!conf) { GfError ("gfParmReadFile: conf header creation failed\n"); goto bailout; } mode |= GFPARM_RMODE_REREAD; } /* Handle creation */ parmHandle = (struct parmHandle *) calloc (1, sizeof (struct parmHandle)); if (!parmHandle) { GfError ("gfParmReadFile: calloc (1, %d) failed\n", sizeof (struct parmHandle)); goto bailout; } parmHandle->magic = PARM_MAGIC; parmHandle->conf = conf; parmHandle->val = NULL; if (mode & GFPARM_RMODE_PRIVATE) { parmHandle->flag = PARM_HANDLE_FLAG_PRIVATE; } /* File openning */ if (mode & GFPARM_RMODE_REREAD) { in = fopen (file, "r"); if (!in && ((mode & GFPARM_RMODE_CREAT) == 0)) { GfOut ("gfParmReadFile: fopen \"%s\" failed\n", file); goto bailout; } if (in) { /* Parsers Initialization */ if (parserXmlInit (parmHandle)) { GfError ("gfParmReadBuf: parserInit failed for file \"%s\"\n", file); goto bailout; } /* Parameters reading */ do { len = fread (buf, 1, sizeof(buf), in); done = len < (int)sizeof(buf); if (parseXml (parmHandle, buf, len, done)) { GfError ("gfParmReadFile: Parse failed in file \"%s\"\n", file); goto bailout; } if (parmHandle->flag & PARM_HANDLE_FLAG_PARSE_ERROR) { /* parse error occured, ignore */ GfError ("gfParmReadFile: Parse failed in file \"%s\"\n", file); goto bailout; } } while (!done); fclose (in); in = NULL; } } GF_TAILQ_INSERT_HEAD (&parmHandleList, parmHandle, linkHandle); GfOut ("GfParmReadFile: Openning \"%s\" (%p)\n", file, parmHandle); return parmHandle; bailout: if (in) { fclose (in); } freez (parmHandle); if (conf) { parmReleaseHeader (conf); } return NULL; } /** * @image html output-state.png */ static int xmlGetOuputLine (struct parmHandle *parmHandle, char *buffer, int /* size */) { struct parmOutput *outCtrl = &(parmHandle->outCtrl); struct parmHeader *conf = parmHandle->conf; struct section *curSection; struct param *curParam; struct within *curWithin; char *s; while (1) { switch (outCtrl->state) { case 0: sprintf (buffer, "\n"); outCtrl->indent = (char *) malloc (LINE_SZ); if (!outCtrl->indent) { GfError ("xmlGetOuputLine: malloc (%d) failed\n", LINE_SZ); return 0; } outCtrl->state = 1; return 1; case 1: if (conf->dtd == NULL) { conf->dtd = strdup("params.dtd"); } if (conf->header == NULL) { conf->header = strdup(""); } sprintf (buffer, "\n%s\n", conf->dtd, conf->header); *outCtrl->indent = 0; outCtrl->state = 2; return 1; case 2: /* Start Params */ outCtrl->curSection = parmHandle->conf->rootSection; sprintf (buffer, "\n\n", parmHandle->conf->name); curSection = GF_TAILQ_FIRST (&(outCtrl->curSection->subSectionList)); if (curSection) { outCtrl->curSection = curSection; sprintf (outCtrl->indent + strlen (outCtrl->indent), " "); outCtrl->state = 4; } else { outCtrl->state = 3; } return 1; case 3: /* End Params */ sprintf (buffer, "\n"); free (outCtrl->indent); outCtrl->state = 9; return 1; case 4: /* Parse section attributes list */ outCtrl->curParam = GF_TAILQ_FIRST (&(outCtrl->curSection->paramList)); s = strrchr (outCtrl->curSection->fullName, '/'); if (!s) { s = outCtrl->curSection->fullName; } else { s++; } sprintf (buffer, "%s
\n", outCtrl->indent, s); sprintf (outCtrl->indent + strlen (outCtrl->indent), " "); outCtrl->state = 5; return 1; case 5: /* Parse one attribute */ if (!outCtrl->curParam) { outCtrl->state = 6; break; } curParam = outCtrl->curParam; if (curParam->type == P_STR) { s = buffer; s += sprintf (s, "%sindent, curParam->name); curWithin = GF_TAILQ_FIRST (&(curParam->withinList)); if (curWithin) { s += sprintf (s, " in=\"%s", curWithin->val); while ((curWithin = GF_TAILQ_NEXT (curWithin, linkWithin)) != NULL) { s += sprintf (s, ",%s", curWithin->val); } s += sprintf (s, "\""); } sprintf (s, " val=\"%s\"/>\n", curParam->value); outCtrl->curParam = GF_TAILQ_NEXT (curParam, linkParam); return 1; } else { s = buffer; s += sprintf (s, "%sindent, curParam->name); if (curParam->unit) { if ((curParam->min != curParam->valnum) || (curParam->max != curParam->valnum)) { s += sprintf (s, " min=\"%g\" max=\"%g\"", GfParmSI2Unit (curParam->unit, curParam->min), GfParmSI2Unit (curParam->unit, curParam->max)); } s += sprintf (s, " unit=\"%s\" val=\"%g\"/>\n", curParam->unit, GfParmSI2Unit (curParam->unit, curParam->valnum)); } else { if ((curParam->min != curParam->valnum) || (curParam->max != curParam->valnum)) { s += sprintf (s, " min=\"%g\" max=\"%g\"", curParam->min, curParam->max); } s += sprintf (s, " val=\"%g\"/>\n", curParam->valnum); } outCtrl->curParam = GF_TAILQ_NEXT (curParam, linkParam); return 1; } case 6: /* Parse sub-section list */ curSection = GF_TAILQ_FIRST (&(outCtrl->curSection->subSectionList)); if (curSection) { outCtrl->curSection = curSection; outCtrl->state = 4; break; } outCtrl->state = 7; break; case 7: /* End Section */ *(outCtrl->indent + strlen (outCtrl->indent) - 2) = 0; sprintf (buffer, "%s
\n\n", outCtrl->indent); outCtrl->state = 8; return 1; case 8: /* Parse next section at the same level */ curSection = GF_TAILQ_NEXT (outCtrl->curSection, linkSection); if (curSection) { outCtrl->curSection = curSection; outCtrl->state = 4; break; } curSection = outCtrl->curSection->parent; *(outCtrl->indent + strlen (outCtrl->indent) - 2) = 0; if (curSection->parent) { outCtrl->curSection = curSection; sprintf (buffer, "%s\n\n", outCtrl->indent); return 1; } outCtrl->state = 3; break; case 9: return 0; } } } /** Write a configuration buffer. @ingroup conf @param logHandle log handle @param parmHandle Configuration handle @param buf buffer to write the configuration @param size buffer size @return 0 if OK
1 if Error */ int GfParmWriteBuf (void *handle, char *buf, int size) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf; char line[LINE_SZ]; int len; int curSize; char *s; conf = parmHandle->conf; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("gfParmWriteBuf: bad handle (%p)\n", parmHandle); return 1; } parmHandle->outCtrl.state = 0; parmHandle->outCtrl.curSection = NULL; parmHandle->outCtrl.curParam = NULL; curSize = size; s = buf; while (curSize && xmlGetOuputLine (parmHandle, line, sizeof (line))) { len = strlen (line); if (len > curSize) { len = curSize; } memcpy (s, line, len); s += len; curSize -= len; } buf [size - 1] = 0; return 0; } /** Set the dtd path and header if necessary @ingroup conf @param parmHandle Configuration handle @param dtd Optional dtd path @param header Optional header @return none */ void GfParmSetDTD (void *parmHandle, char *dtd, char*header) { struct parmHandle *handle = (struct parmHandle *)parmHandle; struct parmHeader *conf = handle->conf; if (dtd) { FREEZ(conf->dtd); conf->dtd = strdup(dtd); } if (header) { FREEZ(conf->header); conf->header = strdup(header); } } /** Write a configuration file. @ingroup conf @param parmHandle Configuration handle @param file Name of the file to write (NULL if previously read file) @param name Name of the parameters @return 0 if OK
1 if Error */ int GfParmWriteFile (const char *file, void *parmHandle, char *name) { struct parmHandle *handle = (struct parmHandle *)parmHandle; struct parmHeader *conf = handle->conf; char line[LINE_SZ]; FILE *fout; conf = handle->conf; if (handle->magic != PARM_MAGIC) { GfFatal ("gfParmWriteFile: bad handle (%p)\n", parmHandle); return 1; } if (!file) { file = conf->filename; if (!file) { GfError ("gfParmWriteFile: bad file name\n"); return 1; } } fout = fopen (file, "wb"); if (!fout) { GfError ("gfParmSetStr: fopen (%s, \"wb\") failed\n", file); return 1; } if (name) { FREEZ (conf->name); conf->name = strdup (name); } handle->outCtrl.state = 0; handle->outCtrl.curSection = NULL; handle->outCtrl.curParam = NULL; while (xmlGetOuputLine (handle, line, sizeof (line))) { fputs (line, fout); } GfOut ("GfParmWriteFile: %s file written\n", file); fclose (fout); return 0; } /** Remove a parameter. @ingroup conf @param parmHandle Configuration handle @param sectionName Parameter section name @param paramName Parameter name @return none */ void GfParmRemove (void *parmHandle, char *sectionName, char *paramName) { struct parmHandle *handle = (struct parmHandle *)parmHandle; struct parmHeader *conf; conf = handle->conf; if (handle->magic != PARM_MAGIC) { GfFatal ("gfParmRemove: bad handle (%p)\n", parmHandle); return; } removeParamByName (conf, sectionName, paramName); } static void parmClean (struct parmHeader *conf) { struct section *section; while ((section = GF_TAILQ_FIRST (&(conf->rootSection->subSectionList))) != GF_TAILQ_END (&(conf->rootSection->subSectionList))) { removeSection (conf, section); } } /** Clean all the parameters of a set. @ingroup conf @param parmHandle Configuration handle @return 0 if OK
-1 if Error */ void GfParmClean (void *parmHandle) { struct parmHandle *handle = (struct parmHandle *)parmHandle; struct parmHeader *conf; conf = handle->conf; if (handle->magic != PARM_MAGIC) { GfFatal ("gfParmClean: bad handle (%p)\n", parmHandle); return; } parmClean (conf); } static void parmReleaseHeader(struct parmHeader *conf) { conf->refcount--; if (conf->refcount > 0) { return; } GfOut ("parmReleaseHeader: refcount null free \"%s\"\n", conf->filename); parmClean (conf); freez (conf->filename); if (conf->paramHash) { GfHashRelease (conf->paramHash, NULL); } if (conf->sectionHash) { GfHashRelease (conf->sectionHash, NULL); } freez (conf->rootSection->fullName); freez (conf->rootSection); freez (conf->dtd); freez (conf->name); freez (conf->header); freez (conf); } static void parmReleaseHandle (struct parmHandle *parmHandle) { struct parmHeader *conf = parmHandle->conf; GfOut ("parmReleaseHandle: release \"%s\" (%p)\n", conf->filename, parmHandle); GF_TAILQ_REMOVE (&parmHandleList, parmHandle, linkHandle); parmHandle->magic = 0; freez (parmHandle->val); freez (parmHandle); parmReleaseHeader(conf); } /** Clean the parms and release the handle without updating the file @note Called by #gfShutdownThread @ingroup conf @param logHandle log handle @param parmHandle Configuration handle @return none */ void GfParmReleaseHandle (void *parmHandle) { struct parmHandle *handle = (struct parmHandle *)parmHandle; if (handle->magic != PARM_MAGIC) { GfFatal ("gfParmReleaseHandle: bad handle (%p)\n", parmHandle); return; } parmReleaseHandle(handle); } static void evalUnit (char *unit, tdble *dest, int flg) { tdble coeff = 1.0; if (strcmp(unit, "m") == 0) return; if (strcmp(unit, "kg") == 0) return; if (strcmp(unit, "s") == 0) return; if (strcmp(unit, "rad") == 0) return; if (strcmp(unit, "Pa") == 0) return; if ((strcmp(unit, "feet") == 0) || (strcmp(unit, "ft") == 0)) { coeff = 0.304801f; /* m */ } else if (strcmp(unit, "deg") == 0) { coeff = (float) (M_PI/180.0); /* rad */ } else if ((strcmp(unit, "h") == 0) || (strcmp(unit, "hour") == 0) || (strcmp(unit, "hours") == 0)) { coeff = 3600.0; /* s */ } else if ((strcmp(unit, "day") == 0) || (strcmp(unit, "days") == 0)) { coeff = 24*3600.0; /* s */ } else if (strcmp(unit, "km") == 0) { coeff = 1000.0; /* m */ } else if (strcmp(unit, "mm") == 0) { coeff = 0.001f; /* m */ } else if (strcmp(unit, "cm") == 0) { coeff = 0.01f; /* m */ } else if ((strcmp(unit, "in") == 0) || (strcmp(unit, "inch") == 0) || (strcmp(unit, "inches") == 0)) { coeff = 0.0254f; /* m */ } else if ((strcmp(unit, "lbs") == 0) || (strcmp(unit, "lb") == 0)) { coeff = 0.45359237f; /* kg */ } else if ((strcmp(unit, "slug") == 0) || (strcmp(unit, "slugs") == 0)) { coeff = 14.59484546f; /* kg */ } else if (strcmp(unit, "kPa") == 0) { coeff = 1000.0; /* Pa */ } else if (strcmp(unit, "MPa") == 0) { coeff = 1000000.0; /* Pa */ } else if ((strcmp(unit, "PSI") == 0) || (strcmp(unit, "psi") == 0)){ coeff = 6894.76f; /* Pa */ } else if ((strcmp(unit, "rpm") == 0) || (strcmp(unit, "RPM") == 0)) { coeff = 0.104719755f; /* rad/s */ } else if ((strcmp(unit, "percent") == 0) || (strcmp(unit, "%") == 0)) { coeff = 0.01f; } else if ((strcmp(unit, "mph") == 0) || (strcmp(unit, "MPH") == 0)) { coeff = 0.44704f; /* m/s */ } if (flg) { *dest /= coeff; } else { *dest *= coeff; } return; } /** Convert a value in "units" into SI. @ingroup paramsdata @param unit unit name @param val value in units @return the value in corresponding SI unit @warning The supported units are:
  • feet or ft converted to m
  • inches or in converted to m
  • lbs converted to kg
  • slug or slugs converted to kg
  • h or hours converted to s
  • day or days converted to s
  • km converted to m
  • cm converted to m
  • mm converted to m
  • kPa converted to Pa
  • deg converted to rad
  • rpm or RPM converted to rad/s
  • percent or % divided by 100
@see GfParmSI2Unit */ tdble GfParmUnit2SI (char *unit, tdble val) { char buf[256]; int idx; char *s; int inv; tdble dest = val; if ((unit == NULL) || (strlen(unit) == 0)) return dest; s = unit; buf[0] = 0; inv = 0; idx = 0; while (*s != 0) { switch (*s) { case '.': evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; break; case '/': evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; inv = 1; break; case '2': evalUnit(buf, &dest, inv); evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; break; default: buf[idx++] = *s; buf[idx] = 0; break; } s++; } evalUnit(buf, &dest, inv); return dest; } /** Convert a value in SI to "units". @ingroup paramsdata @param unit unit name to convert to @param val value in SI units to be converted to units @return converted value to units @see GfParmUnit2SI */ tdble GfParmSI2Unit (char *unit, tdble val) { char buf[256]; int idx; char *s; int inv; tdble dest = val; if ((unit == NULL) || (strlen(unit) == 0)) return dest; s = unit; buf[0] = 0; inv = 1; idx = 0; while (*s != 0) { switch (*s) { case '.': evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; break; case '/': evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; inv = 0; break; case '2': evalUnit(buf, &dest, inv); evalUnit(buf, &dest, inv); buf[0] = 0; idx = 0; break; default: buf[idx++] = *s; buf[idx] = 0; break; } s++; } evalUnit(buf, &dest, inv); return dest; } /** Get the pararmeters name @ingroup paramsdata @param handle Handle on the parameters @return Name */ char * GfParmGetName (void *handle) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetName: bad handle (%p)\n", parmHandle); return NULL; } return conf->name; } /** Get the pararmeters file name @ingroup paramsfile @param handle Handle on the parameters @return File Name */ char * GfParmGetFileName (void *handle) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetFileName: bad handle (%p)\n", parmHandle); return NULL; } return conf->filename; } /** Count the number of section elements of a list. @ingroup paramslist @param handle handle of parameters @param path path of list @return element count */ int GfParmGetEltNb (void *handle, char *path) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; int count; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetEltNb: bad handle (%p)\n", parmHandle); return 0; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if (!section) { return 0; } count = 0; section = GF_TAILQ_FIRST (&(section->subSectionList)); while (section) { count++; section = GF_TAILQ_NEXT (section, linkSection); } return count; } /** Seek the first section element of a list. @ingroup paramslist @param handle handle of parameters @param path list path @return 0 Ok
-1 Failed @see GfParmListSeekNext @see GfParmListGetCurEltName */ int GfParmListSeekFirst (void *handle, char *path) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmListSeekFirst: bad handle (%p)\n", parmHandle); return -1; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if (!section) { return -1; } section->curSubSection = GF_TAILQ_FIRST (&(section->subSectionList)); return 0; } /** Go to the next section element in the current list. @ingroup paramslist @param handle handle of parameters @param path path of list @return 0 Ok
1 End of list reached
-1 Failed @see GfParmListSeekFirst @see GfParmListGetCurEltName */ int GfParmListSeekNext (void *handle, char *path) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmListSeekNext: bad handle (%p)\n", parmHandle); return -1; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return -1; } section->curSubSection = GF_TAILQ_NEXT (section->curSubSection, linkSection); if (section->curSubSection) { return 0; } return 1; /* EOL reached */ } /** Remove all the section elements of a list. @ingroup paramslist @param handle handle of parameters @param path path of list @return 0 Ok
-1 Error */ int GfParmListClean (void *handle, char *path) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *listSection; struct section *section; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmListSeekNext: bad handle (%p)\n", parmHandle); return -1; } listSection = (struct section *)GfHashGetStr (conf->sectionHash, path); if (!listSection) { GfOut ("GfParmListClean: \"%s\" not found\n", path); return -1; } while ((section = GF_TAILQ_FIRST (&(listSection->subSectionList))) != NULL) { removeSection (conf, section); } return 0; } /** Get the current element name. @ingroup paramslist @param handle handle of parameters @param path path of list @return Name of the current element in the list
NULL if failed @see GfParmListSeekFirst @see GfParmListSeekNext @note String MUST be released by called. */ char * GfParmListGetCurEltName (void *handle, char *path) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; char *s; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmListGetCurEltName: bad handle (%p)\n", parmHandle); return NULL; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return NULL; } //printf("WARNING: EVENTUALLY STRDUP ON USER SIDE REQUIRED!"); s = strrchr (section->curSubSection->fullName, '/'); if (s) { s++; return s; //return strdup (s); } return section->curSubSection->fullName; //return strdup (section->curSubSection->fullName); } /** Get string parameter value. @ingroup paramsdata @param parmHandle Configuration handle @param path Parameter section name @param key Parameter name @param deflt Default value if parameter not existing @return Parameter value
deflt if Error or not found @note The pointer returned is for immediate use, if you plan to keep the value for a long time, it is necessary to copy it elsewhere, because removing the attribute will produce incoherent pointer. */ char * GfParmGetStr (void *parmHandle, char *path, char *key, char *deflt) { struct param *param; struct parmHandle *handle = (struct parmHandle *)parmHandle; struct parmHeader *conf; char *val; conf = handle->conf; if (handle->magic != PARM_MAGIC) { GfFatal ("gfParmGetStr: bad handle (%p)\n", parmHandle); return deflt; } param = getParamByName (conf, path, key, 0); if (!param || !(param->value) || !strlen (param->value) || (param->type != P_STR)) { return deflt; } val = param->value; return val; } /** Get a string parameter in a config file. @ingroup paramslist @param handle handle of parameters @param path path of param @param key key name @param deflt default string @return parameter value @warning the return value is allocated by the function the caller must free it. @see GfParmListSeekNext */ char * GfParmGetCurStr (void *handle, char *path, char *key, char *deflt) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetCurStr: bad handle (%p)\n", parmHandle); return deflt; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return deflt; } param = getParamByName (conf, section->curSubSection->fullName, key, 0); if (!param || !(param->value) || !strlen (param->value) || (param->type != P_STR)) { return deflt; } return param->value; } /** Get a numerical parameter in a config file. @ingroup paramsdata @param handle handle of parameters @param path path of param @param key key name @param unit unit to convert the result to (NULL if SI wanted) @param deflt default string @return parameter value */ tdble GfParmGetNum (void *handle, char *path, char *key, char *unit, tdble deflt) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetNum: bad handle (%p)\n", parmHandle); return deflt; } param = getParamByName (conf, path, key, 0); if (!param || (param->type != P_NUM)) { return deflt; } if (unit) { return GfParmSI2Unit(unit, param->valnum); } return param->valnum; } /** Get a numerical parameter in a config file. @ingroup paramslist @param handle handle of parameters @param path path of param @param key key name @param unit unit to convert the result to (NULL if SI wanted) @param deflt default string @return parameter value */ tdble GfParmGetCurNum (void *handle, char *path, char *key, char *unit, tdble deflt) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetCurNum: bad handle (%p)\n", parmHandle); return deflt; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return deflt; } param = getParamByName (conf, section->curSubSection->fullName, key, 0); if (!param || (param->type != P_NUM)) { return deflt; } if (unit) { return GfParmSI2Unit(unit, param->valnum); } return param->valnum; } /** Set a string parameter in a config file. @ingroup paramsdata @param handle handle of parameters @param path path of param @param key key name @param val value (NULL or empty string to remove the parameter) @return 0 ok
-1 error @warning The key is created is necessary */ int GfParmSetStr(void *handle, char *path, char *key, char *val) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmSetStr: bad handle (%p)\n", parmHandle); return -1; } if (!val || !strlen (val)) { /* Remove the entry */ removeParamByName (conf, path, key); return 0; } param = getParamByName (conf, path, key, PARAM_CREATE); if (!param) { return -1; } param->type = P_STR; freez (param->value); param->value = strdup (val); if (!param->value) { GfError ("gfParmSetStr: strdup (%s) failed\n", val); removeParamByName (conf, path, key); return -1; } return 0; } /** Set a string parameter in a config file. @ingroup paramslist @param handle handle of parameters @param path path of param @param key key name @param val value @return 0 ok
-1 error @warning The key is created is necessary */ int GfParmSetCurStr(void *handle, char *path, char *key, char *val) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmSetCurStr: bad handle (%p)\n", parmHandle); return -1; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return -1; } param = getParamByName (conf, section->curSubSection->fullName, key, PARAM_CREATE); if (!param) { return -1; } param->type = P_STR; freez (param->value); param->value = strdup (val); if (!param->value) { GfError ("gfParmSetStr: strdup (%s) failed\n", val); removeParamByName (conf, path, key); return -1; } return 0; } /** Set a numerical parameter in a config file. @ingroup paramsdata @param handle handle of parameters @param path path of param @param key key name @param unit unit to convert the result to (NULL if SI wanted) @param val value to set @return 0 ok
-1 error @warning The key is created is necessary */ int GfParmSetNum(void *handle, char *path, char *key, char *unit, tdble val) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmSetNum: bad handle (%p)\n", parmHandle); return -1; } param = getParamByName (conf, path, key, PARAM_CREATE); if (!param) { return -11; } param->type = P_NUM; FREEZ (param->unit); if (unit) { param->unit = strdup (unit); } val = GfParmUnit2SI (unit, val); param->valnum = val; param->min = val; param->max = val; return 0; } /** Set a numerical parameter in a config file. @ingroup paramsdata @param handle handle of parameters @param path path of param @param key key name @param unit unit to convert the result to (NULL if SI wanted) @param val value to set @param min min value @param max max value @return 0 ok
-1 error @warning The key is created is necessary */ int GfParmSetNumEx(void *handle, char *path, char *key, char *unit, tdble val, tdble min, tdble max) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmSetNumEx: bad handle (%p)\n", parmHandle); return -1; } param = getParamByName (conf, path, key, PARAM_CREATE); if (!param) { return -1; } param->type = P_NUM; FREEZ (param->unit); if (unit) { param->unit = strdup (unit); } param->valnum = GfParmUnit2SI (unit, val); param->min = GfParmUnit2SI (unit, min); param->max = GfParmUnit2SI (unit, max); return 0; } /** Set a numerical parameter in a config file. @ingroup paramslist @param handle handle of parameters @param path path of param @param key key name @param unit unit to convert the result to (NULL if SI wanted) @param val value to set @return 0 ok
-1 error @warning The key is created is necessary */ int GfParmSetCurNum(void *handle, char *path, char *key, char *unit, tdble val) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct section *section; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmSetCurNum: bad handle (%p)\n", parmHandle); return -1; } section = (struct section *)GfHashGetStr (conf->sectionHash, path); if ((!section) || (!section->curSubSection)) { return -1; } param = getParamByName (conf, section->curSubSection->fullName, key, PARAM_CREATE); if (!param) { return -1; } param->type = P_NUM; FREEZ (param->unit); if (unit) { param->unit = strdup (unit); } val = GfParmUnit2SI (unit, val); param->valnum = val; param->min = val; param->max = val; return 0; } /** Check a parameter set against another. @ingroup paramsfile @param ref Contains the min and max values (reference) @param tgt Contains the parameters to check. @return 0 Match
-1 Values are out of bounds @warning Only the parameters present in tgt and in ref are tested. @see GfParmMergeHandles */ int GfParmCheckHandle(void *ref, void *tgt) { struct parmHandle *parmHandleRef = (struct parmHandle *)ref; struct parmHandle *parmHandle = (struct parmHandle *)tgt; struct parmHeader *confRef = parmHandleRef->conf; struct parmHeader *conf = parmHandle->conf; struct section *curSectionRef; struct section *nextSectionRef; struct param *curParamRef; struct param *curParam; struct within *curWithinRef; int found; int error = 0; if ((parmHandleRef->magic != PARM_MAGIC) || (parmHandle->magic != PARM_MAGIC)) { GfFatal ("GfParmCheckHandle: bad handle (%p)\n", parmHandle); return -1; } /* Traverse all the reference tree */ curSectionRef = GF_TAILQ_FIRST (&(confRef->rootSection->subSectionList)); while (curSectionRef) { curParamRef = GF_TAILQ_FIRST (&(curSectionRef->paramList)); while (curParamRef) { /* compare params */ curParam = getParamByName (conf, curSectionRef->fullName, curParamRef->name, 0); if (curParam) { if (curParamRef->type != curParam->type) { GfError("GfParmCheckHandle: type mismatch for parameter \"%s\" in (\"%s\" - \"%s\")\n", curParamRef->fullName, conf->name, conf->filename); error = -1; } else if (curParamRef->type == P_NUM) { if ((curParam->valnum < curParamRef->min) || (curParam->valnum > curParamRef->max)) { GfError("GfParmCheckHandle: parameter \"%s\" out of bounds: min:%g max:%g val:%g in (\"%s\" - \"%s\")\n", curParamRef->fullName, curParamRef->min, curParamRef->max, curParam->valnum, conf->name, conf->filename); //error = -1; } } else { curWithinRef = GF_TAILQ_FIRST (&(curParamRef->withinList)); found = 0; while (!found && curWithinRef) { if (!strcmp (curWithinRef->val, curParam->value)) { found = 1; } else { curWithinRef = GF_TAILQ_NEXT (curWithinRef, linkWithin); } } if (!found && strcmp (curParamRef->value, curParam->value)) { GfError("GfParmCheckHandle: parameter \"%s\" value:\"%s\" not allowed in (\"%s\" - \"%s\")\n", curParamRef->fullName, curParam->value, conf->name, conf->filename); //error = -1; } } } curParamRef = GF_TAILQ_NEXT (curParamRef, linkParam); } nextSectionRef = GF_TAILQ_NEXT (curSectionRef, linkSection); while (!nextSectionRef) { nextSectionRef = curSectionRef->parent; if (!nextSectionRef) { /* Reached the root */ break; } curSectionRef = nextSectionRef; nextSectionRef = GF_TAILQ_NEXT (curSectionRef, linkSection); } curSectionRef = nextSectionRef; } return error; } static void insertParamMerge (struct parmHandle *parmHandle, char *path, struct param *paramRef, struct param *param) { struct parmHeader *conf = parmHandle->conf; struct param *paramNew; struct within *withinRef; struct within *within; tdble num; char *str; paramNew = getParamByName (conf, path, param->name, PARAM_CREATE); if (!paramNew) { return; } if (param->type == P_NUM) { paramNew->type = P_NUM; FREEZ (paramNew->unit); if (param->unit) { paramNew->unit = strdup (param->unit); } if (param->min < paramRef->min) { num = paramRef->min; } else { num = param->min; } paramNew->min = num; if (param->max > paramRef->max) { num = paramRef->max; } else { num = param->max; } paramNew->max = num; num = param->valnum; if (num < paramNew->min) { num = paramNew->min; } if (num > paramNew->max) { num = paramNew->max; } paramNew->valnum = num; } else { paramNew->type = P_STR; FREEZ (paramNew->value); within = GF_TAILQ_FIRST (&(param->withinList)); while (within) { withinRef = GF_TAILQ_FIRST (&(paramRef->withinList)); while (withinRef) { if (!strcmp (withinRef->val, within->val)) { addWithin (paramNew, within->val); break; } withinRef = GF_TAILQ_NEXT (withinRef, linkWithin); } within = GF_TAILQ_NEXT (within, linkWithin); } str = NULL; withinRef = GF_TAILQ_FIRST (&(paramRef->withinList)); while (withinRef) { if (!strcmp (withinRef->val, param->value)) { str = param->value; break; } withinRef = GF_TAILQ_NEXT (withinRef, linkWithin); } if (!str) { str = paramRef->value; } paramNew->value = strdup (str); } } static void insertParam (struct parmHandle *parmHandle, char *path, struct param *param) { struct parmHeader *conf = parmHandle->conf; struct param *paramNew; struct within *within; paramNew = getParamByName (conf, path, param->name, PARAM_CREATE); if (!paramNew) { return; } if (param->type == P_NUM) { paramNew->type = P_NUM; FREEZ (paramNew->unit); if (param->unit) { paramNew->unit = strdup (param->unit); } paramNew->valnum = param->valnum; paramNew->min = param->min; paramNew->max = param->max; } else { paramNew->type = P_STR; FREEZ (paramNew->value); paramNew->value = strdup (param->value); within = GF_TAILQ_FIRST (&(param->withinList)); while (within) { addWithin (paramNew, within->val); within = GF_TAILQ_NEXT (within, linkWithin); } } } /** Merge two parameters sets into a new one. @ingroup paramsfile @param ref reference handle @param tgt target handle for merge @param mode merge mode, can be any combination of:
#GFPARM_MMODE_SRC Use ref and modify existing parameters with tgt
#GFPARM_MMODE_DST Use tgt and verify ref parameters
#GFPARM_MMODE_RELSRC Release ref after the merge
#GFPARM_MMODE_RELDST Release tgt after the merge @return The new handle containing the merge. @see GfParmCheckHandle */ void * GfParmMergeHandles(void *ref, void *tgt, int mode) { struct parmHandle *parmHandleRef = (struct parmHandle *)ref; struct parmHandle *parmHandleTgt = (struct parmHandle *)tgt; struct parmHandle *parmHandleOut; struct parmHeader *confRef = parmHandleRef->conf; struct parmHeader *confTgt = parmHandleTgt->conf; struct parmHeader *confOut; struct section *curSectionRef; struct section *nextSectionRef; struct section *curSectionTgt; struct section *nextSectionTgt; struct param *curParamRef; struct param *curParamTgt; GfOut ("Merging \"%s\" and \"%s\" (%s - %s)\n", confRef->filename, confTgt->filename, ((mode & GFPARM_MMODE_SRC) ? "SRC" : ""), ((mode & GFPARM_MMODE_DST) ? "DST" : "")); if (parmHandleRef->magic != PARM_MAGIC) { GfFatal ("GfParmMergeHandles: bad handle (%p)\n", parmHandleRef); return NULL; } if (parmHandleTgt->magic != PARM_MAGIC) { GfFatal ("GfParmMergeHandles: bad handle (%p)\n", parmHandleTgt); return NULL; } /* Conf Header creation */ confOut = createParmHeader (""); if (!confOut) { GfError ("gfParmReadBuf: conf header creation failed\n"); return NULL; } /* Handle creation */ parmHandleOut = (struct parmHandle *) calloc (1, sizeof (struct parmHandle)); if (!parmHandleOut) { GfError ("gfParmReadBuf: calloc (1, %d) failed\n", sizeof (struct parmHandle)); parmReleaseHeader (confOut); return NULL; } parmHandleOut->magic = PARM_MAGIC; parmHandleOut->conf = confOut; parmHandleOut->flag = PARM_HANDLE_FLAG_PRIVATE; if (mode & GFPARM_MMODE_SRC) { /* Traverse all the reference tree */ curSectionRef = GF_TAILQ_FIRST (&(confRef->rootSection->subSectionList)); while (curSectionRef) { curParamRef = GF_TAILQ_FIRST (&(curSectionRef->paramList)); while (curParamRef) { /* compare params */ curParamTgt = getParamByName (confTgt, curSectionRef->fullName, curParamRef->name, 0); if (curParamTgt) { insertParamMerge (parmHandleOut, curSectionRef->fullName, curParamRef, curParamTgt); } else { insertParam (parmHandleOut, curSectionRef->fullName, curParamRef); } curParamRef = GF_TAILQ_NEXT (curParamRef, linkParam); } nextSectionRef = GF_TAILQ_FIRST (&(curSectionRef->subSectionList)); if (nextSectionRef) { curSectionRef = nextSectionRef; } else { nextSectionRef = GF_TAILQ_NEXT (curSectionRef, linkSection); while (!nextSectionRef) { nextSectionRef = curSectionRef->parent; if (!nextSectionRef) { /* Reached the root */ break; } curSectionRef = nextSectionRef; nextSectionRef = GF_TAILQ_NEXT (curSectionRef, linkSection); } curSectionRef = nextSectionRef; } } } if (mode & GFPARM_MMODE_DST) { /* Traverse all the target tree */ curSectionTgt = GF_TAILQ_FIRST (&(confTgt->rootSection->subSectionList)); while (curSectionTgt) { curParamTgt = GF_TAILQ_FIRST (&(curSectionTgt->paramList)); while (curParamTgt) { /* compare params */ curParamRef = getParamByName (confRef, curSectionTgt->fullName, curParamTgt->name, 0); if (curParamRef) { insertParamMerge (parmHandleOut, curSectionTgt->fullName, curParamRef, curParamTgt); } else { insertParam (parmHandleOut, curSectionTgt->fullName, curParamTgt); } curParamTgt = GF_TAILQ_NEXT (curParamTgt, linkParam); } nextSectionTgt = GF_TAILQ_FIRST (&(curSectionTgt->subSectionList)); if (nextSectionTgt) { curSectionTgt = nextSectionTgt; } else { nextSectionTgt = GF_TAILQ_NEXT (curSectionTgt, linkSection); while (!nextSectionTgt) { nextSectionTgt = curSectionTgt->parent; if (!nextSectionTgt) { /* Reached the root */ break; } curSectionTgt = nextSectionTgt; nextSectionTgt = GF_TAILQ_NEXT (curSectionTgt, linkSection); } curSectionTgt = nextSectionTgt; } } } if (mode & GFPARM_MMODE_RELSRC) { GfParmReleaseHandle(ref); } if (mode & GFPARM_MMODE_RELDST) { GfParmReleaseHandle(tgt); } GF_TAILQ_INSERT_HEAD (&parmHandleList, parmHandleOut, linkHandle); return (void*)parmHandleOut; } /** Get the min and max of a numerical parameter. @ingroup paramsdata @param handle handle of parameters @param path path of the attribute @param key key name @param min Receives the min value @param max Receives the max value @return 0 Ok
-1 Parameter not existing */ int GfParmGetNumBoundaries(void *handle, char *path, char *key, tdble *min, tdble *max) { struct parmHandle *parmHandle = (struct parmHandle *)handle; struct parmHeader *conf = parmHandle->conf; struct param *param; if (parmHandle->magic != PARM_MAGIC) { GfFatal ("GfParmGetNumBoundaries: bad handle (%p)\n", parmHandle); return -1; } param = getParamByName (conf, path, key, 0); if (!param || (param->type != P_NUM)) { return -1; } *min = param->min; *max = param->max; return 0; }