src/settings.cpp
changeset 5838 9c3129cb019b
parent 5835 e0ff603ae0b7
child 5852 cb3f71b16e1a
equal deleted inserted replaced
5837:96b4b92b86ae 5838:9c3129cb019b
    38 #include "newgrf.h"
    38 #include "newgrf.h"
    39 #include "newgrf_config.h"
    39 #include "newgrf_config.h"
    40 #include "genworld.h"
    40 #include "genworld.h"
    41 #include "date.h"
    41 #include "date.h"
    42 #include "rail.h"
    42 #include "rail.h"
       
    43 #include "helpers.hpp"
    43 #ifdef WITH_FREETYPE
    44 #ifdef WITH_FREETYPE
    44 #include "gfx.h"
    45 #include "gfx.h"
    45 #include "fontcache.h"
    46 #include "fontcache.h"
    46 #endif
    47 #endif
    47 
    48 
    72 static SettingsMemoryPool *pool_new(uint minsize)
    73 static SettingsMemoryPool *pool_new(uint minsize)
    73 {
    74 {
    74 	SettingsMemoryPool *p;
    75 	SettingsMemoryPool *p;
    75 	if (minsize < 4096 - 12) minsize = 4096 - 12;
    76 	if (minsize < 4096 - 12) minsize = 4096 - 12;
    76 
    77 
    77 	p = malloc(sizeof(SettingsMemoryPool) - 1 + minsize);
    78 	p = (SettingsMemoryPool*)malloc(sizeof(SettingsMemoryPool) - 1 + minsize);
    78 	p->pos = 0;
    79 	p->pos = 0;
    79 	p->size = minsize;
    80 	p->size = minsize;
    80 	p->next = NULL;
    81 	p->next = NULL;
    81 	return p;
    82 	return p;
    82 }
    83 }
   109 	return p->mem + pos;
   110 	return p->mem + pos;
   110 }
   111 }
   111 
   112 
   112 static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size)
   113 static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size)
   113 {
   114 {
   114 	byte *p = pool_alloc(pool, size + 1);
   115 	byte *p = (byte*)pool_alloc(pool, size + 1);
   115 	p[size] = 0;
   116 	p[size] = 0;
   116 	memcpy(p, mem, size);
   117 	memcpy(p, mem, size);
   117 	return p;
   118 	return p;
   118 }
   119 }
   119 
   120 
   166 }
   167 }
   167 
   168 
   168 // allocate an ini group object
   169 // allocate an ini group object
   169 static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
   170 static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
   170 {
   171 {
   171 	IniGroup *grp = pool_alloc(&ini->pool, sizeof(IniGroup));
   172 	IniGroup *grp = (IniGroup*)pool_alloc(&ini->pool, sizeof(IniGroup));
   172 	grp->ini = ini;
   173 	grp->ini = ini;
   173 	grp->name = pool_strdup(&ini->pool, grpt, len);
   174 	grp->name = (char*)pool_strdup(&ini->pool, grpt, len);
   174 	if (!strcmp(grp->name, "newgrf") || !strcmp(grp->name, "servers") || !strcmp(grp->name, "bans")) {
   175 	if (!strcmp(grp->name, "newgrf") || !strcmp(grp->name, "servers") || !strcmp(grp->name, "bans")) {
   175 		grp->type = IGT_LIST;
   176 		grp->type = IGT_LIST;
   176 	} else {
   177 	} else {
   177 		grp->type = IGT_VARIABLES;
   178 		grp->type = IGT_VARIABLES;
   178 	}
   179 	}
   185 	return grp;
   186 	return grp;
   186 }
   187 }
   187 
   188 
   188 static IniItem *ini_item_alloc(IniGroup *group, const char *name, int len)
   189 static IniItem *ini_item_alloc(IniGroup *group, const char *name, int len)
   189 {
   190 {
   190 	IniItem *item = pool_alloc(&group->ini->pool, sizeof(IniItem));
   191 	IniItem *item = (IniItem*)pool_alloc(&group->ini->pool, sizeof(IniItem));
   191 	item->name = pool_strdup(&group->ini->pool, name, len);
   192 	item->name = (char*)pool_strdup(&group->ini->pool, name, len);
   192 	item->next = NULL;
   193 	item->next = NULL;
   193 	item->comment = NULL;
   194 	item->comment = NULL;
   194 	item->value = NULL;
   195 	item->value = NULL;
   195 	*group->last_item = item;
   196 	*group->last_item = item;
   196 	group->last_item = &item->next;
   197 	group->last_item = &item->next;
   233 			uint pos;
   234 			uint pos;
   234 			// add to comment
   235 			// add to comment
   235 			if (ns > a) {
   236 			if (ns > a) {
   236 				a = max(a, 128);
   237 				a = max(a, 128);
   237 				do a*=2; while (a < ns);
   238 				do a*=2; while (a < ns);
   238 				comment = realloc(comment, comment_alloc = a);
   239 				ReallocT(&comment, comment_alloc = a);
   239 			}
   240 			}
   240 			pos = comment_size;
   241 			pos = comment_size;
   241 			comment_size += (e - s + 1);
   242 			comment_size += (e - s + 1);
   242 			comment[pos + e - s] = '\n'; // comment newline
   243 			comment[pos + e - s] = '\n'; // comment newline
   243 			memcpy(comment + pos, s, e - s); // copy comment contents
   244 			memcpy(comment + pos, s, e - s); // copy comment contents
   252 				e--;
   253 				e--;
   253 			}
   254 			}
   254 			s++; // skip [
   255 			s++; // skip [
   255 			group = ini_group_alloc(ini, s, e - s);
   256 			group = ini_group_alloc(ini, s, e - s);
   256 			if (comment_size) {
   257 			if (comment_size) {
   257 				group->comment = pool_strdup(&ini->pool, comment, comment_size);
   258 				group->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   258 				comment_size = 0;
   259 				comment_size = 0;
   259 			}
   260 			}
   260 		} else if (group) {
   261 		} else if (group) {
   261 			// find end of keyname
   262 			// find end of keyname
   262 			for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
   263 			for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
   263 
   264 
   264 			// it's an item in an existing group
   265 			// it's an item in an existing group
   265 			item = ini_item_alloc(group, s, t-s);
   266 			item = ini_item_alloc(group, s, t-s);
   266 			if (comment_size) {
   267 			if (comment_size) {
   267 				item->comment = pool_strdup(&ini->pool, comment, comment_size);
   268 				item->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   268 				comment_size = 0;
   269 				comment_size = 0;
   269 			}
   270 			}
   270 
   271 
   271 			// find start of parameter
   272 			// find start of parameter
   272 			while (*t == '=' || *t == ' ' || *t == '\t') t++;
   273 			while (*t == '=' || *t == ' ' || *t == '\t') t++;
   277 			// remove ending quotation marks
   278 			// remove ending quotation marks
   278 			e = t + strlen(t);
   279 			e = t + strlen(t);
   279 			if (e > t && e[-1] == '\"') e--;
   280 			if (e > t && e[-1] == '\"') e--;
   280 			*e = '\0';
   281 			*e = '\0';
   281 
   282 
   282 			item->value = pool_strdup(&ini->pool, t, e - t);
   283 			item->value = (char*)pool_strdup(&ini->pool, t, e - t);
   283 		} else {
   284 		} else {
   284 			// it's an orphan item
   285 			// it's an orphan item
   285 			ShowInfoF("ini: '%s' outside of group", buffer);
   286 			ShowInfoF("ini: '%s' outside of group", buffer);
   286 		}
   287 		}
   287 	}
   288 	}
   288 
   289 
   289 	if (comment_size > 0) {
   290 	if (comment_size > 0) {
   290 		ini->comment = pool_strdup(&ini->pool, comment, comment_size);
   291 		ini->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   291 		comment_size = 0;
   292 		comment_size = 0;
   292 	}
   293 	}
   293 
   294 
   294 	free(comment);
   295 	free(comment);
   295 	fclose(in);
   296 	fclose(in);
   309 		if (!memcmp(group->name, name, len) && group->name[len] == 0)
   310 		if (!memcmp(group->name, name, len) && group->name[len] == 0)
   310 			return group;
   311 			return group;
   311 
   312 
   312 	// otherwise make a new one
   313 	// otherwise make a new one
   313 	group = ini_group_alloc(ini, name, len);
   314 	group = ini_group_alloc(ini, name, len);
   314 	group->comment = pool_strdup(&ini->pool, "\n", 1);
   315 	group->comment = (char*)pool_strdup(&ini->pool, "\n", 1);
   315 	return group;
   316 	return group;
   316 }
   317 }
   317 
   318 
   318 // lookup an item or make a new one
   319 // lookup an item or make a new one
   319 static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
   320 static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
   601 		ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
   602 		ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
   602 		break;
   603 		break;
   603 
   604 
   604 	case SDT_STRING:
   605 	case SDT_STRING:
   605 	case SDT_INTLIST: return str;
   606 	case SDT_INTLIST: return str;
       
   607 	default: break;
   606 	}
   608 	}
   607 
   609 
   608 	return NULL;
   610 	return NULL;
   609 }
   611 }
   610 
   612 
   702 
   704 
   703 		case SDT_STRING:
   705 		case SDT_STRING:
   704 			switch (GetVarMemType(sld->conv)) {
   706 			switch (GetVarMemType(sld->conv)) {
   705 				case SLE_VAR_STRB:
   707 				case SLE_VAR_STRB:
   706 				case SLE_VAR_STRBQ:
   708 				case SLE_VAR_STRBQ:
   707 					if (p != NULL) ttd_strlcpy((char*)ptr, p, sld->length);
   709 					if (p != NULL) ttd_strlcpy((char*)ptr, (const char*)p, sld->length);
   708 					break;
   710 					break;
   709 				case SLE_VAR_STR:
   711 				case SLE_VAR_STR:
   710 				case SLE_VAR_STRQ:
   712 				case SLE_VAR_STRQ:
   711 					if (p != NULL) {
   713 					if (p != NULL) {
   712 						free(*(char**)ptr);
   714 						free(*(char**)ptr);
   717 				default: NOT_REACHED(); break;
   719 				default: NOT_REACHED(); break;
   718 			}
   720 			}
   719 			break;
   721 			break;
   720 
   722 
   721 		case SDT_INTLIST: {
   723 		case SDT_INTLIST: {
   722 			if (!load_intlist(p, ptr, sld->length, GetVarMemType(sld->conv)))
   724 			if (!load_intlist((const char*)p, ptr, sld->length, GetVarMemType(sld->conv)))
   723 				ShowInfoF("ini: error in array '%s'", sdb->name);
   725 				ShowInfoF("ini: error in array '%s'", sdb->name);
   724 			break;
   726 			break;
   725 		}
   727 		}
   726 		default: NOT_REACHED(); break;
   728 		default: NOT_REACHED(); break;
   727 		}
   729 		}
   780 			case SDT_NUMX:
   782 			case SDT_NUMX:
   781 			case SDT_ONEOFMANY:
   783 			case SDT_ONEOFMANY:
   782 			case SDT_MANYOFMANY:
   784 			case SDT_MANYOFMANY:
   783 				switch (GetVarMemType(sld->conv)) {
   785 				switch (GetVarMemType(sld->conv)) {
   784 				case SLE_VAR_BL:
   786 				case SLE_VAR_BL:
   785 					if (*(bool*)ptr == (bool)(unsigned long)p) continue;
   787 					if (*(bool*)ptr == (p != NULL)) continue;
   786 					break;
   788 					break;
   787 				case SLE_VAR_I8:
   789 				case SLE_VAR_I8:
   788 				case SLE_VAR_U8:
   790 				case SLE_VAR_U8:
   789 					if (*(byte*)ptr == (byte)(unsigned long)p) continue;
   791 					if (*(byte*)ptr == (byte)(unsigned long)p) continue;
   790 					break;
   792 					break;
   836 			break;
   838 			break;
   837 		default: NOT_REACHED();
   839 		default: NOT_REACHED();
   838 		}
   840 		}
   839 
   841 
   840 		/* The value is different, that means we have to write it to the ini */
   842 		/* The value is different, that means we have to write it to the ini */
   841 		item->value = pool_strdup(&ini->pool, buf, strlen(buf));
   843 		item->value = (char*)pool_strdup(&ini->pool, buf, strlen(buf));
   842 	}
   844 	}
   843 }
   845 }
   844 
   846 
   845 /** Loads all items from a 'grpname' section into a list
   847 /** Loads all items from a 'grpname' section into a list
   846  * The list parameter can be a NULL pointer, in this case nothing will be
   848  * The list parameter can be a NULL pointer, in this case nothing will be
   943  * internal structure somewhat so it needs a little looking. There are _NULL()
   945  * internal structure somewhat so it needs a little looking. There are _NULL()
   944  * macros as well, these fill up space so you can add more patches there (in
   946  * macros as well, these fill up space so you can add more patches there (in
   945  * place) and you DON'T have to increase the savegame version. */
   947  * place) and you DON'T have to increase the savegame version. */
   946 
   948 
   947 #define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, proc)\
   949 #define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, proc)\
   948 	{name, (const void*)(def), cmd, guiflags, min, max, interval, many, str, proc}
   950 	{name, (const void*)(def), {cmd}, {guiflags}, min, max, interval, many, str, proc}
   949 
   951 
   950 /* Macros for various objects to go in the configuration file.
   952 /* Macros for various objects to go in the configuration file.
   951  * This section is for global variables */
   953  * This section is for global variables */
   952 #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, proc, from, to)\
   954 #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, proc, from, to)\
   953 {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
   955 	{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
   954 
   956 
   955 #define SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, from, to)\
   957 #define SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, from, to)\
   956 	SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, proc, from, to)
   958 	SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, proc, from, to)
   957 #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc)\
   959 #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc)\
   958 	SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, 0, SL_MAX_VERSION)
   960 	SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, 0, SL_MAX_VERSION)
   981 	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
   983 	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
   982 #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
   984 #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
   983 	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
   985 	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
   984 
   986 
   985 #define SDTG_CONDNULL(length, from, to)\
   987 #define SDTG_CONDNULL(length, from, to)\
   986 	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_CONDNULL(length, from, to)}
   988 	{{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_CONDNULL(length, from, to)}
   987 
   989 
   988 #define SDTG_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_END()}
   990 #define SDTG_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_END()}
   989 
   991 
   990 /* Macros for various objects to go in the configuration file.
   992 /* Macros for various objects to go in the configuration file.
   991  * This section is for structures where their various members are saved */
   993  * This section is for structures where their various members are saved */
   992 #define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, proc, from, to)\
   994 #define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, proc, from, to)\
   993 	{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)}
   995 	{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)}
  1030 	SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, proc, from, to)
  1032 	SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, proc, from, to)
  1031 #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc)\
  1033 #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc)\
  1032 	SDT_CONDMMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, full, str, proc)
  1034 	SDT_CONDMMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, full, str, proc)
  1033 
  1035 
  1034 #define SDT_CONDNULL(length, from, to)\
  1036 #define SDT_CONDNULL(length, from, to)\
  1035 	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_CONDNULL(length, from, to)}
  1037 	{{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_CONDNULL(length, from, to)}
  1036 
  1038 
  1037 #define SDT_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_END()}
  1039 #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_END()}
  1038 
  1040 
  1039 /* Shortcuts for macros below. Logically if we don't save the value
  1041 /* Shortcuts for macros below. Logically if we don't save the value
  1040  * we also don't sync it in a network game */
  1042  * we also don't sync it in a network game */
  1041 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1043 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1042 #define NS SLF_SAVE_NO
  1044 #define NS SLF_SAVE_NO
  1505 	GRFConfig **curr = &first;
  1507 	GRFConfig **curr = &first;
  1506 
  1508 
  1507 	if (group == NULL) return NULL;
  1509 	if (group == NULL) return NULL;
  1508 
  1510 
  1509 	for (item = group->item; item != NULL; item = item->next) {
  1511 	for (item = group->item; item != NULL; item = item->next) {
  1510 		GRFConfig *c = calloc(1, sizeof(*c));
  1512 		GRFConfig *c;
       
  1513 		CallocT(&c, 1);
  1511 		c->filename = strdup(item->name);
  1514 		c->filename = strdup(item->name);
  1512 
  1515 
  1513 		/* Parse parameters */
  1516 		/* Parse parameters */
  1514 		if (*item->value != '\0') {
  1517 		if (*item->value != '\0') {
  1515 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1518 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1564 	for (c = list; c != NULL; c = c->next) {
  1567 	for (c = list; c != NULL; c = c->next) {
  1565 		char params[512];
  1568 		char params[512];
  1566 		GRFBuildParamList(params, c, lastof(params));
  1569 		GRFBuildParamList(params, c, lastof(params));
  1567 
  1570 
  1568 		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
  1571 		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
  1569 		(*item)->value = pool_strdup(&ini->pool, params, strlen(params));
  1572 		(*item)->value = (char*)pool_strdup(&ini->pool, params, strlen(params));
  1570 		item = &(*item)->next;
  1573 		item = &(*item)->next;
  1571 	}
  1574 	}
  1572 }
  1575 }
  1573 
  1576 
  1574 /* Common handler for saving/loading variables to the configuration file */
  1577 /* Common handler for saving/loading variables to the configuration file */
  1841 	 * them with the default values just as it was in the old days.
  1844 	 * them with the default values just as it was in the old days.
  1842 	 * Also new games need this copying-over */
  1845 	 * Also new games need this copying-over */
  1843 	_patches = _patches_newgame; /* backwards compatibility */
  1846 	_patches = _patches_newgame; /* backwards compatibility */
  1844 }
  1847 }
  1845 
  1848 
  1846 const ChunkHandler _setting_chunk_handlers[] = {
  1849 extern const ChunkHandler _setting_chunk_handlers[] = {
  1847 	{ 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF},
  1850 	{ 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF},
  1848 	{ 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST},
  1851 	{ 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST},
  1849 };
  1852 };
  1850 
  1853 
  1851 static bool IsSignedVarMemType(VarType vt)
  1854 static bool IsSignedVarMemType(VarType vt)