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

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

unix.superglobalmegacorp.com

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