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