Annotation of sbbs/src/xpdev/ini_file.c, revision 1.1.1.2

1.1       root        1: /* ini_file.c */
                      2: 
1.1.1.2 ! root        3: /* Functions to create and parse .ini files */
1.1       root        4: 
1.1.1.2 ! root        5: /* $Id: ini_file.c,v 1.124 2011/09/30 00:34:41 rswindell Exp $ */
1.1       root        6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       12:  *                                                                                                                                                     *
                     13:  * This library is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU Lesser General Public License          *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU Lesser General Public License for more details: lgpl.txt or     *
                     18:  * http://www.fsf.org/copyleft/lesser.html                                                                     *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include <stdlib.h>            /* strtol */
                     39: #include <string.h>            /* strlen */
                     40: #include <ctype.h>             /* isdigit */
                     41: #include <math.h>              /* fmod */
1.1.1.2 ! root       42: #include "xpdatetime.h"        /* isoDateTime_t */
        !            43: #include "datewrap.h"  /* ctime_r */
1.1       root       44: #include "dirwrap.h"   /* fexist */
                     45: #include "filewrap.h"  /* chsize */
                     46: #include "ini_file.h"
                     47: 
                     48: /* Maximum length of entire line, includes '\0' */
                     49: #define INI_MAX_LINE_LEN               (INI_MAX_VALUE_LEN*2)
                     50: #define INI_COMMENT_CHAR               ';'
                     51: #define INI_OPEN_SECTION_CHAR  '['
                     52: #define INI_CLOSE_SECTION_CHAR ']'
                     53: #define INI_SECTION_NAME_SEP   "|"
                     54: #define INI_BIT_SEP                            '|'
                     55: #define INI_NEW_SECTION                        ((char*)~0)
                     56: #define INI_EOF_DIRECTIVE              "!eof"
                     57: #define INI_INCLUDE_DIRECTIVE  "!include"
                     58: #define INI_INCLUDE_MAX                        10000
                     59: 
                     60: static ini_style_t default_style;
                     61: 
                     62: void iniSetDefaultStyle(ini_style_t style)
                     63: {
                     64:        default_style = style;
                     65: }
                     66: 
                     67: /* These correlate with the LOG_* definitions in syslog.h/gen_defs.h */
                     68: static char* logLevelStringList[] 
                     69:        = {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debugging", NULL};
                     70: 
                     71: str_list_t iniLogLevelStringList(void)
                     72: {
                     73:        return(logLevelStringList);
                     74: }
                     75: 
                     76: static BOOL is_eof(char* str)
                     77: {
                     78:        return(*str=='!' && stricmp(truncsp(str),INI_EOF_DIRECTIVE)==0);
                     79: }
                     80: 
                     81: static char* section_name(char* p)
                     82: {
                     83:        char*   tp;
                     84: 
                     85:        SKIP_WHITESPACE(p);
                     86:        if(*p!=INI_OPEN_SECTION_CHAR)
                     87:                return(NULL);
                     88:        p++;
                     89:        SKIP_WHITESPACE(p);
                     90:        tp=strrchr(p,INI_CLOSE_SECTION_CHAR);
                     91:        if(tp==NULL)
                     92:                return(NULL);
                     93:        *tp=0;
                     94:        truncsp(p);
                     95: 
                     96:        return(p);
                     97: }
                     98: 
                     99: static BOOL section_match(const char* name, const char* compare)
                    100: {
                    101:        BOOL found=FALSE;
                    102:        str_list_t names=strListSplitCopy(NULL,name,INI_SECTION_NAME_SEP);
                    103:        str_list_t comps=strListSplitCopy(NULL,compare,INI_SECTION_NAME_SEP);
                    104:        size_t  i,j;
                    105:        char*   n;
                    106:        char*   c;
                    107: 
                    108:        /* Ignore trailing whitepsace */
                    109:        for(i=0; names[i]!=NULL; i++)
                    110:                truncsp(names[i]);
                    111:        for(i=0; comps[i]!=NULL; i++)
                    112:                truncsp(comps[i]);
                    113: 
                    114:        /* Search for matches */
                    115:        for(i=0; names[i]!=NULL && !found; i++)
                    116:                for(j=0; comps[j]!=NULL && !found; j++) {
                    117:                        n=names[i];
                    118:                        SKIP_WHITESPACE(n);
                    119:                        c=comps[j];
                    120:                        SKIP_WHITESPACE(c);
                    121:                        if(stricmp(n,c)==0)
                    122:                                found=TRUE;
                    123:                }
                    124: 
                    125:        strListFree(&names);
                    126:        strListFree(&comps);
                    127: 
                    128:        return(found);
                    129: }
                    130: 
                    131: static BOOL seek_section(FILE* fp, const char* section)
                    132: {
                    133:        char*   p;
                    134:        char    str[INI_MAX_LINE_LEN];
                    135: 
                    136:        rewind(fp);
                    137: 
                    138:        if(section==ROOT_SECTION)
                    139:                return(TRUE);
                    140: 
                    141:        while(!feof(fp)) {
                    142:                if(fgets(str,sizeof(str),fp)==NULL)
                    143:                        break;
                    144:                if(is_eof(str))
                    145:                        break;
                    146:                if((p=section_name(str))==NULL)
                    147:                        continue;
                    148:                if(section_match(p,section))
                    149:                        return(TRUE);
                    150:        }
                    151:        return(FALSE);
                    152: }
                    153: 
                    154: static size_t find_section_index(str_list_t list, const char* section)
                    155: {
                    156:        char*   p;
                    157:        char    str[INI_MAX_VALUE_LEN];
                    158:        size_t  i;
                    159: 
                    160:        for(i=0; list[i]!=NULL; i++) {
                    161:                SAFECOPY(str,list[i]);
                    162:                if(is_eof(str))
                    163:                        return(strListCount(list));
                    164:                if((p=section_name(str))!=NULL && section_match(p,section))
                    165:                        return(i);
                    166:        }
                    167: 
                    168:        return(i);
                    169: }
                    170: 
                    171: static size_t find_section(str_list_t list, const char* section)
                    172: {
                    173:        size_t  i;
                    174: 
                    175:        if(section==ROOT_SECTION)
                    176:                return(0);
                    177: 
                    178:        i=find_section_index(list,section);
                    179:        if(list[i]!=NULL)
                    180:                i++;
                    181:        return(i);
                    182: }
                    183: 
                    184: static char* key_name(char* p, char** vp)
                    185: {
                    186:        char* equal;
                    187:        char* colon;
                    188: 
                    189:     *vp=NULL;
                    190:     
                    191:        if(p==NULL)
                    192:                return(NULL);
                    193: 
                    194:        /* Parse value name */
                    195:        SKIP_WHITESPACE(p);
                    196:        if(*p==INI_COMMENT_CHAR)
                    197:                return(NULL);
                    198:        if(*p==INI_OPEN_SECTION_CHAR)
                    199:                return(INI_NEW_SECTION);
                    200:        equal=strchr(p,'=');
                    201:        colon=strchr(p,':');
                    202:        if(colon==NULL || (equal!=NULL && equal<colon)) {
                    203:                *vp=equal;
                    204:                colon=NULL;
                    205:        } else
                    206:                *vp=colon;
                    207: 
                    208:        if(*vp==NULL)
                    209:                return(NULL);
                    210: 
                    211:        *(*vp)=0;
                    212:        truncsp(p);
                    213: 
                    214:        /* Parse value */
                    215:        (*vp)++;
                    216:        SKIP_WHITESPACE(*vp);
                    217:        if(colon!=NULL)                 
                    218:                truncnl(*vp);           /* "key : value" - truncate new-line chars only */
                    219:        else    
                    220:                truncsp(*vp);           /* "key = value" - truncate all white-space chars */
                    221: 
                    222:        return(p);
                    223: }
                    224: 
                    225: static char* read_value(FILE* fp, const char* section, const char* key, char* value)
                    226: {
                    227:        char*   p;
                    228:        char*   vp=NULL;
                    229:        char    str[INI_MAX_LINE_LEN];
                    230: 
                    231:        if(fp==NULL)
                    232:                return(NULL);
                    233: 
                    234:        if(!seek_section(fp,section))
                    235:                return(NULL);
                    236: 
                    237:        while(!feof(fp)) {
                    238:                if(fgets(str,sizeof(str),fp)==NULL)
                    239:                        break;
                    240:                if(is_eof(str))
                    241:                        break;
                    242:                if((p=key_name(str,&vp))==NULL)
                    243:                        continue;
                    244:                if(p==INI_NEW_SECTION)
                    245:                        break;
                    246:                if(stricmp(p,key)!=0)
                    247:                        continue;
                    248:                if(vp==NULL)
                    249:                        break;
                    250:                /* key found */
                    251:                sprintf(value,"%.*s",INI_MAX_VALUE_LEN-1,vp);
                    252:                return(value);
                    253:        }
                    254: 
                    255:        return(NULL);
                    256: }
                    257: 
1.1.1.2 ! root      258: static size_t get_value(str_list_t list, const char* section, const char* key, char* value, char** vpp)
1.1       root      259: {
1.1.1.2 ! root      260:        char    str[INI_MAX_LINE_LEN];
1.1       root      261:        char*   p;
                    262:        char*   vp;
                    263:        size_t  i;
                    264: 
1.1.1.2 ! root      265:        if(value!=NULL)
        !           266:                value[0]=0;
        !           267:        if(vpp!=NULL)
        !           268:                *vpp=NULL;
        !           269:        if(list==NULL)
        !           270:                return 0;
        !           271: 
1.1       root      272:        for(i=find_section(list, section); list[i]!=NULL; i++) {
1.1.1.2 ! root      273:                SAFECOPY(str,list[i]);
1.1       root      274:                if(is_eof(str))
                    275:                        break;
                    276:                if((p=key_name(str,&vp))==NULL)
                    277:                        continue;
                    278:                if(p==INI_NEW_SECTION)
                    279:                        break;
                    280:                if(stricmp(p,key)!=0)
                    281:                        continue;
1.1.1.2 ! root      282:                if(value!=NULL)
        !           283:                        sprintf(value,"%.*s",INI_MAX_VALUE_LEN-1,vp);
        !           284:                if(vpp!=NULL)
        !           285:                        *vpp=list[i] + (vp - str);
1.1       root      286:                return(i);
                    287:        }
                    288: 
                    289:        return(i);
                    290: }
                    291: 
                    292: BOOL iniSectionExists(str_list_t list, const char* section)
                    293: {
                    294:        size_t  i;
                    295: 
                    296:        if(section==ROOT_SECTION)
                    297:                return(TRUE);
                    298: 
                    299:        i=find_section_index(list,section);
                    300:        return(list[i]!=NULL);
                    301: }
                    302: 
1.1.1.2 ! root      303: str_list_t     iniGetSection(str_list_t list, const char *section)
        !           304: {
        !           305:        size_t          i;
        !           306:        str_list_t      retval;
        !           307:        char            *p;
        !           308: 
        !           309:        if(list==NULL)
        !           310:                return(NULL);
        !           311: 
        !           312:        if((retval=strListInit())==NULL)
        !           313:                return(NULL);
        !           314: 
        !           315:        i=find_section(list,section);
        !           316:        if(list[i]!=NULL) {
        !           317:                strListPush(&retval, list[i]);
        !           318:                for(i++;list[i]!=NULL;i++) {
        !           319:                        p=list[i];
        !           320:                        SKIP_WHITESPACE(p);
        !           321:                        if(*p==INI_OPEN_SECTION_CHAR)
        !           322:                                break;
        !           323:                        strListPush(&retval, list[i]);
        !           324:                }
        !           325:        }
        !           326:        return(retval);
        !           327: }
        !           328: 
1.1       root      329: BOOL iniKeyExists(str_list_t list, const char* section, const char* key)
                    330: {
                    331:        size_t  i;
                    332: 
1.1.1.2 ! root      333:        if(list==NULL)
        !           334:                return(FALSE);
        !           335: 
        !           336:        i=get_value(list, section, key, NULL, NULL);
1.1       root      337: 
                    338:        if(list[i]==NULL || *(list[i])==INI_OPEN_SECTION_CHAR)
                    339:                return(FALSE);
                    340: 
                    341:        return(TRUE);
                    342: }
                    343: 
                    344: BOOL iniValueExists(str_list_t list, const char* section, const char* key)
                    345: {
1.1.1.2 ! root      346:        char*   vp=NULL;
1.1       root      347: 
1.1.1.2 ! root      348:        get_value(list, section, key, NULL, &vp);
1.1       root      349: 
1.1.1.2 ! root      350:        return(vp!=NULL && *vp!=0);
1.1       root      351: }
                    352: 
                    353: BOOL iniRemoveKey(str_list_t* list, const char* section, const char* key)
                    354: {
                    355:        size_t  i;
1.1.1.2 ! root      356:        char*   vp=NULL;
1.1       root      357: 
1.1.1.2 ! root      358:        i=get_value(*list, section, key, NULL, &vp);
1.1       root      359: 
1.1.1.2 ! root      360:        if(vp==NULL)
1.1       root      361:                return(FALSE);
                    362: 
                    363:        return(strListDelete(list,i));
                    364: }
                    365: 
                    366: BOOL iniRemoveValue(str_list_t* list, const char* section, const char* key)
                    367: {
                    368:        char*   vp=NULL;
                    369: 
1.1.1.2 ! root      370:        get_value(*list, section, key, NULL, &vp);
1.1       root      371: 
                    372:        if(vp==NULL)
                    373:                return(FALSE);
                    374: 
1.1.1.2 ! root      375:        *vp=0;
1.1       root      376:        return(TRUE);
                    377: }
                    378: 
                    379: BOOL iniRemoveSection(str_list_t* list, const char* section)
                    380: {
                    381:        size_t  i;
                    382: 
                    383:        i=find_section_index(*list,section);
                    384:        if((*list)[i]==NULL)    /* not found */
                    385:                return(FALSE);
                    386:        do {
                    387:                strListDelete(list,i);
                    388:        } while((*list)[i]!=NULL && *(*list)[i]!=INI_OPEN_SECTION_CHAR);
                    389: 
                    390:        return(TRUE);
                    391: }
                    392: 
                    393: BOOL iniRenameSection(str_list_t* list, const char* section, const char* newname)
                    394: {
                    395:        char    str[INI_MAX_LINE_LEN];
                    396:        size_t  i;
                    397: 
                    398:        if(section==ROOT_SECTION)
                    399:                return(FALSE);
                    400: 
                    401:        i=find_section_index(*list,newname);
                    402:        if((*list)[i]!=NULL)    /* duplicate */
                    403:                return(FALSE);
                    404: 
                    405:        i=find_section_index(*list,section);
                    406:        if((*list)[i]==NULL)    /* not found */
                    407:                return(FALSE);
                    408: 
                    409:        SAFEPRINTF(str,"[%s]",newname);
                    410:        return(strListReplace(*list, i, str)!=NULL);
                    411: }
                    412: 
                    413: static size_t ini_add_section(str_list_t* list, const char* section
                    414:                                        ,ini_style_t* style, size_t index)
                    415: {
                    416:        char    str[INI_MAX_LINE_LEN];
                    417: 
                    418:        if(section==ROOT_SECTION)
                    419:                return(0);
                    420: 
                    421:        if((*list)[index]!=NULL)
                    422:                return(index);
                    423: 
                    424:        if(style==NULL)
                    425:                style=&default_style;
                    426:        if(index > 0 && style->section_separator!=NULL)
                    427:                strListAppend(list, style->section_separator, index++);
                    428:        SAFEPRINTF(str,"[%s]",section);
                    429:        strListAppend(list, str, index);
                    430: 
                    431:        return(index);
                    432: }
                    433: 
                    434: size_t iniAddSection(str_list_t* list, const char* section, ini_style_t* style)
                    435: {
                    436:        if(section==ROOT_SECTION)
                    437:                return(0);
                    438: 
                    439:        return ini_add_section(list,section,style,find_section_index(*list, section));
                    440: }
                    441: 
                    442: size_t iniAppendSection(str_list_t* list, const char* section, ini_style_t* style)
                    443: {
                    444:        if(section==ROOT_SECTION)
                    445:                return(0);
                    446: 
                    447:        return ini_add_section(list,section,style,strListCount(*list));
                    448: }
                    449: 
                    450: char* iniSetString(str_list_t* list, const char* section, const char* key, const char* value
                    451:                                 ,ini_style_t* style)
                    452: {
                    453:        char    str[INI_MAX_LINE_LEN];
                    454:        char    curval[INI_MAX_VALUE_LEN];
                    455:        size_t  i;
                    456: 
                    457:        if(style==NULL)
                    458:                style=&default_style;
                    459: 
                    460:        iniAddSection(list, section, style);
                    461: 
                    462:        if(key==NULL)
                    463:                return(NULL);
                    464:        if(style->key_prefix==NULL)
                    465:                style->key_prefix="";
                    466:        if(style->value_separator==NULL)
                    467:                style->value_separator="=";
                    468:        if(value==NULL)
                    469:                value="";
                    470:        safe_snprintf(str, sizeof(str), "%s%-*s%s%s"
                    471:                , style->key_prefix, style->key_len, key, style->value_separator, value);
1.1.1.2 ! root      472:        i=get_value(*list, section, key, curval, NULL);
1.1       root      473:        if((*list)[i]==NULL || *(*list)[i]==INI_OPEN_SECTION_CHAR) {
                    474:         while(i && *(*list)[i-1]==0) i--;   /* Insert before blank lines, not after */
                    475:                return strListInsert(list, str, i);
                    476:     }
                    477: 
                    478:        if(strcmp(curval,value)==0)
                    479:                return((*list)[i]);     /* no change */
                    480: 
                    481:        return strListReplace(*list, i, str);
                    482: }
                    483: 
                    484: char* iniSetInteger(str_list_t* list, const char* section, const char* key, long value
                    485:                                        ,ini_style_t* style)
                    486: {
                    487:        char    str[INI_MAX_VALUE_LEN];
                    488: 
                    489:        SAFEPRINTF(str,"%ld",value);
                    490:        return iniSetString(list, section, key, str, style);
                    491: }
                    492: 
                    493: char* iniSetShortInt(str_list_t* list, const char* section, const char* key, ushort value
                    494:                                        ,ini_style_t* style)
                    495: {
                    496:        char    str[INI_MAX_VALUE_LEN];
                    497: 
                    498:        SAFEPRINTF(str,"%hu",value);
                    499:        return iniSetString(list, section, key, str, style);
                    500: }
                    501: 
                    502: char* iniSetLongInt(str_list_t* list, const char* section, const char* key, ulong value
                    503:                                        ,ini_style_t* style)
                    504: {
                    505:        char    str[INI_MAX_VALUE_LEN];
                    506: 
                    507:        SAFEPRINTF(str,"%lu",value);
                    508:        return iniSetString(list, section, key, str, style);
                    509: }
                    510: 
                    511: char* iniSetHexInt(str_list_t* list, const char* section, const char* key, ulong value
                    512:                                        ,ini_style_t* style)
                    513: {
                    514:        char    str[INI_MAX_VALUE_LEN];
                    515: 
                    516:        SAFEPRINTF(str,"0x%lx",value);
                    517:        return iniSetString(list, section, key, str, style);
                    518: }
                    519: 
                    520: char* iniSetFloat(str_list_t* list, const char* section, const char* key, double value
                    521:                                        ,ini_style_t* style)
                    522: {
                    523:        char    str[INI_MAX_VALUE_LEN];
                    524: 
                    525:        SAFEPRINTF(str,"%g",value);
                    526:        return iniSetString(list, section, key, str, style);
                    527: }
                    528: 
                    529: char* iniSetBytes(str_list_t* list, const char* section, const char* key, ulong unit
1.1.1.2 ! root      530:                                        ,int64_t value, ini_style_t* style)
1.1       root      531: {
                    532:        char    str[INI_MAX_VALUE_LEN];
                    533:        double  bytes;
                    534: 
1.1.1.2 ! root      535:        if(value==0)
        !           536:                SAFECOPY(str,"0");
        !           537:        else
        !           538:                switch(unit) {
        !           539:                        case 1024*1024*1024:
        !           540:                                SAFEPRINTF(str,"%"PRIi64"G",value);
        !           541:                                break;
        !           542:                        case 1024*1024:
        !           543:                                SAFEPRINTF(str,"%"PRIi64"M",value);
        !           544:                                break;
        !           545:                        case 1024:
        !           546:                                SAFEPRINTF(str,"%"PRIi64"K",value);
        !           547:                                break;
        !           548:                        default:
        !           549:                                if(unit<1)
        !           550:                                        unit=1;
        !           551:                                bytes=(double)(value*unit);
        !           552: 
        !           553:                                if(fmod(bytes,1024.0*1024.0*1024.0*1024.0)==0)
        !           554:                                        SAFEPRINTF(str,"%gT",bytes/(1024.0*1024.0*1024.0*1024.0));
        !           555:                                else if(fmod(bytes,1024*1024*1024)==0)
        !           556:                                        SAFEPRINTF(str,"%gG",bytes/(1024*1024*1024));
        !           557:                                else if(fmod(bytes,1024*1024)==0)
        !           558:                                        SAFEPRINTF(str,"%gM",bytes/(1024*1024));
        !           559:                                else if(fmod(bytes,1024)==0)
        !           560:                                        SAFEPRINTF(str,"%gK",bytes/1024);
        !           561:                                else
        !           562:                                        SAFEPRINTF(str,"%"PRIi64, (int64_t)bytes);
        !           563:                }
1.1       root      564: 
                    565:        return iniSetString(list, section, key, str, style);
                    566: }
                    567: 
                    568: #if !defined(NO_SOCKET_SUPPORT)
                    569: char* iniSetIpAddress(str_list_t* list, const char* section, const char* key, ulong value
                    570:                                        ,ini_style_t* style)
                    571: {
                    572:        struct in_addr in_addr;
                    573:        in_addr.s_addr=htonl(value);
                    574:        return iniSetString(list, section, key, inet_ntoa(in_addr), style);
                    575: }
                    576: #endif
                    577: 
                    578: char* iniSetBool(str_list_t* list, const char* section, const char* key, BOOL value
                    579:                                        ,ini_style_t* style)
                    580: {
                    581:        return iniSetString(list, section, key, value ? "true":"false", style);
                    582: }
                    583: 
                    584: char* iniSetDateTime(str_list_t* list, const char* section, const char* key
                    585:                                         ,BOOL include_time, time_t value, ini_style_t* style)
                    586: {
                    587:        char    str[INI_MAX_VALUE_LEN];
                    588:        char    tstr[32];
                    589:        char*   p;
                    590: 
                    591:        if(value==0)
                    592:                SAFECOPY(str,"Never");
1.1.1.2 ! root      593:        else if((p=ctime_r(&value,tstr))==NULL)
1.1       root      594:                SAFEPRINTF(str,"0x%lx",value);
                    595:        else if(!include_time)  /* reformat into "Mon DD YYYY" */
                    596:                safe_snprintf(str,sizeof(str),"%.3s %.2s %.4s"          ,p+4,p+8,p+20);
                    597:        else                                    /* reformat into "Mon DD YYYY HH:MM:SS" */
                    598:                safe_snprintf(str,sizeof(str),"%.3s %.2s %.4s %.8s"     ,p+4,p+8,p+20,p+11);
                    599: 
                    600:        return iniSetString(list, section, key, str, style);
                    601: }
                    602: 
                    603: char* iniSetEnum(str_list_t* list, const char* section, const char* key, str_list_t names, unsigned value
                    604:                                        ,ini_style_t* style)
                    605: {
                    606:        if(value < strListCount(names))
                    607:                return iniSetString(list, section, key, names[value], style);
                    608: 
                    609:        return iniSetLongInt(list, section, key, value, style);
                    610: }
                    611: 
1.1.1.2 ! root      612: char* iniSetEnumList(str_list_t* list, const char* section, const char* key 
        !           613:                                        ,const char* sep, str_list_t names, unsigned* val_list, unsigned count, ini_style_t* style)
        !           614: {
        !           615:        char    value[INI_MAX_VALUE_LEN];
        !           616:        size_t  i;
        !           617:        size_t  name_count;
        !           618: 
        !           619:        value[0]=0;
        !           620: 
        !           621:        if(sep==NULL)
        !           622:                sep=",";
        !           623: 
        !           624:        if(val_list!=NULL) {
        !           625:                name_count = strListCount(names);
        !           626:                for(i=0; i < count; i++) {
        !           627:                        if(value[0])
        !           628:                                strcat(value,sep);
        !           629:                        if(val_list[i] < name_count)
        !           630:                                strcat(value, names[val_list[i]]);
        !           631:                        else
        !           632:                                sprintf(value + strlen(value), "%u", val_list[i]);
        !           633:                }
        !           634:        }
        !           635: 
        !           636:        return iniSetString(list, section, key, value, style);
        !           637: }
        !           638: 
1.1       root      639: char* iniSetNamedInt(str_list_t* list, const char* section, const char* key, named_long_t* names
                    640:                                         ,long value, ini_style_t* style)
                    641: {
                    642:        size_t  i;
                    643: 
                    644:        for(i=0;names[i].name!=NULL;i++)
                    645:                if(names[i].value==value)
                    646:                        return iniSetString(list, section, key, names[i].name, style);
                    647: 
                    648:        return iniSetInteger(list, section, key, value, style);
                    649: }
                    650: 
                    651: char* iniSetNamedFloat(str_list_t* list, const char* section, const char* key, named_double_t* names
                    652:                                         ,double value, ini_style_t* style)
                    653: {
                    654:        size_t  i;
                    655: 
                    656:        for(i=0;names[i].name!=NULL;i++)
                    657:                if(names[i].value==value)
                    658:                        return iniSetString(list, section, key, names[i].name, style);
                    659: 
                    660:        return iniSetFloat(list, section, key, value, style);
                    661: }
                    662: 
                    663: char* iniSetBitField(str_list_t* list, const char* section, const char* key
                    664:                                         ,ini_bitdesc_t* bitdesc, ulong value, ini_style_t* style)
                    665: {
                    666:        char    str[INI_MAX_VALUE_LEN];
                    667:        int             i;
                    668: 
                    669:        if(style==NULL)
                    670:                style=&default_style;
                    671:        if(style->bit_separator==NULL)
                    672:                style->bit_separator="|";
                    673:        str[0]=0;
                    674:        for(i=0;bitdesc[i].name;i++) {
                    675:                if((value&bitdesc[i].bit)==0)
                    676:                        continue;
                    677:                if(str[0])
                    678:                        strcat(str,style->bit_separator);
                    679:                strcat(str,bitdesc[i].name);
                    680:                value&=~bitdesc[i].bit;
                    681:        }
                    682:        if(value) {     /* left over bits? */
                    683:                if(str[0])
                    684:                        strcat(str,style->bit_separator);
                    685:                sprintf(str+strlen(str), "0x%lX", value);
                    686:        }
                    687:        return iniSetString(list, section, key, str, style);
                    688: }
                    689: 
                    690: char* iniSetStringList(str_list_t* list, const char* section, const char* key
                    691:                                        ,const char* sep, str_list_t val_list, ini_style_t* style)
                    692: {
                    693:        char    value[INI_MAX_VALUE_LEN];
                    694: 
                    695:        if(sep==NULL)
                    696:                sep=",";
                    697: 
1.1.1.2 ! root      698:        return iniSetString(list, section, key, strListCombine(val_list, value, sizeof(value), sep), style);
        !           699: }
1.1       root      700: 
1.1.1.2 ! root      701: static char* default_value(const char* deflt, char* value)
        !           702: {
        !           703:        if(deflt!=NULL && deflt!=value && value!=NULL)
        !           704:                sprintf(value,"%.*s",INI_MAX_VALUE_LEN-1,deflt);
        !           705: 
        !           706:        return((char*)deflt);
1.1       root      707: }
                    708: 
                    709: char* iniReadString(FILE* fp, const char* section, const char* key, const char* deflt, char* value)
                    710: {
1.1.1.2 ! root      711:        if(read_value(fp,section,key,value)==NULL || *value==0 /* blank */)
        !           712:                return default_value(deflt,value);
1.1       root      713: 
                    714:        return(value);
                    715: }
                    716: 
                    717: char* iniGetString(str_list_t list, const char* section, const char* key, const char* deflt, char* value)
                    718: {
1.1.1.2 ! root      719:        char*   vp=NULL;
1.1       root      720: 
1.1.1.2 ! root      721:        get_value(list, section, key, value, &vp);
        !           722: 
        !           723:        if(vp==NULL || *vp==0 /* blank value or missing key */)
        !           724:                return default_value(deflt,value);
        !           725: 
        !           726:        return(vp);
        !           727: }
        !           728: 
        !           729: char* iniPopKey(str_list_t* list, const char* section, const char* key, char* value)
        !           730: {
        !           731:        size_t i;
        !           732:        
        !           733:        if(list==NULL || *list==NULL)
        !           734:                return NULL;
        !           735: 
        !           736:        i=get_value(*list, section, key, value, NULL);
        !           737: 
        !           738:        if((*list)[i]==NULL)
        !           739:                return NULL;
        !           740: 
        !           741:        strListDelete(list,i);
        !           742: 
        !           743:        return(value);
        !           744: }
        !           745: 
        !           746: char* iniReadExistingString(FILE* fp, const char* section, const char* key, const char* deflt, char* value)
        !           747: {
        !           748:        if(read_value(fp,section,key,value)==NULL)
        !           749:                return(NULL);
        !           750: 
        !           751:        if(*value==0 /* blank */)
        !           752:                return default_value(deflt,value);
1.1       root      753: 
                    754:        return(value);
                    755: }
                    756: 
1.1.1.2 ! root      757: char* iniGetExistingString(str_list_t list, const char* section, const char* key, const char* deflt, char* value)
        !           758: {
        !           759:        if(!iniKeyExists(list, section, key))
        !           760:                return(NULL);
        !           761: 
        !           762:        return iniGetString(list, section, key, deflt, value);
        !           763: }
        !           764: 
1.1       root      765: static str_list_t splitList(char* list, const char* sep)
                    766: {
                    767:        char*           token;
                    768:        char*           tmp;
                    769:        ulong           items=0;
                    770:        str_list_t      lp;
                    771: 
                    772:        if((lp=strListInit())==NULL)
                    773:                return(NULL);
                    774: 
                    775:        if(sep==NULL)
                    776:                sep=",";
                    777: 
                    778:        token=strtok_r(list,sep,&tmp);
                    779:        while(token!=NULL) {
                    780:                SKIP_WHITESPACE(token);
                    781:                truncsp(token);
                    782:                if(strListAppend(&lp,token,items++)==NULL)
                    783:                        break;
                    784:                token=strtok_r(NULL,sep,&tmp);
                    785:        }
                    786: 
                    787:        return(lp);
                    788: }
                    789: 
                    790: str_list_t iniReadStringList(FILE* fp, const char* section, const char* key
                    791:                                                 ,const char* sep, const char* deflt)
                    792: {
                    793:        char*   value;
                    794:        char    buf[INI_MAX_VALUE_LEN];
                    795:        char    list[INI_MAX_VALUE_LEN];
                    796: 
                    797:        if((value=read_value(fp,section,key,buf))==NULL || *value==0 /* blank */)
                    798:                value=(char*)deflt;
                    799: 
                    800:        if(value==NULL)
                    801:                return(NULL);
                    802: 
                    803:        SAFECOPY(list,value);
                    804: 
                    805:        return(splitList(list,sep));
                    806: }
                    807: 
                    808: str_list_t iniGetStringList(str_list_t list, const char* section, const char* key
                    809:                                                 ,const char* sep, const char* deflt)
                    810: {
                    811:        char    value[INI_MAX_VALUE_LEN];
                    812: 
1.1.1.2 ! root      813:        get_value(list, section, key, value, NULL);
1.1       root      814: 
                    815:        if(*value==0 /* blank value or missing key */) {
                    816:                if(deflt==NULL)
                    817:                        return(NULL);
                    818:                SAFECOPY(value,deflt);
                    819:        }
                    820: 
                    821:        return(splitList(value,sep));
                    822: }
                    823: 
                    824: void* iniFreeStringList(str_list_t list)
                    825: {
                    826:        strListFree(&list);
                    827:        return(list);
                    828: }
                    829: 
                    830: void* iniFreeNamedStringList(named_string_t** list)
                    831: {
                    832:        ulong   i;
                    833: 
                    834:        if(list==NULL)
                    835:                return(NULL);
                    836: 
                    837:        for(i=0;list[i]!=NULL;i++) {
                    838:                if(list[i]->name!=NULL)
                    839:                        free(list[i]->name);
                    840:                if(list[i]->value!=NULL)
                    841:                        free(list[i]->value);
                    842:                free(list[i]);
                    843:        }
                    844: 
                    845:        free(list);
                    846:        return(NULL);
                    847: }
                    848: 
                    849: str_list_t iniReadSectionList(FILE* fp, const char* prefix)
                    850: {
                    851:        char*   p;
                    852:        char    str[INI_MAX_LINE_LEN];
                    853:        ulong   items=0;
                    854:        str_list_t      lp;
                    855: 
                    856:        if((lp=strListInit())==NULL)
                    857:                return(NULL);
                    858: 
                    859:        if(fp==NULL)
                    860:                return(lp);
                    861: 
                    862:        rewind(fp);
                    863: 
                    864:        while(!feof(fp)) {
                    865:                if(fgets(str,sizeof(str),fp)==NULL)
                    866:                        break;
                    867:                if(is_eof(str))
                    868:                        break;
                    869:                if((p=section_name(str))==NULL)
                    870:                        continue;
                    871:                if(prefix!=NULL)
                    872:                        if(strnicmp(p,prefix,strlen(prefix))!=0)
                    873:                                continue;
                    874:                if(strListAppend(&lp,p,items++)==NULL)
                    875:                        break;
                    876:        }
                    877: 
                    878:        return(lp);
                    879: }
                    880: 
                    881: str_list_t iniGetSectionList(str_list_t list, const char* prefix)
                    882: {
                    883:        char*   p;
                    884:        char    str[INI_MAX_LINE_LEN];
                    885:        ulong   i,items=0;
                    886:        str_list_t      lp;
                    887: 
                    888:        if((lp=strListInit())==NULL)
                    889:                return(NULL);
                    890: 
                    891:        if(list==NULL)
                    892:                return(lp);
                    893: 
                    894:        for(i=0; list[i]!=NULL; i++) {
                    895:                SAFECOPY(str,list[i]);
                    896:                if(is_eof(str))
                    897:                        break;
                    898:                if((p=section_name(str))==NULL)
                    899:                        continue;
                    900:                if(prefix!=NULL)
                    901:                        if(strnicmp(p,prefix,strlen(prefix))!=0)
                    902:                                continue;
                    903:                if(strListAppend(&lp,p,items++)==NULL)
                    904:                        break;
                    905:        }
                    906: 
                    907:        return(lp);
                    908: }
                    909: 
                    910: size_t iniGetSectionCount(str_list_t list, const char* prefix)
                    911: {
                    912:        char*   p;
                    913:        char    str[INI_MAX_LINE_LEN];
                    914:        size_t  i,items=0;
                    915: 
                    916:        if(list==NULL)
                    917:                return(0);
                    918: 
                    919:        for(i=0; list[i]!=NULL; i++) {
                    920:                SAFECOPY(str,list[i]);
                    921:                if(is_eof(str))
                    922:                        break;
                    923:                if((p=section_name(str))==NULL)
                    924:                        continue;
                    925:                if(prefix!=NULL)
                    926:                        if(strnicmp(p,prefix,strlen(prefix))!=0)
                    927:                                continue;
                    928:                items++;
                    929:        }
                    930: 
                    931:        return(items);
                    932: }
                    933: 
                    934: 
                    935: str_list_t iniReadKeyList(FILE* fp, const char* section)
                    936: {
                    937:        char*   p;
                    938:        char*   vp;
                    939:        char    str[INI_MAX_LINE_LEN];
                    940:        ulong   items=0;
                    941:        str_list_t      lp;
                    942: 
                    943:        if((lp=strListInit())==NULL)
                    944:                return(NULL);
                    945: 
                    946:        if(fp==NULL)
                    947:                return(lp);
                    948: 
                    949:        rewind(fp);
                    950: 
                    951:        if(!seek_section(fp,section))
                    952:                return(lp);
                    953: 
                    954:        while(!feof(fp)) {
                    955:                if(fgets(str,sizeof(str),fp)==NULL)
                    956:                        break;
                    957:                if(is_eof(str))
                    958:                        break;
                    959:                if((p=key_name(str,&vp))==NULL)
                    960:                        continue;
                    961:                if(p==INI_NEW_SECTION)
                    962:                        break;
                    963:                if(strListAppend(&lp,p,items++)==NULL)
                    964:                        break;
                    965:        }
                    966: 
                    967:        return(lp);
                    968: }
                    969: 
                    970: str_list_t iniGetKeyList(str_list_t list, const char* section)
                    971: {
                    972:        char*   p;
                    973:        char*   vp;
                    974:        char    str[INI_MAX_LINE_LEN];
                    975:        ulong   i,items=0;
                    976:        str_list_t      lp;
                    977: 
                    978:        if((lp=strListInit())==NULL)
                    979:                return(NULL);
                    980: 
                    981:        if(list==NULL)
                    982:                return(lp);
                    983: 
                    984:        for(i=find_section(list,section);list[i]!=NULL;i++) {
                    985:                SAFECOPY(str,list[i]);
                    986:                if(is_eof(str))
                    987:                        break;
                    988:                if((p=key_name(str,&vp))==NULL)
                    989:                        continue;
                    990:                if(p==INI_NEW_SECTION)
                    991:                        break;
                    992:                if(strListAppend(&lp,p,items++)==NULL)
                    993:                        break;
                    994:        }
                    995: 
                    996:        return(lp);
                    997: }
                    998: 
                    999: 
                   1000: named_string_t**
                   1001: iniReadNamedStringList(FILE* fp, const char* section)
                   1002: {
                   1003:        char*   name;
                   1004:        char*   value;
                   1005:        char    str[INI_MAX_LINE_LEN];
                   1006:        ulong   items=0;
1.1.1.2 ! root     1007:        named_string_t** lp=NULL;
1.1       root     1008:        named_string_t** np;
                   1009: 
                   1010:        if(fp==NULL)
1.1.1.2 ! root     1011:                return(NULL);
1.1       root     1012: 
                   1013:        rewind(fp);
                   1014: 
                   1015:        if(!seek_section(fp,section))
1.1.1.2 ! root     1016:                return(NULL);
        !          1017: 
        !          1018:        /* New behavior, if section exists but is empty, return single element array (terminator only) */
        !          1019:        if((lp=(named_string_t**)malloc(sizeof(named_string_t*)))==NULL)
        !          1020:                return(NULL);
1.1       root     1021: 
                   1022:        while(!feof(fp)) {
                   1023:                if(fgets(str,sizeof(str),fp)==NULL)
                   1024:                        break;
                   1025:                if(is_eof(str))
                   1026:                        break;
                   1027:                if((name=key_name(str,&value))==NULL)
                   1028:                        continue;
                   1029:                if(name==INI_NEW_SECTION)
                   1030:                        break;
                   1031:                if((np=(named_string_t**)realloc(lp,sizeof(named_string_t*)*(items+2)))==NULL)
                   1032:                        break;
                   1033:                lp=np;
                   1034:                if((lp[items]=(named_string_t*)malloc(sizeof(named_string_t)))==NULL)
                   1035:                        break;
                   1036:                if((lp[items]->name=strdup(name))==NULL)
                   1037:                        break;
                   1038:                if((lp[items]->value=strdup(value))==NULL)
                   1039:                        break;
                   1040:                items++;
                   1041:        }
                   1042: 
                   1043:        lp[items]=NULL; /* terminate list */
                   1044: 
                   1045:        return(lp);
                   1046: }
                   1047: 
                   1048: named_string_t**
                   1049: iniGetNamedStringList(str_list_t list, const char* section)
                   1050: {
                   1051:        char*   name;
                   1052:        char*   value;
                   1053:        char    str[INI_MAX_LINE_LEN];
                   1054:        ulong   i,items=0;
1.1.1.2 ! root     1055:        named_string_t** lp=NULL;
1.1       root     1056:        named_string_t** np;
                   1057: 
1.1.1.2 ! root     1058:        if(list==NULL)
1.1       root     1059:                return(NULL);
                   1060: 
1.1.1.2 ! root     1061:        i=find_section(list,section);
        !          1062:        if(list[i]==NULL)
        !          1063:                return(NULL);
1.1       root     1064: 
1.1.1.2 ! root     1065:        /* New behavior, if section exists but is empty, return single element array (terminator only) */
        !          1066:        if((lp=(named_string_t**)malloc(sizeof(named_string_t*)))==NULL)
        !          1067:                return(NULL);
1.1       root     1068: 
1.1.1.2 ! root     1069:        for(;list[i]!=NULL;i++) {
1.1       root     1070:                SAFECOPY(str,list[i]);
                   1071:                if(is_eof(str))
                   1072:                        break;
                   1073:                if((name=key_name(str,&value))==NULL)
                   1074:                        continue;
                   1075:                if(name==INI_NEW_SECTION)
                   1076:                        break;
                   1077:                if((np=(named_string_t**)realloc(lp,sizeof(named_string_t*)*(items+2)))==NULL)
                   1078:                        break;
                   1079:                lp=np;
                   1080:                if((lp[items]=(named_string_t*)malloc(sizeof(named_string_t)))==NULL)
                   1081:                        break;
                   1082:                if((lp[items]->name=strdup(name))==NULL)
                   1083:                        break;
                   1084:                if((lp[items]->value=strdup(value))==NULL)
                   1085:                        break;
                   1086:                items++;
                   1087:        }
                   1088: 
                   1089:        lp[items]=NULL; /* terminate list */
                   1090: 
                   1091:        return(lp);
                   1092: }
                   1093: 
                   1094: 
                   1095: /* These functions read a single key of the specified type */
                   1096: 
                   1097: static BOOL isTrue(const char* value)
                   1098: {
                   1099:        return(stricmp(value,"TRUE")==0 || stricmp(value,"YES")==0 || stricmp(value,"ON")==0);
                   1100: }
                   1101: 
                   1102: static long parseInteger(const char* value)
                   1103: {
                   1104:        if(isTrue(value))
                   1105:                return(TRUE);
                   1106: 
                   1107:        return(strtol(value,NULL,0));
                   1108: }
                   1109: 
                   1110: static ulong parseLongInteger(const char* value)
                   1111: {
                   1112:        if(isTrue(value))
                   1113:                return(TRUE);
                   1114: 
                   1115:        return(strtoul(value,NULL,0));
                   1116: }
                   1117: 
                   1118: static BOOL parseBool(const char* value)
                   1119: {
                   1120:        return(INT_TO_BOOL(parseInteger(value)));
                   1121: }
                   1122: 
                   1123: long iniReadInteger(FILE* fp, const char* section, const char* key, long deflt)
                   1124: {
                   1125:        char*   value;
                   1126:        char    buf[INI_MAX_VALUE_LEN];
                   1127: 
                   1128:        if((value=read_value(fp,section,key,buf))==NULL)
                   1129:                return(deflt);
                   1130: 
                   1131:        if(*value==0)           /* blank value */
                   1132:                return(deflt);
                   1133: 
                   1134:        return(parseInteger(value));
                   1135: }
                   1136: 
                   1137: long iniGetInteger(str_list_t list, const char* section, const char* key, long deflt)
                   1138: {
1.1.1.2 ! root     1139:        char*   vp=NULL;
1.1       root     1140: 
1.1.1.2 ! root     1141:        get_value(list, section, key, NULL, &vp);
1.1       root     1142: 
1.1.1.2 ! root     1143:        if(vp==NULL || *vp==0)  /* blank value or missing key */
1.1       root     1144:                return(deflt);
                   1145: 
1.1.1.2 ! root     1146:        return(parseInteger(vp));
1.1       root     1147: }
                   1148: 
                   1149: ushort iniReadShortInt(FILE* fp, const char* section, const char* key, ushort deflt)
                   1150: {
                   1151:        return((ushort)iniReadInteger(fp, section, key, deflt));
                   1152: }
                   1153: 
                   1154: ushort iniGetShortInt(str_list_t list, const char* section, const char* key, ushort deflt)
                   1155: {
                   1156:        return((ushort)iniGetInteger(list, section, key, deflt));
                   1157: }
                   1158: 
                   1159: ulong iniReadLongInt(FILE* fp, const char* section, const char* key, ulong deflt)
                   1160: {
                   1161:        char*   value;
                   1162:        char    buf[INI_MAX_VALUE_LEN];
                   1163: 
                   1164:        if((value=read_value(fp,section,key,buf))==NULL)
                   1165:                return(deflt);
                   1166: 
                   1167:        if(*value==0)           /* blank value */
                   1168:                return(deflt);
                   1169: 
                   1170:        return(parseLongInteger(value));
                   1171: }
                   1172: 
                   1173: ulong iniGetLongInt(str_list_t list, const char* section, const char* key, ulong deflt)
                   1174: {
1.1.1.2 ! root     1175:        char*   vp=NULL;
1.1       root     1176: 
1.1.1.2 ! root     1177:        get_value(list, section, key, NULL, &vp);
1.1       root     1178: 
1.1.1.2 ! root     1179:        if(vp==NULL || *vp==0)  /* blank value or missing key */
1.1       root     1180:                return(deflt);
                   1181: 
1.1.1.2 ! root     1182:        return(parseLongInteger(vp));
1.1       root     1183: }
                   1184: 
1.1.1.2 ! root     1185: static int64_t parseBytes(const char* value, ulong unit)
1.1       root     1186: {
                   1187:        char*   p=NULL;
                   1188:        double  bytes;
                   1189: 
                   1190:        bytes=strtod(value,&p);
                   1191:        if(p!=NULL) {
                   1192:                switch(toupper(*p)) {
1.1.1.2 ! root     1193:                        case 'E':
        !          1194:                                bytes*=1024;
        !          1195:                                /* fall-through */
        !          1196:                        case 'P':
        !          1197:                                bytes*=1024;
        !          1198:                                /* fall-through */
1.1       root     1199:                        case 'T':
                   1200:                                bytes*=1024;
1.1.1.2 ! root     1201:                                /* fall-through */
1.1       root     1202:                        case 'G':
                   1203:                                bytes*=1024;
1.1.1.2 ! root     1204:                                /* fall-through */
1.1       root     1205:                        case 'M':
                   1206:                                bytes*=1024;
1.1.1.2 ! root     1207:                                /* fall-through */
1.1       root     1208:                        case 'K':
                   1209:                                bytes*=1024;
                   1210:                                break;
                   1211:                }
                   1212:        }
1.1.1.2 ! root     1213:        return((int64_t)(unit>1 ? (bytes/unit):bytes));
1.1       root     1214: }
                   1215: 
1.1.1.2 ! root     1216: int64_t iniReadBytes(FILE* fp, const char* section, const char* key, ulong unit, int64_t deflt)
1.1       root     1217: {
                   1218:        char*   value;
                   1219:        char    buf[INI_MAX_VALUE_LEN];
                   1220: 
                   1221:        if((value=read_value(fp,section,key,buf))==NULL)
                   1222:                return(deflt);
                   1223: 
                   1224:        if(*value==0)           /* blank value */
                   1225:                return(deflt);
                   1226: 
                   1227:        return(parseBytes(value,unit));
                   1228: }
                   1229: 
1.1.1.2 ! root     1230: int64_t iniGetBytes(str_list_t list, const char* section, const char* key, ulong unit, int64_t deflt)
1.1       root     1231: {
1.1.1.2 ! root     1232:        char*   vp=NULL;
1.1       root     1233: 
1.1.1.2 ! root     1234:        get_value(list, section, key, NULL, &vp);
1.1       root     1235: 
1.1.1.2 ! root     1236:        if(vp==NULL || *vp==0)  /* blank value or missing key */
1.1       root     1237:                return(deflt);
                   1238: 
1.1.1.2 ! root     1239:        return(parseBytes(vp,unit));
1.1       root     1240: }
                   1241: 
                   1242: #if !defined(NO_SOCKET_SUPPORT)
                   1243: 
                   1244: int iniGetSocketOptions(str_list_t list, const char* section, SOCKET sock
                   1245:                                                 ,char* error, size_t errlen)
                   1246: {
                   1247:        int                     i;
                   1248:        int                     result;
                   1249:        char*           name;
                   1250:        BYTE*           vp;
                   1251:        socklen_t       len;
                   1252:        int                     option;
                   1253:        int                     level;
                   1254:        int                     value;
                   1255:        LINGER          linger;
                   1256:        socket_option_t* socket_options=getSocketOptionList();
                   1257: 
                   1258:        for(i=0;socket_options[i].name!=NULL;i++) {
                   1259:                name = socket_options[i].name;
                   1260:                if(!iniValueExists(list, section, name))
                   1261:                        continue;
                   1262:                value=iniGetInteger(list, section, name, 0);
                   1263: 
                   1264:                vp=(BYTE*)&value;
                   1265:                len=sizeof(value);
                   1266: 
                   1267:                level   = socket_options[i].level;
                   1268:                option  = socket_options[i].value;
                   1269: 
                   1270:                if(option == SO_LINGER) {
                   1271:                        if(value) {
                   1272:                                linger.l_onoff = TRUE;
                   1273:                                linger.l_linger = value;
                   1274:                        } else {
                   1275:                                ZERO_VAR(linger);
                   1276:                        }
                   1277:                        vp=(BYTE*)&linger;
                   1278:                        len=sizeof(linger);
                   1279:                }
                   1280: 
                   1281:                if((result=setsockopt(sock,level,option,vp,len)) != 0) {
                   1282:                        safe_snprintf(error,errlen,"%d setting socket option (%s, %d) to %d"
                   1283:                                ,ERROR_VALUE, name, option, value);
                   1284:                        return(result);
                   1285:                }
                   1286:        }
                   1287: 
                   1288:        return(0);
                   1289: }
                   1290: 
                   1291: static ulong parseIpAddress(const char* value)
                   1292: {
                   1293:        if(strchr(value,'.')==NULL)
                   1294:                return(strtol(value,NULL,0));
                   1295: 
                   1296:        return(ntohl(inet_addr(value)));
                   1297: }
                   1298: 
                   1299: ulong iniReadIpAddress(FILE* fp, const char* section, const char* key, ulong deflt)
                   1300: {
                   1301:        char    buf[INI_MAX_VALUE_LEN];
                   1302:        char*   value;
                   1303: 
                   1304:        if((value=read_value(fp,section,key,buf))==NULL)
                   1305:                return(deflt);
                   1306: 
                   1307:        if(*value==0)           /* blank value */
                   1308:                return(deflt);
                   1309: 
                   1310:        return(parseIpAddress(value));
                   1311: }
                   1312: 
                   1313: ulong iniGetIpAddress(str_list_t list, const char* section, const char* key, ulong deflt)
                   1314: {
1.1.1.2 ! root     1315:        char*   vp=NULL;
1.1       root     1316: 
1.1.1.2 ! root     1317:        get_value(list, section, key, NULL, &vp);
1.1       root     1318: 
1.1.1.2 ! root     1319:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1320:                return(deflt);
                   1321: 
1.1.1.2 ! root     1322:        return(parseIpAddress(vp));
1.1       root     1323: }
                   1324: 
                   1325: #endif /* !NO_SOCKET_SUPPORT */
                   1326: 
                   1327: char* iniFileName(char* dest, size_t maxlen, const char* indir, const char* infname)
                   1328: {
                   1329:        char    dir[MAX_PATH+1];
                   1330:        char    fname[MAX_PATH+1];
                   1331:        char    ext[MAX_PATH+1];
                   1332:        char*   p;
                   1333: 
                   1334:        SAFECOPY(dir,indir);
                   1335:        backslash(dir);
                   1336:        SAFECOPY(fname,infname);
                   1337:        ext[0]=0;
                   1338:        if((p=getfext(fname))!=NULL) {
                   1339:                SAFECOPY(ext,p);
                   1340:                *p=0;
                   1341:        }
                   1342: 
                   1343: #if !defined(NO_SOCKET_SUPPORT)
                   1344:        {
                   1345:                char hostname[128];
                   1346: 
                   1347:                if(gethostname(hostname,sizeof(hostname))==0) {
                   1348:                        safe_snprintf(dest,maxlen,"%s%s.%s%s",dir,fname,hostname,ext);
                   1349:                        if(fexistcase(dest))            /* path/file.host.domain.ini */
                   1350:                                return(dest);
                   1351:                        if((p=strchr(hostname,'.'))!=NULL) {
                   1352:                                *p=0;
                   1353:                                safe_snprintf(dest,maxlen,"%s%s.%s%s",dir,fname,hostname,ext);
                   1354:                                if(fexistcase(dest))    /* path/file.host.ini */
                   1355:                                        return(dest);
                   1356:                        }
                   1357:                }
                   1358:        }
                   1359: #endif
                   1360: 
                   1361:        safe_snprintf(dest,maxlen,"%s%s.%s%s",dir,fname,PLATFORM_DESC,ext);
                   1362:        if(fexistcase(dest))    /* path/file.platform.ini */
                   1363:                return(dest);
                   1364:        
                   1365:        safe_snprintf(dest,maxlen,"%s%s%s",dir,fname,ext);
                   1366:        fexistcase(dest);       /* path/file.ini */
                   1367:        return(dest);
                   1368: }
                   1369: 
                   1370: double iniReadFloat(FILE* fp, const char* section, const char* key, double deflt)
                   1371: {
                   1372:        char    buf[INI_MAX_VALUE_LEN];
                   1373:        char*   value;
                   1374: 
                   1375:        if((value=read_value(fp,section,key,buf))==NULL)
                   1376:                return(deflt);
                   1377: 
                   1378:        if(*value==0)           /* blank value */
                   1379:                return(deflt);
                   1380: 
                   1381:        return(atof(value));
                   1382: }
                   1383: 
                   1384: double iniGetFloat(str_list_t list, const char* section, const char* key, double deflt)
                   1385: {
1.1.1.2 ! root     1386:        char*   vp=NULL;
1.1       root     1387: 
1.1.1.2 ! root     1388:        get_value(list, section, key, NULL, &vp);
1.1       root     1389: 
1.1.1.2 ! root     1390:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1391:                return(deflt);
                   1392: 
1.1.1.2 ! root     1393:        return(atof(vp));
1.1       root     1394: }
                   1395: 
                   1396: BOOL iniReadBool(FILE* fp, const char* section, const char* key, BOOL deflt)
                   1397: {
                   1398:        char    buf[INI_MAX_VALUE_LEN];
                   1399:        char*   value;
                   1400: 
                   1401:        if((value=read_value(fp,section,key,buf))==NULL)
                   1402:                return(deflt);
                   1403: 
                   1404:        if(*value==0)           /* blank value */
                   1405:                return(deflt);
                   1406: 
                   1407:        return(parseBool(value));
                   1408: }
                   1409: 
                   1410: BOOL iniGetBool(str_list_t list, const char* section, const char* key, BOOL deflt)
                   1411: {
1.1.1.2 ! root     1412:        char*   vp=NULL;
1.1       root     1413: 
1.1.1.2 ! root     1414:        get_value(list, section, key, NULL, &vp);
1.1       root     1415: 
1.1.1.2 ! root     1416:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1417:                return(deflt);
                   1418: 
1.1.1.2 ! root     1419:        return(parseBool(vp));
1.1       root     1420: }
                   1421: 
                   1422: static BOOL validDate(struct tm* tm)
                   1423: {
                   1424:        return(tm->tm_mon && tm->tm_mon<=12 
                   1425:                && tm->tm_mday && tm->tm_mday<=31);
                   1426: }
                   1427: 
                   1428: static time_t fixedDateTime(struct tm* tm, const char* tstr, char pm)
                   1429: {
                   1430:        if(tm->tm_year<70)
                   1431:                tm->tm_year+=100;       /* 05 == 2005 (not 1905) and 70 == 1970 (not 2070) */
                   1432:        else if(tm->tm_year>1900)
                   1433:                tm->tm_year-=1900;
                   1434:        if(tm->tm_mon)
                   1435:                tm->tm_mon--;           /* zero-based month field */
                   1436: 
                   1437:        /* hh:mm:ss [p] */
                   1438:        sscanf(tstr,"%u:%u:%u",&tm->tm_hour,&tm->tm_min,&tm->tm_sec);
                   1439:        if(tm->tm_hour < 12 && (toupper(pm)=='P' || strchr(tstr,'p') || strchr(tstr,'P')))
                   1440:                tm->tm_hour += 12;      /* pm, correct for 24 hour clock */
                   1441: 
                   1442:        tm->tm_isdst=-1;        /* auto-detect */
                   1443: 
                   1444:        return(mktime(tm));
                   1445: }
                   1446: 
                   1447: static int getMonth(const char* month)
                   1448: {
                   1449:        char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
                   1450:             ,"Jul","Aug","Sep","Oct","Nov","Dec",NULL};
                   1451:        int i;
                   1452: 
                   1453:        for(i=0;mon[i]!=NULL;i++)
                   1454:                if(strnicmp(month,mon[i],3)==0)
                   1455:                        return(i+1);
                   1456: 
                   1457:        return(atoi(month));
                   1458: }
                   1459: 
                   1460: static time_t parseDateTime(const char* value)
                   1461: {
                   1462:        char    month[INI_MAX_VALUE_LEN];
                   1463:        char    tstr[INI_MAX_VALUE_LEN];
                   1464:        char    pm=0;
                   1465:        time_t  t;
                   1466:        struct tm tm;
                   1467:        struct tm curr_tm;
                   1468:        isoDate_t       isoDate;
                   1469:        isoTime_t       isoTime;
                   1470: 
                   1471:        ZERO_VAR(tm);
                   1472:        tstr[0]=0;
                   1473: 
                   1474:        /* Use current month and year as default */
                   1475:        t=time(NULL);
                   1476:        if(localtime_r(&t,&curr_tm)!=NULL) {    
                   1477:                tm.tm_mon=curr_tm.tm_mon+1;     /* convert to one-based (reversed later) */
                   1478:                tm.tm_year=curr_tm.tm_year;
                   1479:        }
                   1480: 
                   1481:        /* CCYYMMDDTHHMMSS <--- ISO-8601 date and time format */
                   1482:        if(sscanf(value,"%uT%u"
                   1483:                ,&isoDate,&isoTime)>=2)
                   1484:                return(isoDateTime_to_time(isoDate,isoTime));
                   1485: 
                   1486:        /* DD.MM.[CC]YY [time] [p] <-- Euro/Canadian numeric date format */
                   1487:        if(sscanf(value,"%u.%u.%u %s %c"
                   1488:                ,&tm.tm_mday,&tm.tm_mon,&tm.tm_year,tstr,&pm)>=2
                   1489:                && validDate(&tm))
                   1490:                return(fixedDateTime(&tm,tstr,pm));
                   1491: 
                   1492:        /* MM/DD/[CC]YY [time] [p] <-- American numeric date format */
                   1493:        if(sscanf(value,"%u%*c %u%*c %u %s %c"
                   1494:                ,&tm.tm_mon,&tm.tm_mday,&tm.tm_year,tstr,&pm)>=2
                   1495:                && validDate(&tm))
                   1496:                return(fixedDateTime(&tm,tstr,pm));
                   1497: 
                   1498:        /* DD[-]Mon [CC]YY [time] [p] <-- Perversion of RFC822 date format */
                   1499:        if(sscanf(value,"%u%*c %s %u %s %c"
                   1500:                ,&tm.tm_mday,month,&tm.tm_year,tstr,&pm)>=2
                   1501:                && (tm.tm_mon=getMonth(month))!=0
                   1502:                && validDate(&tm))
                   1503:                return(fixedDateTime(&tm,tstr,pm));
                   1504: 
                   1505:        /* Wday, DD Mon YYYY [time] <-- IETF standard (RFC2822) date format */
                   1506:        if(sscanf(value,"%*s %u %s %u %s"
                   1507:                ,&tm.tm_mday,month,&tm.tm_year,tstr)>=2
                   1508:                && (tm.tm_mon=getMonth(month))!=0
                   1509:                && validDate(&tm))
                   1510:                return(fixedDateTime(&tm,tstr,0));
                   1511: 
                   1512:        /* Mon DD[,] [CC]YY [time] [p] <-- Preferred date format */
                   1513:        if(sscanf(value,"%s %u%*c %u %s %c"
                   1514:                ,month,&tm.tm_mday,&tm.tm_year,tstr,&pm)>=2
                   1515:                && (tm.tm_mon=getMonth(month))!=0
                   1516:                && validDate(&tm))
                   1517:                return(fixedDateTime(&tm,tstr,pm));
                   1518: 
                   1519:        /* Wday Mon DD YYYY [time] <-- JavaScript (SpiderMonkey) Date.toString() format */
                   1520:        if(sscanf(value,"%*s %s %u %u %s"
                   1521:                ,month,&tm.tm_mday,&tm.tm_year,tstr)>=2
                   1522:                && (tm.tm_mon=getMonth(month))!=0
                   1523:                && validDate(&tm))
                   1524:                return(fixedDateTime(&tm,tstr,0));
                   1525: 
                   1526:        /* Wday Mon DD [time] YYYY <-- ctime() format */
                   1527:        if(sscanf(value,"%*s %s %u %s %u"
                   1528:                ,month,&tm.tm_mday,tstr,&tm.tm_year)>=2
                   1529:                && (tm.tm_mon=getMonth(month))!=0
                   1530:                && validDate(&tm))
                   1531:                return(fixedDateTime(&tm,tstr,0));
                   1532:        
                   1533:        return(strtoul(value,NULL,0));
                   1534: }
                   1535: 
                   1536: time_t iniReadDateTime(FILE* fp, const char* section, const char* key, time_t deflt)
                   1537: {
                   1538:        char    buf[INI_MAX_VALUE_LEN];
                   1539:        char*   value;
                   1540: 
                   1541:        if((value=read_value(fp,section,key,buf))==NULL)
                   1542:                return(deflt);
                   1543: 
                   1544:        if(*value==0)           /* blank value */
                   1545:                return(deflt);
                   1546: 
                   1547:        return(parseDateTime(value));
                   1548: }
                   1549: 
                   1550: time_t iniGetDateTime(str_list_t list, const char* section, const char* key, time_t deflt)
                   1551: {
1.1.1.2 ! root     1552:        char*   vp=NULL;
1.1       root     1553: 
1.1.1.2 ! root     1554:        get_value(list, section, key, NULL, &vp);
1.1       root     1555: 
1.1.1.2 ! root     1556:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1557:                return(deflt);
                   1558: 
1.1.1.2 ! root     1559:        return(parseDateTime(vp));
1.1       root     1560: }
                   1561: 
                   1562: static unsigned parseEnum(const char* value, str_list_t names)
                   1563: {
1.1.1.2 ! root     1564:        unsigned i,count;
        !          1565:        char val[INI_MAX_VALUE_LEN];
        !          1566:        char* p=val;
        !          1567: 
        !          1568:        /* Strip trailing words (enums must be a single word with no white-space) */
        !          1569:        /* to support comments following enum values */
        !          1570:        SAFECOPY(val,value);
        !          1571:        FIND_WHITESPACE(p);
        !          1572:        *p=0;
        !          1573: 
        !          1574:     if((count=strListCount(names)) == 0)
        !          1575:         return 0;
        !          1576:         
1.1       root     1577:        /* Look for exact matches first */
1.1.1.2 ! root     1578:        for(i=0; i<count; i++)
        !          1579:                if(stricmp(names[i],val)==0)
1.1       root     1580:                        return(i);
                   1581: 
                   1582:        /* Look for partial matches second */
1.1.1.2 ! root     1583:        for(i=0; i<count; i++)
        !          1584:                if(strnicmp(names[i],val,strlen(val))==0)
1.1       root     1585:                        return(i);
                   1586: 
1.1.1.2 ! root     1587:     i=strtoul(val,NULL,0);
        !          1588:     if(i>=count)
        !          1589:         i=count-1;
        !          1590:        return i;
        !          1591: }
        !          1592: 
        !          1593: unsigned* parseEnumList(const char* values, const char* sep, str_list_t names, unsigned* count)
        !          1594: {
        !          1595:        char*           vals;
        !          1596:        str_list_t      list;
        !          1597:        unsigned*       enum_list;
        !          1598:        size_t          i;
        !          1599: 
        !          1600:        *count=0;
        !          1601: 
        !          1602:        if(values==NULL)
        !          1603:                return NULL;
        !          1604: 
        !          1605:        if((vals=strdup(values)) == NULL)
        !          1606:                return NULL;
        !          1607: 
        !          1608:        list=splitList(vals, sep);
        !          1609: 
        !          1610:        free(vals);
        !          1611: 
        !          1612:        if((*count=strListCount(list)) < 1)
        !          1613:                return NULL;
        !          1614: 
        !          1615:        if((enum_list=(unsigned *)malloc((*count)*sizeof(unsigned)))!=NULL) {
        !          1616:                for(i=0;i<*count;i++)
        !          1617:                        enum_list[i]=parseEnum(list[i], names);
        !          1618:        }
        !          1619: 
        !          1620:        strListFree(&list);
        !          1621: 
        !          1622:        return enum_list;
1.1       root     1623: }
                   1624: 
                   1625: unsigned iniReadEnum(FILE* fp, const char* section, const char* key, str_list_t names, unsigned deflt)
                   1626: {
                   1627:        char    buf[INI_MAX_VALUE_LEN];
                   1628:        char*   value;
                   1629: 
                   1630:        if((value=read_value(fp,section,key,buf))==NULL)
                   1631:                return(deflt);
                   1632: 
                   1633:        if(*value==0)           /* blank value */
                   1634:                return(deflt);
                   1635: 
                   1636:        return(parseEnum(value,names));
                   1637: }
                   1638: 
