|
|
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: if (fptr == NULL) ! 99: break; ! 100: } ! 101: while (memcmp(fptr,header,strlen(header))); ! 102: } ! 103: ! 104: if ( !feof(file) ) ! 105: do ! 106: { ! 107: fptr = Str_Trim(fgets(line, sizeof(line), file)); /* get input line */ ! 108: if (fptr == NULL) ! 109: continue; ! 110: lineno++; ! 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 */ ! 122: { ! 123: if (!strcmp(tok, ptr->code)) /* got a match? */ ! 124: { ! 125: count++; ! 126: switch (ptr->type) /* check type */ ! 127: { ! 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; ! 168: } ! 169: } ! 170: } ! 171: } ! 172: while (fptr != NULL && fptr[0] != '['); ! 173: ! 174: fclose(file); ! 175: return count; ! 176: } ! 177: ! 178: ! 179: /** ! 180: * Write out an settings line ! 181: */ ! 182: static int write_token(FILE *outfile, const struct Config_Tag *ptr) ! 183: { ! 184: fprintf(outfile,"%s = ",ptr->code); ! 185: ! 186: switch (ptr->type) /* check type */ ! 187: { ! 188: case Bool_Tag: ! 189: fprintf(outfile,"%s\n", *((bool *)(ptr->buf)) ? "TRUE" : "FALSE"); ! 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: } ! 225: ! 226: return 0; ! 227: } ! 228: ! 229: ! 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: */ ! 268: int update_config(const char *filename, const struct Config_Tag configs[], const char *header) ! 269: { ! 270: const struct Config_Tag *ptr; ! 271: int count=0, retval; ! 272: FILE *cfgfile, *tempfile; ! 273: char *fptr, *tok; ! 274: char line[1024]; ! 275: bool bUseTempCfg = false; ! 276: const char *sTempCfgName = "_temp_.cfg"; ! 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. */ ! 286: count = write_header_tokens(cfgfile, configs, header); ! 287: fclose(cfgfile); ! 288: return count; ! 289: } ! 290: ! 291: tempfile = tmpfile(); /* Open a temporary file for output */ ! 292: if (tempfile == NULL) ! 293: { ! 294: /* tmpfile() failed, let's try a normal open */ ! 295: tempfile = fopen(sTempCfgName, "w+"); ! 296: bUseTempCfg = true; ! 297: } ! 298: if (tempfile == NULL) ! 299: { ! 300: perror("update_config"); ! 301: fclose(cfgfile); ! 302: return -1; /* return error designation. */ ! 303: } ! 304: ! 305: if (header != NULL) ! 306: { ! 307: int headerlen = strlen(header); ! 308: do ! 309: { ! 310: fptr = Str_Trim(fgets(line, sizeof(line), cfgfile)); /* get input line */ ! 311: if (fptr == NULL) ! 312: break; ! 313: fprintf(tempfile, "%s\n", fptr); ! 314: } ! 315: while(memcmp(fptr, header, headerlen)); ! 316: } ! 317: ! 318: if (feof(cfgfile)) ! 319: { ! 320: count += write_header_tokens(tempfile, configs, header); ! 321: } ! 322: else ! 323: { ! 324: char *savedtokenflags = NULL; /* Array to log the saved tokens */ ! 325: int numtokens = 0; /* Total number of tokens to save */ ! 326: ! 327: /* Find total number of tokens: */ ! 328: for (ptr=configs; ptr->buf; ++ptr) ! 329: { ! 330: numtokens += 1; ! 331: } ! 332: if (numtokens) ! 333: { ! 334: savedtokenflags = malloc(numtokens * sizeof(char)); ! 335: if (savedtokenflags) ! 336: memset(savedtokenflags, 0, numtokens * sizeof(char)); ! 337: } ! 338: ! 339: for(;;) ! 340: { ! 341: fptr = Str_Trim(fgets(line, sizeof(line), cfgfile)); /* get input line */ ! 342: /* error or eof? */ ! 343: if (fptr == NULL) ! 344: break; ! 345: if (fptr[0] == '#') ! 346: { ! 347: fprintf(tempfile, "%s\n", fptr); ! 348: continue; /* skip comments */ ! 349: } ! 350: if (fptr[0] == '[') ! 351: { ! 352: break; ! 353: } ! 354: ! 355: tok = Str_Trim(strtok(fptr, "=")); /* get first token */ ! 356: if (tok != NULL) ! 357: { ! 358: int i = 0; ! 359: for (ptr = configs; ptr->buf; ++ptr, i++) /* scan for token */ ! 360: { ! 361: if (!strcmp(tok, ptr->code)) /* got a match? */ ! 362: { ! 363: if (write_token(tempfile, ptr) == 0) ! 364: { ! 365: if (savedtokenflags) ! 366: savedtokenflags[i] = true; ! 367: count += 1; ! 368: } ! 369: } ! 370: } ! 371: } ! 372: } ! 373: ! 374: /* Write remaining (new?) tokens that were not in the configuration file, yet */ ! 375: if (count != numtokens && savedtokenflags != NULL) ! 376: { ! 377: int i; ! 378: for (ptr = configs, i = 0; ptr->buf; ++ptr, i++) ! 379: { ! 380: if (!savedtokenflags[i]) ! 381: { ! 382: if (write_token(tempfile, ptr) == 0) ! 383: { ! 384: count += 1; ! 385: fprintf(stderr, "Wrote new token %s -> %s \n", header, ptr->code); ! 386: } ! 387: } ! 388: } ! 389: } ! 390: ! 391: if (savedtokenflags) ! 392: { ! 393: free(savedtokenflags); ! 394: savedtokenflags = NULL; ! 395: } ! 396: ! 397: if (!feof(cfgfile) && fptr != NULL) ! 398: fprintf(tempfile, "\n%s\n", line); ! 399: ! 400: for(;;) ! 401: { ! 402: fptr = Str_Trim(fgets(line, sizeof(line), cfgfile)); /* get input line */ ! 403: if (fptr == NULL) ! 404: break; ! 405: fprintf(tempfile, "%s\n", fptr); ! 406: } ! 407: } ! 408: ! 409: ! 410: /* Re-open the config file for writing: */ ! 411: fclose(cfgfile); ! 412: cfgfile = fopen(filename, "wb"); ! 413: if (cfgfile == NULL || fseek(tempfile, 0, SEEK_SET) != 0) ! 414: { ! 415: retval = -1; ! 416: goto cleanup; ! 417: } ! 418: ! 419: /* Now copy the temporary file to the configuration file: */ ! 420: retval = count; ! 421: while(!(feof(tempfile) || ferror(cfgfile))) ! 422: { ! 423: size_t copycount; ! 424: copycount = fread(line, sizeof(char), sizeof(line), tempfile); ! 425: if (copycount == 0) ! 426: break; ! 427: if (fwrite(line, sizeof(char), copycount, cfgfile) != copycount) ! 428: { ! 429: retval = -1; ! 430: break; ! 431: } ! 432: } ! 433: cleanup: ! 434: if (cfgfile) ! 435: { ! 436: if (ferror(cfgfile)) ! 437: perror("update_config"); ! 438: fclose(cfgfile); ! 439: } ! 440: if (tempfile) ! 441: { ! 442: /* tmpfile() is removed automatically on close */ ! 443: fclose(tempfile); ! 444: if (bUseTempCfg) ! 445: unlink(sTempCfgName); ! 446: } ! 447: return retval; ! 448: } ! 449:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.