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

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

unix.superglobalmegacorp.com

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