⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 config.c

📁 著名SFC模拟器Snes9x的源代码。
💻 C
字号:
/*         ______   ___    ___  *        /\  _  \ /\_ \  /\_ \  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ *                                           /\____/ *                                           \_/__/ *      By Shawn Hargreaves, *      1 Salisbury Road, *      Market Drayton, *      Shropshire, *      England, TF9 1AJ. * *      Configuration routines. * *      See readme.txt for copyright information. */#include <stdlib.h>#include <stdio.h>#include <strings.h>#include <ctype.h>#include <dirent.h>#include <unistd.h>#include "snes9x.h"#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endiftypedef struct CONFIG_ENTRY{   char *name;                      /* variable name (NULL if comment) */   char *data;                      /* variable value */   struct CONFIG_ENTRY *next;       /* linked list */} CONFIG_ENTRY;typedef struct CONFIG{   CONFIG_ENTRY *head;              /* linked list of config entries */   char *filename;                  /* where were we loaded from? */   int dirty;                       /* has our data changed? */} CONFIG;#define MAX_CONFIGS     4static CONFIG *config[MAX_CONFIGS] = { NULL, NULL, NULL, NULL };static CONFIG *config_override = NULL;static int config_installed = FALSE;char *get_filename(char *path){    int pos;       for (pos=0; path[pos]; pos++)        ; /* do nothing */	        while ((pos>0) && (path[pos-1] != '\\') && (path[pos-1] != '/'))	pos--;    return path+pos;}long file_size (char *filename){    FILE *fs = fopen (filename, "r");    if (fs)    {	long len;		fseek (fs, 0, SEEK_END);	len = ftell (fs);	fclose (fs);	return (len);    }    return (0);}/* destroy_config: *  Destroys a config structure, writing it out to disk if the contents *  have changed. */static void destroy_config(CONFIG *cfg){   CONFIG_ENTRY *pos, *prev;   if (cfg) {      if (cfg->filename) {	 if (cfg->dirty) {	    /* write changed data to disk */	    FILE *f = fopen(cfg->filename, "w");	    if (f) {	       pos = cfg->head;	       while (pos) {		  if (pos->name) {		     fputs(pos->name, f);		     if (pos->name[0] != '[')			fputs(" = ", f);		  }		  if (pos->data)		     fputs(pos->data, f);		  fputs("\n", f);		  pos = pos->next;	       }	       fclose(f);	    }	 }	 free(cfg->filename);      }      /* destroy the variable list */      pos = cfg->head;      while (pos) {	 prev = pos;	 pos = pos->next;	 if (prev->name)	    free(prev->name);	 if (prev->data)	    free(prev->data);	 free(prev);      }      free(cfg);   }}/* config_cleanup: *  Called at shutdown time to free memory being used by the config routines, *  and write any changed data out to disk. */static void config_cleanup(){   int i;   for (i=0; i<MAX_CONFIGS; i++) {      if (config[i]) {	 destroy_config(config[i]);	 config[i] = NULL;      }   }   if (config_override) {      destroy_config(config_override);      config_override = NULL;   }/*   _remove_exit_func(config_cleanup);*/   config_installed = FALSE;}/* init_config: *  Sets up the configuration routines ready for use, also loading the *  default config file if the loaddata flag is set and no other config *  file is in memory. */static void init_config(int loaddata){#if 0   char buf[4][1025];   char *s;   int i;   if (!config_installed) {/*      _add_exit_func(config_cleanup);*/      config_installed = TRUE;   }   if ((loaddata) && (!config[0])) {      /* look for allegro.cfg in the same directory as the program */      strcpy(buf[0], __crt0_argv[0]);      strlwr(buf[0]);      *get_filename(buf[0]) = 0;      put_backslash(buf[0]);      strcat(buf[0], "allegro.cfg");      /* if that fails, try sound.cfg */      strcpy(buf[1], __crt0_argv[0]);      strlwr(buf[1]);      *get_filename(buf[1]) = 0;      put_backslash(buf[1]);      strcat(buf[1], "sound.cfg");      /* no luck? try the ALLEGRO enviroment variable... */      s = getenv("ALLEGRO");      if (s) {	 strcpy(buf[2], s);	 strlwr(buf[2]);	 put_backslash(buf[2]);	 strcat(buf[2], "allegro.cfg");	 strcpy(buf[3], s);	 strlwr(buf[3]);	 put_backslash(buf[3]);	 strcat(buf[3], "sound.cfg");      }      else {	 strcpy(buf[2], buf[0]);	 strcpy(buf[3], buf[1]);      }      /* see which of these files actually exist */      for (i=0; i<4; i++) {	 if (access (buf[i], R_OK)) {	    set_config_file(buf[i]);	    break;	 }      }      if (i >= 4)	 set_config_file(buf[0]);   }#endif   }/* get_line:  *  Helper for splitting files up into individual lines. */static int get_line(char *data, int length, char *name, char *val){   char buf[256], buf2[256];   int pos, i, j;   for (pos=0; (pos<length) && (pos<255); pos++) {      if ((data[pos] == '\r') || (data[pos] == '\n')) {	 buf[pos] = 0;	 if ((pos < length-1) && 	     (((data[pos] == '\r') && (data[pos+1] == '\n')) ||	      ((data[pos] == '\n') && (data[pos+1] == '\r')))) {	    pos++;	 }	 pos++;	 break;      }      buf[pos] = data[pos];   }   buf[MIN(pos,255)] = 0;   /* skip leading spaces */   i = 0;   while ((buf[i]) && (isspace(buf[i])))      i++;   /* read name string */   j = 0;   while ((buf[i]) && (!isspace(buf[i])) && (buf[i] != '=') && (buf[i] != '#'))      buf2[j++] = buf[i++];   if (j) {      /* got a variable */      buf2[j] = 0;      strcpy(name, buf2);      while ((buf[i]) && ((isspace(buf[i])) || (buf[i] == '=')))	 i++;      strcpy(val, buf+i);      /* strip trailing spaces */      i = strlen(val) - 1;      while ((i >= 0) && (isspace(val[i])))	 val[i--] = 0;   }   else {      /* blank line or comment */      name[0] = 0;      strcpy(val, buf);   }   return pos;}/* set_config: *  Does the work of setting up a config structure. */static void set_config(CONFIG **config, char *data, int length, char *filename){   char name[256];   char val[256];   CONFIG_ENTRY **prev, *p;   int pos;   init_config(FALSE);   if (*config) {      destroy_config(*config);      *config = NULL;   }   *config = (CONFIG *) malloc(sizeof(CONFIG));   (*config)->head = NULL;   (*config)->dirty = FALSE;   if (filename) {      (*config)->filename = (char *) malloc(strlen(filename)+1);      strcpy((*config)->filename, filename);    }   else      (*config)->filename = NULL;   prev = &(*config)->head;   pos = 0;   while (pos < length) {      pos += get_line(data+pos, length-pos, name, val);      p = (CONFIG_ENTRY *) malloc(sizeof(CONFIG_ENTRY));      if (name[0]) {	 p->name = (char *) malloc(strlen(name)+1);	 strcpy(p->name, name);      }      else	 p->name = NULL;      p->data = (char *) malloc(strlen(val)+1);      strcpy(p->data, val);      p->next = NULL;      *prev = p;      prev = &p->next;   }}/* load_config_file: *  Does the work of loading a config file. */static void load_config_file(CONFIG **config, char *filename, char *savefile){   int length = file_size(filename);   if (length > 0) {      FILE *f = fopen(filename, "r");      if (f) {	 char *tmp = (char *) malloc(length);	 fread(tmp, 1, length, f);	 fclose(f);	 set_config(config, tmp, length, savefile);	 free(tmp);      }      else	 set_config(config, NULL, 0, savefile);   }   else      set_config(config, NULL, 0, savefile);}/* set_config_file: *  Sets the file to be used for all future configuration operations. */void set_config_file(char *filename){   load_config_file(&config[0], filename, filename);}/* set_config_data: *  Sets the block of data to be used for all future configuration  *  operations. */void set_config_data(char *data, int length){   set_config(&config[0], data, length, NULL);}/* override_config_file: *  Sets the file that will override all future configuration operations. */void override_config_file(char *filename){   load_config_file(&config_override, filename, NULL);}/* override_config_data: *  Sets the block of data that will override all future configuration  *  operations. */void override_config_data(char *data, int length){   set_config(&config_override, data, length, NULL);}/* push_config_state: *  Pushes the current config state onto the stack. */void push_config_state(){   int i;   if (config[MAX_CONFIGS-1])      destroy_config(config[MAX_CONFIGS-1]);   for (i=MAX_CONFIGS-1; i>0; i--)      config[i] = config[i-1];   config[0] = NULL;}/* pop_config_state: *  Pops the current config state off the stack. */void pop_config_state(){   int i;   if (config[0])      destroy_config(config[0]);   for (i=0; i<MAX_CONFIGS-1; i++)      config[i] = config[i+1];   config[MAX_CONFIGS-1] = NULL;}/* prettify_section_name: *  Helper for ensuring that a section name is enclosed by [ ] braces. */static void prettify_section_name(char *in, char *out){   if (in) {      if (in[0] != '[')	 strcpy(out, "[");      else	 out[0] = 0;      strcat(out, in);      if (out[strlen(out)-1] != ']')	 strcat(out, "]");   }   else      out[0] = 0;}/* find_config_string: *  Helper for finding an entry in the configuration file. */static CONFIG_ENTRY *find_config_string(CONFIG *config, char *section, char *name, CONFIG_ENTRY **prev){   CONFIG_ENTRY *p;   int in_section = TRUE;   char section_name[256];   prettify_section_name(section, section_name);   if (config) {      p = config->head;      if (prev)	 *prev = NULL;      while (p) {	 if (p->name) {	    if ((p->name[0] == '[') && (p->name[strlen(p->name)-1] == ']')) {	       /* change section */	       in_section = (strcasecmp(section_name, p->name) == 0);	    }	    if ((in_section) || (name[0] == '[')) {	       /* is this the one? */	       if (strcasecmp(p->name, name) == 0)		  return p;	    }	 }	 if (prev)	    *prev = p;	 p = p->next;      }   }   return NULL;}/* get_config_string: *  Reads a string from the configuration file. */char *get_config_string(char *section, char *name, char *def){   CONFIG_ENTRY *p;   init_config(TRUE);   p = find_config_string(config_override, section, name, NULL);   if (!p)      p = find_config_string(config[0], section, name, NULL);   if (p)      return (p->data ? p->data : "");   else      return def;}/* get_config_int: *  Reads an integer from the configuration file. */int get_config_int(char *section, char *name, int def){   char *s = get_config_string(section, name, NULL);   if ((s) && (*s))      return strtol(s, NULL, 0);   return def;}/* get_config_hex: *  Reads a hexadecimal integer from the configuration file. */int get_config_hex(char *section, char *name, int def){   char *s = get_config_string(section, name, NULL);   int i;   if ((s) && (*s)) {      i = strtol(s, NULL, 16);      if ((i == 0x7FFFFFFF) && (strcasecmp(s, "7FFFFFFF") != 0))	 i = -1;      return i;   }   return def;}/* get_config_float: *  Reads a float from the configuration file. */float get_config_float(char *section, char *name, float def){   char *s = get_config_string(section, name, NULL);   if ((s) && (*s))      return atof(s);   return def;}/* get_config_argv: *  Reads an argc/argv style token list from the configuration file. */char **get_config_argv(char *section, char *name, int *argc){   #define MAX_ARGV  16   static char buf[256];   static char *argv[MAX_ARGV];   int pos, ac;   char *s = get_config_string(section, name, NULL);   if (!s) {      *argc = 0;      return NULL;   }   strcpy(buf, s);   pos = 0;   ac = 0;   while ((ac<MAX_ARGV) && (buf[pos]) && (buf[pos] != '#')) {      while ((buf[pos]) && (isspace(buf[pos])))	 pos++;      if ((buf[pos]) && (buf[pos] != '#')) {	 argv[ac++] = buf+pos;	 while ((buf[pos]) && (!isspace(buf[pos])))	    pos++;	 if (buf[pos])	    buf[pos++] = 0;      }   }   *argc = ac;   return argv;}/* insert_variable: *  Helper for inserting a new variable into a configuration file. */static CONFIG_ENTRY *insert_variable(CONFIG_ENTRY *p, char *name, char *data){   CONFIG_ENTRY *n = (CONFIG_ENTRY *) malloc(sizeof(CONFIG_ENTRY));   if (name) {      n->name = (char *) malloc(strlen(name)+1);      strcpy(n->name, name);   }   else      n->name = NULL;   if (data) {      n->data = (char *) malloc(strlen(data)+1);      strcpy(n->data, data);   }   else      n->data = NULL;   if (p) {      n->next = p->next;      p->next = n;    }   else {      n->next = NULL;      config[0]->head = n;   }   return n;}/* set_config_string: *  Writes a string to the configuration file. */void set_config_string(char *section, char *name, char *val){   CONFIG_ENTRY *p, *prev;   char section_name[256];   init_config(TRUE);   if (config[0]) {      p = find_config_string(config[0], section, name, &prev);      if (p) {	 if ((val) && (*val)) {	    /* modify existing variable */	    if (p->data)	       free(p->data);	    p->data = (char *) malloc(strlen(val)+1);	    strcpy(p->data, val);	 }	 else {	    /* delete variable */	    if (p->name)	       free(p->name);	    if (p->data)	       free(p->data);	    if (prev)	       prev->next = p->next;	    else	       config[0]->head = p->next;	    free(p);	 }      }      else {	 if ((val) && (*val)) {	    /* add a new variable */	    prettify_section_name(section, section_name);	    if (section_name[0]) {	       p = find_config_string(config[0], NULL, section_name, &prev);	       if (!p) {		  /* create a new section */		  p = config[0]->head;		  while ((p) && (p->next))		     p = p->next;		  if ((p) && (p->data) && (*p->data))		     p = insert_variable(p, NULL, NULL);		  p = insert_variable(p, section_name, NULL);	       }	       /* append to the end of the section */	       while ((p) && (p->next) && 		      (((p->next->name) && (*p->next->name)) || 		       ((p->next->data) && (*p->next->data))))		  p = p->next;	       p = insert_variable(p, name, val);	    }	    else {	       /* global variable */	       p = config[0]->head;	       insert_variable(NULL, name, val);	       config[0]->head->next = p;	    }	 }       }      config[0]->dirty = TRUE;   }}/* set_config_int: *  Writes an integer to the configuration file. */void set_config_int(char *section, char *name, int val){   char buf[32];   sprintf(buf, "%d", val);   set_config_string(section, name, buf);}/* set_config_hex: *  Writes a hexadecimal integer to the configuration file. */void set_config_hex(char *section, char *name, int val){   if (val >= 0) {      char buf[32];      sprintf(buf, "%X", val);      set_config_string(section, name, buf);   }   else      set_config_string(section, name, "-1");}/* set_config_float: *  Writes a float to the configuration file. */void set_config_float(char *section, char *name, float val){   char buf[32];   sprintf(buf, "%f", val);   set_config_string(section, name, buf);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -