1 /* ---------------------------------------------------------------------- *
2 * fileutil.c
3 * This file is part of lincity.
4 * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
5 * ---------------------------------------------------------------------- */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h> /* XXX: GCS FIX: What does configure need to know? */
10 #include <string.h>
11 #include <physfs.h>
12 #include "engglobs.h"
13 #include "gui_interface/screen_interface.h"
14 #include "tinygettext/gettext.hpp"
15 #include "lincity-ng/ErrorInterface.hpp"
16
17 /* XXX: Where are SVGA specific includes? */
18
19 /* this is for OS/2 - RVI */
20 #ifdef __EMX__
21 #include <sys/select.h>
22 #include <X11/Xlibint.h> /* required for __XOS2RedirRoot */
23 #define chown(x,y,z)
24 #define OS2_DEFAULT_LIBDIR "/XFree86/lib/X11/lincity"
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #ifdef _MSC_VER
31 #include <direct.h>
32 #include <io.h>
33 #endif
34
35 #if defined (TIME_WITH_SYS_TIME)
36 #include <time.h>
37 #include <sys/time.h>
38 #else
39 #if defined (HAVE_SYS_TIME_H)
40 #include <sys/time.h>
41 #else
42 #include <time.h>
43 #endif
44 #endif
45
46 /*
47 #if defined (WIN32)
48 #include <winsock.h>
49 #if defined (__BORLANDC__)
50 #include <dir.h>
51 #include <dirent.h>
52 #include <dos.h>
53 #endif
54 #include <io.h>
55 #include <direct.h>
56 #include <process.h>
57 #include "lcwin32.h"
58 #endif
59 */
60 #if defined (HAVE_DIRENT_H)
61 #include <dirent.h>
62 #define NAMLEN(dirent) strlen((dirent)->d_name)
63 #else
64 #define dirent direct
65 #define NAMLEN(dirent) (dirent)->d_namlen
66 #if defined (HAVE_SYS_NDIR_H)
67 #include <sys/ndir.h>
68 #endif
69 #if defined (HAVE_SYS_DIR_H)
70 #include <sys/dir.h>
71 #endif
72 #if defined (HAVE_NDIR_H)
73 #include <ndir.h>
74 #endif
75 #endif
76
77 #include <ctype.h>
78 #if defined (HAVE_UNISTD_H)
79 #include <unistd.h>
80 #endif
81 #include <errno.h>
82 /*
83 #include "common.h"
84 #ifdef LC_X11
85 #include <X11/cursorfont.h>
86 #include <lcx11.h>
87 #endif
88 */
89 #include "lctypes.h"
90 #include "lin-city.h"
91 //#include "cliglobs.h"
92 #include "engglobs.h"
93 #include "fileutil.h"
94 #include "loadsave.h"
95
96 /* GCS: This is from dcgettext.c in the gettext package. */
97 /* XPG3 defines the result of `setlocale (category, NULL)' as:
98 ``Directs `setlocale()' to query `category' and return the current
99 setting of `local'.''
100 However it does not specify the exact format. And even worse: POSIX
101 defines this not at all. So we can use this feature only on selected
102 system (e.g. those using GNU C Library). */
103 #ifdef _LIBC
104 # define HAVE_LOCALE_NULL
105 #endif
106
107 #define DEBUG_PRINTF_TO_FILE 0
108 void debug_printf(char *fmt, ...);
109
110 /* ---------------------------------------------------------------------- *
111 * Private Fn Prototypes
112 * ---------------------------------------------------------------------- */
113 void dump_screen(void);
114 void verify_package(void);
115 static const char *guess_category_value(int category, const char *categoryname);
116
117 /* ---------------------------------------------------------------------- *
118 * Public Global Variables
119 * ---------------------------------------------------------------------- */
120 #ifdef LIBDIR
121 #undef LIBDIR
122 #endif
123 char LIBDIR[LC_PATH_MAX];
124
125 char *lc_save_dir;
126 int lc_save_dir_len;
127 static char *lc_temp_filename;
128
129 char given_scene[LC_PATH_MAX];
130 char colour_pal_file[LC_PATH_MAX];
131 char opening_pic[LC_PATH_MAX];
132 char graphic_path[LC_PATH_MAX];
133 char fontfile[LC_PATH_MAX];
134 char opening_path[LC_PATH_MAX];
135 char help_path[LC_PATH_MAX];
136 char message_path[LC_PATH_MAX];
137 char lc_textdomain_directory[LC_PATH_MAX];
138 char lincityrc_file[LC_PATH_MAX];
139
140 /* ---------------------------------------------------------------------- *
141 * Public Functions
142 * ---------------------------------------------------------------------- */
143 #if defined (__BORLANDC__)
_chdir(const char * dirname)144 int _chdir(const char *dirname)
145 {
146 return chdir(dirname);
147 }
148
_access(const char * path,int mode)149 int _access(const char *path, int mode)
150 {
151 return access(path, mode)
152 }
153 #endif
154
155 /* Executes a system command */
execute_command(char * cmd,char * p1,char * p2,char * p3)156 int execute_command(char *cmd, char *p1, char *p2, char *p3)
157 {
158 char *sys_cmd = (char *)malloc(strlen(cmd) + strlen(p1) + strlen(p2)
159 + strlen(p3) + 4);
160 int ret_value;
161
162 if (sys_cmd == 0) {
163 malloc_failure();
164 }
165 sprintf(sys_cmd, "%s %s %s %s", cmd, p1, p2, p3);
166 ret_value = system(sys_cmd);
167 /* fprintf(stderr, "system(%s)=%i\n", sys_cmd, ret_value); */
168 free(sys_cmd);
169 return ret_value;
170 }
171
copy_file(char * f1,char * f2)172 void copy_file(char *f1, char *f2)
173 {
174 int ret_value = execute_command((char*)"cp", f1, f2, (char*)"");
175 if (ret_value != 0) {
176 /* GCS FIX: Need to make do_error into var_args fn? */
177 printf("Tried to cp %s %s\n", f1, f2);
178 do_error("Can't copy requested file");
179 }
180 }
181
directory_exists(char * dir)182 int directory_exists(char *dir)
183 {
184 #if defined (WIN32)
185 struct stat s;
186 if (stat(dir, &s) != 0 || !(s.st_mode & S_IFDIR)) {
187 return 0;
188 }
189 #else /* UNIX */
190 DIR *dp;
191 if ((dp = opendir(dir)) == NULL) {
192 return 0;
193 }
194 closedir(dp);
195 #endif
196 return 1;
197 }
198
file_exists(char * filename)199 int file_exists(char *filename)
200 {
201 FILE *fp;
202 fp = fopen(filename, "rb");
203 if (fp == NULL) {
204 return 0;
205 }
206 fclose(fp);
207 return 1;
208 }
209
210 #if defined (WIN32)
find_libdir(void)211 void find_libdir(void)
212 {
213 const char searchfile[] = "Colour.pal";
214 /* default_dir will be something like "C:\\LINCITY1.11" */
215 const char default_dir[] = "C:\\LINCITY" PACKAGE_VERSION;
216 // const char default_dir[] = "D:\\LINCITY"; /* For GCS's use */
217
218 /* Check 1: environment variable */
219 _searchenv(searchfile, "LINCITY_HOME", LIBDIR);
220 if (*LIBDIR != '\0') {
221 int endofpath_offset = strlen(LIBDIR) - strlen(searchfile) - 1;
222 LIBDIR[endofpath_offset] = '\0';
223 return;
224 }
225
226 /* Check 2: default location */
227 if ((_access(default_dir, 0)) != -1) {
228 strcpy(LIBDIR, default_dir);
229 return;
230 }
231
232 /* Finally give up */
233 HandleError(_("Error. Can't find LINCITY_HOME"), FATAL);
234 }
235
236 #elif defined (__EMX__)
find_libdir(void)237 void find_libdir(void)
238 {
239 strcpy(LIBDIR, __XOS2RedirRoot(OS2_DEFAULT_LIBDIR));
240 }
241
242 #else /* Unix with configure */
find_libdir(void)243 void find_libdir(void)
244 {
245 const char searchfile[] = "colour.pal";
246 char *home_dir, *cwd;
247 char cwd_buf[LC_PATH_MAX];
248 char filename_buf[LC_PATH_MAX];
249
250 /* Check 1: environment variable */
251 home_dir = getenv("LINCITY_HOME");
252 if (home_dir) {
253 snprintf(filename_buf, LC_PATH_MAX, "%s%c%s", home_dir, PATH_SLASH, searchfile);
254 if (file_exists(filename_buf)) {
255 strncpy(LIBDIR, home_dir, LC_PATH_MAX);
256 return;
257 }
258 }
259
260 /* Check 2: current working directory */
261 cwd = getcwd(cwd_buf, LC_PATH_MAX);
262 if (cwd) {
263 snprintf(filename_buf, LC_PATH_MAX, "%s%c%s", cwd_buf, PATH_SLASH, searchfile);
264 if (file_exists(filename_buf)) {
265 strncpy(LIBDIR, cwd_buf, LC_PATH_MAX);
266 return;
267 }
268 }
269
270 snprintf(filename_buf, LC_PATH_MAX, "%s%c%s", DEFAULT_LIBDIR, PATH_SLASH, searchfile);
271 if (file_exists(filename_buf)) {
272 strncpy(LIBDIR, DEFAULT_LIBDIR, LC_PATH_MAX);
273 return;
274 }
275
276 /* Finally give up */
277 HandleError(_("Error. Can't find LINCITY_HOME"), FATAL);
278 }
279 #endif
280
281 /* GCS: This function comes from dcgettext.c in the gettext package. */
282 /* Guess value of current locale from value of the environment variables. */
283 /* GCS Feb 23, 2003. This was updated in gettext, but I'm going with the */
284 /* old version here. */
guess_category_value(int category,const char * categoryname)285 static const char *guess_category_value(int category, const char *categoryname)
286 {
287 (void)category;
288 const char *retval;
289
290 /* The highest priority value is the `LANGUAGE' environment
291 variable. This is a GNU extension. */
292 retval = getenv("LANGUAGE");
293 if (retval != NULL && retval[0] != '\0')
294 return retval;
295
296 /* `LANGUAGE' is not set. So we have to proceed with the POSIX
297 methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
298 systems this can be done by the `setlocale' function itself. */
299 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
300 retval = setlocale(category, NULL);
301 if (retval != NULL)
302 return retval;
303 else
304 return "C";
305 #else
306 /* Setting of LC_ALL overwrites all other. */
307 retval = getenv("LC_ALL");
308 if (retval != NULL && retval[0] != '\0')
309 return retval;
310
311 /* Next comes the name of the desired category. */
312 retval = getenv(categoryname);
313 if (retval != NULL && retval[0] != '\0')
314 return retval;
315
316 /* Last possibility is the LANG environment variable. */
317 retval = getenv("LANG");
318 if (retval != NULL && retval[0] != '\0')
319 return retval;
320
321 /* We use C as the default domain. POSIX says this is implementation
322 defined. */
323 return "C";
324 #endif
325 }
326
327 /* GCS: This function is modified from gettext. It finds the language
328 portion of the locale. */
lincity_nl_find_language(char * name)329 static void lincity_nl_find_language(char *name)
330 {
331 while (name[0] != '\0' && name[0] != '_' && name[0] != '@' && name[0] != '+' && name[0] != ',')
332 ++name;
333
334 *name = '\0';
335 }
336
find_localized_paths(void)337 void find_localized_paths(void)
338 {
339 int messages_done = 0;
340 int help_done = 0;
341
342 const char *intl_suffix = "";
343 char intl_lang[128];
344
345 /* First, try the locale "as is" */
346 #if defined (ENABLE_NLS) && defined (HAVE_LC_MESSAGES)
347 intl_suffix = guess_category_value(LC_MESSAGES, "LC_MESSAGES");
348 #else
349 intl_suffix = guess_category_value(0, "LC_MESSAGES");
350 #endif
351 debug_printf((char*)"GUESS 1 -- intl_suffix is %s\n", intl_suffix);
352 if (strcmp(intl_suffix, "C") && strcmp(intl_suffix, "")) {
353 snprintf(message_path, sizeof(message_path), "%s%c%s%c%s%c", LIBDIR,
354 PATH_SLASH, "messages", PATH_SLASH, intl_suffix, PATH_SLASH);
355 debug_printf((char*)"Trying Message Path %s\n", message_path);
356 if (directory_exists(message_path)) {
357 debug_printf((char*)"Set Message Path %s\n", message_path);
358 messages_done = 1;
359 }
360 snprintf(help_path, sizeof(help_path), "%s%c%s%c%s%c", LIBDIR, PATH_SLASH,
361 "help", PATH_SLASH, intl_suffix, PATH_SLASH);
362 debug_printf((char*)"Trying Help Path %s\n", help_path);
363 if (directory_exists(help_path)) {
364 debug_printf((char*)"Set Help Path %s\n", help_path);
365 help_done = 1;
366 }
367 }
368 if (messages_done && help_done)
369 return;
370
371 /* Next, try stripping off the country suffix */
372 strncpy(intl_lang, intl_suffix, 128);
373 intl_lang[127] = '\0';
374 lincity_nl_find_language(intl_lang);
375 intl_suffix = intl_lang;
376 debug_printf((char*)"GUESS 2 -- intl_suffix is %s\n", intl_suffix);
377 if (strcmp(intl_suffix, "C") && strcmp(intl_suffix, "")) {
378 if (!messages_done) {
379 sprintf(message_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "messages", PATH_SLASH, intl_suffix, PATH_SLASH);
380 debug_printf((char*)"Trying Message Path %s\n", message_path);
381 if (directory_exists(message_path)) {
382 debug_printf((char*)"Set Message Path %s\n", message_path);
383 messages_done = 1;
384 }
385 }
386 if (!help_done) {
387 sprintf(help_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "help", PATH_SLASH, intl_suffix, PATH_SLASH);
388 debug_printf((char*)"Trying Help Path %s\n", help_path);
389 if (directory_exists(help_path)) {
390 debug_printf((char*)"Set Help Path %s\n", help_path);
391 help_done = 1;
392 }
393 }
394 }
395 if (messages_done && help_done)
396 return;
397
398 /* Finally, settle for default English messages */
399 if (!messages_done) {
400 sprintf(message_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "messages", PATH_SLASH);
401 debug_printf((char*)"Settling for message Path %s\n", message_path);
402 }
403 if (!help_done) {
404 sprintf(help_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "help", PATH_SLASH);
405 debug_printf((char*)"Settling for help Path %s\n", help_path);
406 }
407 }
408
init_path_strings(void)409 void init_path_strings(void)
410 {
411 find_libdir();
412 //TODO: use, remove unused vars.
413 const char* homedir = PHYSFS_getUserDir();
414
415 /* Various dirs and files */
416 lc_save_dir_len = strlen(homedir) + strlen(LC_SAVE_DIR) + 1;
417 if ((lc_save_dir = (char *)malloc(lc_save_dir_len + 1)) == 0)
418 malloc_failure();
419 sprintf(lc_save_dir, "%s%c%s", homedir, PATH_SLASH, LC_SAVE_DIR);
420 sprintf(colour_pal_file, "%s%c%s", LIBDIR, PATH_SLASH, "colour.pal");
421 sprintf(opening_path, "%s%c%s", LIBDIR, PATH_SLASH, "opening");
422 #if defined (WIN32)
423 sprintf(opening_pic, "%s%c%s", opening_path, PATH_SLASH, "open.tga");
424 #else
425 sprintf(opening_pic, "%s%c%s", opening_path, PATH_SLASH, "open.tga.gz");
426 #endif
427 sprintf(graphic_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "icons", PATH_SLASH);
428 sprintf(lincityrc_file, "%s%c%s", homedir, PATH_SLASH, LINCITYRC_FILENAME);
429
430 /* Paths for message & help files, etc */
431 find_localized_paths();
432
433 /* Font stuff */
434 sprintf(fontfile, "%s%c%s", opening_path, PATH_SLASH, "iso8859-1-8x8.raw");
435
436 /* Temp file for results */
437 lc_temp_filename = (char *)malloc(lc_save_dir_len + 16);
438 if (lc_temp_filename == 0) {
439 malloc_failure();
440 }
441 sprintf(lc_temp_filename, "%s%c%s", lc_save_dir, PATH_SLASH, "tmp-file");
442
443 /* Path for localization */
444 #if defined (ENABLE_NLS)
445 #if defined (WIN32)
446 sprintf(lc_textdomain_directory, "%s%c%s", LIBDIR, PATH_SLASH, "locale");
447 #else
448 strcpy(lc_textdomain_directory, LOCALEDIR);
449 #endif
450 char *dm = NULL;
451 char *td = NULL;
452 dm = bindtextdomain(PACKAGE, lc_textdomain_directory);
453 debug_printf("Bound textdomain directory is %s\n", dm);
454 td = textdomain(PACKAGE);
455 debug_printf("Textdomain is %s\n", td);
456 #endif
457 }
458
verify_package(void)459 void verify_package(void)
460 {
461 FILE *fp = fopen(colour_pal_file, "rb");
462 if (!fp) {
463 do_error(_("Error verifying package. Can't find colour.pal."));
464 }
465 fclose(fp);
466 }
467
make_savedir(void)468 void make_savedir(void)
469 {
470 #if !defined (WIN32)
471 DIR *dp;
472 #endif
473
474 #if defined (WIN32)
475 if (_mkdir(lc_save_dir) == -1 && errno != EEXIST) {
476 printf(_("Couldn't create the save directory '%s'\n"), lc_save_dir);
477 exit(-1);
478 }
479 #else
480 mkdir(lc_save_dir, 0755);
481 chown(lc_save_dir, getuid(), getgid());
482 if ((dp = opendir(lc_save_dir)) == NULL) {
483 /* change this to a screen message. */
484 printf(_("Couldn't create the save directory '%s'\n"), lc_save_dir);
485 exit(1);
486 }
487 closedir(dp);
488 #endif
489
490 }
491
check_savedir(void)492 void check_savedir(void)
493 {
494 if (!directory_exists(lc_save_dir)) {
495 make_savedir();
496 }
497 }
498
malloc_failure(void)499 void malloc_failure(void)
500 {
501 printf(_("Out of memory: malloc failure\n"));
502 exit(1);
503 }
504
load_graphic(char * s)505 char *load_graphic(char *s)
506 {
507 int x, l;
508 char ss[LC_PATH_MAX], *graphic;
509 FILE *inf;
510 strcpy(ss, graphic_path);
511 strcat(ss, s);
512 if ((inf = fopen(ss, "rb")) == NULL) {
513 strcat(ss, " -- UNABLE TO LOAD");
514 do_error(ss);
515 }
516 fseek(inf, 0L, SEEK_END);
517 l = ftell(inf);
518 fseek(inf, 0L, SEEK_SET);
519 graphic = (char *)malloc(l);
520 for (x = 0; x < l; x++)
521 *(graphic + x) = fgetc(inf);
522 fclose(inf);
523 return (graphic);
524 }
525
undosify_string(char * s)526 void undosify_string(char *s)
527 {
528 /* Convert '\r\n' to '\n' in string */
529 char prev_char = 0;
530 char *p = s, *q = s;
531 while (*p) {
532 if (*p != '\r') {
533 if (prev_char == '\r' && *p != '\n') {
534 *q++ = '\n';
535 }
536 *q++ = *p;
537 }
538 prev_char = *p;
539 p++;
540 }
541 if (prev_char == '\r') {
542 *q++ = '\n';
543 }
544 *q = '\0';
545 }
546
debug_printf(char * fmt,...)547 void debug_printf(char *fmt, ...)
548 {
549 (void)fmt;
550 #if (DEBUG_PRINTF_TO_FILE)
551 static int initialized = 0;
552 char *filename = "debug.txt";
553 FILE *fp;
554 #endif
555 va_list argptr;
556 (void)argptr;
557
558 #if (DEBUG_PRINTF_TO_FILE)
559 va_start(argptr, fmt);
560 fp = fopen(filename, "a");
561 if (!initialized) {
562 initialized = 1;
563 fprintf(fp, "=========================\n");
564 }
565 vfprintf(fp, fmt, argptr);
566 #endif
567
568 /* FIXME: maybe uncomment this
569 if (command_line_debug) {
570 #if (!DEBUG_PRINTF_TO_FILE)
571 va_start (argptr, fmt);
572 #endif
573 vprintf (fmt, argptr);
574 #if (!DEBUG_PRINTF_TO_FILE)
575 va_end (argptr);
576 #endif
577 }
578 */
579 #if (DEBUG_PRINTF_TO_FILE)
580 va_end(argptr);
581 fclose(fp);
582 #endif
583 }
584