1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * misc.c                                                   *
12 ***********************************************************/
13 
14 #include <time.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <stdarg.h>
19 #include <ctype.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include "platform.h"
24 
25 #if !defined(PLATFORM_WIN32)
26 #include <pwd.h>
27 #include <sys/param.h>
28 #endif
29 
30 #include "misc.h"
31 #include "random.h"
32 
33 
34 #if defined(PLATFORM_MSDOS)
35 volatile unsigned long counter = 0;
36 
increment_counter()37 void increment_counter()
38 {
39   counter++;
40 }
41 
42 END_OF_FUNCTION(increment_counter);
43 #endif
44 
45 
46 /* maximal allowed length of a command line option */
47 #define MAX_OPTION_LEN		256
48 
49 #ifdef TARGET_SDL
mainCounter(int mode)50 static unsigned long mainCounter(int mode)
51 {
52   static unsigned long base_ms = 0;
53   unsigned long current_ms;
54   unsigned long counter_ms;
55 
56   current_ms = SDL_GetTicks();
57 
58   /* reset base time in case of counter initializing or wrap-around */
59   if (mode == INIT_COUNTER || current_ms < base_ms)
60     base_ms = current_ms;
61 
62   counter_ms = current_ms - base_ms;
63 
64   return counter_ms;		/* return milliseconds since last init */
65 }
66 
67 #else /* !TARGET_SDL */
68 
69 #if defined(PLATFORM_UNIX)
mainCounter(int mode)70 static unsigned long mainCounter(int mode)
71 {
72   static struct timeval base_time = { 0, 0 };
73   struct timeval current_time;
74   unsigned long counter_ms;
75 
76   gettimeofday(&current_time, NULL);
77 
78   /* reset base time in case of counter initializing or wrap-around */
79   if (mode == INIT_COUNTER || current_time.tv_sec < base_time.tv_sec)
80     base_time = current_time;
81 
82   counter_ms = (current_time.tv_sec  - base_time.tv_sec)  * 1000
83              + (current_time.tv_usec - base_time.tv_usec) / 1000;
84 
85   return counter_ms;		/* return milliseconds since last init */
86 }
87 #endif /* PLATFORM_UNIX */
88 #endif /* !TARGET_SDL */
89 
InitCounter()90 void InitCounter()		/* set counter back to zero */
91 {
92 #if !defined(PLATFORM_MSDOS)
93   mainCounter(INIT_COUNTER);
94 #else
95   LOCK_VARIABLE(counter);
96   LOCK_FUNCTION(increment_counter);
97   install_int_ex(increment_counter, BPS_TO_TIMER(100));
98 #endif
99 }
100 
Counter()101 unsigned long Counter()	/* get milliseconds since last call of InitCounter() */
102 {
103 #if !defined(PLATFORM_MSDOS)
104   return mainCounter(READ_COUNTER);
105 #else
106   return (counter * 10);
107 #endif
108 }
109 
sleep_milliseconds(unsigned long milliseconds_delay)110 static void sleep_milliseconds(unsigned long milliseconds_delay)
111 {
112   boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
113 
114 #if defined(PLATFORM_MSDOS)
115   /* don't use select() to perform waiting operations under DOS/Windows
116      environment; always use a busy loop for waiting instead */
117   do_busy_waiting = TRUE;
118 #endif
119 
120   if (do_busy_waiting)
121   {
122     /* we want to wait only a few ms -- if we assume that we have a
123        kernel timer resolution of 10 ms, we would wait far to long;
124        therefore it's better to do a short interval of busy waiting
125        to get our sleeping time more accurate */
126 
127     unsigned long base_counter = Counter(), actual_counter = Counter();
128 
129     while (actual_counter < base_counter + milliseconds_delay &&
130 	   actual_counter >= base_counter)
131       actual_counter = Counter();
132   }
133   else
134   {
135 #if defined(TARGET_SDL)
136     SDL_Delay(milliseconds_delay);
137 #else
138     struct timeval delay;
139 
140     delay.tv_sec  = milliseconds_delay / 1000;
141     delay.tv_usec = 1000 * (milliseconds_delay % 1000);
142 
143     if (select(0, NULL, NULL, NULL, &delay) != 0)
144       Error(ERR_WARN, "sleep_milliseconds(): select() failed");
145 #endif
146   }
147 }
148 
Delay(unsigned long delay)149 void Delay(unsigned long delay)	/* Sleep specified number of milliseconds */
150 {
151   sleep_milliseconds(delay);
152 }
153 
FrameReached(unsigned long * frame_counter_var,unsigned long frame_delay)154 boolean FrameReached(unsigned long *frame_counter_var,
155 		     unsigned long frame_delay)
156 {
157   unsigned long actual_frame_counter = FrameCounter;
158 
159   if (actual_frame_counter < *frame_counter_var+frame_delay &&
160       actual_frame_counter >= *frame_counter_var)
161     return(FALSE);
162 
163   *frame_counter_var = actual_frame_counter;
164   return(TRUE);
165 }
166 
DelayReached(unsigned long * counter_var,unsigned long delay)167 boolean DelayReached(unsigned long *counter_var,
168 		     unsigned long delay)
169 {
170   unsigned long actual_counter = Counter();
171 
172   if (actual_counter < *counter_var + delay &&
173       actual_counter >= *counter_var)
174     return(FALSE);
175 
176   *counter_var = actual_counter;
177   return(TRUE);
178 }
179 
WaitUntilDelayReached(unsigned long * counter_var,unsigned long delay)180 void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
181 {
182   unsigned long actual_counter;
183 
184   while(1)
185   {
186     actual_counter = Counter();
187 
188     if (actual_counter < *counter_var + delay &&
189 	actual_counter >= *counter_var)
190       sleep_milliseconds((*counter_var + delay - actual_counter) / 2);
191     else
192       break;
193   }
194 
195   *counter_var = actual_counter;
196 }
197 
198 /* int2str() returns a number converted to a string;
199    the used memory is static, but will be overwritten by later calls,
200    so if you want to save the result, copy it to a private string buffer;
201    there can be 10 local calls of int2str() without buffering the result --
202    the 11th call will then destroy the result from the first call and so on.
203 */
204 
int2str(int number,int size)205 char *int2str(int number, int size)
206 {
207   static char shift_array[10][40];
208   static int shift_counter = 0;
209   char *s = shift_array[shift_counter];
210 
211   shift_counter = (shift_counter + 1) % 10;
212 
213   if (size > 20)
214     size = 20;
215 
216   if (size)
217   {
218     sprintf(s, "                    %09d", number);
219     return &s[strlen(s) - size];
220   }
221   else
222   {
223     sprintf(s, "%d", number);
224     return s;
225   }
226 }
227 
SimpleRND(unsigned int max)228 unsigned int SimpleRND(unsigned int max)
229 {
230 #if defined(TARGET_SDL)
231   static unsigned long root = 654321;
232   unsigned long current_ms;
233 
234   current_ms = SDL_GetTicks();
235   root = root * 4253261 + current_ms;
236   return (root % max);
237 #else
238   static unsigned long root = 654321;
239   struct timeval current_time;
240 
241   gettimeofday(&current_time, NULL);
242   root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
243   return (root % max);
244 #endif
245 }
246 
247 #ifdef DEBUG
248 static unsigned int last_RND_value = 0;
249 
last_RND()250 unsigned int last_RND()
251 {
252   return last_RND_value;
253 }
254 #endif
255 
RND(unsigned int max)256 unsigned int RND(unsigned int max)
257 {
258 #ifdef DEBUG
259   return (last_RND_value = random_linux_libc() % max);
260 #else
261   return (random_linux_libc() % max);
262 #endif
263 }
264 
InitRND(long seed)265 unsigned int InitRND(long seed)
266 {
267 #if defined(TARGET_SDL)
268   unsigned long current_ms;
269 
270   if (seed == NEW_RANDOMIZE)
271   {
272     current_ms = SDL_GetTicks();
273     srandom_linux_libc((unsigned int) current_ms);
274     return (unsigned int) current_ms;
275   }
276   else
277   {
278     srandom_linux_libc((unsigned int) seed);
279     return (unsigned int) seed;
280   }
281 #else
282   struct timeval current_time;
283 
284   if (seed == NEW_RANDOMIZE)
285   {
286     gettimeofday(&current_time, NULL);
287     srandom_linux_libc((unsigned int) current_time.tv_usec);
288     return (unsigned int) current_time.tv_usec;
289   }
290   else
291   {
292     srandom_linux_libc((unsigned int) seed);
293     return (unsigned int) seed;
294   }
295 #endif
296 }
297 
getLoginName()298 char *getLoginName()
299 {
300 #if defined(PLATFORM_WIN32)
301   return ANONYMOUS_NAME;
302 #else
303   struct passwd *pwd;
304 
305   if ((pwd = getpwuid(getuid())) == NULL)
306     return ANONYMOUS_NAME;
307   else
308     return pwd->pw_name;
309 #endif
310 }
311 
getRealName()312 char *getRealName()
313 {
314 #if defined(PLATFORM_UNIX)
315   struct passwd *pwd;
316 
317   if ((pwd = getpwuid(getuid())) == NULL || strlen(pwd->pw_gecos) == 0)
318     return ANONYMOUS_NAME;
319   else
320   {
321     static char real_name[1024];
322     char *from_ptr = pwd->pw_gecos, *to_ptr = real_name;
323 
324     if (strchr(pwd->pw_gecos, '�') == NULL)
325       return pwd->pw_gecos;
326 
327     /* the user's real name contains a '�' character (german sharp s),
328        which has no equivalent in upper case letters (which our fonts use) */
329     while (*from_ptr != '\0' && (long)(to_ptr - real_name) < 1024 - 2)
330     {
331       if (*from_ptr != '�')
332 	*to_ptr++ = *from_ptr++;
333       else
334       {
335 	from_ptr++;
336 	*to_ptr++ = 's';
337 	*to_ptr++ = 's';
338       }
339     }
340     *to_ptr = '\0';
341 
342     return real_name;
343   }
344 #else /* !PLATFORM_UNIX */
345   return ANONYMOUS_NAME;
346 #endif
347 }
348 
getHomeDir()349 char *getHomeDir()
350 {
351 #if defined(PLATFORM_UNIX)
352   static char *home_dir = NULL;
353 
354   if (!home_dir)
355   {
356     if (!(home_dir = getenv("HOME")))
357     {
358       struct passwd *pwd;
359 
360       if ((pwd = getpwuid(getuid())))
361 	home_dir = pwd->pw_dir;
362       else
363 	home_dir = ".";
364     }
365   }
366 
367   return home_dir;
368 #else
369   return ".";
370 #endif
371 }
372 
getPath2(char * path1,char * path2)373 char *getPath2(char *path1, char *path2)
374 {
375   char *complete_path = checked_malloc(strlen(path1) + 1 +
376 				       strlen(path2) + 1);
377 
378   sprintf(complete_path, "%s/%s", path1, path2);
379   return complete_path;
380 }
381 
getPath3(char * path1,char * path2,char * path3)382 char *getPath3(char *path1, char *path2, char *path3)
383 {
384   char *complete_path = checked_malloc(strlen(path1) + 1 +
385 				       strlen(path2) + 1 +
386 				       strlen(path3) + 1);
387 
388   sprintf(complete_path, "%s/%s/%s", path1, path2, path3);
389   return complete_path;
390 }
391 
getStringCopy(char * s)392 char *getStringCopy(char *s)
393 {
394   char *s_copy;
395 
396   if (s == NULL)
397     return NULL;
398 
399   s_copy = checked_malloc(strlen(s) + 1);
400 
401   strcpy(s_copy, s);
402   return s_copy;
403 }
404 
getStringToLower(char * s)405 char *getStringToLower(char *s)
406 {
407   char *s_copy = checked_malloc(strlen(s) + 1);
408   char *s_ptr = s_copy;
409 
410   while (*s)
411     *s_ptr++ = tolower(*s++);
412   *s_ptr = '\0';
413 
414   return s_copy;
415 }
416 
GetOptions(char * argv[])417 void GetOptions(char *argv[])
418 {
419   char **options_left = &argv[1];
420 
421   /* initialize global program options */
422   options.display_name = NULL;
423   options.server_host = NULL;
424   options.server_port = 0;
425   options.ro_base_directory = RO_BASE_PATH;
426   options.rw_base_directory = RW_BASE_PATH;
427   options.level_directory = RO_BASE_PATH "/" LEVELS_DIRECTORY;
428   options.serveronly = FALSE;
429   options.network = FALSE;
430   options.verbose = FALSE;
431   options.debug = FALSE;
432 
433   while (*options_left)
434   {
435     char option_str[MAX_OPTION_LEN];
436     char *option = options_left[0];
437     char *next_option = options_left[1];
438     char *option_arg = NULL;
439     int option_len = strlen(option);
440 
441     if (option_len >= MAX_OPTION_LEN)
442       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
443 
444     strcpy(option_str, option);			/* copy argument into buffer */
445     option = option_str;
446 
447     if (strcmp(option, "--") == 0)		/* stop scanning arguments */
448       break;
449 
450     if (strncmp(option, "--", 2) == 0)		/* treat '--' like '-' */
451       option++;
452 
453     option_arg = strchr(option, '=');
454     if (option_arg == NULL)			/* no '=' in option */
455       option_arg = next_option;
456     else
457     {
458       *option_arg++ = '\0';			/* cut argument from option */
459       if (*option_arg == '\0')			/* no argument after '=' */
460 	Error(ERR_EXIT_HELP, "option '%s' has invalid argument", option_str);
461     }
462 
463     option_len = strlen(option);
464 
465     if (strcmp(option, "-") == 0)
466       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
467     else if (strncmp(option, "-help", option_len) == 0)
468     {
469       printf("Usage: %s [options] [server.name [port]]\n"
470 	     "Options:\n"
471 	     "  -d, --display machine:0       X server display\n"
472 	     "  -b, --basepath directory      alternative base directory\n"
473 	     "  -l, --level directory         alternative level directory\n"
474 	     "  -s, --serveronly              only start network server\n"
475 	     "  -n, --network                 network multiplayer game\n"
476 	     "  -v, --verbose                 verbose mode\n"
477 	     "      --debug                   display debugging information\n",
478 	     program.command_basename);
479       exit(0);
480     }
481     else if (strncmp(option, "-display", option_len) == 0)
482     {
483       if (option_arg == NULL)
484 	Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
485 
486       options.display_name = option_arg;
487       if (option_arg == next_option)
488 	options_left++;
489     }
490     else if (strncmp(option, "-basepath", option_len) == 0)
491     {
492       if (option_arg == NULL)
493 	Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
494 
495       /* this should be extended to separate options for ro and rw data */
496       options.ro_base_directory = option_arg;
497       options.rw_base_directory = option_arg;
498       if (option_arg == next_option)
499 	options_left++;
500 
501       /* adjust path for level directory accordingly */
502       options.level_directory =
503 	getPath2(options.ro_base_directory, LEVELS_DIRECTORY);
504     }
505     else if (strncmp(option, "-levels", option_len) == 0)
506     {
507       if (option_arg == NULL)
508 	Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
509 
510       options.level_directory = option_arg;
511       if (option_arg == next_option)
512 	options_left++;
513     }
514     else if (strncmp(option, "-network", option_len) == 0)
515     {
516       options.network = TRUE;
517     }
518     else if (strncmp(option, "-serveronly", option_len) == 0)
519     {
520       options.serveronly = TRUE;
521     }
522     else if (strncmp(option, "-verbose", option_len) == 0)
523     {
524       options.verbose = TRUE;
525     }
526     else if (strncmp(option, "-debug", option_len) == 0)
527     {
528       options.debug = TRUE;
529     }
530     else if (*option == '-')
531     {
532       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
533     }
534     else if (options.server_host == NULL)
535     {
536       options.server_host = *options_left;
537     }
538     else if (options.server_port == 0)
539     {
540       options.server_port = atoi(*options_left);
541       if (options.server_port < 1024)
542 	Error(ERR_EXIT_HELP, "bad port number '%d'", options.server_port);
543     }
544     else
545       Error(ERR_EXIT_HELP, "too many arguments");
546 
547     options_left++;
548   }
549 }
550 
Error(int mode,char * format,...)551 void Error(int mode, char *format, ...)
552 {
553   char *process_name = "";
554   FILE *error = stderr;
555   char *newline = "\n";
556 
557   /* display warnings only when running in verbose mode */
558   if (mode & ERR_WARN && !options.verbose)
559     return;
560 
561 #if !defined(PLATFORM_UNIX)
562   newline = "\r\n";
563 
564   if ((error = openErrorFile()) == NULL)
565   {
566     printf("Cannot write to error output file!%s", newline);
567     program.exit_function(1);
568   }
569 #endif
570 
571   if (mode & ERR_SOUND_SERVER)
572     process_name = " sound server";
573   else if (mode & ERR_NETWORK_SERVER)
574     process_name = " network server";
575   else if (mode & ERR_NETWORK_CLIENT)
576     process_name = " network client **";
577 
578   if (format)
579   {
580     va_list ap;
581 
582     fprintf(error, "%s%s: ", program.command_basename, process_name);
583 
584     if (mode & ERR_WARN)
585       fprintf(error, "warning: ");
586 
587     va_start(ap, format);
588     vfprintf(error, format, ap);
589     va_end(ap);
590 
591     fprintf(error, "%s", newline);
592   }
593 
594   if (mode & ERR_HELP)
595     fprintf(error, "%s: Try option '--help' for more information.%s",
596 	    program.command_basename, newline);
597 
598   if (mode & ERR_EXIT)
599     fprintf(error, "%s%s: aborting%s",
600 	    program.command_basename, process_name, newline);
601 
602   if (error != stderr)
603     fclose(error);
604 
605   if (mode & ERR_EXIT)
606   {
607     if (mode & ERR_FROM_SERVER)
608       exit(1);				/* child process: normal exit */
609     else
610       program.exit_function(1);		/* main process: clean up stuff */
611   }
612 }
613 
checked_malloc(unsigned long size)614 void *checked_malloc(unsigned long size)
615 {
616   void *ptr;
617 
618   ptr = malloc(size);
619 
620   if (ptr == NULL)
621     Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size);
622 
623   return ptr;
624 }
625 
checked_calloc(unsigned long size)626 void *checked_calloc(unsigned long size)
627 {
628   void *ptr;
629 
630   ptr = calloc(1, size);
631 
632   if (ptr == NULL)
633     Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size);
634 
635   return ptr;
636 }
637 
checked_realloc(void * ptr,unsigned long size)638 void *checked_realloc(void *ptr, unsigned long size)
639 {
640   ptr = realloc(ptr, size);
641 
642   if (ptr == NULL)
643     Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size);
644 
645   return ptr;
646 }
647 
getFile16BitInteger(FILE * file,int byte_order)648 short getFile16BitInteger(FILE *file, int byte_order)
649 {
650   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
651     return ((fgetc(file) <<  8) |
652 	    (fgetc(file) <<  0));
653   else		 /* BYTE_ORDER_LITTLE_ENDIAN */
654     return ((fgetc(file) <<  0) |
655 	    (fgetc(file) <<  8));
656 }
657 
putFile16BitInteger(FILE * file,short value,int byte_order)658 void putFile16BitInteger(FILE *file, short value, int byte_order)
659 {
660   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
661   {
662     fputc((value >>  8) & 0xff, file);
663     fputc((value >>  0) & 0xff, file);
664   }
665   else		 /* BYTE_ORDER_LITTLE_ENDIAN */
666   {
667     fputc((value >>  0) & 0xff, file);
668     fputc((value >>  8) & 0xff, file);
669   }
670 }
671 
getFile32BitInteger(FILE * file,int byte_order)672 int getFile32BitInteger(FILE *file, int byte_order)
673 {
674   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
675     return ((fgetc(file) << 24) |
676 	    (fgetc(file) << 16) |
677 	    (fgetc(file) <<  8) |
678 	    (fgetc(file) <<  0));
679   else		 /* BYTE_ORDER_LITTLE_ENDIAN */
680     return ((fgetc(file) <<  0) |
681 	    (fgetc(file) <<  8) |
682 	    (fgetc(file) << 16) |
683 	    (fgetc(file) << 24));
684 }
685 
putFile32BitInteger(FILE * file,int value,int byte_order)686 void putFile32BitInteger(FILE *file, int value, int byte_order)
687 {
688   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
689   {
690     fputc((value >> 24) & 0xff, file);
691     fputc((value >> 16) & 0xff, file);
692     fputc((value >>  8) & 0xff, file);
693     fputc((value >>  0) & 0xff, file);
694   }
695   else		 /* BYTE_ORDER_LITTLE_ENDIAN */
696   {
697     fputc((value >>  0) & 0xff, file);
698     fputc((value >>  8) & 0xff, file);
699     fputc((value >> 16) & 0xff, file);
700     fputc((value >> 24) & 0xff, file);
701   }
702 }
703 
getFileChunk(FILE * file,char * chunk_name,int * chunk_size,int byte_order)704 boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
705 		     int byte_order)
706 {
707   const int chunk_name_length = 4;
708 
709   /* read chunk name */
710   fgets(chunk_name, chunk_name_length + 1, file);
711 
712   if (chunk_size != NULL)
713   {
714     /* read chunk size */
715     *chunk_size = getFile32BitInteger(file, byte_order);
716   }
717 
718   return (feof(file) || ferror(file) ? FALSE : TRUE);
719 }
720 
putFileChunk(FILE * file,char * chunk_name,int chunk_size,int byte_order)721 void putFileChunk(FILE *file, char *chunk_name, int chunk_size,
722 		  int byte_order)
723 {
724   /* write chunk name */
725   fputs(chunk_name, file);
726 
727   if (chunk_size >= 0)
728   {
729     /* write chunk size */
730     putFile32BitInteger(file, chunk_size, byte_order);
731   }
732 }
733 
ReadUnusedBytesFromFile(FILE * file,unsigned long bytes)734 void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
735 {
736   while (bytes--)
737     fgetc(file);
738 }
739 
WriteUnusedBytesToFile(FILE * file,unsigned long bytes)740 void WriteUnusedBytesToFile(FILE *file, unsigned long bytes)
741 {
742   while (bytes--)
743     fputc(0, file);
744 }
745 
746 #define TRANSLATE_KEYSYM_TO_KEYNAME	0
747 #define TRANSLATE_KEYSYM_TO_X11KEYNAME	1
748 #define TRANSLATE_X11KEYNAME_TO_KEYSYM	2
749 
translate_keyname(Key * keysym,char ** x11name,char ** name,int mode)750 void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
751 {
752   static struct
753   {
754     Key key;
755     char *x11name;
756     char *name;
757   } translate_key[] =
758   {
759     /* normal cursor keys */
760     { KSYM_Left,	"XK_Left",		"cursor left" },
761     { KSYM_Right,	"XK_Right",		"cursor right" },
762     { KSYM_Up,		"XK_Up",		"cursor up" },
763     { KSYM_Down,	"XK_Down",		"cursor down" },
764 
765     /* keypad cursor keys */
766 #ifdef KSYM_KP_Left
767     { KSYM_KP_Left,	"XK_KP_Left",		"keypad left" },
768     { KSYM_KP_Right,	"XK_KP_Right",		"keypad right" },
769     { KSYM_KP_Up,	"XK_KP_Up",		"keypad up" },
770     { KSYM_KP_Down,	"XK_KP_Down",		"keypad down" },
771 #endif
772 
773     /* other keypad keys */
774 #ifdef KSYM_KP_Enter
775     { KSYM_KP_Enter,	"XK_KP_Enter",		"keypad enter" },
776     { KSYM_KP_Add,	"XK_KP_Add",		"keypad +" },
777     { KSYM_KP_Subtract,	"XK_KP_Subtract",	"keypad -" },
778     { KSYM_KP_Multiply,	"XK_KP_Multiply",	"keypad mltply" },
779     { KSYM_KP_Divide,	"XK_KP_Divide",		"keypad /" },
780     { KSYM_KP_Separator,"XK_KP_Separator",	"keypad ," },
781 #endif
782 
783     /* modifier keys */
784     { KSYM_Shift_L,	"XK_Shift_L",		"left shift" },
785     { KSYM_Shift_R,	"XK_Shift_R",		"right shift" },
786     { KSYM_Control_L,	"XK_Control_L",		"left control" },
787     { KSYM_Control_R,	"XK_Control_R",		"right control" },
788     { KSYM_Meta_L,	"XK_Meta_L",		"left meta" },
789     { KSYM_Meta_R,	"XK_Meta_R",		"right meta" },
790     { KSYM_Alt_L,	"XK_Alt_L",		"left alt" },
791     { KSYM_Alt_R,	"XK_Alt_R",		"right alt" },
792     { KSYM_Super_L,	"XK_Super_L",		"left super" },	 /* Win-L */
793     { KSYM_Super_R,	"XK_Super_R",		"right super" }, /* Win-R */
794     { KSYM_Mode_switch,	"XK_Mode_switch",	"mode switch" }, /* Alt-R */
795     { KSYM_Multi_key,	"XK_Multi_key",		"multi key" },	 /* Ctrl-R */
796 
797     /* some special keys */
798     { KSYM_BackSpace,	"XK_BackSpace",		"backspace" },
799     { KSYM_Delete,	"XK_Delete",		"delete" },
800     { KSYM_Insert,	"XK_Insert",		"insert" },
801     { KSYM_Tab,		"XK_Tab",		"tab" },
802     { KSYM_Home,	"XK_Home",		"home" },
803     { KSYM_End,		"XK_End",		"end" },
804     { KSYM_Page_Up,	"XK_Page_Up",		"page up" },
805     { KSYM_Page_Down,	"XK_Page_Down",		"page down" },
806     { KSYM_Menu,	"XK_Menu",		"menu" },	 /* Win-Menu */
807 
808     /* ASCII 0x20 to 0x40 keys (except numbers) */
809     { KSYM_space,	"XK_space",		"space" },
810     { KSYM_exclam,	"XK_exclam",		"!" },
811     { KSYM_quotedbl,	"XK_quotedbl",		"\"" },
812     { KSYM_numbersign,	"XK_numbersign",	"#" },
813     { KSYM_dollar,	"XK_dollar",		"$" },
814     { KSYM_percent,	"XK_percent",		"%" },
815     { KSYM_ampersand,	"XK_ampersand",		"&" },
816     { KSYM_apostrophe,	"XK_apostrophe",	"'" },
817     { KSYM_parenleft,	"XK_parenleft",		"(" },
818     { KSYM_parenright,	"XK_parenright",	")" },
819     { KSYM_asterisk,	"XK_asterisk",		"*" },
820     { KSYM_plus,	"XK_plus",		"+" },
821     { KSYM_comma,	"XK_comma",		"," },
822     { KSYM_minus,	"XK_minus",		"-" },
823     { KSYM_period,	"XK_period",		"." },
824     { KSYM_slash,	"XK_slash",		"/" },
825     { KSYM_colon,	"XK_colon",		":" },
826     { KSYM_semicolon,	"XK_semicolon",		";" },
827     { KSYM_less,	"XK_less",		"<" },
828     { KSYM_equal,	"XK_equal",		"=" },
829     { KSYM_greater,	"XK_greater",		">" },
830     { KSYM_question,	"XK_question",		"?" },
831     { KSYM_at,		"XK_at",		"@" },
832 
833     /* more ASCII keys */
834     { KSYM_bracketleft,	"XK_bracketleft",	"[" },
835     { KSYM_backslash,	"XK_backslash",		"backslash" },
836     { KSYM_bracketright,"XK_bracketright",	"]" },
837     { KSYM_asciicircum,	"XK_asciicircum",	"circumflex" },
838     { KSYM_underscore,	"XK_underscore",	"_" },
839     { KSYM_grave,	"XK_grave",		"grave" },
840     { KSYM_quoteleft,	"XK_quoteleft",		"quote left" },
841     { KSYM_braceleft,	"XK_braceleft",		"brace left" },
842     { KSYM_bar,		"XK_bar",		"bar" },
843     { KSYM_braceright,	"XK_braceright",	"brace right" },
844     { KSYM_asciitilde,	"XK_asciitilde",	"ascii tilde" },
845 
846     /* special (non-ASCII) keys */
847     { KSYM_Adiaeresis,	"XK_Adiaeresis",	"�" },
848     { KSYM_Odiaeresis,	"XK_Odiaeresis",	"�" },
849     { KSYM_Udiaeresis,	"XK_Udiaeresis",	"�" },
850     { KSYM_adiaeresis,	"XK_adiaeresis",	"�" },
851     { KSYM_odiaeresis,	"XK_odiaeresis",	"�" },
852     { KSYM_udiaeresis,	"XK_udiaeresis",	"�" },
853     { KSYM_ssharp,	"XK_ssharp",		"sharp s" },
854 
855     /* end-of-array identifier */
856     { 0,                NULL,			NULL }
857   };
858 
859   int i;
860 
861   if (mode == TRANSLATE_KEYSYM_TO_KEYNAME)
862   {
863     static char name_buffer[30];
864     Key key = *keysym;
865 
866     if (key >= KSYM_A && key <= KSYM_Z)
867       sprintf(name_buffer, "%c", 'A' + (char)(key - KSYM_A));
868     else if (key >= KSYM_a && key <= KSYM_z)
869       sprintf(name_buffer, "%c", 'a' + (char)(key - KSYM_a));
870     else if (key >= KSYM_0 && key <= KSYM_9)
871       sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0));
872     else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
873       sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0));
874     else if (key >= KSYM_F1 && key <= KSYM_F24)
875       sprintf(name_buffer, "function F%d", (int)(key - KSYM_F1 + 1));
876     else if (key == KSYM_UNDEFINED)
877       strcpy(name_buffer, "(undefined)");
878     else
879     {
880       i = 0;
881 
882       do
883       {
884 	if (key == translate_key[i].key)
885 	{
886 	  strcpy(name_buffer, translate_key[i].name);
887 	  break;
888 	}
889       }
890       while (translate_key[++i].name);
891 
892       if (!translate_key[i].name)
893 	strcpy(name_buffer, "(unknown)");
894     }
895 
896     *name = name_buffer;
897   }
898   else if (mode == TRANSLATE_KEYSYM_TO_X11KEYNAME)
899   {
900     static char name_buffer[30];
901     Key key = *keysym;
902 
903     if (key >= KSYM_A && key <= KSYM_Z)
904       sprintf(name_buffer, "XK_%c", 'A' + (char)(key - KSYM_A));
905     else if (key >= KSYM_a && key <= KSYM_z)
906       sprintf(name_buffer, "XK_%c", 'a' + (char)(key - KSYM_a));
907     else if (key >= KSYM_0 && key <= KSYM_9)
908       sprintf(name_buffer, "XK_%c", '0' + (char)(key - KSYM_0));
909     else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
910       sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - KSYM_KP_0));
911     else if (key >= KSYM_F1 && key <= KSYM_F24)
912       sprintf(name_buffer, "XK_F%d", (int)(key - KSYM_F1 + 1));
913     else if (key == KSYM_UNDEFINED)
914       strcpy(name_buffer, "[undefined]");
915     else
916     {
917       i = 0;
918 
919       do
920       {
921 	if (key == translate_key[i].key)
922 	{
923 	  strcpy(name_buffer, translate_key[i].x11name);
924 	  break;
925 	}
926       }
927       while (translate_key[++i].x11name);
928 
929       if (!translate_key[i].x11name)
930 	sprintf(name_buffer, "0x%04lx", (unsigned long)key);
931     }
932 
933     *x11name = name_buffer;
934   }
935   else if (mode == TRANSLATE_X11KEYNAME_TO_KEYSYM)
936   {
937     Key key = KSYM_UNDEFINED;
938     char *name_ptr = *x11name;
939 
940     if (strncmp(name_ptr, "XK_", 3) == 0 && strlen(name_ptr) == 4)
941     {
942       char c = name_ptr[3];
943 
944       if (c >= 'A' && c <= 'Z')
945 	key = KSYM_A + (Key)(c - 'A');
946       else if (c >= 'a' && c <= 'z')
947 	key = KSYM_a + (Key)(c - 'a');
948       else if (c >= '0' && c <= '9')
949 	key = KSYM_0 + (Key)(c - '0');
950     }
951     else if (strncmp(name_ptr, "XK_KP_", 6) == 0 && strlen(name_ptr) == 7)
952     {
953       char c = name_ptr[6];
954 
955       if (c >= '0' && c <= '9')
956 	key = KSYM_0 + (Key)(c - '0');
957     }
958     else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
959     {
960       char c1 = name_ptr[4];
961       char c2 = name_ptr[5];
962       int d = 0;
963 
964       if ((c1 >= '0' && c1 <= '9') &&
965 	  ((c2 >= '0' && c1 <= '9') || c2 == '\0'))
966 	d = atoi(&name_ptr[4]);
967 
968       if (d >=1 && d <= 24)
969 	key = KSYM_F1 + (Key)(d - 1);
970     }
971     else if (strncmp(name_ptr, "XK_", 3) == 0)
972     {
973       i = 0;
974 
975       do
976       {
977 	if (strcmp(name_ptr, translate_key[i].x11name) == 0)
978 	{
979 	  key = translate_key[i].key;
980 	  break;
981 	}
982       }
983       while (translate_key[++i].x11name);
984     }
985     else if (strncmp(name_ptr, "0x", 2) == 0)
986     {
987       unsigned long value = 0;
988 
989       name_ptr += 2;
990 
991       while (name_ptr)
992       {
993 	char c = *name_ptr++;
994 	int d = -1;
995 
996 	if (c >= '0' && c <= '9')
997 	  d = (int)(c - '0');
998 	else if (c >= 'a' && c <= 'f')
999 	  d = (int)(c - 'a' + 10);
1000 	else if (c >= 'A' && c <= 'F')
1001 	  d = (int)(c - 'A' + 10);
1002 
1003 	if (d == -1)
1004 	{
1005 	  value = -1;
1006 	  break;
1007 	}
1008 
1009 	value = value * 16 + d;
1010       }
1011 
1012       if (value != -1)
1013 	key = (Key)value;
1014     }
1015 
1016     *keysym = key;
1017   }
1018 }
1019 
getKeyNameFromKey(Key key)1020 char *getKeyNameFromKey(Key key)
1021 {
1022   char *name;
1023 
1024   translate_keyname(&key, NULL, &name, TRANSLATE_KEYSYM_TO_KEYNAME);
1025   return name;
1026 }
1027 
getX11KeyNameFromKey(Key key)1028 char *getX11KeyNameFromKey(Key key)
1029 {
1030   char *x11name;
1031 
1032   translate_keyname(&key, &x11name, NULL, TRANSLATE_KEYSYM_TO_X11KEYNAME);
1033   return x11name;
1034 }
1035 
getKeyFromX11KeyName(char * x11name)1036 Key getKeyFromX11KeyName(char *x11name)
1037 {
1038   Key key;
1039 
1040   translate_keyname(&key, &x11name, NULL, TRANSLATE_X11KEYNAME_TO_KEYSYM);
1041   return key;
1042 }
1043 
getCharFromKey(Key key)1044 char getCharFromKey(Key key)
1045 {
1046   char *keyname = getKeyNameFromKey(key);
1047   char letter = 0;
1048 
1049   if (strlen(keyname) == 1)
1050     letter = keyname[0];
1051   else if (strcmp(keyname, "space") == 0)
1052     letter = ' ';
1053   else if (strcmp(keyname, "circumflex") == 0)
1054     letter = '^';
1055 
1056   return letter;
1057 }
1058 
1059 /* ------------------------------------------------------------------------- */
1060 /* some functions to handle lists of level directories                       */
1061 /* ------------------------------------------------------------------------- */
1062 
newLevelDirInfo()1063 struct LevelDirInfo *newLevelDirInfo()
1064 {
1065   return checked_calloc(sizeof(struct LevelDirInfo));
1066 }
1067 
pushLevelDirInfo(struct LevelDirInfo ** node_first,struct LevelDirInfo * node_new)1068 void pushLevelDirInfo(struct LevelDirInfo **node_first,
1069 		      struct LevelDirInfo *node_new)
1070 {
1071   node_new->next = *node_first;
1072   *node_first = node_new;
1073 }
1074 
numLevelDirInfo(struct LevelDirInfo * node)1075 int numLevelDirInfo(struct LevelDirInfo *node)
1076 {
1077   int num = 0;
1078 
1079   while (node)
1080   {
1081     num++;
1082     node = node->next;
1083   }
1084 
1085   return num;
1086 }
1087 
validLevelSeries(struct LevelDirInfo * node)1088 boolean validLevelSeries(struct LevelDirInfo *node)
1089 {
1090   return (node != NULL && !node->node_group && !node->parent_link);
1091 }
1092 
getFirstValidLevelSeries(struct LevelDirInfo * node)1093 struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node)
1094 {
1095   if (node == NULL)
1096   {
1097     if (leveldir_first)		/* start with first level directory entry */
1098       return getFirstValidLevelSeries(leveldir_first);
1099     else
1100       return NULL;
1101   }
1102   else if (node->node_group)	/* enter level group (step down into tree) */
1103     return getFirstValidLevelSeries(node->node_group);
1104   else if (node->parent_link)	/* skip start entry of level group */
1105   {
1106     if (node->next)		/* get first real level series entry */
1107       return getFirstValidLevelSeries(node->next);
1108     else			/* leave empty level group and go on */
1109       return getFirstValidLevelSeries(node->node_parent->next);
1110   }
1111   else				/* this seems to be a regular level series */
1112     return node;
1113 }
1114 
getLevelDirInfoFirstGroupEntry(struct LevelDirInfo * node)1115 struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node)
1116 {
1117   if (node == NULL)
1118     return NULL;
1119 
1120   if (node->node_parent == NULL)		/* top level group */
1121     return leveldir_first;
1122   else						/* sub level group */
1123     return node->node_parent->node_group;
1124 }
1125 
numLevelDirInfoInGroup(struct LevelDirInfo * node)1126 int numLevelDirInfoInGroup(struct LevelDirInfo *node)
1127 {
1128   return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node));
1129 }
1130 
posLevelDirInfo(struct LevelDirInfo * node)1131 int posLevelDirInfo(struct LevelDirInfo *node)
1132 {
1133   struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node);
1134   int pos = 0;
1135 
1136   while (node_cmp)
1137   {
1138     if (node_cmp == node)
1139       return pos;
1140 
1141     pos++;
1142     node_cmp = node_cmp->next;
1143   }
1144 
1145   return 0;
1146 }
1147 
getLevelDirInfoFromPos(struct LevelDirInfo * node,int pos)1148 struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos)
1149 {
1150   struct LevelDirInfo *node_default = node;
1151   int pos_cmp = 0;
1152 
1153   while (node)
1154   {
1155     if (pos_cmp == pos)
1156       return node;
1157 
1158     pos_cmp++;
1159     node = node->next;
1160   }
1161 
1162   return node_default;
1163 }
1164 
getLevelDirInfoFromFilenameExt(struct LevelDirInfo * node,char * filename)1165 struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node,
1166 						    char *filename)
1167 {
1168   if (filename == NULL)
1169     return NULL;
1170 
1171   while (node)
1172   {
1173     if (node->node_group)
1174     {
1175       struct LevelDirInfo *node_group;
1176 
1177       node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename);
1178 
1179       if (node_group)
1180 	return node_group;
1181     }
1182     else if (!node->parent_link)
1183     {
1184       if (strcmp(filename, node->filename) == 0)
1185 	return node;
1186     }
1187 
1188     node = node->next;
1189   }
1190 
1191   return NULL;
1192 }
1193 
getLevelDirInfoFromFilename(char * filename)1194 struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename)
1195 {
1196   return getLevelDirInfoFromFilenameExt(leveldir_first, filename);
1197 }
1198 
dumpLevelDirInfo(struct LevelDirInfo * node,int depth)1199 void dumpLevelDirInfo(struct LevelDirInfo *node, int depth)
1200 {
1201   int i;
1202 
1203   while (node)
1204   {
1205     for (i=0; i<depth * 3; i++)
1206       printf(" ");
1207 
1208     printf("filename == '%s'\n", node->filename);
1209 
1210     if (node->node_group != NULL)
1211       dumpLevelDirInfo(node->node_group, depth + 1);
1212 
1213     node = node->next;
1214   }
1215 }
1216 
sortLevelDirInfo(struct LevelDirInfo ** node_first,int (* compare_function)(const void *,const void *))1217 void sortLevelDirInfo(struct LevelDirInfo **node_first,
1218 		      int (*compare_function)(const void *, const void *))
1219 {
1220   int num_nodes = numLevelDirInfo(*node_first);
1221   struct LevelDirInfo **sort_array;
1222   struct LevelDirInfo *node = *node_first;
1223   int i = 0;
1224 
1225   if (num_nodes == 0)
1226     return;
1227 
1228   /* allocate array for sorting structure pointers */
1229   sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *));
1230 
1231   /* writing structure pointers to sorting array */
1232   while (i < num_nodes && node)		/* double boundary check... */
1233   {
1234     sort_array[i] = node;
1235 
1236     i++;
1237     node = node->next;
1238   }
1239 
1240   /* sorting the structure pointers in the sorting array */
1241   qsort(sort_array, num_nodes, sizeof(struct LevelDirInfo *),
1242 	compare_function);
1243 
1244   /* update the linkage of list elements with the sorted node array */
1245   for (i=0; i<num_nodes - 1; i++)
1246     sort_array[i]->next = sort_array[i + 1];
1247   sort_array[num_nodes - 1]->next = NULL;
1248 
1249   /* update the linkage of the main list anchor pointer */
1250   *node_first = sort_array[0];
1251 
1252   free(sort_array);
1253 
1254   /* now recursively sort the level group structures */
1255   node = *node_first;
1256   while (node)
1257   {
1258     if (node->node_group != NULL)
1259       sortLevelDirInfo(&node->node_group, compare_function);
1260 
1261     node = node->next;
1262   }
1263 }
1264 
swap_numbers(int * i1,int * i2)1265  void swap_numbers(int *i1, int *i2)
1266 {
1267   int help = *i1;
1268 
1269   *i1 = *i2;
1270   *i2 = help;
1271 }
1272 
swap_number_pairs(int * x1,int * y1,int * x2,int * y2)1273  void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
1274 {
1275   int help_x = *x1;
1276   int help_y = *y1;
1277 
1278   *x1 = *x2;
1279   *x2 = help_x;
1280 
1281   *y1 = *y2;
1282   *y2 = help_y;
1283 }
1284 
1285 
1286 /* ========================================================================= */
1287 /* some stuff from "files.c"                                                 */
1288 /* ========================================================================= */
1289 
1290 #if defined(PLATFORM_WIN32)
1291 #ifndef S_IRGRP
1292 #define S_IRGRP S_IRUSR
1293 #endif
1294 #ifndef S_IROTH
1295 #define S_IROTH S_IRUSR
1296 #endif
1297 #ifndef S_IWGRP
1298 #define S_IWGRP S_IWUSR
1299 #endif
1300 #ifndef S_IWOTH
1301 #define S_IWOTH S_IWUSR
1302 #endif
1303 #ifndef S_IXGRP
1304 #define S_IXGRP S_IXUSR
1305 #endif
1306 #ifndef S_IXOTH
1307 #define S_IXOTH S_IXUSR
1308 #endif
1309 #ifndef S_IRWXG
1310 #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
1311 #endif
1312 #ifndef S_ISGID
1313 #define S_ISGID 0
1314 #endif
1315 #endif	/* PLATFORM_WIN32 */
1316 
1317 /* file permissions for newly written files */
1318 #define MODE_R_ALL		(S_IRUSR | S_IRGRP | S_IROTH)
1319 #define MODE_W_ALL		(S_IWUSR | S_IWGRP | S_IWOTH)
1320 #define MODE_X_ALL		(S_IXUSR | S_IXGRP | S_IXOTH)
1321 
1322 #define MODE_W_PRIVATE		(S_IWUSR)
1323 #define MODE_W_PUBLIC		(S_IWUSR | S_IWGRP)
1324 #define MODE_W_PUBLIC_DIR	(S_IWUSR | S_IWGRP | S_ISGID)
1325 
1326 #define DIR_PERMS_PRIVATE	(MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE)
1327 #define DIR_PERMS_PUBLIC	(MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR)
1328 
1329 #define FILE_PERMS_PRIVATE	(MODE_R_ALL | MODE_W_PRIVATE)
1330 #define FILE_PERMS_PUBLIC	(MODE_R_ALL | MODE_W_PUBLIC)
1331 
getUserDataDir(void)1332 char *getUserDataDir(void)
1333 {
1334   static char *userdata_dir = NULL;
1335 
1336   if (!userdata_dir)
1337   {
1338     char *home_dir = getHomeDir();
1339     char *data_dir = program.userdata_directory;
1340 
1341     userdata_dir = getPath2(home_dir, data_dir);
1342   }
1343 
1344   return userdata_dir;
1345 }
1346 
getSetupDir()1347 char *getSetupDir()
1348 {
1349   return getUserDataDir();
1350 }
1351 
posix_umask(mode_t mask)1352 static mode_t posix_umask(mode_t mask)
1353 {
1354 #if defined(PLATFORM_UNIX)
1355   return umask(mask);
1356 #else
1357   return 0;
1358 #endif
1359 }
1360 
posix_mkdir(const char * pathname,mode_t mode)1361 static int posix_mkdir(const char *pathname, mode_t mode)
1362 {
1363 #if defined(PLATFORM_WIN32)
1364   return mkdir(pathname);
1365 #else
1366   return mkdir(pathname, mode);
1367 #endif
1368 }
1369 
createDirectory(char * dir,char * text,int permission_class)1370 void createDirectory(char *dir, char *text, int permission_class)
1371 {
1372   /* leave "other" permissions in umask untouched, but ensure group parts
1373      of USERDATA_DIR_MODE are not masked */
1374   mode_t dir_mode = (permission_class == PERMS_PRIVATE ?
1375 		     DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC);
1376   mode_t normal_umask = posix_umask(0);
1377   mode_t group_umask = ~(dir_mode & S_IRWXG);
1378   posix_umask(normal_umask & group_umask);
1379 
1380   if (access(dir, F_OK) != 0)
1381     if (posix_mkdir(dir, dir_mode) != 0)
1382       Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
1383 
1384   posix_umask(normal_umask);		/* reset normal umask */
1385 }
1386 
InitUserDataDirectory()1387 void InitUserDataDirectory()
1388 {
1389   createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
1390 }
1391 
SetFilePermissions(char * filename,int permission_class)1392 void SetFilePermissions(char *filename, int permission_class)
1393 {
1394   chmod(filename, (permission_class == PERMS_PRIVATE ?
1395 		   FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC));
1396 }
1397 
getFileVersionFromCookieString(const char * cookie)1398 int getFileVersionFromCookieString(const char *cookie)
1399 {
1400   const char *ptr_cookie1, *ptr_cookie2;
1401   const char *pattern1 = "_FILE_VERSION_";
1402   const char *pattern2 = "?.?";
1403   const int len_cookie = strlen(cookie);
1404   const int len_pattern1 = strlen(pattern1);
1405   const int len_pattern2 = strlen(pattern2);
1406   const int len_pattern = len_pattern1 + len_pattern2;
1407   int version_major, version_minor;
1408 
1409   if (len_cookie <= len_pattern)
1410     return -1;
1411 
1412   ptr_cookie1 = &cookie[len_cookie - len_pattern];
1413   ptr_cookie2 = &cookie[len_cookie - len_pattern2];
1414 
1415   if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0)
1416     return -1;
1417 
1418   if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' ||
1419       ptr_cookie2[1] != '.' ||
1420       ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9')
1421     return -1;
1422 
1423   version_major = ptr_cookie2[0] - '0';
1424   version_minor = ptr_cookie2[2] - '0';
1425 
1426   return VERSION_IDENT(version_major, version_minor, 0);
1427 }
1428 
checkCookieString(const char * cookie,const char * template)1429 boolean checkCookieString(const char *cookie, const char *template)
1430 {
1431   const char *pattern = "_FILE_VERSION_?.?";
1432   const int len_cookie = strlen(cookie);
1433   const int len_template = strlen(template);
1434   const int len_pattern = strlen(pattern);
1435 
1436   if (len_cookie != len_template)
1437     return FALSE;
1438 
1439   if (strncmp(cookie, template, len_cookie - len_pattern) != 0)
1440     return FALSE;
1441 
1442   return TRUE;
1443 }
1444 
1445 /* ------------------------------------------------------------------------- */
1446 /* setup file stuff                                                          */
1447 /* ------------------------------------------------------------------------- */
1448 
string_tolower(char * s)1449 static char *string_tolower(char *s)
1450 {
1451   static char s_lower[100];
1452   int i;
1453 
1454   if (strlen(s) >= 100)
1455     return s;
1456 
1457   strcpy(s_lower, s);
1458 
1459   for (i=0; i<strlen(s_lower); i++)
1460     s_lower[i] = tolower(s_lower[i]);
1461 
1462   return s_lower;
1463 }
1464 
get_string_integer_value(char * s)1465 int get_string_integer_value(char *s)
1466 {
1467   static char *number_text[][3] =
1468   {
1469     { "0", "zero", "null", },
1470     { "1", "one", "first" },
1471     { "2", "two", "second" },
1472     { "3", "three", "third" },
1473     { "4", "four", "fourth" },
1474     { "5", "five", "fifth" },
1475     { "6", "six", "sixth" },
1476     { "7", "seven", "seventh" },
1477     { "8", "eight", "eighth" },
1478     { "9", "nine", "ninth" },
1479     { "10", "ten", "tenth" },
1480     { "11", "eleven", "eleventh" },
1481     { "12", "twelve", "twelfth" },
1482   };
1483 
1484   int i, j;
1485 
1486   for (i=0; i<13; i++)
1487     for (j=0; j<3; j++)
1488       if (strcmp(string_tolower(s), number_text[i][j]) == 0)
1489 	return i;
1490 
1491   return atoi(s);
1492 }
1493 
get_string_boolean_value(char * s)1494 boolean get_string_boolean_value(char *s)
1495 {
1496   if (strcmp(string_tolower(s), "true") == 0 ||
1497       strcmp(string_tolower(s), "yes") == 0 ||
1498       strcmp(string_tolower(s), "on") == 0 ||
1499       get_string_integer_value(s) == 1)
1500     return TRUE;
1501   else
1502     return FALSE;
1503 }
1504 
getFormattedSetupEntry(char * token,char * value)1505 char *getFormattedSetupEntry(char *token, char *value)
1506 {
1507   int i;
1508   static char entry[MAX_LINE_LEN];
1509 
1510   sprintf(entry, "%s:", token);
1511   for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
1512     entry[i] = ' ';
1513   entry[i] = '\0';
1514 
1515   strcat(entry, value);
1516 
1517   return entry;
1518 }
1519 
freeSetupFileList(struct SetupFileList * setup_file_list)1520 void freeSetupFileList(struct SetupFileList *setup_file_list)
1521 {
1522   if (!setup_file_list)
1523     return;
1524 
1525   if (setup_file_list->token)
1526     free(setup_file_list->token);
1527   if (setup_file_list->value)
1528     free(setup_file_list->value);
1529   if (setup_file_list->next)
1530     freeSetupFileList(setup_file_list->next);
1531   free(setup_file_list);
1532 }
1533 
newSetupFileList(char * token,char * value)1534 static struct SetupFileList *newSetupFileList(char *token, char *value)
1535 {
1536   struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
1537 
1538   new->token = checked_malloc(strlen(token) + 1);
1539   strcpy(new->token, token);
1540 
1541   new->value = checked_malloc(strlen(value) + 1);
1542   strcpy(new->value, value);
1543 
1544   new->next = NULL;
1545 
1546   return new;
1547 }
1548 
getTokenValue(struct SetupFileList * setup_file_list,char * token)1549 char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
1550 {
1551   if (!setup_file_list)
1552     return NULL;
1553 
1554   if (strcmp(setup_file_list->token, token) == 0)
1555     return setup_file_list->value;
1556   else
1557     return getTokenValue(setup_file_list->next, token);
1558 }
1559 
setTokenValue(struct SetupFileList * setup_file_list,char * token,char * value)1560 static void setTokenValue(struct SetupFileList *setup_file_list,
1561 			  char *token, char *value)
1562 {
1563   if (!setup_file_list)
1564     return;
1565 
1566   if (strcmp(setup_file_list->token, token) == 0)
1567   {
1568     free(setup_file_list->value);
1569     setup_file_list->value = checked_malloc(strlen(value) + 1);
1570     strcpy(setup_file_list->value, value);
1571   }
1572   else if (setup_file_list->next == NULL)
1573     setup_file_list->next = newSetupFileList(token, value);
1574   else
1575     setTokenValue(setup_file_list->next, token, value);
1576 }
1577 
1578 #ifdef DEBUG
printSetupFileList(struct SetupFileList * setup_file_list)1579 static void printSetupFileList(struct SetupFileList *setup_file_list)
1580 {
1581   if (!setup_file_list)
1582     return;
1583 
1584   printf("token: '%s'\n", setup_file_list->token);
1585   printf("value: '%s'\n", setup_file_list->value);
1586 
1587   printSetupFileList(setup_file_list->next);
1588 }
1589 #endif
1590 
loadSetupFileList(char * filename)1591 struct SetupFileList *loadSetupFileList(char *filename)
1592 {
1593   int line_len;
1594   char line[MAX_LINE_LEN];
1595   char *token, *value, *line_ptr;
1596   struct SetupFileList *setup_file_list = newSetupFileList("", "");
1597   struct SetupFileList *first_valid_list_entry;
1598 
1599   FILE *file;
1600 
1601   if (!(file = fopen(filename, MODE_READ)))
1602   {
1603     Error(ERR_WARN, "cannot open configuration file '%s'", filename);
1604     return NULL;
1605   }
1606 
1607   while(!feof(file))
1608   {
1609     /* read next line of input file */
1610     if (!fgets(line, MAX_LINE_LEN, file))
1611       break;
1612 
1613     /* cut trailing comment or whitespace from input line */
1614     for (line_ptr = line; *line_ptr; line_ptr++)
1615     {
1616       if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
1617       {
1618 	*line_ptr = '\0';
1619 	break;
1620       }
1621     }
1622 
1623     /* cut trailing whitespaces from input line */
1624     for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
1625       if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
1626 	*line_ptr = '\0';
1627 
1628     /* ignore empty lines */
1629     if (*line == '\0')
1630       continue;
1631 
1632     line_len = strlen(line);
1633 
1634     /* cut leading whitespaces from token */
1635     for (token = line; *token; token++)
1636       if (*token != ' ' && *token != '\t')
1637 	break;
1638 
1639     /* find end of token */
1640     for (line_ptr = token; *line_ptr; line_ptr++)
1641     {
1642       if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
1643       {
1644 	*line_ptr = '\0';
1645 	break;
1646       }
1647     }
1648 
1649     if (line_ptr < line + line_len)
1650       value = line_ptr + 1;
1651     else
1652       value = "\0";
1653 
1654     /* cut leading whitespaces from value */
1655     for (; *value; value++)
1656       if (*value != ' ' && *value != '\t')
1657 	break;
1658 
1659     if (*token && *value)
1660       setTokenValue(setup_file_list, token, value);
1661   }
1662 
1663   fclose(file);
1664 
1665   first_valid_list_entry = setup_file_list->next;
1666 
1667   /* free empty list header */
1668   setup_file_list->next = NULL;
1669   freeSetupFileList(setup_file_list);
1670 
1671   if (first_valid_list_entry == NULL)
1672     Error(ERR_WARN, "configuration file '%s' is empty", filename);
1673 
1674   return first_valid_list_entry;
1675 }
1676 
checkSetupFileListIdentifier(struct SetupFileList * setup_file_list,char * identifier)1677 void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
1678 				  char *identifier)
1679 {
1680   if (!setup_file_list)
1681     return;
1682 
1683   if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
1684   {
1685     if (strcmp(setup_file_list->value, identifier) != 0)
1686     {
1687       Error(ERR_WARN, "configuration file has wrong version");
1688       return;
1689     }
1690     else
1691       return;
1692   }
1693 
1694   if (setup_file_list->next)
1695     checkSetupFileListIdentifier(setup_file_list->next, identifier);
1696   else
1697   {
1698     Error(ERR_WARN, "configuration file has no version information");
1699     return;
1700   }
1701 }
1702 
1703 
1704 /* ========================================================================= */
1705 /* functions only needed for non-Unix (non-command-line) systems */
1706 /* ========================================================================= */
1707 
1708 #if !defined(PLATFORM_UNIX)
1709 
1710 #define ERROR_FILENAME		"error.out"
1711 
initErrorFile()1712 void initErrorFile()
1713 {
1714   char *filename;
1715 
1716   InitUserDataDirectory();
1717 
1718   filename = getPath2(getUserDataDir(), ERROR_FILENAME);
1719   unlink(filename);
1720   free(filename);
1721 }
1722 
openErrorFile()1723 FILE *openErrorFile()
1724 {
1725   char *filename;
1726   FILE *error_file;
1727 
1728   filename = getPath2(getUserDataDir(), ERROR_FILENAME);
1729   error_file = fopen(filename, MODE_APPEND);
1730   free(filename);
1731 
1732   return error_file;
1733 }
1734 
dumpErrorFile()1735 void dumpErrorFile()
1736 {
1737   char *filename;
1738   FILE *error_file;
1739 
1740   filename = getPath2(getUserDataDir(), ERROR_FILENAME);
1741   error_file = fopen(filename, MODE_READ);
1742   free(filename);
1743 
1744   if (error_file != NULL)
1745   {
1746     while (!feof(error_file))
1747       fputc(fgetc(error_file), stderr);
1748 
1749     fclose(error_file);
1750   }
1751 }
1752 #endif
1753 
1754 
1755 /* ========================================================================= */
1756 /* the following is only for debugging purpose and normally not used         */
1757 /* ========================================================================= */
1758 
1759 #define DEBUG_NUM_TIMESTAMPS	3
1760 
debug_print_timestamp(int counter_nr,char * message)1761 void debug_print_timestamp(int counter_nr, char *message)
1762 {
1763   static long counter[DEBUG_NUM_TIMESTAMPS][2];
1764 
1765   if (counter_nr >= DEBUG_NUM_TIMESTAMPS)
1766     Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c");
1767 
1768   counter[counter_nr][0] = Counter();
1769 
1770   if (message)
1771     printf("%s %.2f seconds\n", message,
1772 	   (float)(counter[counter_nr][0] - counter[counter_nr][1]) / 1000);
1773 
1774   counter[counter_nr][1] = Counter();
1775 }
1776