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