Annotation of hatari/src/cfgopts.c, revision 1.1.1.3

1.1.1.2   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: /---------------------------------------------------------------------*/
1.1.1.3 ! root       57: char CfgOpts_rcsid[] = "Hatari $Id: cfgopts.c,v 1.7 2005/06/05 14:19:39 thothy Exp $";
1.1.1.2   root       58: 
                     59: #include <stdio.h>
                     60: #include <stdlib.h>
                     61: #include <string.h>
                     62: 
                     63: #include "main.h"
                     64: #include "cfgopts.h"
                     65: 
                     66: 
                     67: 
                     68: /* --- Remove spaces from beginning and end of a string --- */
                     69: static char *trim(char *buffer)
                     70: {
1.1.1.3 ! root       71:        const char SPACE = ' ';
        !            72:        const char TABULA = '\t';
1.1.1.2   root       73: 
1.1.1.3 ! root       74:        if (buffer != NULL)
        !            75:        {
        !            76:                int i, linelen;
        !            77: 
        !            78:                linelen = strlen(buffer);
        !            79: 
        !            80:                for (i = 0; i < linelen; i++)
        !            81:                {
        !            82:                        if (buffer[i] != SPACE && buffer[i] != TABULA)
        !            83:                                break;
        !            84:                }
        !            85: 
        !            86:                if (i > 0 && i < linelen)
        !            87:                {
        !            88:                        linelen -= i;
        !            89:                        memmove(buffer, buffer + i, linelen);
        !            90:                }
        !            91: 
        !            92:                for (i = linelen; i > 0; i--)
        !            93:                {
        !            94:                        int j = i - 1;
        !            95:                        if (buffer[j] != SPACE && buffer[j] != TABULA)
        !            96:                                break;
        !            97:                }
1.1.1.2   root       98: 
1.1.1.3 ! root       99:                buffer[i] = '\0';
        !           100:        }
1.1.1.2   root      101: 
1.1.1.3 ! root      102:        return buffer;
1.1.1.2   root      103: }
                    104: 
                    105: 
                    106: /*---------------------------------------------------------------------/
                    107: /   reads from an input configuration (INI) file.
                    108: /---------------------------------------------------------------------*/
                    109: /*>>------[   input_config()   ]-------------[ 08-02-95 14:02PM ]------/
                    110: / return value:
                    111: /     int                     ; number of records read or -1 on error
                    112: / parameters:
                    113: /     char *filename          ; filename of INI style file
                    114: /     struct Config_Tag configs[]; Configuration structure
                    115: /     char *header            ; INI header name (i.e. "[TEST]")
                    116: /-------------------------------------------------------------------<<*/
