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