|
|
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.