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

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

unix.superglobalmegacorp.com

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