dnxCfgParser.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002 
00003    Copyright (c) 2006-2007, Intellectual Reserve, Inc. All rights reserved.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License version 2 as
00007    published by the Free Software Foundation.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   --------------------------------------------------------------------------*/
00019 
00042 #include "dnxCfgParser.h"
00043 
00044 #include "dnxLogging.h"
00045 #include "dnxError.h"
00046 #include "dnxDebug.h"
00047 
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <stdint.h>
00051 #include <string.h>
00052 #include <ctype.h>
00053 #include <assert.h>
00054 #include <errno.h>
00055 
00056 #define elemcount(x) (sizeof(x)/sizeof(*(x)))
00057 
00058 #define DNX_MAX_CFG_LINE   2048     
00059 
00060 
00065 typedef struct iDnxCfgParser
00066 {
00067    char * cfgfile;                  
00068    char ** cfgdefs;                 
00069    char ** cmdover;                 
00070    DnxCfgDict * dict;               
00071    unsigned dictsz;                 
00072    DnxCfgValidator_t * vfp;         
00073    char * curcfg;                   
00074    size_t ccsize;                   
00075 } iDnxCfgParser;
00076 
00078 typedef int DnxVarParser_t(char * val, DnxCfgType type, void * prval);
00079 
00081 typedef char * DnxVarFormatter_t(char * var, DnxCfgType type, void * prval);
00082 
00083 /*--------------------------------------------------------------------------
00084                               IMPLEMENTATION
00085   --------------------------------------------------------------------------*/
00086 
00095 static char ** strToStrArray(char * str, char delim)
00096 {
00097    int cnt;
00098    size_t strsz;
00099    char * p, ** sap;
00100 
00101    // first check for empty string
00102    if (!str) return 0;
00103 
00104    // count elements first
00105    (cnt = 1), p = str;
00106    while ((p = strchr(p, delim)) != 0)
00107       p++, cnt++;
00108 
00109    // allocate char* array and string buffer
00110    strsz = strlen(str) + 1;
00111    if ((sap = (char **)xmalloc((cnt + 1) * sizeof *sap + strsz)) == 0)
00112       return 0;
00113 
00114    // copy string into storage buffer at end of array
00115    p = (char *)&sap[cnt + 1];
00116    memcpy(p, str, strsz);
00117 
00118    // store pointers in ptr array, and terminate strings
00119    (cnt = 0), sap[cnt++] = p;
00120    while ((p = strchr(p, delim)) != 0)
00121       (*p++ = 0), sap[cnt++] = p;
00122    sap[cnt] = 0;
00123 
00124    return sap;
00125 }
00126 
00127 //----------------------------------------------------------------------------
00128 
00141 static DnxCfgDict * copyDictionary(DnxCfgDict * dict, unsigned * dictszp)
00142 {
00143    DnxCfgDict * cpy;
00144    size_t bufsz = 0;
00145    unsigned cnt = 0;
00146    char * sptr;
00147 
00148    assert(dict);
00149 
00150    // calculate space required for copy; add one for null-terminator
00151    while (dict[cnt].varname)
00152       bufsz += strlen(dict[cnt++].varname) + 1;
00153    cnt++;
00154 
00155    // allocate space for array copy with buffer space for strings and values
00156    if ((cpy = (DnxCfgDict *)xmalloc(cnt * sizeof *dict + bufsz)) == 0)
00157       return 0;
00158 
00159    // find string buffer pointer
00160    sptr = (char *)&cpy[cnt];
00161 
00162    // store parameter-based return values; return count of real elements
00163    *dictszp = --cnt;
00164 
00165    // copy the dictionary; zero user values
00166    cpy[cnt].varname = 0;
00167    while (cnt--)
00168    {
00169       size_t strsz = strlen(dict[cnt].varname) + 1;
00170       memcpy(sptr, dict[cnt].varname, strsz);
00171       cpy[cnt].varname = sptr;
00172       cpy[cnt].type = dict[cnt].type;
00173       cpy[cnt].valptr = dict[cnt].valptr;
00174       if (cpy[cnt].type != DNX_CFG_INT && cpy[cnt].type != DNX_CFG_UNSIGNED
00175             && cpy[cnt].type != DNX_CFG_BOOL)
00176          *(void **)cpy[cnt].valptr = 0;
00177       else
00178          *(unsigned *)cpy[cnt].valptr = 0;
00179       sptr += strsz;
00180    }
00181    return cpy;
00182 }
00183 
00184 //----------------------------------------------------------------------------
00185 
00194 static int validateURL(char * url) { return 0; }
00195 
00196 //----------------------------------------------------------------------------
00197 
00206 static int validateFSPath(char * path) { return 0; }
00207 
00208 //----------------------------------------------------------------------------
00209 
00223 static int parseString(char * val, DnxCfgType type, char ** prval)
00224 {
00225    int ret;
00226    char * str;
00227    assert(type == DNX_CFG_URL || type == DNX_CFG_FSPATH || type == DNX_CFG_STRING);
00228    if (type == DNX_CFG_URL && (ret = validateURL(val)) != 0)
00229       return ret;
00230    if (type == DNX_CFG_FSPATH && (ret = validateFSPath(val)) != 0)
00231       return ret;
00232    if ((str = xstrdup(val)) == 0)
00233       return DNX_ERR_MEMORY;
00234    xfree(*prval);    // free old, return new
00235    *prval = str;
00236    return DNX_OK;
00237 }
00238 
00239 //----------------------------------------------------------------------------
00240 
00251 static char * strtrim(char * s)
00252 {
00253    assert(s);
00254    while (isspace(*s)) s++;
00255    if (*s)
00256    {
00257       size_t l = strlen(s);
00258       while (l && isspace(s[l - 1])) l--;
00259       s[l] = 0;
00260    }
00261    return s;
00262 }
00263 
00264 //----------------------------------------------------------------------------
00265 
00279 static int parseStringArray(char * val, DnxCfgType type, char *** prval)
00280 {
00281    char ** array;
00282    int i;
00283 
00284    assert(type == DNX_CFG_STRING_ARRAY);
00285 
00286    // parse value string into sub-string array
00287    if ((array = strToStrArray(val, ',')) == 0)
00288       return DNX_ERR_MEMORY;
00289 
00290    // trim trailing and leading white space on each sub-string
00291    for (i = 0; array[i]; i++)
00292       array[i] = strtrim(array[i]);
00293 
00294    xfree(*prval);
00295    *prval = array;
00296    return DNX_OK;
00297 }
00298 
00299 //----------------------------------------------------------------------------
00300 
00309 static int parseIntOrUnsigned(char * val, DnxCfgType type, int * prval)
00310 {
00311    char * ep;
00312    long (*str2num)(char*, char**, int) =
00313          (type == DNX_CFG_INT? (void*)strtol: (void*)strtoul);
00314    long n = str2num(val, &ep, 0);
00315    assert(type == DNX_CFG_INT || type == DNX_CFG_UNSIGNED);
00316    if (*ep != 0) return DNX_ERR_SYNTAX;
00317    *prval = (int)n;
00318    return DNX_OK;
00319 }
00320 
00321 //----------------------------------------------------------------------------
00322 
00339 static int parseIntOrUnsignedArray(char * val, DnxCfgType type, int ** prval)
00340 {
00341    int * array;
00342    char ** sa;
00343    int i;
00344 
00345    assert(type == DNX_CFG_INT_ARRAY || type == DNX_CFG_UNSIGNED_ARRAY);
00346 
00347    // parse value string into a sub-string array
00348    if ((sa = strToStrArray(val, ',')) == 0)
00349       return DNX_ERR_MEMORY;
00350 
00351    // count sub-strings and trim trailing and leading white space
00352    for (i = 0; sa[i]; i++)
00353       sa[i] = strtrim(sa[i]);
00354 
00355    // allocate space for count + ints
00356    if ((array = (int *)xmalloc((i + 1) * sizeof *array)) == 0)
00357    {
00358       xfree(sa);
00359       return DNX_ERR_MEMORY;
00360    }
00361    // setup for call to parseIntOrUnsigned
00362    type = (type == DNX_CFG_INT_ARRAY)? DNX_CFG_INT : DNX_CFG_UNSIGNED;
00363 
00364    // convert each value in sa to an int or unsigned in array
00365    array[0] = i;   // store count in first integer slot
00366    for (i = 0; sa[i]; i++)
00367    {
00368       int ret;
00369       if ((ret = parseIntOrUnsigned(sa[i], type, &array[i + 1])) != 0)
00370       {
00371          xfree(array);
00372          xfree(sa);
00373          return ret;
00374       }
00375    }
00376    xfree(sa);
00377    xfree(*prval);
00378    *prval = array;
00379    return DNX_OK;
00380 }
00381 
00382 //----------------------------------------------------------------------------
00383 
00395 static int parseBool(char * val, DnxCfgType type, unsigned * prval)
00396 {
00397    assert(type == DNX_CFG_BOOL);
00398    if (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0
00399          || strcasecmp(val, "ON") == 0 || strtoul(val, 0, 0) != 0)
00400       *prval = 1;
00401    else if (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0
00402          || strcasecmp(val, "OFF") == 0 || (val[0] == '0' && val[1] == 0))
00403       *prval = 0;
00404    else
00405       return DNX_ERR_SYNTAX;
00406    return DNX_OK;
00407 }
00408 
00409 //----------------------------------------------------------------------------
00410 
00426 static int dnxParseCfgVar(char * var, char * val, DnxCfgDict * dict, void ** vptrs)
00427 {
00428    static DnxVarParser_t * parsetbl[] =
00429    {
00430       (DnxVarParser_t *)parseString,
00431       (DnxVarParser_t *)parseStringArray,
00432       (DnxVarParser_t *)parseIntOrUnsigned,
00433       (DnxVarParser_t *)parseIntOrUnsignedArray,
00434       (DnxVarParser_t *)parseIntOrUnsigned,
00435       (DnxVarParser_t *)parseIntOrUnsignedArray,
00436       (DnxVarParser_t *)parseString,
00437       (DnxVarParser_t *)parseString,
00438       (DnxVarParser_t *)parseBool,
00439    };
00440 
00441    unsigned i;
00442 
00443    for (i = 0; dict[i].varname; i++)
00444       if (strcmp(dict[i].varname, var) == 0)
00445       {
00446          assert(dict[i].type >= 0 && dict[i].type < elemcount(parsetbl));
00447          return parsetbl[dict[i].type](val, dict[i].type, &vptrs[i]);
00448       }
00449 
00450    return DNX_ERR_INVALID; // invalid entry - no dictionary mapping
00451 }
00452 
00453 //----------------------------------------------------------------------------
00454 
00467 static int dnxParseCfgLine(char * s, DnxCfgDict * dict, void ** vptrs)
00468 {
00469    char * cpy, * val;
00470    int ret;
00471 
00472    // trim comment from end of line
00473    if ((val = strchr(s, '#')) != 0) *val = 0;
00474 
00475    // trim leading and trailing ws; return success on empty line
00476    if (*(s = strtrim(s)) == 0) return 0;
00477 
00478    // look for assignment operator; must be in the middle of the text
00479    if (*s == '=' || (val = strchr(s, '=')) == 0 || val[1] == 0)
00480       return DNX_ERR_SYNTAX;
00481 
00482    // make a working copy of the remaining buffer text
00483    if ((cpy = xstrdup(s)) == 0)
00484       return DNX_ERR_MEMORY;
00485 
00486    // copy remaining text; reset val ptr; terminate copy at '='
00487    val = &cpy[val - s];
00488    *val++ = 0;
00489 
00490    // trim trailing space from copy, leading space from value
00491    strtrim(cpy);
00492    val = strtrim(val);
00493 
00494    // validate, convert and store the variable and its value
00495    ret = dnxParseCfgVar(cpy, val, dict, vptrs);
00496 
00497    xfree(cpy);
00498 
00499    return ret;
00500 }
00501 
00502 //----------------------------------------------------------------------------
00503 
00519 static int applyCfgSetString(char ** sap, DnxCfgDict * dict, void ** vptrs)
00520 {
00521    assert(dict && vptrs);
00522 
00523    if (!sap)
00524       return DNX_OK;
00525 
00526    while (*sap)
00527    {
00528       int ret;
00529       if ((ret = dnxParseCfgLine(*sap++, dict, vptrs)) != 0)
00530          return ret;
00531    }
00532    return DNX_OK;
00533 }
00534 
00535 //----------------------------------------------------------------------------
00536 
00548 static void freeArrayPtrs(DnxCfgDict * dict, void ** vptrs)
00549 {
00550    unsigned i, j;
00551 
00552    assert(dict);
00553 
00554    for (i = 0; dict[i].varname; i++)
00555       if (dict[i].type != DNX_CFG_INT && dict[i].type != DNX_CFG_UNSIGNED
00556             && dict[i].type != DNX_CFG_BOOL)
00557          xfree(vptrs? vptrs[i]: *(void **)dict[i].valptr);
00558 }
00559 
00560 //----------------------------------------------------------------------------
00561 
00572 static char * formatString(char * var, DnxCfgType type, char * prval)
00573 {
00574    size_t len = prval? strlen(prval): 0;
00575    char * cfg;
00576 
00577    assert(var);
00578    assert(type == DNX_CFG_STRING || type == DNX_CFG_URL || type == DNX_CFG_FSPATH);
00579 
00580    // var + '=' + val + '\n' + '\0'
00581    if ((cfg = (char *)xmalloc(strlen(var) + 1 + len + 2)) != 0)
00582       sprintf(cfg, "%s=%s\n", var, prval? prval: "");
00583 
00584    return cfg;
00585 }
00586 
00587 //----------------------------------------------------------------------------
00588 
00599 static char * formatStringArray(char * var, DnxCfgType type, char ** prval)
00600 {
00601    char ** cp = prval;
00602    size_t len = 0;
00603    char * cfg;
00604 
00605    assert(var && type == DNX_CFG_STRING_ARRAY);
00606 
00607    if (cp)
00608       while (*cp)
00609          len += strlen(*cp++) + 1;  // add one for trailing ',' or '\n'
00610 
00611    // var + '=' + val + '\n' + '\0'
00612    if ((cfg = (char *)xmalloc(strlen(var) + 1 + len + 1)) != 0)
00613    {
00614       char * cp = cfg;
00615       cp += sprintf(cp, "%s=", var);
00616       if (prval)
00617          while (*prval)
00618             cp += sprintf(cp, "%s,", *prval++);
00619       if (cp[-1] == ',') cp--;   // overwrite trailing ','
00620       *cp++ = '\n';
00621       *cp = 0;
00622    }
00623    return cfg;
00624 }
00625 
00626 //----------------------------------------------------------------------------
00627 
00638 static char * formatIntOrUnsigned(char * var, DnxCfgType type, int prval)
00639 {
00640    char intbuf[16];
00641    size_t len;
00642    char * cfg;
00643 
00644    assert(var && (type == DNX_CFG_INT || type == DNX_CFG_UNSIGNED));
00645 
00646    len = sprintf(intbuf, type == DNX_CFG_INT? "%d": "%u", prval);
00647 
00648    // var + '=' + val + '\n' + '\0'
00649    if ((cfg = (char *)xmalloc(strlen(var) + 1 + len + 2)) != 0)
00650       sprintf(cfg, "%s=%s\n", var, intbuf);
00651 
00652    return cfg;
00653 }
00654 
00655 //----------------------------------------------------------------------------
00656 
00668 static char * formatIntOrUnsignedArray(char * var, DnxCfgType type, int * prval)
00669 {
00670    size_t len = prval? prval[0] * 16: 0;
00671    char * cfg;
00672 
00673    assert(var);
00674    assert(type == DNX_CFG_INT_ARRAY || type == DNX_CFG_UNSIGNED_ARRAY);
00675 
00676    // var + '=' + val + '\n' + '\0'
00677    if ((cfg = (char *)xmalloc(strlen(var) + 1 + len + 2)) != 0)
00678    {
00679       int i;
00680       char * cp = cfg;
00681       cp += sprintf(cp, "%s=", var);
00682       if (prval)
00683          for (i = 1; i <= prval[0]; i++)
00684             cp += sprintf(cp, type == DNX_CFG_INT_ARRAY? "%d,": "%u,", prval[i]);
00685       if (cp[-1] == ',') cp--;   // overwrite trailing ','
00686       *cp++ = '\n';
00687       *cp = 0;
00688    }
00689    return cfg;
00690 }
00691 
00692 //----------------------------------------------------------------------------
00693 
00704 static char * formatBool(char * var, DnxCfgType type, unsigned prval)
00705 {
00706    char * cfg;
00707 
00708    assert(var);
00709    assert(type == DNX_CFG_BOOL);
00710 
00711    // var + '=' + YES + '\n' + '\0'
00712    if ((cfg = (char *)xmalloc(strlen(var) + 1 + 3 + 2)) != 0)
00713       sprintf(cfg, "%s=%s\n", var, prval? "YES" : "NO");
00714 
00715    return cfg;
00716 }
00717 
00718 //----------------------------------------------------------------------------
00719 
00729 static char * buildCurrentCfgCache(DnxCfgDict * dict, size_t * ccsizep)
00730 {
00731    static DnxVarFormatter_t * fmttbl[] =
00732    {
00733       (DnxVarFormatter_t *)formatString,
00734       (DnxVarFormatter_t *)formatStringArray,
00735       (DnxVarFormatter_t *)formatIntOrUnsigned,
00736       (DnxVarFormatter_t *)formatIntOrUnsignedArray,
00737       (DnxVarFormatter_t *)formatIntOrUnsigned,
00738       (DnxVarFormatter_t *)formatIntOrUnsignedArray,
00739       (DnxVarFormatter_t *)formatString,
00740       (DnxVarFormatter_t *)formatString,
00741       (DnxVarFormatter_t *)formatBool,
00742    };
00743 
00744    char * cfg = 0;
00745    size_t cfgsz = 1;     // start with one for null-terminator
00746    unsigned i;
00747 
00748    assert(dict && ccsizep);
00749 
00750    for (i = 0; dict[i].varname; i++)
00751    {
00752       char * str, * newcfg;
00753       size_t len;
00754 
00755       if ((str = fmttbl[dict[i].type](dict[i].varname,
00756                dict[i].type, *(void **)dict[i].valptr)) == 0
00757             || (newcfg = (char *)xrealloc(cfg, cfgsz + (len = strlen(str)))) == 0)
00758       {
00759          xfree(str);
00760          xfree(cfg);
00761          return 0;
00762       }
00763       cfg = newcfg;
00764       memcpy(&cfg[cfgsz - 1], str, len);
00765       xfree(str);
00766       cfgsz += len;
00767       cfg[cfgsz - 1] = 0;
00768    }
00769 
00770    // remove trailing '\n'
00771    if (cfgsz > 1 && cfg[cfgsz - 2] == '\n')
00772       cfg[--cfgsz - 1] = 0;
00773 
00774    *ccsizep = cfgsz;
00775 
00776    return cfg;
00777 }
00778 
00779 /*--------------------------------------------------------------------------
00780                                  INTERFACE
00781   --------------------------------------------------------------------------*/
00782 
00783 int dnxCfgParserCreate(char * cfgdefs, char * cfgfile, char * cmdover,
00784       DnxCfgDict * dict, DnxCfgValidator_t * vfp, DnxCfgParser ** cpp)
00785 {
00786    iDnxCfgParser * icp;
00787 
00788    assert(dict && cpp);
00789 
00790    // allocate an internal config parser object; clear it
00791    if ((icp = (iDnxCfgParser *)xmalloc(sizeof *icp)) == 0)
00792       return DNX_ERR_MEMORY;
00793    memset(icp, 0, sizeof *icp);
00794 
00795    // copy all specified values and structures
00796    if (cfgfile && (icp->cfgfile = xstrdup(cfgfile)) == 0
00797          || cfgdefs && (icp->cfgdefs = strToStrArray(cfgdefs, '\n')) == 0
00798          || cmdover && (icp->cmdover = strToStrArray(cmdover, '\n')) == 0
00799          || (icp->dict = copyDictionary(dict, &icp->dictsz)) == 0)
00800    {
00801       xfree(icp->cmdover);
00802       xfree(icp->cfgdefs);
00803       xfree(icp->cfgfile);
00804       xfree(icp);
00805       return DNX_ERR_MEMORY;
00806    }
00807    icp->vfp = vfp;
00808    *cpp = (DnxCfgParser *)icp;
00809    return DNX_OK;
00810 }
00811 
00812 //----------------------------------------------------------------------------
00813 
00814 int dnxCfgParserParse(DnxCfgParser * cp, void * passthru)
00815 {
00816    iDnxCfgParser * icp = (iDnxCfgParser *)cp;
00817    void ** vptrs;
00818    int ret;
00819 
00820    assert(cp);
00821 
00822    // allocate a temp array of values; zero it out so we don't free bad ptrs
00823    if ((vptrs = (void **)xmalloc(icp->dictsz * sizeof *vptrs)) == 0)
00824       return DNX_ERR_MEMORY;
00825    memset(vptrs, 0, icp->dictsz * sizeof *vptrs);
00826 
00827    // apply config defaults
00828    if ((ret = applyCfgSetString(icp->cfgdefs, icp->dict, vptrs)) != 0)
00829    {
00830       xfree(vptrs);
00831       return ret;
00832    }
00833 
00834    // parse configuration file
00835    if (icp->cfgfile)
00836    {
00837       FILE * fp;
00838       if ((fp = fopen(icp->cfgfile, "r")) == 0)
00839          ret = errno == EACCES? DNX_ERR_ACCESS : DNX_ERR_NOTFOUND;
00840       else
00841       {
00842          int line = 0;
00843          char buf[DNX_MAX_CFG_LINE];
00844 
00845          while (fgets(buf, sizeof buf, fp) != 0)
00846          {
00847             int err;
00848             line++;
00849 
00850             // lines with unknown values are silently ignored
00851             if ((err = dnxParseCfgLine(buf, icp->dict, vptrs)) != 0
00852                   && err != DNX_ERR_INVALID)
00853             {
00854                dnxLog("cfgParser [%s]: Syntax error on line %d: %s.",
00855                      icp->cfgfile, line, dnxErrorString(err));
00856                if (!ret) ret = err; // return only the first error
00857             }
00858          }
00859          fclose(fp);
00860       }
00861    }
00862 
00863 #define INTSWAP(a,b) do { int n = (a); (a) = (int)(intptr_t)(b); (b) = (void *)(intptr_t)n; } while(0)
00864 #define PTRSWAP(a,b) do { void * p = (a); (a) = (b); (b) = p; } while (0)
00865 
00866    // apply command line overrides; validate configuration; store values
00867    if (!ret && (ret = applyCfgSetString(icp->cmdover, icp->dict, vptrs)) == 0
00868          && (!icp->vfp || (ret = icp->vfp(icp->dict, vptrs, passthru)) == 0))
00869    {
00870       unsigned i;
00871 
00872       // swap new for old values in vptrs
00873       for (i = 0; i < icp->dictsz; i++)
00874          if (icp->dict[i].type == DNX_CFG_INT
00875                || icp->dict[i].type == DNX_CFG_UNSIGNED
00876                || icp->dict[i].type == DNX_CFG_BOOL)
00877             INTSWAP(*(int *)icp->dict[i].valptr, vptrs[i]);
00878          else
00879             PTRSWAP(*(void **)icp->dict[i].valptr, vptrs[i]);
00880 
00881       // free current config cache string
00882       xfree(icp->curcfg);
00883       icp->curcfg = 0;
00884       icp->ccsize = 0;
00885    }
00886 
00887    // free either new or old values; free temp array
00888    freeArrayPtrs(icp->dict, vptrs);
00889    xfree(vptrs);
00890 
00891    return ret;
00892 }
00893 
00894 //----------------------------------------------------------------------------
00895 
00896 int dnxCfgParserGetCfg(DnxCfgParser * cp, char * buf, size_t * bufszp)
00897 {
00898    iDnxCfgParser * icp = (iDnxCfgParser *)cp;
00899 
00900    assert(cp && bufszp && (buf || !*bufszp));
00901 
00902    // build current config if not already there
00903    if (icp->curcfg == 0
00904          && (icp->curcfg = buildCurrentCfgCache(icp->dict, &icp->ccsize)) == 0)
00905       return DNX_ERR_MEMORY;
00906 
00907    // copy what we can into buffer; return required/used size
00908    if (buf && *bufszp)
00909    {
00910       size_t cpysz = *bufszp > icp->ccsize? icp->ccsize: *bufszp;
00911       memcpy(buf, icp->curcfg, cpysz - 1);
00912       buf[cpysz - 1] = 0;
00913    }
00914    *bufszp = icp->ccsize;
00915 
00916    return 0;
00917 }
00918 
00919 //----------------------------------------------------------------------------
00920 
00921 void dnxCfgParserDestroy(DnxCfgParser * cp)
00922 {
00923    iDnxCfgParser * icp = (iDnxCfgParser *)cp;
00924 
00925    assert(cp);
00926 
00927    freeArrayPtrs(icp->dict, 0);
00928 
00929    xfree(icp->dict);
00930    xfree(icp->cmdover);
00931    xfree(icp->cfgdefs);
00932    xfree(icp->cfgfile);
00933    xfree(icp->curcfg);
00934    xfree(icp);
00935 }
00936 
00937 /*--------------------------------------------------------------------------
00938                                  TEST MAIN
00939 
00940    From within dnx/common, compile with GNU tools using this command line:
00941 
00942       gcc -DDEBUG -DDNX_CFGPARSER_TEST -g -O0 \
00943          -o dnxCfgParserTest dnxCfgParser.c dnxError.c
00944 
00945    Alternatively, a heap check may be done with the following command line:
00946 
00947       gcc -DDEBUG -DDEBUG_HEAP -DDNX_CFGPARSER_TEST -g -O0 \
00948          -o dnxCfgParserTest dnxCfgParser.c dnxError.c dnxHeap.c
00949 
00950   --------------------------------------------------------------------------*/
00951 
00952 #ifdef DNX_CFGPARSER_TEST
00953 
00954 #include "utesthelp.h"
00955 
00956 #define TEST_FILE_NAME "cfgtest.cfg"
00957 #define TEST_FILE_CONTENTS                                                    \
00958    "# Test Configuration File\n\n"                                            \
00959    "   testCfgString = some string\n"                                         \
00960    "testCfgStringArray = This is,a test, of the , string array.   \n"         \
00961    "testCfgInt1 = -10024\n"                                                   \
00962    "testCfgInt3 = -57\n"                                                      \
00963    "testCfgInt4 = 100\n"                                                      \
00964    "testCfgIntArray=-1, 87,3   ,2, 32,3,1,-23,  -112,2,234\n"                 \
00965    "testCfgUnsigned = 332245235\r\n"                                          \
00966    "testCfgUnsignedArray = 2342, 234,234,4,  2342  ,2342  ,234234 \n"         \
00967    "testCfgUrl = http://www.example.com\n"                                    \
00968    "testCfgFSPath = /some/path\n"                                             \
00969    "testCfgBool = YES\n"
00970 
00971 #define TEST_CFG_CONTENTS                                                     \
00972    "testCfgString=some string\n"                                              \
00973    "testCfgStringArray=This is,a test,of the,string array.\n"                 \
00974    "testCfgInt1=-10024\n"                                                     \
00975    "testCfgInt2=82\n"                                                         \
00976    "testCfgInt3=-57\n"                                                        \
00977    "testCfgInt4=102\n"                                                        \
00978    "testCfgIntArray=-1,87,3,2,32,3,1,-23,-112,2,234\n"                        \
00979    "testCfgUnsigned=332245235\n"                                              \
00980    "testCfgUnsignedArray=2342,234,234,4,2342,2342,234234\n"                   \
00981    "testCfgUrl=http://www.example.com\n"                                      \
00982    "testCfgFSPath=/some/path\n"                                               \
00983    "testCfgBool=YES"
00984 
00985 static int verbose;
00986 
00987 IMPLEMENT_DNX_SYSLOG(verbose);
00988 IMPLEMENT_DNX_DEBUG(verbose);
00989 
00990 int main(int argc, char ** argv)
00991 {
00992    char *             testCfgString;
00993    char **            testCfgStringArray;
00994    int                testCfgInt1;
00995    int                testCfgInt2;
00996    int                testCfgInt3;
00997    int                testCfgInt4;
00998    int *              testCfgIntArray;
00999    unsigned           testCfgUnsigned;
01000    unsigned *         testCfgUnsignedArray;
01001    char *             testCfgUrl;
01002    char *             testCfgFSPath;
01003    unsigned           testCfgBool;
01004 
01005    DnxCfgDict dict[] =
01006    {
01007       { "testCfgString",       DNX_CFG_STRING,         &testCfgString        },
01008       { "testCfgStringArray",  DNX_CFG_STRING_ARRAY,   &testCfgStringArray   },
01009       { "testCfgInt1",         DNX_CFG_INT,            &testCfgInt1          },
01010       { "testCfgInt2",         DNX_CFG_INT,            &testCfgInt2          },
01011       { "testCfgInt3",         DNX_CFG_INT,            &testCfgInt3          },
01012       { "testCfgInt4",         DNX_CFG_INT,            &testCfgInt4          },
01013       { "testCfgIntArray",     DNX_CFG_INT_ARRAY,      &testCfgIntArray      },
01014       { "testCfgUnsigned",     DNX_CFG_UNSIGNED,       &testCfgUnsigned      },
01015       { "testCfgUnsignedArray",DNX_CFG_UNSIGNED_ARRAY, &testCfgUnsignedArray },
01016       { "testCfgUrl",          DNX_CFG_URL,            &testCfgUrl           },
01017       { "testCfgFSPath",       DNX_CFG_FSPATH,         &testCfgFSPath        },
01018       { "testCfgBool",         DNX_CFG_BOOL,           &testCfgBool          },
01019       { 0 },
01020    };
01021    char * defs = "testCfgInt2 = 82\ntestCfgInt3 = -67\ntestCfgInt4 = 101";
01022    char * cmds = "testCfgInt4 = 102\n";
01023 
01024    char * StrArray_cmp[] = {"This is","a test","of the","string array."};
01025    int IntArray_cmp[] = {11,-1,87,3,2,32,3,1,-23,-112,2,234};
01026    int UnsignedArray_cmp[] = {7,2342,234,234,4,2342,2342,234234};
01027 
01028    char test_cfg[] = TEST_CFG_CONTENTS;
01029 
01030    int i;
01031    FILE * fp;
01032    DnxCfgParser * cp;
01033    char * cfg;
01034    size_t bufsz;
01035 
01036    verbose = argc > 1 ? 1 : 0;
01037 
01038    CHECK_TRUE((fp = fopen(TEST_FILE_NAME, "w")) != 0);
01039    fputs(TEST_FILE_CONTENTS, fp);
01040    fclose(fp);
01041 
01042    CHECK_ZERO(dnxCfgParserCreate(defs, TEST_FILE_NAME, cmds, dict, 0, &cp));
01043    CHECK_ZERO(dnxCfgParserParse(cp, 0));
01044 
01045    CHECK_TRUE(strcmp(testCfgString, "some string") == 0);
01046 
01047    for (i = 0; i < elemcount(StrArray_cmp); i++)
01048       CHECK_TRUE(strcmp(testCfgStringArray[i], StrArray_cmp[i]) == 0);
01049 
01050    CHECK_TRUE(testCfgInt1 == -10024);
01051    CHECK_TRUE(testCfgInt2 == 82);
01052    CHECK_TRUE(testCfgInt3 == -57);
01053    CHECK_TRUE(testCfgInt4 == 102);
01054 
01055    for (i = 0; i < elemcount(IntArray_cmp); i++)
01056       CHECK_TRUE(testCfgIntArray[i] == IntArray_cmp[i]);
01057 
01058    CHECK_TRUE(testCfgUnsigned == 332245235);
01059 
01060    for (i = 0; i < elemcount(UnsignedArray_cmp); i++)
01061       CHECK_TRUE(testCfgUnsignedArray[i] == UnsignedArray_cmp[i]);
01062 
01063    CHECK_ZERO(strcmp(testCfgUrl, "http://www.example.com"));
01064    CHECK_ZERO(strcmp(testCfgFSPath, "/some/path"));
01065 
01066    CHECK_TRUE(testCfgBool != 0);
01067 
01068    // test getcfg
01069    bufsz = 0;
01070    CHECK_ZERO(dnxCfgParserGetCfg(cp, 0, &bufsz));
01071    CHECK_NONZERO(cfg = (char *)xmalloc(bufsz));
01072    CHECK_ZERO(dnxCfgParserGetCfg(cp, cfg, &bufsz));
01073    CHECK_TRUE(memcmp(cfg, test_cfg, bufsz) == 0);
01074    CHECK_TRUE(bufsz == sizeof test_cfg);
01075    xfree(cfg);
01076 
01077    // test reparse here...
01078 
01079    dnxCfgParserDestroy(cp);
01080 
01081    remove(TEST_FILE_NAME);
01082 
01083 #ifdef DEBUG_HEAP
01084    CHECK_ZERO(dnxCheckHeap());
01085 #endif
01086 
01087    return 0;
01088 }
01089 
01090 #endif   /* DNX_CFGPARSER_TEST */
01091 
01092 /*--------------------------------------------------------------------------*/
01093 

Generated on Tue Apr 13 15:48:07 2010 for DNX by  doxygen 1.5.6