tconfigfile.c - vaccinewars - be a doctor and try to vaccinate the world
HTML git clone git://src.adamsgaard.dk/vaccinewars
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tconfigfile.c (7670B)
---
1 /************************************************************************
2 * configfile.c Functions for dealing with dopewars config files *
3 * Copyright (C) 2002-2004 Ben Webb *
4 * Email: benwebb@users.sf.net *
5 * WWW: https://dopewars.sourceforge.io/ *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License *
9 * as published by the Free Software Foundation; either version 2 *
10 * of the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
20 * MA 02111-1307, USA. *
21 ************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h> /* For memcmp etc. */
28 #include <stdio.h> /* For fgetc etc. */
29 #include <stdlib.h> /* For atoi */
30 #include <errno.h> /* For errno */
31 #include <ctype.h> /* For isprint */
32 #include <glib.h>
33
34 #include "configfile.h"
35 #include "convert.h" /* For Converter */
36 #include "dopewars.h" /* For struct GLOBALS etc. */
37 #include "nls.h" /* For _ function */
38 #include "error.h" /* For ErrStrFromErrno */
39
40 gchar *LocalCfgEncoding = NULL;
41
42 /*
43 * Prints the given string to a file, converting control characters
44 * and escaping other special characters.
45 */
46 static void PrintEscaped(FILE *fp, gchar *str)
47 {
48 guint i;
49
50 for (i = 0; i < strlen(str); i++) {
51 int ch = (int)(guchar)str[i];
52 switch(ch) {
53 case '"':
54 case '\'':
55 case '\\':
56 fputc('\\', fp);
57 fputc(ch, fp);
58 break;
59 case '\n':
60 fputs("\\n", fp);
61 break;
62 case '\t':
63 fputs("\\t", fp);
64 break;
65 case '\r':
66 fputs("\\r", fp);
67 break;
68 case '\b':
69 fputs("\\b", fp);
70 break;
71 case '\f':
72 fputs("\\f", fp);
73 break;
74 default:
75 if (isascii(ch) && isprint(ch)) {
76 fputc(ch, fp);
77 } else {
78 fprintf(fp, "\\%o", ch);
79 }
80 }
81 }
82 }
83
84 /*
85 * Writes a single configuration file variable (identified by GlobalIndex
86 * and StructIndex) to the specified file, in a format suitable for reading
87 * back in (via. ParseNextConfig and friends).
88 */
89 static void WriteConfigValue(FILE *fp, Converter *conv, int GlobalIndex,
90 int StructIndex)
91 {
92 gchar *GlobalName;
93
94 if (Globals[GlobalIndex].NameStruct[0]) {
95 GlobalName =
96 g_strdup_printf("%s[%d].%s", Globals[GlobalIndex].NameStruct,
97 StructIndex, Globals[GlobalIndex].Name);
98 } else {
99 GlobalName = Globals[GlobalIndex].Name;
100 }
101
102 if (Globals[GlobalIndex].IntVal) {
103 fprintf(fp, "%s = %d\n", GlobalName,
104 *GetGlobalInt(GlobalIndex, StructIndex));
105 } else if (Globals[GlobalIndex].BoolVal) {
106 fprintf(fp, "%s = %s\n", GlobalName,
107 *GetGlobalBoolean(GlobalIndex, StructIndex) ?
108 "TRUE" : "FALSE");
109 } else if (Globals[GlobalIndex].PriceVal) {
110 gchar *prstr = pricetostr(*GetGlobalPrice(GlobalIndex, StructIndex));
111
112 fprintf(fp, "%s = %s\n", GlobalName, prstr);
113 g_free(prstr);
114 } else if (Globals[GlobalIndex].StringVal) {
115 gchar *convstr;
116
117 fprintf(fp, "%s = \"", GlobalName);
118 convstr = Conv_ToExternal(conv,
119 *GetGlobalString(GlobalIndex, StructIndex), -1);
120 PrintEscaped(fp, convstr);
121 g_free(convstr);
122 fputs("\"\n", fp);
123 } else if (Globals[GlobalIndex].StringList) {
124 int i;
125 gchar *convstr;
126
127 fprintf(fp, "%s = { ", GlobalName);
128 for (i = 0; i < *Globals[GlobalIndex].MaxIndex; i++) {
129 if (i > 0)
130 fputs(", ", fp);
131 fputc('"', fp);
132 convstr = Conv_ToExternal(conv,
133 (*Globals[GlobalIndex].StringList)[i], -1);
134 PrintEscaped(fp, convstr);
135 g_free(convstr);
136 fputc('"', fp);
137 }
138 fputs(" }\n", fp);
139 }
140
141 if (Globals[GlobalIndex].NameStruct[0])
142 g_free(GlobalName);
143 }
144
145
146 static void ReadFileToString(FILE *fp, gchar *str, int matchlen)
147 {
148 int len, mpos, ch;
149 gchar *match;
150 GString *file;
151
152 file = g_string_new("");
153 len = strlen(str);
154 if (matchlen > 0) {
155 len = MIN(len, matchlen);
156 }
157 match = g_new(gchar, len);
158 mpos = 0;
159
160 while (mpos < len && (ch = fgetc(fp)) != EOF) {
161 g_string_append_c(file, ch);
162 match[mpos++] = ch;
163 if (ch != str[mpos - 1]) {
164 int start;
165 gboolean shortmatch = FALSE;
166
167 for (start = 1; start < mpos; start++) {
168 if (memcmp(str, &match[start], mpos - start) == 0) {
169 mpos -= start;
170 memmove(match, &match[start], mpos);
171 shortmatch = TRUE;
172 break;
173 }
174 }
175 if (!shortmatch)
176 mpos = 0;
177 }
178 }
179 g_string_truncate(file, file->len - mpos);
180
181 g_free(match);
182
183 rewind(fp);
184 ftruncate(fileno(fp), 0);
185 fputs(file->str, fp);
186
187 fputs(str, fp);
188
189 g_string_free(file, TRUE);
190 }
191
192 /*
193 * Writes all of the configuration file variables that have changed
194 * (together with their values) to the given file.
195 */
196 static void WriteConfigFile(FILE *fp, gboolean ForceUTF8)
197 {
198 int i, j;
199 Converter *conv = Conv_New();
200
201 if (ForceUTF8 && !IsConfigFileUTF8()) {
202 g_free(LocalCfgEncoding);
203 LocalCfgEncoding = g_strdup("UTF-8");
204 fputs("encoding \"UTF-8\"\n", fp);
205 }
206
207 if (LocalCfgEncoding && LocalCfgEncoding[0]) {
208 Conv_SetCodeset(conv, LocalCfgEncoding);
209 }
210
211 for (i = 0; i < NUMGLOB; i++) {
212 if (Globals[i].Modified) {
213 if (Globals[i].NameStruct[0]) {
214 for (j = 1; j <= *Globals[i].MaxIndex; j++) {
215 WriteConfigValue(fp, conv, i, j);
216 }
217 } else {
218 WriteConfigValue(fp, conv, i, 0);
219 }
220 }
221 }
222 Conv_Free(conv);
223 }
224
225 gboolean UpdateConfigFile(const gchar *cfgfile, gboolean ForceUTF8)
226 {
227 FILE *fp;
228 gchar *defaultfile;
229 static gchar *header =
230 "\n### Everything from here on is written automatically by\n"
231 "### the dopewars program; you can edit it manually, but any\n"
232 "### formatting (comments, etc.) will be lost at the next rewrite.\n\n";
233
234 defaultfile = GetLocalConfigFile();
235 if (!cfgfile || !cfgfile[0]) {
236 cfgfile = defaultfile;
237 if (!cfgfile) {
238 g_warning(_("Could not determine local config file to write to"));
239 return FALSE;
240 }
241 }
242
243 fp = fopen(cfgfile, "r+");
244 if (!fp) {
245 fp = fopen(cfgfile, "w+");
246 }
247
248 if (!fp) {
249 gchar *errstr = ErrStrFromErrno(errno);
250 g_warning(_("Could not open file %s: %s"), cfgfile, errstr);
251 g_free(errstr);
252 g_free(defaultfile);
253 return FALSE;
254 }
255
256 ReadFileToString(fp, header, 50);
257 WriteConfigFile(fp, ForceUTF8);
258
259 fclose(fp);
260 g_free(defaultfile);
261 return TRUE;
262 }
263
264 gboolean IsConfigFileUTF8(void)
265 {
266 return (LocalCfgEncoding && strcmp(LocalCfgEncoding, "UTF-8") == 0);
267 }