1.1.1.3 ! root      117: int input_config(const char *filename, const struct Config_Tag configs[], const char *header)
1.1.1.2   root      118: {
1.1.1.3 ! root      119:        const struct Config_Tag *ptr;
        !           120:        int count=0, lineno=0;
        !           121:        FILE *file;
        !           122:        char *fptr,*tok,*next;
        !           123:        char line[1024];
        !           124: 
        !           125:        file = fopen(filename,"r");
        !           126:        if (file == NULL)
        !           127:                return -1;                 /* return error designation. */
        !           128: 
        !           129:        if (header != NULL)
        !           130:        {
        !           131:                do
        !           132:                {
        !           133:                        fptr = trim(fgets(line, sizeof(line), file));  /* get input line */
        !           134:                }
        !           135:                while ( memcmp(line,header,strlen(header)) && !feof(file));
        !           136:        }
        !           137: 
        !           138:        if ( !feof(file) )
        !           139:                do
        !           140:                {
        !           141:                        fptr = trim(fgets(line, sizeof(line), file));   /* get input line */
        !           142:                        if (fptr == NULL)
        !           143:                                continue;
        !           144:                        lineno++;
        !           145:                        if (line[0] == '#')
        !           146:                                continue;                               /* skip comments */
        !           147:                        if (line[0] == '[')
        !           148:                                continue;                               /* skip next header */
        !           149:                        tok = trim(strtok(line, "=\n\r"));          /* get first token */
        !           150:                        if (tok != NULL)
        !           151:                        {
        !           152:                                next = trim(strtok(NULL, "=\n\r"));     /* get actual config information */
        !           153:                                for (ptr = configs; ptr->buf; ++ptr)    /* scan for token */
        !           154:                                {
        !           155:                                        if (!strcmp(tok, ptr->code))        /* got a match? */
        !           156:                                        {
        !           157:                                                switch (ptr->type)              /* check type */
        !           158:                                                {
        !           159:                                                 case Bool_Tag:
        !           160:                                                        if (!strcasecmp(next,"FALSE"))
        !           161:                                                                *((BOOL *)(ptr->buf)) = FALSE;
        !           162:                                                        else if (!strcasecmp(next,"TRUE"))
        !           163:                                                                *((BOOL *)(ptr->buf)) = TRUE;
        !           164:                                                        ++count;
        !           165:                                                        break;
        !           166: 
        !           167:                                                 case Char_Tag:
        !           168:                                                        sscanf(next, "%c", (char *)(ptr->buf));
        !           169:                                                        ++count;
        !           170:                                                        break;
        !           171: 
        !           172:                                                 case Short_Tag:
        !           173:                                                        sscanf(next, "%hd", (short *)(ptr->buf));
        !           174:                                                        ++count;
        !           175:                                                        break;
        !           176: 
        !           177:                                                 case Int_Tag:
        !           178:                                                        sscanf(next, "%d", (int *)(ptr->buf));
        !           179:                                                        ++count;
        !           180:                                                        break;
        !           181: 
        !           182:                                                 case Long_Tag:
        !           183:                                                        sscanf(next, "%ld", (long *)(ptr->buf));
        !           184:                                                        ++count;
        !           185:                                                        break;
        !           186: 
        !           187:                                                 case Float_Tag:
        !           188:                                                        sscanf(next, "%g", (float *)ptr->buf);
        !           189:                                                        ++count;
        !           190:                                                        break;
        !           191: 
        !           192:                                                 case Double_Tag:
        !           193:                                                        sscanf(next, "%lg", (double *)ptr->buf);
        !           194:                                                        ++count;
        !           195:                                                        break;
        !           196: 
        !           197:                                                 case String_Tag:
        !           198:                                                        if(next)
        !           199:                                                                strcpy((char *)ptr->buf, next);
        !           200:                                                        else
        !           201:                                                                *(char *)ptr->buf = 0;
        !           202:                                                        ++count;
        !           203:                                                        break;
        !           204: 
        !           205:                                                 case Error_Tag:
        !           206:                                                 default:
        !           207:                                                        printf("Error in Config file %s on line %d\n", filename, lineno);
        !           208:                                                        break;
        !           209:                                                }
        !           210:                                        }
        !           211: 
        !           212:                                }
        !           213:                        }
        !           214:                }
        !           215:                while ( fptr!=NULL && line[0]!='[');
1.1.1.2   root      216: 
1.1.1.3 ! root      217:        fclose(file);
        !           218:        return count;
1.1.1.2   root      219: }
                    220: 
                    221: 
                    222: /* Write out an settings line */
1.1.1.3 ! root      223: static int write_token(FILE *outfile, const struct Config_Tag *ptr)
1.1.1.2   root      224: {
1.1.1.3 ! root      225:        fprintf(outfile,"%s = ",ptr->code);
1.1.1.2   root      226: 
1.1.1.3 ! root      227:        switch (ptr->type)    /* check type */
        !           228:        {
        !           229:         case Bool_Tag:
        !           230:                fprintf(outfile,"%s\n", *((BOOL *)(ptr->buf)) ? "TRUE" : "FALSE");
        !           231:                break;
        !           232: 
        !           233:         case Char_Tag:
        !           234:                fprintf(outfile, "%c\n", *((char *)(ptr->buf)));
        !           235:                break;
        !           236: 
        !           237:         case Short_Tag:
        !           238:                fprintf(outfile, "%hd\n", *((short *)(ptr->buf)));
        !           239:                break;
        !           240: 
        !           241:         case Int_Tag:
        !           242:                fprintf(outfile, "%d\n", *((int *)(ptr->buf)));
        !           243:                break;
        !           244: 
        !           245:         case Long_Tag:
        !           246:                fprintf(outfile, "%ld\n", *((long *)(ptr->buf)));
        !           247:                break;
        !           248: 
        !           249:         case Float_Tag:
        !           250:                fprintf(outfile, "%g\n", *((float *)ptr->buf));
        !           251:                break;
        !           252: 
        !           253:         case Double_Tag:
        !           254:                fprintf(outfile, "%g\n", *((double *)ptr->buf));
        !           255:                break;
        !           256: 
        !           257:         case String_Tag:
        !           258:                fprintf(outfile, "%s\n",(char *)ptr->buf);
        !           259:                break;
        !           260: 
        !           261:         case Error_Tag:
        !           262:         default:
        !           263:                fprintf(stderr, "Error in Config structure (Contact author).\n");
        !           264:                return -1;
        !           265:        }
1.1.1.2   root      266: 
1.1.1.3 ! root      267:        return 0;
1.1.1.2   root      268: }
                    269: 
                    270: 
                    271: /*---------------------------------------------------------------------/
                    272: /   updates an input configuration (INI) file from a structure.
                    273: /---------------------------------------------------------------------*/
                    274: /*>>------[   update_config()  ]-------------[ 08-02-95 14:02PM ]------/
                    275: / return value:
                    276: /     int                     ; Number of records read & updated
                    277: / parameters:
                    278: /     char *filename          ; filename of INI file
                    279: /     struct Config_Tag configs[]; Configuration structure
                    280: /     char *header            ; INI header name (i.e. "[TEST]")
                    281: /-------------------------------------------------------------------<<*/
