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