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

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

unix.superglobalmegacorp.com

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