1 /***************************************************************************
2 usmisc.cpp - Misc utility functions
3 -------------------
4 begin : wo feb 2 2005
5 copyright : (C) 2005 by CJP
6 email : cornware-cjp@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21
22 #include <cstdio>
23 #include <cstdlib>
24
25 #include "config.h"
26
27 //internationalisation:
28 #include <locale.h>
29 #include <libintl.h>
30 #define _(String) gettext (String)
31
32 #include "usmisc.h"
33 #include "usmacros.h"
34
35 #include "cstring.h"
36 #include "lconfig.h"
37 #include "filecontrol.h"
38 #include "cfile.h"
39
40 #ifdef __APPLE__
41 // dynamic data path location on OS X
42
43 #include <CoreFoundation/CoreFoundation.h>
44
setPathIfInBundle(CString & returnpath)45 bool setPathIfInBundle(CString& returnpath)
46 {
47 char path[1024];
48
49 CFBundleRef mainBundle = CFBundleGetMainBundle();
50 assert(mainBundle);
51
52 CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
53 assert(mainBundleURL);
54
55 CFStringRef cfStringRef =
56 CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
57 assert(cfStringRef);
58
59 CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
60
61 CFRelease(mainBundleURL);
62 CFRelease(cfStringRef);
63
64 CString contents = CString(path) + "/Contents/Resources";
65 if(contents.find(".app") != std::string::npos)
66 {
67 // executable is inside an app bundle, use app bundle-relative paths
68 returnpath = contents;
69 return true;
70 }
71 else
72 {
73 // executable is installed Unix-style, use default paths
74 return false;
75 }
76 }
77 #endif
78
79 #ifdef __CYGWIN__
80
getSystemLocale()81 CString getSystemLocale()
82 {
83 CString ret;
84
85 const char *cmd1 = "locale";
86 const char *cmd2 = "-u";
87
88 //Create a pipe
89 int pipe_fds[2]; //[0] = reading [1] = writing
90 if(pipe(pipe_fds) < 0)
91 return ""; //failed
92 int out = pipe_fds[1];
93 int in = pipe_fds[0];
94
95 //Fork this process
96 pid_t PID = fork(); //is vfork allowed?
97 if(PID == 0)
98 {
99 //we are the child process
100
101 close(in); //we don't need this side in this process
102
103 //set the output to the pipe
104 if(out != 1)
105 {
106 dup2(out, 1);
107 close(out);
108 }
109
110 //Jump to the server binary
111 execlp(cmd1, cmd1, cmd2, NULL);
112
113 printf("Error: locale program could not be started\n");
114 fflush(stdout);
115
116 _exit(1); //failed to start the server process
117 }
118
119 //we are in the original process
120
121 close(out); //we don't need this side in this process
122
123 if(PID < 0) //fork failed
124 {
125 close(in);
126 return "";
127 }
128
129 //Read from the pipe
130 char c;
131 while(read(in, &c, 1) == 1 && c != '\n')
132 ret += c;
133
134 close(in);
135
136 //wait until the process stops
137 int wstatus;
138 int wait_pid = -1;
139 do
140 {
141 wait_pid = waitpid(PID, &wstatus, 0);
142 }
143 while(wait_pid == -1 && errno == EINTR);
144
145 return ret;
146 }
147
148 #endif
149
copyConfiguration(CString & conffile)150 bool copyConfiguration(CString &conffile)
151 {
152 printf("File %s not found. Searching on alternative locations...\n", conffile.c_str());
153
154 CString sysconfdir = SYSCONFDIR;
155 printf("sysconfdir = %s\n", sysconfdir.c_str());
156
157 std::vector<CString> locations;
158 locations.push_back(sysconfdir + "/ultimatestunts.conf");
159 locations.push_back("/etc/ultimatestunts.conf");
160 locations.push_back("/usr/local/etc/ultimatestunts.conf");
161 locations.push_back("./ultimatestunts.conf");
162
163 #if defined(__APPLE__)
164 // find config path dynamically
165 CString osx_path;
166 if(setPathIfInBundle(osx_path))
167 locations.push_back(osx_path + "/etc/ultimatestunts.conf");
168 #endif
169
170 CString sourceConffile;
171 for(unsigned int i=0; i < locations.size(); i++)
172 {
173 CString &loc = locations[i];
174
175 printf("Trying %s...", loc.c_str());
176 if(fileExists(loc))
177 {
178 printf("found\n");
179 sourceConffile = loc;
180 break;
181 }
182 else
183 {
184 printf("not found\n");
185 }
186 }
187
188 if(sourceConffile == "")
189 {
190 printf("WARNING: no configuration file found!\n");
191 return false;
192 }
193
194 printf("Copying %s to %s\n", sourceConffile.c_str(), conffile.c_str());
195 if(!copyFile(sourceConffile, conffile))
196 {
197 printf(" copying FAILED! (maybe we don't have the right permissions)\n");
198 return false;
199 }
200
201 return true;
202 }
203
204 //exceptions for the development environment:
inDevelopmentTree()205 bool inDevelopmentTree()
206 {
207 return fileExists("./execselect.sh");
208 }
209
210 CFileControl *fctl = NULL;
211 CString originalLANGUAGEenv;
212 CString originalSystemLocale;
213
shared_main(int argc,char * argv[])214 void shared_main(int argc, char *argv[])
215 {
216 CString conffile;
217
218 //First process some commandline arguments
219 for(int i=0; i < argc; i++)
220 {
221 CString arg = argv[i];
222
223 if(arg == "--help")
224 {
225 printf(
226 "Usage: %s [--help] [--conf=conffile] [SECTION:OPTION=VALUE]...\n"
227 "Starts the Ultimate Stunts program %s\n"
228 "\n"
229 " --help Show this help and exit\n"
230 " --conf=conffile Load settings from conffile\n"
231 " SECTION:OPTION=VALUE Override a conffile setting (NYI!)\n"
232 "\n",
233 argv[0], argv[0]
234 );
235 exit(EXIT_SUCCESS);
236 }
237
238 if(arg.mid(0, 7) == "--conf=")
239 {
240 conffile = arg.mid(7);
241 }
242 }
243
244
245 #ifdef UNIX_TREE
246 CString homedir = getenv("HOME");
247 #endif
248
249 {
250 char *env = getenv("LANGUAGE");
251 if(env != NULL)
252 originalLANGUAGEenv = env;
253 }
254 #ifdef __CYGWIN__
255 originalSystemLocale = getSystemLocale();
256 #endif
257
258 //Find the conf file location, if not given on commandline
259 if(conffile=="")
260 {
261 //the default directory of the configuration file
262 CString confdir;
263 #ifdef UNIX_TREE
264 confdir = homedir + "/.ultimatestunts/";
265 #else
266 confdir = "./";
267 #endif
268
269 if(inDevelopmentTree())
270 {
271 printf(
272 "execselect.sh detected:\n"
273 " We are probably in the Ultimate Stunts SOURCE TREE\n"
274 "EXECUTED FROM THE SOURCE TREE:\n"
275 " Using the conf file in the source tree\n"
276 );
277 confdir = "./";
278 }
279
280 //make sure that the directory exists
281 makeDir(confdir);
282
283 //make sure that the conf file exists
284 conffile = confdir + "ultimatestunts.conf";
285 if(!fileExists(conffile))
286 copyConfiguration(conffile);
287 }
288
289 printf("Using configuration file %s\n", conffile.c_str());
290
291 theMainConfig = new CLConfig(argc, argv);
292 if(!theMainConfig->setFilename(conffile))
293 {
294 printf("Error: could not read configuration file\n");
295 //TODO: create a default one
296 }
297
298 update_shared_configuration();
299 }
300
update_shared_configuration()301 void update_shared_configuration()
302 {
303 //The data dir and the save dir
304 CString DataDir, SaveDir;
305
306 CString cnf = theMainConfig->getValue("files", "datadir");
307 if(cnf != "")
308 {
309 if(cnf[cnf.length()-1] != '/') cnf += '/';
310 DataDir = cnf;
311 }
312
313 cnf = theMainConfig->getValue("files", "savedir");
314 if(cnf != "")
315 {
316 if(cnf[cnf.length()-1] != '/') cnf += '/';
317 SaveDir = cnf;
318 }
319
320 #ifdef UNIX_TREE
321 //fill in home dir for "~/"
322 CString homedir = getenv("HOME");
323 if(DataDir.mid(0, 2) == "~/")
324 DataDir = homedir + DataDir.mid(1);
325 if(SaveDir.mid(0, 2) == "~/")
326 SaveDir = homedir + SaveDir.mid(1);
327 #endif
328
329 if(inDevelopmentTree())
330 {
331 printf("EXECUTED FROM THE SOURCE TREE:\n Using the data dirs in the source tree\n");
332 DataDir = "./data/";
333 SaveDir = "./saveddata/";
334 }
335
336 #ifdef __APPLE__
337
338 if(DataDir == "@appbundle/")
339 {
340 // find data path dynamically
341 CString osx_path;
342 if(setPathIfInBundle(osx_path))
343 {
344 DataDir = osx_path + "/data/";
345 }
346 }
347
348 #endif
349
350 printf("DataDir is \"%s\"\n", DataDir.c_str());
351 printf("SaveDir is \"%s\"\n", SaveDir.c_str());
352 if(fctl == NULL) fctl = new CFileControl; //TODO: find a way to delete this object
353 fctl->setDataDir(DataDir);
354 fctl->setSaveDir(SaveDir);
355
356 printf("Enabling localisation\n");
357
358 //select a language
359 CString conf_lang = theMainConfig->getValue("user_interface", "language");
360 if(conf_lang == "system")
361 {
362
363 #ifdef __CYGWIN__
364 printf("System locale: %s\n", originalSystemLocale.c_str());
365 char *retval = setlocale(LC_MESSAGES, originalSystemLocale.c_str());
366 #else
367 char *retval = setlocale(LC_MESSAGES, "");
368 #endif
369
370 if(retval == NULL)
371 {
372 printf("Setting the system LC_MESSAGES locale failed\n");
373 }
374 else
375 {
376 printf("Locale LC_MESSAGES is set to \"%s\"\n", retval);
377 }
378
379 #ifdef __CYGWIN__
380 //F* Cygwin doesn't set the locale correctly
381 setenv("LC_MESSAGES", originalSystemLocale.c_str(), 1);
382 #endif
383
384 setenv("LANGUAGE", originalLANGUAGEenv.c_str(), 1);
385 }
386 else
387 {
388 char *retval = setlocale(LC_MESSAGES, conf_lang.c_str());
389 if(retval == NULL)
390 {
391 printf("Setting the LC_MESSAGES locale to \"%s\" failed\n", conf_lang.c_str());
392 }
393 else
394 {
395 printf("Locale LC_MESSAGES is set to \"%s\"\n", retval);
396 }
397
398 #ifdef __CYGWIN__
399 //F* Cygwin doesn't set the locale correctly
400 setenv("LC_MESSAGES", conf_lang.c_str(), 1);
401 #endif
402
403 setenv("LANGUAGE", conf_lang.c_str(), 1);
404 }
405
406 //find the absolute path
407 //very long paths might cause segfaults
408 CString absdir = getAbsDir(DataDir);
409
410 //select the Ultimate Stunts domain
411 //We can only use ISO 8859-1 because of the font texture
412 printf(" Package %s, directory %s\n", PACKAGE, (absdir + "lang").c_str());
413 printf(" bindtextdomain returns %s\n",
414 bindtextdomain(PACKAGE, (absdir + "lang").c_str())
415 );
416 printf(" bind_textdomain_codeset returns %s\n",
417 bind_textdomain_codeset(PACKAGE, "ISO-8859-1")
418 );
419 printf(" textdomain returns %s\n",
420 textdomain(PACKAGE)
421 );
422 }
423
getCredits()424 vector<CString> getCredits()
425 {
426 #include "credits.h"
427 }
428