1.1.1.2 ! root     1639: unsigned* iniReadEnumList(FILE* fp, const char* section, const char* key
        !          1640:                                                 ,str_list_t names, unsigned* cp
        !          1641:                                                 ,const char* sep, const char* deflt)
        !          1642: {
        !          1643:        char*           value;
        !          1644:        char            buf[INI_MAX_VALUE_LEN];
        !          1645:        unsigned        count;
        !          1646: 
        !          1647:        if(cp==NULL)
        !          1648:                cp=&count;
        !          1649: 
        !          1650:        *cp=0;
        !          1651: 
        !          1652:        if((value=read_value(fp,section,key,buf))==NULL || *value==0 /* blank */)
        !          1653:                value=(char*)deflt;
        !          1654: 
        !          1655:        return(parseEnumList(value, sep, names, cp));
        !          1656: }
        !          1657: 
1.1       root     1658: unsigned iniGetEnum(str_list_t list, const char* section, const char* key, str_list_t names, unsigned deflt)
                   1659: {
1.1.1.2 ! root     1660:        char*   vp=NULL;
1.1       root     1661: 
1.1.1.2 ! root     1662:        get_value(list, section, key, NULL, &vp);
1.1       root     1663: 
1.1.1.2 ! root     1664:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1665:                return(deflt);
                   1666: 
1.1.1.2 ! root     1667:        return(parseEnum(vp,names));
        !          1668: }
        !          1669: 
        !          1670: unsigned* iniGetEnumList(str_list_t list, const char* section, const char* key
        !          1671:                                                 ,str_list_t names, unsigned* cp, const char* sep, const char* deflt)
        !          1672: {
        !          1673:        char*           vp=NULL;
        !          1674:        unsigned        count;
        !          1675: 
        !          1676:        if(cp==NULL)
        !          1677:                cp=&count;
        !          1678: 
        !          1679:        *cp=0;
        !          1680: 
        !          1681:        get_value(list, section, key, NULL, &vp);
        !          1682: 
        !          1683:        if(vp==NULL || *vp==0 /* blank value or missing key */) {
        !          1684:                if(deflt==NULL)
        !          1685:                        return(NULL);
        !          1686:                vp=(char*)deflt;
        !          1687:        }
        !          1688:        return(parseEnumList(vp, sep, names, cp));
1.1       root     1689: }
                   1690: 
                   1691: static long parseNamedInt(const char* value, named_long_t* names)
                   1692: {
                   1693:        unsigned i;
                   1694: 
                   1695:        /* Look for exact matches first */
                   1696:        for(i=0; names[i].name!=NULL; i++)
                   1697:                if(stricmp(names[i].name,value)==0)
                   1698:                        return(names[i].value);
                   1699: 
                   1700:        /* Look for partial matches second */
                   1701:        for(i=0; names[i].name!=NULL; i++)
                   1702:                if(strnicmp(names[i].name,value,strlen(value))==0)
                   1703:                        return(names[i].value);
                   1704: 
                   1705:        return(parseInteger(value));
                   1706: }
                   1707: 
                   1708: long iniReadNamedInt(FILE* fp, const char* section, const char* key
                   1709:                                         ,named_long_t* names, long deflt)
                   1710: {
                   1711:        char    buf[INI_MAX_VALUE_LEN];
                   1712:        char*   value;
                   1713: 
                   1714:        if((value=read_value(fp,section,key,buf))==NULL)
                   1715:                return(deflt);
                   1716: 
                   1717:        if(*value==0)           /* blank value */
                   1718:                return(deflt);
                   1719: 
                   1720:        return(parseNamedInt(value,names));
                   1721: }
                   1722: 
                   1723: long iniGetNamedInt(str_list_t list, const char* section, const char* key
                   1724:                                        ,named_long_t* names, long deflt)
                   1725: {
1.1.1.2 ! root     1726:        char*   vp=NULL;
1.1       root     1727: 
1.1.1.2 ! root     1728:        get_value(list, section, key, NULL, &vp);
1.1       root     1729: 
1.1.1.2 ! root     1730:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1731:                return(deflt);
                   1732: 
1.1.1.2 ! root     1733:        return(parseNamedInt(vp,names));
1.1       root     1734: }
                   1735: 
                   1736: static double parseNamedFloat(const char* value, named_double_t* names)
                   1737: {
                   1738:        unsigned i;
                   1739: 
                   1740:        /* Look for exact matches first */
                   1741:        for(i=0; names[i].name!=NULL; i++)
                   1742:                if(stricmp(names[i].name,value)==0)
                   1743:                        return(names[i].value);
                   1744: 
                   1745:        /* Look for partial matches second */
                   1746:        for(i=0; names[i].name!=NULL; i++)
                   1747:                if(strnicmp(names[i].name,value,strlen(value))==0)
                   1748:                        return(names[i].value);
                   1749: 
                   1750:        return(atof(value));
                   1751: }
                   1752: 
                   1753: double iniReadNamedFloat(FILE* fp, const char* section, const char* key
                   1754:                                         ,named_double_t* names, double deflt)
                   1755: {
                   1756:        char    buf[INI_MAX_VALUE_LEN];
                   1757:        char*   value;
                   1758: 
                   1759:        if((value=read_value(fp,section,key,buf))==NULL)
                   1760:                return(deflt);
                   1761: 
                   1762:        if(*value==0)           /* blank value */
                   1763:                return(deflt);
                   1764: 
                   1765:        return(parseNamedFloat(value,names));
                   1766: }
                   1767: 
                   1768: double iniGetNamedFloat(str_list_t list, const char* section, const char* key
                   1769:                                        ,named_double_t* names, double deflt)
                   1770: {
1.1.1.2 ! root     1771:        char*   vp=NULL;
1.1       root     1772: 
1.1.1.2 ! root     1773:        get_value(list, section, key, NULL, &vp);
1.1       root     1774: 
1.1.1.2 ! root     1775:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1776:                return(deflt);
                   1777: 
1.1.1.2 ! root     1778:        return(parseNamedFloat(vp,names));
1.1       root     1779: }
                   1780: 
                   1781: static ulong parseBitField(char* value, ini_bitdesc_t* bitdesc)
                   1782: {
                   1783:        int             i;
                   1784:        char*   p;
                   1785:        char*   tp;
                   1786:        ulong   v=0;
                   1787: 
                   1788:        for(p=value;*p;) {
                   1789:                tp=strchr(p,INI_BIT_SEP);
                   1790:                if(tp!=NULL)
                   1791:                        *tp=0;
                   1792:                truncsp(p);
                   1793: 
                   1794:                for(i=0;bitdesc[i].name;i++)
                   1795:                        if(!stricmp(bitdesc[i].name,p))
                   1796:                                break;
                   1797: 
                   1798:                if(bitdesc[i].name)
                   1799:                        v|=bitdesc[i].bit;
                   1800:                else
                   1801:                        v|=strtoul(p,NULL,0);
                   1802: 
                   1803:                if(tp==NULL)
                   1804:                        break;
                   1805: 
                   1806:                p=tp+1;
                   1807:                SKIP_WHITESPACE(p);
                   1808:        }
                   1809: 
                   1810:        return(v);
                   1811: }
                   1812: 
                   1813: ulong iniReadBitField(FILE* fp, const char* section, const char* key, 
                   1814:                                                ini_bitdesc_t* bitdesc, ulong deflt)
                   1815: {
                   1816:        char*   value;
                   1817:        char    buf[INI_MAX_VALUE_LEN];
                   1818: 
                   1819:        if((value=read_value(fp,section,key,buf))==NULL)
                   1820:                return(deflt);
                   1821: 
                   1822:        return(parseBitField(value,bitdesc));
                   1823: }
                   1824: 
                   1825: ulong iniGetBitField(str_list_t list, const char* section, const char* key, 
                   1826:                                                ini_bitdesc_t* bitdesc, ulong deflt)
                   1827: {
1.1.1.2 ! root     1828:        char*   vp=NULL;;
1.1       root     1829: 
1.1.1.2 ! root     1830:        get_value(list, section, key, NULL, &vp);
1.1       root     1831: 
1.1.1.2 ! root     1832:        if(vp==NULL || *vp==0)          /* blank value or missing key */
1.1       root     1833:                return(deflt);
                   1834: 
1.1.1.2 ! root     1835:        return(parseBitField(vp,bitdesc));
1.1       root     1836: }
                   1837: 
                   1838: FILE* iniOpenFile(const char* fname, BOOL create)
                   1839: {
                   1840:        char* mode="r+";
                   1841: 
                   1842:        if(create && !fexist(fname))
                   1843:                mode="w+";
                   1844: 
                   1845:        return(fopen(fname,mode));
                   1846: }
                   1847: 
                   1848: BOOL iniCloseFile(FILE* fp)
                   1849: {
                   1850:        return(fclose(fp)==0);
                   1851: }
                   1852: 
                   1853: str_list_t iniReadFile(FILE* fp)
                   1854: {
                   1855:        char            str[INI_MAX_LINE_LEN];
                   1856:        char*           p;
                   1857:        size_t          i;
                   1858:        size_t          inc_len;
                   1859:        size_t          inc_counter=0;
                   1860:        str_list_t      list;
                   1861:        FILE*           insert_fp=NULL;
                   1862:        
                   1863:        if(fp!=NULL)
                   1864:                rewind(fp);
                   1865: 
                   1866:        list = strListReadFile(fp, NULL, INI_MAX_LINE_LEN);
                   1867:        if(list==NULL)
                   1868:                return(NULL);
                   1869: 
                   1870:        /* Look for !include directives */
                   1871:        inc_len=strlen(INI_INCLUDE_DIRECTIVE);
                   1872:        for(i=0; list[i]!=NULL; i++) {
                   1873:                if(strnicmp(list[i],INI_INCLUDE_DIRECTIVE,inc_len)==0) {
                   1874:                        p=list[i]+inc_len;
                   1875:                        FIND_WHITESPACE(p);
                   1876:                        SKIP_WHITESPACE(p);
                   1877:                        truncsp(p);
                   1878:                        if(inc_counter >= INI_INCLUDE_MAX)
                   1879:                                SAFEPRINTF2(str, ";%s - MAXIMUM INCLUDES REACHED: %u", list[i], INI_INCLUDE_MAX);
                   1880:                        else if((insert_fp=fopen(p,"r"))==NULL)
                   1881:                                SAFEPRINTF2(str, ";%s - FAILURE: %s", list[i], STRERROR(errno));
                   1882:                        else
                   1883:                                SAFEPRINTF(str, ";%s", list[i]);
                   1884:                        strListReplace(list, i, str);
                   1885:                        if(insert_fp!=NULL) {
                   1886:                                strListInsertFile(insert_fp, &list, i+1, INI_MAX_LINE_LEN);
                   1887:                                fclose(insert_fp);
                   1888:                                insert_fp=NULL;
                   1889:                                inc_counter++;
                   1890:                        }
                   1891:                }
                   1892:        }
                   1893: 
                   1894:        /* truncate new-line chars off end of strings */
                   1895:        for(i=0; list[i]!=NULL; i++)
                   1896:                truncnl(list[i]);
                   1897: 
                   1898:        return(list);
                   1899: }
                   1900: 
                   1901: BOOL iniWriteFile(FILE* fp, const str_list_t list)
                   1902: {
                   1903:        size_t          count;
                   1904: 
                   1905:        rewind(fp);
                   1906: 
                   1907:        if(chsize(fileno(fp),0)!=0)     /* truncate */
                   1908:                return(FALSE);
                   1909: 
                   1910:        count = strListWriteFile(fp,list,"\n");
                   1911: 
                   1912:        return(count == strListCount(list));
                   1913: }
                   1914: 
                   1915: #ifdef INI_FILE_TEST
                   1916: void main(int argc, char** argv)
                   1917: {
                   1918:        int                     i;
                   1919:        size_t          l;
                   1920:        char            str[128];
                   1921:        FILE*           fp;
                   1922:        str_list_t      list;
                   1923: 
                   1924:        for(i=1;i<argc;i++) {
                   1925:                if((fp=iniOpenFile(argv[i],FALSE)) == NULL)
                   1926:                        continue;
                   1927:                if((list=iniReadFile(fp)) != NULL) {
                   1928:                        printf("%s\n",iniGetString(list," test | bogus ","key","default",str));
                   1929:                        strListFree(&list);
                   1930:                }
                   1931:                fclose(fp);
                   1932:        }
                   1933: }
                   1934: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.