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 "lcconfig.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h> /* XXX: GCS FIX: What does configure need to know? */
10 #include "lcintl.h"
11 #include "lcstring.h"
12 #include "ldsvgui.h"
13 
14 /* XXX: Where are SVGA specific includes? */
15 
16 /* this is for OS/2 - RVI */
17 #ifdef __EMX__
18 #include <sys/select.h>
19 #include <X11/Xlibint.h>      /* required for __XOS2RedirRoot */
20 #define chown(x,y,z)
21 #define OS2_DEFAULT_LIBDIR "/XFree86/lib/X11/lincity"
22 #endif
23 
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 
28 #if defined (TIME_WITH_SYS_TIME)
29 #include <time.h>
30 #include <sys/time.h>
31 #else
32 #if defined (HAVE_SYS_TIME_H)
33 #include <sys/time.h>
34 #else
35 #include <time.h>
36 #endif
37 #endif
38 
39 #if defined (WIN32)
40 #include <winsock.h>
41 #if defined (__BORLANDC__)
42 #include <dir.h>
43 #include <dirent.h>
44 #include <dos.h>
45 #endif
46 #include <io.h>
47 #include <direct.h>
48 #include <process.h>
49 #include <lcwin32.h>
50 #endif
51 
52 #if defined (HAVE_DIRENT_H)
53 #include <dirent.h>
54 #define NAMLEN(dirent) strlen((dirent)->d_name)
55 #else
56 #define dirent direct
57 #define NAMLEN(dirent) (dirent)->d_namlen
58 #if defined (HAVE_SYS_NDIR_H)
59 #include <sys/ndir.h>
60 #endif
61 #if defined (HAVE_SYS_DIR_H)
62 #include <sys/dir.h>
63 #endif
64 #if defined (HAVE_NDIR_H)
65 #include <ndir.h>
66 #endif
67 #endif
68 
69 #include <ctype.h>
70 #include "common.h"
71 #ifdef LC_X11
72 #include <X11/cursorfont.h>
73 #include <lcx11.h>
74 #endif
75 #include "lctypes.h"
76 #include "lin-city.h"
77 #include "cliglobs.h"
78 #include "engglobs.h"
79 #include "fileutil.h"
80 
81 /* GCS: This is from dcgettext.c in the gettext package.      */
82 /* XPG3 defines the result of `setlocale (category, NULL)' as:
83    ``Directs `setlocale()' to query `category' and return the current
84      setting of `local'.''
85    However it does not specify the exact format.  And even worse: POSIX
86    defines this not at all.  So we can use this feature only on selected
87    system (e.g. those using GNU C Library).  */
88 #ifdef _LIBC
89 # define HAVE_LOCALE_NULL
90 #endif
91 
92 #define DEBUG_PRINTF_TO_FILE 0
93 void debug_printf (char* fmt, ...);
94 
95 /* ---------------------------------------------------------------------- *
96  * Private Fn Prototypes
97  * ---------------------------------------------------------------------- */
98 void dump_screen (void);
99 void verify_package (void);
100 static const char *guess_category_value (int category,
101 					 const char *categoryname);
102 
103 /* ---------------------------------------------------------------------- *
104  * Public Global Variables
105  * ---------------------------------------------------------------------- */
106 char LIBDIR[LC_PATH_MAX];
107 
108 char *lc_save_dir;
109 int lc_save_dir_len;
110 static char *lc_temp_filename;
111 
112 char given_scene[LC_PATH_MAX];
113 char colour_pal_file[LC_PATH_MAX];
114 char opening_pic[LC_PATH_MAX];
115 char graphic_path[LC_PATH_MAX];
116 char fontfile[LC_PATH_MAX];
117 char opening_path[LC_PATH_MAX];
118 char help_path[LC_PATH_MAX];
119 char message_path[LC_PATH_MAX];
120 char lc_textdomain_directory[LC_PATH_MAX];
121 char lincityrc_file[LC_PATH_MAX];
122 
123 /* The variable make_dir_ok_flag has 2 uses.
124 
125    First, it is initialized to 1, and set to zero if the directory
126    already exists.  Later, if it is found to be 1, the "create directory
127    help page (ask-dir) is display, and then set to zero.
128 
129    Next, in the help handler, if the user says it's OK to create the
130    directory, it is reset to 1.  Finally, in the main loop, if it is
131    found to have value 1, the directory is created and it is reset to 0.
132    */
133 #if defined (commentout)
134 int make_dir_ok_flag;
135 #endif
136 
137 /* ---------------------------------------------------------------------- *
138  * Public Functions
139  * ---------------------------------------------------------------------- */
140 #if defined (__BORLANDC__)
141 int
_chdir(const char * dirname)142 _chdir (const char *dirname)
143 {
144     return chdir (dirname);
145 }
146 
147 int
_access(const char * path,int mode)148 _access (const char *path, int mode)
149 {
150     return access (path, mode)
151 }
152 #endif
153 
154 /* Executes a system command */
155 int
156 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 
172 void
173 copy_file (char *f1, char *f2)
174 {
175   int ret_value = execute_command ("cp", f1, f2, "");
176   if (ret_value != 0)
177     {
178       /* GCS FIX:  Need to make do_error into var_args fn? */
179       printf ("Tried to cp %s %s\n", f1, f2);
180       do_error ("Can't copy requested file");
181     }
182 }
183 
184 void
185 gunzip_file (char *f1, char *f2)
186 {
187   int ret_value = execute_command ("gzip -c -d", f1, ">", f2);
188   if (ret_value != 0)
189     {
190       /* GCS FIX:  Need to make do_error into var_args fn? */
191       printf ("Tried to gzip -c -d %s > %s\n", f1, f2);
192       do_error ("Can't gunzip requested file");
193     }
194 }
195 
196 FILE*
197 fopen_read_gzipped (char* fn)
198 {
199     FILE* fp;
200 
201 #if defined (HAVE_GZIP) && defined (HAVE_POPEN)
202 #ifdef __EMX__
203     const char* cmd_str = "gzip -d -c < %s 2> nul";
204 #else
205     const char* cmd_str = "gzip -d -c < %s 2> /dev/null";
206 #endif
207     char *cmd = (char*) malloc (strlen (cmd_str) + strlen (fn) + 1);
208 
209     sprintf (cmd, cmd_str, fn);
210 #ifdef __EMX__
211     fp=popen(cmd,"rb");
212 #else
213     fp=popen(cmd,"r");
214 #endif
215     if (fp==NULL) {
216        fprintf(stderr, "Failed to open pipe cmd: %s\n", cmd);
217     }
218     free(cmd);
219 
220 #elif defined (HAVE_GZIP) && !defined (HAVE_POPEN)
221     gunzip_file (fn, lc_temp_filename);
222     fp = fopen (lc_temp_filename, "rb");
223 
224 #else /* No gzip */
225     fp = fopen (fn, "rb");
226 #endif
227 
228     return fp;
229 }
230 
231 void
232 fclose_read_gzipped (FILE* fp)
233 {
234 #if defined (HAVE_GZIP) && defined (HAVE_POPEN)
235     pclose (fp);
236 #elif defined (HAVE_GZIP) && !defined (HAVE_POPEN)
237     fclose (fp);
238     remove (lc_temp_filename);
239 #else
240     fclose (fp);
241 #endif
242 }
243 
244 int
245 directory_exists (char *dir)
246 {
247 #if defined (WIN32)
248     if (_chdir (dir) == -1) {
249 	_chdir (LIBDIR);		/* go back... */
250 	return 0;
251     }
252     _chdir (LIBDIR);		/* go back... */
253 #else /* UNIX */
254     DIR *dp;
255     if ((dp = opendir (dir)) == NULL) {
256 	return 0;
257     }
258     closedir (dp);
259 #endif
260     return 1;
261 }
262 
263 int
264 file_exists (char *filename)
265 {
266     FILE* fp;
267     fp = fopen (filename,"rb");
268     if (fp == NULL) {
269 	return 0;
270     }
271     fclose (fp);
272     return 1;
273 }
274 
275 #if defined (WIN32)
276 void
277 find_libdir (void)
278 {
279     const char searchfile[] = "Colour.pal";
280     /* default_dir will be something like "C:\\LINCITY1.11" */
281     const char default_dir[] = "C:\\LINCITY" VERSION;
282 //    const char default_dir[] = "D:\\LINCITY";	/* For GCS's use */
283 
284     /* Check 1: environment variable */
285     _searchenv (searchfile, "LINCITY_HOME", LIBDIR);
286     if (*LIBDIR != '\0') {
287 	int endofpath_offset = strlen (LIBDIR) - strlen (searchfile) - 1;
288 	LIBDIR[endofpath_offset] = '\0';
289 	return;
290     }
291 
292     /* Check 2: default location */
293     if ((_access (default_dir, 0)) != -1) {
294 	strcpy (LIBDIR, default_dir);
295 	return;
296     }
297 
298     /* Finally give up */
299     HandleError (_("Error. Can't find LINCITY_HOME"), FATAL);
300 }
301 
302 #elif defined (__EMX__)
303 void
304 find_libdir (void)
305 {
306     strcpy(LIBDIR, __XOS2RedirRoot(OS2_DEFAULT_LIBDIR));
307 }
308 
309 #else /* Unix with configure */
310 void
311 find_libdir (void)
312 {
313     const char searchfile[] = "colour.pal";
314     char *home_dir, *cwd;
315     char cwd_buf[LC_PATH_MAX];
316     char filename_buf[LC_PATH_MAX];
317 
318     /* Check 1: environment variable */
319     home_dir = getenv ("LINCITY_HOME");
320     if (home_dir) {
321 	snprintf (filename_buf, LC_PATH_MAX, "%s%c%s",
322 		  home_dir, PATH_SLASH, searchfile);
323 	if (file_exists(filename_buf)) {
324 	    strncpy (LIBDIR, home_dir, LC_PATH_MAX);
325 	    return;
326 	}
327     }
328 
329     /* Check 2: current working directory */
330     cwd = getcwd (cwd_buf, LC_PATH_MAX);
331     if (cwd) {
332 	snprintf (filename_buf, LC_PATH_MAX, "%s%c%s",
333 		  cwd_buf, PATH_SLASH, searchfile);
334 	if (file_exists(filename_buf)) {
335 	    strncpy (LIBDIR, cwd_buf, LC_PATH_MAX);
336 	    return;
337 	}
338     }
339 
340     /* Check 3: default (configuration) directory */
341     snprintf (filename_buf, LC_PATH_MAX, "%s%c%s",
342 	      DEFAULT_LIBDIR, PATH_SLASH, searchfile);
343     if (file_exists(filename_buf)) {
344 	strncpy (LIBDIR, DEFAULT_LIBDIR, LC_PATH_MAX);
345 	return;
346     }
347 
348     /* Finally give up */
349     HandleError (_("Error. Can't find LINCITY_HOME"), FATAL);
350 }
351 #endif
352 
353 
354 /* GCS:  This function comes from dcgettext.c in the gettext package.      */
355 /* Guess value of current locale from value of the environment variables.  */
356 /* GCS Feb 23, 2003.  This was updated in gettext, but I'm going with the  */
357 /* old version here. */
358 static const char *
359 guess_category_value (int category, const char *categoryname)
360 {
361     const char *retval;
362 
363     /* The highest priority value is the `LANGUAGE' environment
364        variable.  This is a GNU extension.  */
365     retval = getenv ("LANGUAGE");
366     if (retval != NULL && retval[0] != '\0')
367 	return retval;
368 
369     /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
370        methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
371        systems this can be done by the `setlocale' function itself.  */
372 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
373     retval = setlocale (category, NULL);
374     if (retval != NULL)
375       return retval;
376     else
377       return "C";
378 #else
379     /* Setting of LC_ALL overwrites all other.  */
380     retval = getenv ("LC_ALL");
381     if (retval != NULL && retval[0] != '\0')
382 	return retval;
383 
384     /* Next comes the name of the desired category.  */
385     retval = getenv (categoryname);
386     if (retval != NULL && retval[0] != '\0')
387 	return retval;
388 
389     /* Last possibility is the LANG environment variable.  */
390     retval = getenv ("LANG");
391     if (retval != NULL && retval[0] != '\0')
392 	return retval;
393 
394     /* We use C as the default domain.  POSIX says this is implementation
395        defined.  */
396     return "C";
397 #endif
398 }
399 
400 /* GCS:  This function is modified from gettext.  It finds the language
401    portion of the locale. */
402 static void
403 lincity_nl_find_language (char *name)
404 {
405   while (name[0] != '\0' && name[0] != '_' && name[0] != '@'
406 	 && name[0] != '+' && name[0] != ',')
407     ++name;
408 
409   *name = '\0';
410 }
411 
412 
413 void
414 find_localized_paths (void)
415 {
416   int messages_done = 0;
417   int help_done = 0;
418 
419   const char* intl_suffix = "";
420   char intl_lang[128];
421 
422   /* First, try the locale "as is" */
423 #if defined (ENABLE_NLS) && defined (HAVE_LC_MESSAGES)
424   intl_suffix = guess_category_value(LC_MESSAGES,"LC_MESSAGES");
425 #else
426   intl_suffix = guess_category_value(0,"LC_MESSAGES");
427 #endif
428   debug_printf ("GUESS 1 -- intl_suffix is %s\n", intl_suffix);
429   if (strcmp(intl_suffix,"C") && strcmp(intl_suffix,"")) {
430     sprintf (message_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "messages",
431 	     PATH_SLASH, intl_suffix, PATH_SLASH);
432     debug_printf ("Trying Message Path %s\n", message_path);
433     if (directory_exists(message_path)) {
434       debug_printf ("Set Message Path %s\n", message_path);
435       messages_done = 1;
436     }
437     sprintf (help_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "help",
438 	     PATH_SLASH, intl_suffix, PATH_SLASH);
439     debug_printf ("Trying Help Path %s\n", help_path);
440     if (directory_exists(help_path)) {
441       debug_printf ("Set Help Path %s\n", help_path);
442       help_done = 1;
443     }
444   }
445   if (messages_done && help_done) return;
446 
447   /* Next, try stripping off the country suffix */
448   strncpy (intl_lang, intl_suffix, 128);
449   intl_lang[127] = '\0';
450   lincity_nl_find_language (intl_lang);
451   intl_suffix = intl_lang;
452   debug_printf ("GUESS 2 -- intl_suffix is %s\n", intl_suffix);
453   if (strcmp(intl_suffix,"C") && strcmp(intl_suffix,"")) {
454     if (!messages_done) {
455       sprintf (message_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "messages",
456 	       PATH_SLASH, intl_suffix, PATH_SLASH);
457       debug_printf ("Trying Message Path %s\n", message_path);
458       if (directory_exists(message_path)) {
459 	debug_printf ("Set Message Path %s\n", message_path);
460 	messages_done = 1;
461       }
462     }
463     if (!help_done) {
464       sprintf (help_path, "%s%c%s%c%s%c", LIBDIR, PATH_SLASH, "help",
465 	       PATH_SLASH, intl_suffix, PATH_SLASH);
466       debug_printf ("Trying Help Path %s\n", help_path);
467       if (directory_exists(help_path)) {
468 	debug_printf ("Set Help Path %s\n", help_path);
469 	help_done = 1;
470       }
471     }
472   }
473   if (messages_done && help_done) return;
474 
475   /* Finally, settle for default English messages */
476   if (!messages_done) {
477     sprintf (message_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "messages",
478 	     PATH_SLASH);
479     debug_printf ("Settling for message Path %s\n", message_path);
480   }
481   if (!help_done) {
482     sprintf (help_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "help",
483 	     PATH_SLASH);
484     debug_printf ("Settling for help Path %s\n", help_path);
485   }
486 }
487 
488 
489 void
490 init_path_strings (void)
491 {
492     char* homedir = NULL;
493     char* dm = NULL;
494     char* td = NULL;
495 
496     find_libdir ();
497 
498 #if defined (WIN32)
499     homedir = LIBDIR;
500 #elif defined (__EMX__)
501     homedir = getenv ("HOME");
502 #else
503     homedir = getenv ("HOME");
504 #endif
505 
506     /* Various dirs and files */
507     lc_save_dir_len = strlen (homedir) + strlen (LC_SAVE_DIR) + 1;
508     if ((lc_save_dir = (char *) malloc (lc_save_dir_len + 1)) == 0)
509 	malloc_failure ();
510     sprintf (lc_save_dir, "%s%c%s", homedir, PATH_SLASH, LC_SAVE_DIR);
511     sprintf (colour_pal_file, "%s%c%s", LIBDIR, PATH_SLASH, "colour.pal");
512     sprintf (opening_path, "%s%c%s", LIBDIR, PATH_SLASH, "opening");
513 #if defined (WIN32)
514     sprintf (opening_pic, "%s%c%s",opening_path,PATH_SLASH,"open.tga");
515 #else
516     sprintf (opening_pic, "%s%c%s",opening_path,PATH_SLASH,"open.tga.gz");
517 #endif
518     sprintf (graphic_path, "%s%c%s%c", LIBDIR, PATH_SLASH, "icons",
519 	     PATH_SLASH);
520     sprintf (lincityrc_file, "%s%c%s", homedir, PATH_SLASH,
521 	LINCITYRC_FILENAME);
522 
523     /* Paths for message & help files, etc */
524     find_localized_paths ();
525 
526     /* Font stuff */
527     sprintf (fontfile, "%s%c%s", opening_path, PATH_SLASH,
528 	     "iso8859-1-8x8.raw");
529 #if defined (WIN32)
530     /* GCS: Use windows font for extra speed */
531     strcpy (windowsfontfile, LIBDIR);
532 #if defined (commentout)
533     if (!pix_double)
534 	strcat (windowsfontfile, "\\opening\\iso8859-1-8x8.fnt");
535     else
536 	strcat (windowsfontfile, "\\opening\\iso8859-1-9x15.fnt");
537 #endif
538     if (!pix_double)
539 	strcat (windowsfontfile, "\\opening\\winfont_8x8.fnt");
540     else
541 	strcat (windowsfontfile, "\\opening\\winfont_16x16.fnt");
542 #endif
543 
544     /* Temp file for results */
545     lc_temp_filename = (char *) malloc (lc_save_dir_len + 16);
546     if (lc_temp_filename == 0) {
547 	malloc_failure ();
548     }
549     sprintf (lc_temp_filename, "%s%c%s", lc_save_dir, PATH_SLASH, "tmp-file");
550 
551     /* Path for localization */
552 #if defined (ENABLE_NLS)
553 #if defined (WIN32)
554     sprintf (lc_textdomain_directory, "%s%c%s", LIBDIR, PATH_SLASH, "locale");
555 #else
556     strcpy (lc_textdomain_directory, LOCALEDIR);
557 #endif
558     dm = bindtextdomain (PACKAGE, lc_textdomain_directory);
559     debug_printf ("Bound textdomain directory is %s\n", dm);
560     td = textdomain (PACKAGE);
561     debug_printf ("Textdomain is %s\n", td);
562 #endif
563 }
564 
565 void
566 verify_package (void)
567 {
568     FILE *fp = fopen (colour_pal_file,"rb");
569     if (!fp) {
570 	do_error (_("Error verifying package. Can't find colour.pal."));
571     }
572     fclose (fp);
573 }
574 
575 void
576 make_savedir (void)
577 {
578 #if !defined (WIN32)
579     DIR *dp;
580 #endif
581 
582 #if defined (commentout)
583     if (make_dir_ok_flag == 0)
584 	return;
585 #endif
586 
587 #if defined (WIN32)
588     if (_mkdir (lc_save_dir)) {
589 	printf (_("Couldn't create the save directory %s\n"), lc_save_dir);
590 	exit (-1);
591     }
592 #else
593     mkdir (lc_save_dir, 0755);
594     chown (lc_save_dir, getuid (), getgid ());
595     if ((dp = opendir (lc_save_dir)) == NULL)
596     {
597 	/* change this to a screen message. */
598 	printf (_("Couldn't create the save directory %s\n"), lc_save_dir);
599 	exit (1);
600     }
601     closedir (dp);
602 #endif
603 
604 #if defined (commentout)
605     make_dir_ok_flag = 0;
606 #endif
607 }
608 
609 void
610 check_savedir (void)
611 {
612 #if defined (commentout)
613     int i = 0, j, k, r, l;
614 #endif
615 
616     if (!directory_exists (lc_save_dir)) {
617 	make_savedir ();
618 #if defined (commentout)
619 	l = lc_save_dir_len;
620 	if (l > 160) {
621 	    i = l - 160;
622 	    l = 160;
623 	}
624 	askdir_lines = l / 40 + ((l % 40) ? 1 : 0);
625 	r = l / askdir_lines + ((l % askdir_lines) ? 1 : 0);
626 	for (j = 0; j < askdir_lines; j++) {
627 	    if ((askdir_path[j] = (char *) malloc (r + 1)) == 0)
628 		malloc_failure ();
629 	    for (k = 0; k < r; k++, i++)
630 		*(askdir_path[j] + k) = lc_save_dir[i];
631 	    *(askdir_path[j] + k) = 0;
632 	}
633 	return;
634 #endif
635     }
636 #if defined (commentout)
637     make_dir_ok_flag = 0;		/* don't load the ask-dir */
638 #endif
639 }
640 
641 void
642 malloc_failure (void)
643 {
644   printf (_("Out of memory: malloc failure\n"));
645   exit (1);
646 }
647 
648 char*
649 load_graphic(char *s)
650 {
651     int x,l;
652     char ss[LC_PATH_MAX],*graphic;
653     FILE *inf;
654     strcpy(ss,graphic_path);
655     strcat(ss,s);
656     if ((inf=fopen(ss,"rb"))==NULL)
657     {
658 	strcat(ss," -- UNABLE TO LOAD");
659 	do_error(ss);
660     }
661     fseek(inf,0L,SEEK_END);
662     l=ftell(inf);
663     fseek(inf,0L,SEEK_SET);
664     graphic=(char *)malloc(l);
665     for (x=0;x<l;x++)
666 	*(graphic+x)=fgetc(inf);
667     fclose(inf);
668     return(graphic);
669 }
670 
671 void
672 load_lincityrc (void)
673 {
674     FILE *fp;
675     int arg;
676     char buf[128];
677 
678     if ((fp = fopen (lincityrc_file, "r")) == 0) {
679 	save_lincityrc();
680 	return;
681     }
682     while (fgets (buf,128,fp)) {
683 	if (sscanf(buf,"overwrite_transport=%d",&arg)==1) {
684 	    overwrite_transport_flag = !!arg;
685 	    continue;
686 	}
687 	if (sscanf(buf,"no_init_help=%d",&arg)==1) {
688 	    /* Careful here ... */
689 	    no_init_help = !!arg;
690 	    continue;
691 	}
692 	if (sscanf(buf,"skip_splash_screen=%d",&arg)==1) {
693 	    skip_splash_screen = !!arg;
694 	    continue;
695 	}
696 	if (sscanf(buf,"suppress_firsttime_module_help=%d",&arg)==1) {
697 	    suppress_firsttime_module_help = !!arg;
698 	    continue;
699 	}
700 	if (sscanf(buf,"suppress_popups=%d",&arg)==1) {
701 	    suppress_popups = !!arg;
702 	    continue;
703 	}
704 	if (sscanf(buf,"time_multiplex_stats=%d",&arg)==1) {
705 	    time_multiplex_stats = !!arg;
706 	    continue;
707 	}
708 	if (sscanf(buf,"x_confine_pointer=%d",&arg)==1) {
709 	    confine_flag = !!arg;
710 	    continue;
711 	}
712     }
713     fclose (fp);
714 }
715 
716 void
717 save_lincityrc (void)
718 {
719     FILE *fp;
720 
721     if ((fp = fopen (lincityrc_file, "w")) == 0) {
722 	return;
723     }
724 
725     fprintf (fp,
726 	"# Set this if you want to be able to overwrite one\n"
727 	"# kind of transport with another.\n"
728 	"overwrite_transport=%d\n\n",
729 	overwrite_transport_flag);
730     fprintf (fp,
731 	"# Set this if you don't want the opening help screen.\n"
732 	"no_init_help=%d\n\n",
733 	no_init_help
734 	);
735     fprintf (fp,
736 	"# Set this if you don't want the opening splash screen.\n"
737 	"skip_splash_screen=%d\n\n",
738 	skip_splash_screen
739 	);
740     fprintf (fp,
741 	"# Set this if you don't want help the first time you\n"
742 	"# click to place an item.\n"
743 	"suppress_firsttime_module_help=%d\n\n",
744 	suppress_firsttime_module_help
745 	);
746     fprintf (fp,
747 	"# Set this if don't want modal dialog boxes which you\n"
748 	"# are required to click OK.  Instead, report the dialog\n"
749 	"# box information to the message area.\n"
750 	"suppress_popups=%d\n\n",
751 	suppress_popups
752 	);
753     fprintf (fp,
754 	"# Set this if want the different statistic windows to cycle\n"
755 	"# through the right panel.\n"
756 	"time_multiplex_stats=%d\n\n",
757 	time_multiplex_stats
758 	);
759     fprintf (fp,
760 	"# (X Windows only) Set this if you want to confine the pointer\n"
761 	"# to within the window.\n"
762 	"x_confine_pointer=%d\n\n",
763 	confine_flag
764 	);
765 
766     fclose (fp);
767 }
768 
769 void
770 undosify_string (char *s)
771 {
772     /* Convert '\r\n' to '\n' in string */
773     char prev_char = 0;
774     char *p = s, *q = s;
775     while (*p) {
776 	if (*p != '\r') {
777 	    if (prev_char == '\r' && *p != '\n') {
778 		*q++ = '\n';
779 	    }
780 	    *q++ = *p;
781 	}
782 	prev_char = *p;
783         p++;
784     }
785     if (prev_char == '\r') {
786 	*q++ = '\n';
787     }
788     *q = '\0';
789 }
790 
791 void
792 debug_printf (char* fmt, ...)
793 {
794 #if (DEBUG_PRINTF_TO_FILE)
795     static int initialized = 0;
796     char* filename = "debug.txt";
797     FILE* fp;
798 #endif
799     va_list argptr;
800 
801 #if (DEBUG_PRINTF_TO_FILE)
802     va_start (argptr, fmt);
803     fp = fopen(filename, "a");
804     if (!initialized) {
805 	initialized = 1;
806 	fprintf (fp, "=========================\n");
807     }
808     vfprintf (fp, fmt, argptr);
809 #endif
810 
811     if (command_line_debug) {
812 #if (!DEBUG_PRINTF_TO_FILE)
813       va_start (argptr, fmt);
814 #endif
815       vprintf (fmt, argptr);
816 #if (!DEBUG_PRINTF_TO_FILE)
817       va_end (argptr);
818 #endif
819     }
820 
821 #if (DEBUG_PRINTF_TO_FILE)
822     va_end (argptr);
823     fclose (fp);
824 #endif
825 }
826 
827