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