Annotation of previous_trunk/src/cfgopts.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Hatari - cfgopts.c
        !             3:  *
        !             4:  * The functions in this file are used to load and save the ASCII
        !             5:  * configuration file.
        !             6:  * Original information text follows:
        !             7:  */
        !             8: /*<<---------------[         cfgopts.c        ]------------------------/
        !             9: /                                                                      /
        !            10: /  Functional                                                          /
        !            11: /     Description: Configuration file I/O                              /
        !            12: /                                                                      /
        !            13: /  Input         : Configuration file name                             /
        !            14: /                  Configuration parameters in a structure             /
        !            15: /                                                                      /
        !            16: /  Process       : Interpret information by parameter and read or      /
        !            17: /                  write back to the configuration file.               /
        !            18: /                                                                      /
        !            19: /  Ouput         : updated configuration file or updated structure.    /
        !            20: /                                                                      /
        !            21: /  Programmer    : Jeffry J. Brickley                                  /
        !            22: /                                                                      /
        !            23: /                                                                      /
        !            24: /---------------------------------------------------------------------*/
        !            25: 
        !            26: /*---------------------------------------------------------------------/
        !            27: /
        !            28: /  Description:  CfgOpts is based on GETOPTS by Bob Stout.  It will
        !            29: /                process a configuration file based one words and
        !            30: /                store it in a structure pointing to physical data
        !            31: /                area for each storage item.
        !            32: /  i.e. ???.CFG:
        !            33: /    Port=1
        !            34: /    work_space=C:\temp
        !            35: /    menus=TRUE
        !            36: /    user=Jeffry Brickley
        !            37: /  will write to the following structure:
        !            38: /    struct Config_Tag configs[] = {
        !            39: /    {"port",       Int_Tag,    &port_number},
        !            40: /    {"work_space", String_Tag,  &work_space},
        !            41: /    {"menus",      Bool_Tag, &menu_flag},
        !            42: /    {"user",       String_Tag,  &User_name},
        !            43: /    {NULL,         Error_Tag,   NULL}
        !            44: /    };
        !            45: /  Note that the structure must always be terminated by a NULL row as
        !            46: /     was the same with GETOPTS.  This however is slightly more
        !            47: /     complicated than scaning the command line (but not by much) for
        !            48: /     data as there can be more variety in words than letters and an
        !            49: /     number of data items limited only by memory.
        !            50: /
        !            51: /  Like the original code from which this was taken, this is released
        !            52: /  to the Public Domain.  I cannot make any guarentees other than these
        !            53: /  work for me and I find them usefull.  Feel free to pass these on to
        !            54: /  a friend, but please do not charge him....
        !            55: /
        !            56: /---------------------------------------------------------------------*/
        !            57: const char CfgOpts_fileid[] = "Hatari cfgopts.c : " __DATE__ " " __TIME__;
        !            58: 
        !            59: #include <stdio.h>
        !            60: #include <stdlib.h>
        !            61: #include <unistd.h>
        !            62: 
        !            63: #include "main.h"
        !            64: #include "cfgopts.h"
        !            65: #include "str.h"
        !            66: 
        !            67: 
        !            68: /**
        !            69:  * ---------------------------------------------------------------------/
        !            70:  * /   reads from an input configuration (INI) file.
        !            71:  * /---------------------------------------------------------------------
        !            72:  * >>------[   input_config()   ]-------------[ 08-02-95 14:02PM ]------/
        !            73:  * / return value:
        !            74:  * /     int                     ; number of records read or -1 on error
        !            75:  * / parameters:
        !            76:  * /     char *filename          ; filename of INI style file
        !            77:  * /     struct Config_Tag configs[]; Configuration structure
        !            78:  * /     char *header            ; INI header name (i.e. "[TEST]")
        !            79:  * /-------------------------------------------------------------------<<
        !            80:  */
        !            81: int input_config(const char *filename, const struct Config_Tag configs[], const char *header)
        !            82: {
        !            83:        const struct Config_Tag *ptr;
        !            84:        int count=0, lineno=0;
        !            85:        FILE *file;
        !            86:        char *fptr,*tok,*next;
        !            87:        char line[1024];
        !            88: 
        !            89:        file = fopen(filename,"r");
        !            90:        if (file == NULL)
        !            91:                return -1;                 /* return error designation. */
        !            92: 
        !            93:        if (header != NULL)
        !            94:        {
        !            95:                do
        !            96:                {
        !            97:                        fptr = Str_Trim(fgets(line, sizeof(line), file));  /* get input line */
        !            98:             if (fptr == NULL)
        !            99:                 break;
        !           100:                }
        !           101:                while (memcmp(fptr,header,strlen(header)));
        !           102:        }
        !           103: 
        !           104:        if ( !feof(file) )
        !           105:                do
        !           106:                {
        !           107:                        fptr = Str_Trim(fgets(line, sizeof(line), file));   /* get input line */
        !           108:                        if (fptr == NULL)
        !           109:                                continue;
        !           110:                        lineno++;
        !           111:             if (fptr[0] == '#')
        !           112:                 continue;                       /* skip comments */
        !           113:             if (fptr[0] == '[')
        !           114:                 continue;                       /* skip next header */
        !           115:             tok = Str_Trim(strtok(fptr, "="));      /* get first token */
        !           116:             if (tok == NULL)
        !           117:                 continue;
        !           118:             next = Str_Trim(strtok(NULL, "="));     /* get actual config information */
        !           119:             if (next == NULL)
        !           120:                 continue;
        !           121:             for (ptr = configs; ptr->buf; ++ptr)    /* scan for token */
        !           122:             {
        !           123:                 if (!strcmp(tok, ptr->code))    /* got a match? */
        !           124:                 {
        !           125:                     count++;
        !           126:                     switch (ptr->type)      /* check type */
        !           127:                     {
        !           128:                         case Bool_Tag:
        !           129:                             if (!strcasecmp(next,"FALSE"))
        !           130:                                 *((bool *)(ptr->buf)) = false;
        !           131:                             else if (!strcasecmp(next,"TRUE"))
        !           132:                                 *((bool *)(ptr->buf)) = true;
        !           133:                             break;
        !           134: 
        !           135:                         case Char_Tag:
        !           136:                             sscanf(next, "%c", (char *)(ptr->buf));
        !           137:                             break;
        !           138: 
        !           139:                         case Short_Tag:
        !           140:                             sscanf(next, "%hd", (short *)(ptr->buf));
        !           141:                             break;
        !           142: 
        !           143:                         case Int_Tag:
        !           144:                             sscanf(next, "%d", (int *)(ptr->buf));
        !           145:                             break;
        !           146: 
        !           147:                         case Long_Tag:
        !           148:                             sscanf(next, "%ld", (long *)(ptr->buf));
        !           149:                             break;
        !           150: 
        !           151:                         case Float_Tag:
        !           152:                             sscanf(next, "%g", (float *)ptr->buf);
        !           153:                             break;
        !           154: 
        !           155:                         case Double_Tag:
        !           156:                             sscanf(next, "%lg", (double *)ptr->buf);
        !           157:                             break;
        !           158: 
        !           159:                         case String_Tag:
        !           160:                             strcpy((char *)ptr->buf, next);
        !           161:                             break;
        !           162: 
        !           163:                         case Error_Tag:
        !           164:                         default:
        !           165:                             count--;
        !           166:                             printf("Error in Config file %s on line %d\n", filename, lineno);
        !           167:                             break;
        !           168:                     }
        !           169:                                }
        !           170:                        }
        !           171:                }
        !           172:                while (fptr != NULL && fptr[0] != '[');
        !           173: 
        !           174:        fclose(file);
        !           175:        return count;
        !           176: }
        !           177: 
        !           178: 
        !           179: /**
        !           180:  *  Write out an settings line
        !           181:  */
        !           182: static int write_token(FILE *outfile, const struct Config_Tag *ptr)
        !           183: {
        !           184:        fprintf(outfile,"%s = ",ptr->code);
        !           185: 
        !           186:        switch (ptr->type)    /* check type */
        !           187:        {
        !           188:         case Bool_Tag:
        !           189:                fprintf(outfile,"%s\n", *((bool *)(ptr->buf)) ? "TRUE" : "FALSE");
        !           190:                break;
        !           191: 
        !           192:         case Char_Tag:
        !           193:                fprintf(outfile, "%c\n", *((char *)(ptr->buf)));
        !           194:                break;
        !           195: 
        !           196:         case Short_Tag:
        !           197:                fprintf(outfile, "%hd\n", *((short *)(ptr->buf)));
        !           198:                break;
        !           199: 
        !           200:         case Int_Tag:
        !           201:                fprintf(outfile, "%d\n", *((int *)(ptr->buf)));
        !           202:                break;
        !           203: 
        !           204:         case Long_Tag:
        !           205:                fprintf(outfile, "%ld\n", *((long *)(ptr->buf)));
        !           206:                break;
        !           207: 
        !           208:         case Float_Tag:
        !           209:                fprintf(outfile, "%g\n", *((float *)ptr->buf));
        !           210:                break;
        !           211: 
        !           212:         case Double_Tag:
        !           213:                fprintf(outfile, "%g\n", *((double *)ptr->buf));
        !           214:                break;
        !           215: 
        !           216:         case String_Tag:
        !           217:                fprintf(outfile, "%s\n",(char *)ptr->buf);
        !           218:                break;
        !           219: 
        !           220:         case Error_Tag:
        !           221:         default:
        !           222:                fprintf(stderr, "Error in Config structure (Contact author).\n");
        !           223:                return -1;
        !           224:        }
        !           225: 
        !           226:        return 0;
        !           227: }
        !           228: 
        !           229: 
        !           230: /**
        !           231:  * Write given section header and tokens for that
        !           232:  * Return number of written tokens
        !           233:  */
        !           234: static int write_header_tokens(FILE *fp, const struct Config_Tag *ptr, const char *header)
        !           235: {
        !           236:        int count = 0;
        !           237: 
        !           238:        if (header != NULL)
        !           239:        {
        !           240:                fprintf(fp, "%s\n", header);
        !           241:        }
        !           242: 
        !           243:        for (; ptr->buf; ++ptr)        /* scan for token */
        !           244:        {
        !           245:                if (write_token(fp, ptr) == 0)
        !           246:                        ++count;
        !           247:        }
        !           248: 
        !           249:        fprintf(fp, "\n");
        !           250: 
        !           251:        return count;
        !           252: }
        !           253: 
        !           254: 
        !           255: /**
        !           256:  * ---------------------------------------------------------------------/
        !           257:  * /   updates an input configuration (INI) file from a structure.
        !           258:  * /---------------------------------------------------------------------
        !           259:  * >>------[   update_config()  ]-------------[ 08-02-95 14:02PM ]------/
        !           260:  * / return value:
        !           261:  * /     int                     ; Number of records read & updated
        !           262:  * / parameters:
        !           263:  * /     char *filename          ; filename of INI file
        !           264:  * /     struct Config_Tag configs[]; Configuration structure
        !           265:  * /     char *header            ; INI header name (i.e. "[TEST]")
        !           266:  * /-------------------------------------------------------------------<<
        !           267:  */
        !           268: int update_config(const char *filename, const struct Config_Tag configs[], const char *header)
        !           269: {
        !           270:        const struct Config_Tag *ptr;
        !           271:        int count=0, retval;
        !           272:        FILE *cfgfile, *tempfile;
        !           273:        char *fptr, *tok;
        !           274:        char line[1024];
        !           275:        bool bUseTempCfg = false;
        !           276:        const char *sTempCfgName = "_temp_.cfg";
        !           277: 
        !           278:        cfgfile = fopen(filename, "r");
        !           279: 
        !           280:        /* If the cfg file does not yet exists, we can create it directly: */
        !           281:        if (cfgfile == NULL)
        !           282:        {
        !           283:                cfgfile = fopen(filename, "w");
        !           284:                if (cfgfile == NULL)
        !           285:                        return -1;                             /* return error designation. */
        !           286:                count = write_header_tokens(cfgfile, configs, header);
        !           287:                fclose(cfgfile);
        !           288:                return count;
        !           289:        }
        !           290: 
        !           291:        tempfile = tmpfile();                        /* Open a temporary file for output */
        !           292:        if (tempfile == NULL)
        !           293:        {
        !           294:                /* tmpfile() failed, let's try a normal open */
        !           295:                tempfile = fopen(sTempCfgName, "w+");
        !           296:                bUseTempCfg = true;
        !           297:        }
        !           298:        if (tempfile == NULL)
        !           299:        {
        !           300:                perror("update_config");
        !           301:                fclose(cfgfile);
        !           302:                return -1;                         /* return error designation. */
        !           303:        }
        !           304: 
        !           305:        if (header != NULL)
        !           306:        {
        !           307:                int headerlen = strlen(header);
        !           308:                do
        !           309:                {
        !           310:                        fptr = Str_Trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           311:                        if (fptr == NULL)
        !           312:                                break;
        !           313:                        fprintf(tempfile, "%s\n", fptr);
        !           314:                }
        !           315:                while(memcmp(fptr, header, headerlen));
        !           316:        }
        !           317: 
        !           318:        if (feof(cfgfile))
        !           319:        {
        !           320:                count += write_header_tokens(tempfile, configs, header);
        !           321:        }
        !           322:        else
        !           323:        {
        !           324:                char *savedtokenflags = NULL;   /* Array to log the saved tokens */
        !           325:                int numtokens = 0;              /* Total number of tokens to save */
        !           326: 
        !           327:                /* Find total number of tokens: */
        !           328:                for (ptr=configs; ptr->buf; ++ptr)
        !           329:                {
        !           330:                        numtokens += 1;
        !           331:                }
        !           332:                if (numtokens)
        !           333:                {
        !           334:                        savedtokenflags = malloc(numtokens * sizeof(char));
        !           335:                        if (savedtokenflags)
        !           336:                                memset(savedtokenflags, 0, numtokens * sizeof(char));
        !           337:                }
        !           338: 
        !           339:                for(;;)
        !           340:                {
        !           341:                        fptr = Str_Trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           342:             /* error or eof? */
        !           343:                        if (fptr == NULL)
        !           344:                                break;
        !           345:             if (fptr[0] == '#')
        !           346:                        {
        !           347:                 fprintf(tempfile, "%s\n", fptr);
        !           348:                                continue;                                 /* skip comments */
        !           349:                        }
        !           350:             if (fptr[0] == '[')
        !           351:                        {
        !           352:                                break;
        !           353:                        }
        !           354:             
        !           355:             tok = Str_Trim(strtok(fptr, "="));               /* get first token */
        !           356:                        if (tok != NULL)
        !           357:                        {
        !           358:                                int i = 0;
        !           359:                                for (ptr = configs; ptr->buf; ++ptr, i++) /* scan for token */
        !           360:                                {
        !           361:                                        if (!strcmp(tok, ptr->code))           /* got a match? */
        !           362:                                        {
        !           363:                                                if (write_token(tempfile, ptr) == 0)
        !           364:                                                {
        !           365:                                                        if (savedtokenflags)
        !           366:                                                                savedtokenflags[i] = true;
        !           367:                                                        count += 1;
        !           368:                                                }
        !           369:                                        }
        !           370:                                }
        !           371:                        }
        !           372:                }
        !           373: 
        !           374:                /* Write remaining (new?) tokens that were not in the configuration file, yet */
        !           375:                if (count != numtokens && savedtokenflags != NULL)
        !           376:                {
        !           377:                        int i;
        !           378:                        for (ptr = configs, i = 0; ptr->buf; ++ptr, i++)
        !           379:                        {
        !           380:                                if (!savedtokenflags[i])
        !           381:                                {
        !           382:                                        if (write_token(tempfile, ptr) == 0)
        !           383:                                        {
        !           384:                                                count += 1;
        !           385:                                                fprintf(stderr, "Wrote new token %s -> %s \n", header, ptr->code);
        !           386:                                        }
        !           387:                                }
        !           388:                        }
        !           389:                }
        !           390: 
        !           391:                if (savedtokenflags)
        !           392:                {
        !           393:                        free(savedtokenflags);
        !           394:                        savedtokenflags = NULL;
        !           395:                }
        !           396: 
        !           397:                if (!feof(cfgfile) && fptr != NULL)
        !           398:                        fprintf(tempfile, "\n%s\n", line);
        !           399: 
        !           400:                for(;;)
        !           401:                {
        !           402:                        fptr = Str_Trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           403:                        if (fptr == NULL)
        !           404:                                break;
        !           405:                        fprintf(tempfile, "%s\n", fptr);
        !           406:                }
        !           407:        }
        !           408: 
        !           409: 
        !           410:        /* Re-open the config file for writing: */
        !           411:        fclose(cfgfile);
        !           412:        cfgfile = fopen(filename, "wb");
        !           413:        if (cfgfile == NULL || fseek(tempfile, 0, SEEK_SET) != 0)
        !           414:        {
        !           415:                retval = -1;
        !           416:                goto cleanup;
        !           417:        }
        !           418: 
        !           419:        /* Now copy the temporary file to the configuration file: */
        !           420:        retval = count;
        !           421:        while(!(feof(tempfile) || ferror(cfgfile)))
        !           422:        {
        !           423:                size_t copycount;
        !           424:                copycount = fread(line, sizeof(char), sizeof(line), tempfile);
        !           425:                if (copycount == 0)
        !           426:                        break;
        !           427:                if (fwrite(line, sizeof(char), copycount, cfgfile) != copycount)
        !           428:                {
        !           429:                        retval = -1;
        !           430:                        break;
        !           431:                }
        !           432:        }
        !           433: cleanup:
        !           434:        if (cfgfile)
        !           435:        {
        !           436:                if (ferror(cfgfile))
        !           437:                        perror("update_config");
        !           438:                fclose(cfgfile);
        !           439:        }
        !           440:        if (tempfile)
        !           441:        {
        !           442:                /* tmpfile() is removed automatically on close */
        !           443:                fclose(tempfile);
        !           444:                if (bUseTempCfg)
        !           445:                        unlink(sTempCfgName);
        !           446:        }
        !           447:        return retval;
        !           448: }
        !           449: 

unix.superglobalmegacorp.com

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