1.1.1.3 ! root      282: int update_config(const char *filename, const struct Config_Tag configs[], const char *header)
1.1.1.2   root      283: {
1.1.1.3 ! root      284:        const struct Config_Tag *ptr;
        !           285:        int count=0, lineno=0;
        !           286:        FILE *cfgfile, *tempfile;
        !           287:        char *fptr, *tok, *next;
        !           288:        char line[1024];
        !           289: 
        !           290:        cfgfile = fopen(filename, "r");
        !           291: 
        !           292:        /* If the cfg file does not yet exists, we can create it directly: */
        !           293:        if (cfgfile == NULL)
        !           294:        {
        !           295:                cfgfile = fopen(filename, "w");
        !           296:                if (cfgfile == NULL)
        !           297:                        return -1;                             /* return error designation. */
        !           298:                if (header != NULL)
        !           299:                {
        !           300:                        fprintf(cfgfile,"%s\n",header);
        !           301:                }
        !           302:                for (ptr=configs; ptr->buf; ++ptr)        /* scan for token */
        !           303:                {
        !           304:                        if (write_token(cfgfile, ptr) == 0)
        !           305:                                ++count;
        !           306:                }
        !           307: 
        !           308:                fclose(cfgfile);
        !           309:                return count;
        !           310:        }
        !           311: 
        !           312:        tempfile = tmpfile();                        /* Open a temporary file for output */
        !           313:        if (tempfile == NULL)
        !           314:        {
        !           315:                fclose(cfgfile);
        !           316:                return -1;                                /* return error designation. */
        !           317:        }
        !           318: 
        !           319:        if (header != NULL)
        !           320:        {
        !           321:                do
        !           322:                {
        !           323:                        fptr = trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           324:                        if (feof(cfgfile))
        !           325:                                break;
        !           326:                        fprintf(tempfile, "%s", line);
        !           327:                }
        !           328:                while(memcmp(line, header, strlen(header)));
        !           329:        }
        !           330: 
        !           331:        if (feof(cfgfile))
        !           332:        {
        !           333:                if (header != NULL)
        !           334:                {
        !           335:                        fprintf(tempfile, "\n%s\n", header);
        !           336:                }
        !           337:                for (ptr = configs; ptr->buf; ++ptr)                /* scan for token */
        !           338:                {
        !           339:                        if (write_token(tempfile, ptr) == 0)
        !           340:                                ++count;
        !           341:                }
        !           342:        }
        !           343:        else
        !           344:        {
        !           345:                char *savedtokenflags;            /* Array to log the saved tokens */
        !           346:                int numtokens;                    /* Total number of tokens to save */
        !           347: 
        !           348:                /* Find total number of tokens: */
        !           349:                numtokens = 0;
        !           350:                for (ptr=configs; ptr->buf; ++ptr)
        !           351:                {
        !           352:                        numtokens += 1;
        !           353:                }
        !           354: 
        !           355:                savedtokenflags = malloc(numtokens * sizeof(char));
        !           356:                if (savedtokenflags)
        !           357:                        memset(savedtokenflags, 0, numtokens * sizeof(char));
        !           358: 
        !           359:                for(;;)
        !           360:                {
        !           361:                        fptr = trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           362:                        if (fptr == NULL)
        !           363:                                break;
        !           364:                        lineno++;
        !           365:                        if (line[0] == '#')
        !           366:                        {
        !           367:                                fprintf(tempfile, "%s", line);
        !           368:                                continue;                                 /* skip comments */
        !           369:                        }
        !           370:                        if (line[0] == '[' || feof(cfgfile))
        !           371:                        {
        !           372:                                break;
        !           373:                        }
        !           374: 
        !           375:                        tok = trim(strtok(line, "=\n\r"));           /* get first token */
        !           376:                        if (tok != NULL)
        !           377:                        {
        !           378:                                int i = 0;
        !           379:                                next = strtok(line, "=\n\r");             /* get actual config information */
        !           380:                                for (ptr = configs; ptr->buf; ++ptr, i++) /* scan for token */
        !           381:                                {
        !           382:                                        if (!strcmp(tok, ptr->code))           /* got a match? */
        !           383:                                        {
        !           384:                                                if (write_token(tempfile, ptr) == 0)
        !           385:                                                {
        !           386:                                                        if (savedtokenflags)
        !           387:                                                                savedtokenflags[i] = TRUE;
        !           388:                                                        count += 1;
        !           389:                                                }
        !           390:                                        }
        !           391:                                }
        !           392:                        }
        !           393:                }
        !           394: 
        !           395:                /* Write remaining (new?) tokens that were not in the configuration file, yet */
        !           396:                if (count != numtokens && savedtokenflags != NULL)
        !           397:                {
        !           398:                        int i;
        !           399:                        for (ptr = configs, i = 0; ptr->buf; ++ptr, i++)
        !           400:                        {
        !           401:                                if (!savedtokenflags[i])
        !           402:                                {
        !           403:                                        if (write_token(tempfile, ptr) == 0)
        !           404:                                        {
        !           405:                                                count += 1;
        !           406:                                                fprintf(stderr, "Wrote new token %s -> %s \n", header, ptr->code);
        !           407:                                        }
        !           408:                                }
        !           409:                        }
        !           410:                }
        !           411: 
        !           412:                if (savedtokenflags)
        !           413:                        free(savedtokenflags);
        !           414:                savedtokenflags = NULL;
        !           415: 
        !           416:                if (!feof(cfgfile) && fptr != NULL)
        !           417:                        fprintf(tempfile, "\n%s", line);
        !           418: 
        !           419:                for(;;)
        !           420:                {
        !           421:                        fptr = trim(fgets(line, sizeof(line), cfgfile));  /* get input line */
        !           422:                        if (feof(cfgfile))
        !           423:                                break;
        !           424:                        fprintf(tempfile, "%s", line);
        !           425:                }
        !           426:        }
        !           427: 
        !           428: 
        !           429:        /* Re-open the config file for writing: */
        !           430:        fclose(cfgfile);
        !           431:        cfgfile = fopen(filename, "wb");
        !           432:        if (cfgfile == NULL)
        !           433:        {
        !           434:                fclose(tempfile);
        !           435:                return -1;
        !           436:        }
        !           437: 
        !           438:        if (fseek(tempfile, 0, SEEK_SET) != 0)
        !           439:        {
        !           440:                fclose(cfgfile);
        !           441:                fclose(tempfile);
        !           442:                return -1;
        !           443:        }
        !           444: 
        !           445:        /* Now copy the temporary file to the configuration file: */
        !           446:        while(!feof(tempfile))
        !           447:        {
        !           448:                size_t copycount;
        !           449:                copycount = fread(line, sizeof(char), sizeof(line), tempfile);
        !           450:                if (fwrite(line, sizeof(char), copycount, cfgfile) != copycount)
        !           451:                {
        !           452:                        fclose(cfgfile);
        !           453:                        fclose(tempfile);
        !           454:                        return -1;
        !           455:                }
        !           456:        }
        !           457: 
        !           458:        fclose(cfgfile);
        !           459:        fclose(tempfile);
        !           460:        return count;
1.1.1.2   root      461: }
                    462: 

unix.superglobalmegacorp.com

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