|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.