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