Annotation of sbbs/src/xpdev/ini_file.c, revision 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.