X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Flibgame%2Fmisc.c;h=536d90b53816d3b4ab11e26f28ed0f54edd9842e;hb=HEAD;hp=ff64284eee2061a52b267666418b1a95d63100c5;hpb=b8f3395f07c7a7c044384893c751f9b486d8f0d9;p=rocksndiamonds.git diff --git a/src/libgame/misc.c b/src/libgame/misc.c index ff64284e..536d90b5 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -41,8 +41,7 @@ // logging functions // ---------------------------------------------------------------------------- -#define DUPLICATE_LOG_OUT_TO_STDOUT TRUE -#define DUPLICATE_LOG_ERR_TO_STDERR TRUE +#define DUPLICATE_LOGGING_TO_STDOUT TRUE #if defined(PLATFORM_ANDROID) @@ -94,15 +93,15 @@ static void vprintf_log(char *format, va_list ap) static void vprintf_log_nonewline(char *format, va_list ap) { - FILE *file = program.log_file[LOG_ERR_ID]; + FILE *file = program.log_file; -#if DUPLICATE_LOG_ERR_TO_STDERR - if (file != program.log_file_default[LOG_ERR_ID]) +#if DUPLICATE_LOGGING_TO_STDOUT + if (file != program.log_file_default) { va_list ap2; va_copy(ap2, ap); - vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2); + vfprintf(program.log_file_default, format, ap2); va_end(ap2); } @@ -113,17 +112,17 @@ static void vprintf_log_nonewline(char *format, va_list ap) static void vprintf_log(char *format, va_list ap) { - FILE *file = program.log_file[LOG_ERR_ID]; + FILE *file = program.log_file; char *newline = STRING_NEWLINE; -#if DUPLICATE_LOG_ERR_TO_STDERR - if (file != program.log_file_default[LOG_ERR_ID]) +#if DUPLICATE_LOGGING_TO_STDOUT + if (file != program.log_file_default) { va_list ap2; va_copy(ap2, ap); - vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2); - fprintf(program.log_file_default[LOG_ERR_ID], "%s", newline); + vfprintf(program.log_file_default, format, ap2); + fprintf(program.log_file_default, "%s", newline); va_end(ap2); } @@ -196,15 +195,15 @@ void printf_line_with_prefix(char *prefix, char *line_chars, int line_length) static void vPrint(char *format, va_list ap) { - FILE *file = program.log_file[LOG_OUT_ID]; + FILE *file = program.log_file; -#if DUPLICATE_LOG_OUT_TO_STDOUT - if (file != program.log_file_default[LOG_OUT_ID]) +#if DUPLICATE_LOGGING_TO_STDOUT + if (file != program.log_file_default) { va_list ap2; va_copy(ap2, ap); - vfprintf(program.log_file_default[LOG_OUT_ID], format, ap2); + vfprintf(program.log_file_default, format, ap2); va_end(ap2); } @@ -224,7 +223,7 @@ void Print(char *format, ...) void PrintNoLog(char *format, ...) { - FILE *file = program.log_file_default[LOG_OUT_ID]; + FILE *file = program.log_file_default; va_list ap; va_start(ap, format); @@ -549,6 +548,50 @@ boolean getTokenValueFromString(char *string, char **token, char **value) } +// ---------------------------------------------------------------------------- +// UUID functions +// ---------------------------------------------------------------------------- + +#define UUID_BYTES 16 +#define UUID_CHARS (UUID_BYTES * 2) +#define UUID_LENGTH (UUID_CHARS + 4) + +static unsigned int uuid_random_function(int max) +{ + return GetBetterRandom(max); +} + +char *getUUIDExt(unsigned int (*random_function)(int max)) +{ + static char uuid[UUID_LENGTH + 1]; + int data[UUID_BYTES]; + int count = 0; + int i; + + for (i = 0; i < UUID_BYTES; i++) + data[i] = random_function(256); + + data[6] = 0x40 | (data[6] & 0x0f); + data[8] = 0x80 | (data[8] & 0x3f); + + for (i = 0; i < UUID_BYTES; i++) + { + sprintf(&uuid[count], "%02x", data[i]); + count += 2; + + if (i == 3 || i == 5 || i == 7 || i == 9) + strcat(&uuid[count++], "-"); + } + + return uuid; +} + +char *getUUID(void) +{ + return getUUIDExt(uuid_random_function); +} + + // ---------------------------------------------------------------------------- // counter functions // ---------------------------------------------------------------------------- @@ -597,8 +640,8 @@ void Delay(unsigned int delay) // Sleep specified number of milliseconds sleep_milliseconds(delay); } -boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay, - unsigned int actual_counter) +boolean DelayReachedExt2(unsigned int *counter_var, unsigned int delay, + unsigned int actual_counter) { if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) @@ -609,34 +652,40 @@ boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay, return TRUE; } -boolean FrameReached(unsigned int *frame_counter_var, unsigned int frame_delay) +boolean DelayReachedExt(DelayCounter *counter, unsigned int actual_counter) +{ + return DelayReachedExt2(&counter->count, counter->value, actual_counter); +} + +boolean FrameReached(DelayCounter *counter) { - return DelayReachedExt(frame_counter_var, frame_delay, FrameCounter); + return DelayReachedExt(counter, FrameCounter); } -boolean DelayReached(unsigned int *counter_var, unsigned int delay) +boolean DelayReached(DelayCounter *counter) { - return DelayReachedExt(counter_var, delay, Counter()); + return DelayReachedExt(counter, Counter()); } -void ResetDelayCounterExt(unsigned int *counter_var, - unsigned int actual_counter) +void ResetDelayCounterExt(DelayCounter *counter, unsigned int actual_counter) { - DelayReachedExt(counter_var, 0, actual_counter); + DelayReachedExt2(&counter->count, 0, actual_counter); } -void ResetFrameCounter(unsigned int *frame_counter_var) +void ResetFrameCounter(DelayCounter *counter) { - FrameReached(frame_counter_var, 0); + ResetDelayCounterExt(counter, FrameCounter); } -void ResetDelayCounter(unsigned int *counter_var) +void ResetDelayCounter(DelayCounter *counter) { - DelayReached(counter_var, 0); + ResetDelayCounterExt(counter, Counter()); } -int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay) +int WaitUntilDelayReached(DelayCounter *counter) { + unsigned int *counter_var = &counter->count; + unsigned int delay = counter->value; unsigned int actual_counter; int skip_frames = 0; @@ -667,22 +716,22 @@ int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay) return skip_frames; } -void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay, +void SkipUntilDelayReached(DelayCounter *counter, int *loop_var, int last_loop_value) { - int skip_frames = WaitUntilDelayReached(counter_var, delay); + int skip_frames = WaitUntilDelayReached(counter); #if 0 #if DEBUG if (skip_frames) Debug("internal:SkipUntilDelayReached", "%d: %d ms -> SKIP %d FRAME(S) [%d ms]", - *loop_var, delay, - skip_frames, skip_frames * delay); + *loop_var, counter->value, + skip_frames, skip_frames * counter->value); else Debug("internal:SkipUntilDelayReached", "%d: %d ms", - *loop_var, delay); + *loop_var, counter->value); #endif #endif @@ -712,14 +761,14 @@ void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay, // random generator functions // ---------------------------------------------------------------------------- -unsigned int init_random_number(int nr, int seed) +static unsigned int init_random_number_ext(int nr, int seed) { if (seed == NEW_RANDOMIZE) { // default random seed seed = (int)time(NULL); // seconds since the epoch -#if !defined(PLATFORM_WIN32) +#if !defined(PLATFORM_WINDOWS) // add some more randomness struct timeval current_time; @@ -740,9 +789,32 @@ unsigned int init_random_number(int nr, int seed) return (unsigned int) seed; } +static unsigned int prng_seed_gettimeofday(void) +{ + struct timeval current_time; + + gettimeofday(¤t_time, NULL); + + prng_seed_bytes(¤t_time, sizeof(current_time)); + + return 0; +} + +unsigned int init_random_number(int nr, int seed) +{ + return (nr == RANDOM_BETTER ? prng_seed_gettimeofday() : + init_random_number_ext(nr, seed)); +} + +static unsigned int get_random_number_ext(int nr) +{ + return (nr == RANDOM_BETTER ? prng_get_uint() : + random_linux_libc(nr)); +} + unsigned int get_random_number(int nr, int max) { - return (max > 0 ? random_linux_libc(nr) % max : 0); + return (max > 0 ? get_random_number_ext(nr) % max : 0); } @@ -829,7 +901,7 @@ char *getLoginName(void) { static char *login_name = NULL; -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) if (login_name == NULL) { unsigned long buffer_size = MAX_USERNAME_LEN + 1; @@ -860,7 +932,7 @@ char *getRealName(void) { static char *real_name = NULL; -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) if (real_name == NULL) { static char buffer[MAX_USERNAME_LEN + 1]; @@ -1016,7 +1088,9 @@ char *getBasePath(char *filename) // various string functions // ---------------------------------------------------------------------------- -char *getStringCat2WithSeparator(char *s1, char *s2, char *sep) +char *getStringCat2WithSeparator(const char *s1, + const char *s2, + const char *sep) { if (s1 == NULL || s2 == NULL || sep == NULL) return NULL; @@ -1029,7 +1103,10 @@ char *getStringCat2WithSeparator(char *s1, char *s2, char *sep) return complete_string; } -char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep) +char *getStringCat3WithSeparator(const char *s1, + const char *s2, + const char *s3, + const char *sep) { if (s1 == NULL || s2 == NULL || s3 == NULL || sep == NULL) return NULL; @@ -1043,17 +1120,17 @@ char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep) return complete_string; } -char *getStringCat2(char *s1, char *s2) +char *getStringCat2(const char *s1, const char *s2) { return getStringCat2WithSeparator(s1, s2, ""); } -char *getStringCat3(char *s1, char *s2, char *s3) +char *getStringCat3(const char *s1, const char *s2, const char *s3) { return getStringCat3WithSeparator(s1, s2, s3, ""); } -char *getPath2(char *path1, char *path2) +char *getPath2(const char *path1, const char *path2) { #if defined(PLATFORM_ANDROID) // workaround for reading from assets directory -- skip "." subdirs in path @@ -1066,7 +1143,7 @@ char *getPath2(char *path1, char *path2) return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR); } -char *getPath3(char *path1, char *path2, char *path3) +char *getPath3(const char *path1, const char *path2, const char *path3) { #if defined(PLATFORM_ANDROID) // workaround for reading from assets directory -- skip "." subdirs in path @@ -1094,12 +1171,12 @@ static char *getPngOrPcxIfNotExists(char *filename) return filename; } -char *getImg2(char *path1, char *path2) +char *getImg2(const char *path1, const char *path2) { return getPngOrPcxIfNotExists(getPath2(path1, path2)); } -char *getImg3(char *path1, char *path2, char *path3) +char *getImg3(const char *path1, const char *path2, const char *path3) { return getPngOrPcxIfNotExists(getPath3(path1, path2, path3)); } @@ -1155,14 +1232,14 @@ char *getStringToLower(const char *s) return s_copy; } -void setString(char **old_value, char *new_value) +void setString(char **old_value, const char *new_value) { checked_free(*old_value); *old_value = getStringCopy(new_value); } -boolean strEqual(char *s1, char *s2) +boolean strEqual(const char *s1, const char *s2) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : @@ -1170,7 +1247,7 @@ boolean strEqual(char *s1, char *s2) strcmp(s1, s2) == 0); } -boolean strEqualN(char *s1, char *s2, int n) +boolean strEqualN(const char *s1, const char *s2, int n) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : @@ -1178,7 +1255,7 @@ boolean strEqualN(char *s1, char *s2, int n) strncmp(s1, s2, n) == 0); } -boolean strEqualCase(char *s1, char *s2) +boolean strEqualCase(const char *s1, const char *s2) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : @@ -1186,7 +1263,7 @@ boolean strEqualCase(char *s1, char *s2) strcasecmp(s1, s2) == 0); } -boolean strEqualCaseN(char *s1, char *s2, int n) +boolean strEqualCaseN(const char *s1, const char *s2, int n) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : @@ -1194,7 +1271,7 @@ boolean strEqualCaseN(char *s1, char *s2, int n) strncasecmp(s1, s2, n) == 0); } -boolean strPrefix(char *s, char *prefix) +boolean strPrefix(const char *s, const char *prefix) { return (s == NULL && prefix == NULL ? TRUE : s == NULL && prefix != NULL ? FALSE : @@ -1202,7 +1279,7 @@ boolean strPrefix(char *s, char *prefix) strncmp(s, prefix, strlen(prefix)) == 0); } -boolean strSuffix(char *s, char *suffix) +boolean strSuffix(const char *s, const char *suffix) { return (s == NULL && suffix == NULL ? TRUE : s == NULL && suffix != NULL ? FALSE : @@ -1211,7 +1288,7 @@ boolean strSuffix(char *s, char *suffix) strcmp(&s[strlen(s) - strlen(suffix)], suffix) == 0); } -boolean strPrefixLower(char *s, char *prefix) +boolean strPrefixLower(const char *s, const char *prefix) { char *s_lower = getStringToLower(s); boolean match = strPrefix(s_lower, prefix); @@ -1221,7 +1298,7 @@ boolean strPrefixLower(char *s, char *prefix) return match; } -boolean strSuffixLower(char *s, char *suffix) +boolean strSuffixLower(const char *s, const char *suffix) { char *s_lower = getStringToLower(s); boolean match = strSuffix(s_lower, suffix); @@ -1231,6 +1308,14 @@ boolean strSuffixLower(char *s, char *suffix) return match; } +boolean isURL(const char *s) +{ + while (*s && *s >= 'a' && *s <= 'z') + s++; + + return strPrefix(s, "://"); +} + // ---------------------------------------------------------------------------- // command line option handling functions @@ -1262,8 +1347,14 @@ void GetOptions(int argc, char *argv[], options.conf_directory = getPath2(base_path, CONF_DIRECTORY); options.execute_command = NULL; + options.tape_log_filename = NULL; options.special_flags = NULL; options.debug_mode = NULL; + options.player_name = NULL; + options.identifier = NULL; + options.level_nr = NULL; + + options.display_nr = 0; options.mytapes = FALSE; options.serveronly = FALSE; @@ -1401,6 +1492,33 @@ void GetOptions(int argc, char *argv[], if (option_arg != next_option) options.debug_mode = getStringCopy(option_arg); } + else if (strncmp(option, "-player-name", option_len) == 0) + { + if (option_arg == NULL) + FailWithHelp("option '%s' requires an argument", option_str); + + options.player_name = getStringCopy(option_arg); + if (option_arg == next_option) + options_left++; + } + else if (strncmp(option, "-identifier", option_len) == 0) + { + if (option_arg == NULL) + FailWithHelp("option '%s' requires an argument", option_str); + + options.identifier = getStringCopy(option_arg); + if (option_arg == next_option) + options_left++; + } + else if (strncmp(option, "-level-nr", option_len) == 0) + { + if (option_arg == NULL) + FailWithHelp("option '%s' requires an argument", option_str); + + options.level_nr = getStringCopy(option_arg); + if (option_arg == next_option) + options_left++; + } else if (strncmp(option, "-verbose", option_len) == 0) { options.verbose = TRUE; @@ -1428,7 +1546,38 @@ void GetOptions(int argc, char *argv[], // when doing batch processing, always enable verbose mode (warnings) options.verbose = TRUE; } -#if defined(PLATFORM_MACOSX) + else if (strncmp(option, "-tape_logfile", option_len) == 0) + { + if (option_arg == NULL) + FailWithHelp("option '%s' requires an argument", option_str); + + options.tape_log_filename = getStringCopy(option_arg); + if (option_arg == next_option) + options_left++; + } + else if (strncmp(option, "-display", option_len) == 0) + { + if (option_arg == NULL) + FailWithHelp("option '%s' requires an argument", option_str); + + if (option_arg == next_option) + options_left++; + + int display_nr = atoi(option_arg); + +#if 1 + // dirty hack: SDL_GetNumVideoDisplays() seems broken on some systems + options.display_nr = display_nr; +#else + options.display_nr = + MAX(0, MIN(display_nr, SDL_GetNumVideoDisplays() - 1)); + + if (display_nr != options.display_nr) + Warn("invalid display %d -- using display %d", + display_nr, options.display_nr); +#endif + } +#if defined(PLATFORM_MAC) else if (strPrefix(option, "-psn")) { // ignore process serial number when launched via GUI on Mac OS X @@ -1502,7 +1651,7 @@ void checked_free(void *ptr) void clear_mem(void *ptr, unsigned int size) { -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) // for unknown reason, memset() sometimes crashes when compiled with MinGW char *cptr = (char *)ptr; @@ -1538,6 +1687,31 @@ void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) *y2 = help_y; } +int get_number_of_bits(int bits) +{ + /* + Counting bits set, Brian Kernighan's way + + Brian Kernighan's method goes through as many iterations as there are set + bits. So if we have a 32-bit word with only the high bit set, then it will + only go once through the loop. + + Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan + and Dennis M. Ritchie) mentions this in exercise 2-9. + First published by Peter Wegner in CACM 3 (1960), 322. + */ + + int num_bits = 0; + + while (bits) + { + bits &= bits - 1; // clear the least significant bit set + num_bits++; + } + + return num_bits; +} + /* the "put" variants of the following file access functions check for the file pointer being != NULL and return the number of bytes they have or would have written; this allows for chunk writing functions to first determine the size @@ -1839,6 +2013,107 @@ char *getLatin1FromUTF8(char *utf8) return latin1; } +int getTextEncoding(char *text) +{ + unsigned char *src = (unsigned char *)text; + int encoding = TEXT_ENCODING_ASCII; // default: assume encoding is ASCII + + while (*src) + { + if (*src >= 128) + encoding = TEXT_ENCODING_UTF_8; // non-ASCII character: assume UTF-8 + + if (*src < 128) + { + src++; + } + else if (src[0] >= 192 && src[0] < 224 && + src[1] >= 128 && src[1] < 192) + { + src += 2; + } + else if (src[0] >= 224 && src[0] < 240 && + src[1] >= 128 && src[1] < 192 && + src[2] >= 128 && src[2] < 192) + { + src += 3; + } + else if (src[0] >= 240 && src[0] < 248 && + src[1] >= 128 && src[1] < 192 && + src[2] >= 128 && src[2] < 192 && + src[3] >= 128 && src[3] < 192) + { + src += 4; + } + else if (src[0] >= 248 && src[0] < 252 && + src[1] >= 128 && src[1] < 192 && + src[2] >= 128 && src[2] < 192 && + src[3] >= 128 && src[3] < 192 && + src[4] >= 128 && src[4] < 192) + { + src += 5; + } + else if (src[0] >= 252 && src[0] < 254 && + src[1] >= 128 && src[1] < 192 && + src[2] >= 128 && src[2] < 192 && + src[3] >= 128 && src[3] < 192 && + src[4] >= 128 && src[4] < 192 && + src[5] >= 128 && src[5] < 192) + { + src += 6; + } + else + { + return TEXT_ENCODING_UNKNOWN; // non-UTF-8 character: unknown encoding + } + } + + return encoding; +} + + +// ---------------------------------------------------------------------------- +// functions for JSON handling +// ---------------------------------------------------------------------------- + +char *getEscapedJSON(char *s) +{ + int max_json_size = 2 * strlen(s) + 1; + char *json = checked_calloc(max_json_size); + unsigned char *src = (unsigned char *)s; + unsigned char *dst = (unsigned char *)json; + char *escaped[256] = + { + ['\b'] = "\\b", + ['\f'] = "\\f", + ['\n'] = "\\n", + ['\r'] = "\\r", + ['\t'] = "\\t", + ['\"'] = "\\\"", + ['\\'] = "\\\\", + }; + + while (*src) + { + if (escaped[*src] != NULL) + { + char *esc = escaped[*src++]; + + while (*esc) + *dst++ = *esc++; + } + else + { + *dst++ = *src++; + } + } + + // only use the smallest possible string buffer size + json = checked_realloc(json, strlen(json) + 1); + + return json; +} + // ---------------------------------------------------------------------------- // functions to translate key identifiers between different format @@ -2277,47 +2552,23 @@ char getValidConfigValueChar(char c) int get_integer_from_string(char *s) { - static char *number_text[][3] = - { - { "0", "zero", "null", }, - { "1", "one", "first" }, - { "2", "two", "second" }, - { "3", "three", "third" }, - { "4", "four", "fourth" }, - { "5", "five", "fifth" }, - { "6", "six", "sixth" }, - { "7", "seven", "seventh" }, - { "8", "eight", "eighth" }, - { "9", "nine", "ninth" }, - { "10", "ten", "tenth" }, - { "11", "eleven", "eleventh" }, - { "12", "twelve", "twelfth" }, - - { NULL, NULL, NULL }, - }; + // check for the most common case first + if (s[0] >= '0' && s[0] <= '9') + return atoi(s); - int i, j; char *s_lower = getStringToLower(s); int result = -1; - for (i = 0; number_text[i][0] != NULL; i++) - for (j = 0; j < 3; j++) - if (strEqual(s_lower, number_text[i][j])) - result = i; - - if (result == -1) - { - if (strEqual(s_lower, "false") || - strEqual(s_lower, "no") || - strEqual(s_lower, "off")) - result = 0; - else if (strEqual(s_lower, "true") || - strEqual(s_lower, "yes") || - strEqual(s_lower, "on")) - result = 1; - else - result = atoi(s); - } + if (strEqual(s_lower, "false") || + strEqual(s_lower, "no") || + strEqual(s_lower, "off")) + result = 0; + else if (strEqual(s_lower, "true") || + strEqual(s_lower, "yes") || + strEqual(s_lower, "on")) + result = 1; + else + result = atoi(s); free(s_lower); @@ -2669,6 +2920,22 @@ int copyFile(char *filename_from, char *filename_to) return 0; } +boolean touchFile(char *filename) +{ + FILE *file; + + if (!(file = fopen(filename, MODE_WRITE))) + { + Warn("cannot touch file '%s'", filename); + + return FALSE; + } + + fclose(file); + + return TRUE; +} + // ---------------------------------------------------------------------------- // functions for directory handling @@ -2810,7 +3077,7 @@ void freeDirectoryEntry(DirectoryEntry *dir_entry) // functions for checking files and filenames // ---------------------------------------------------------------------------- -boolean directoryExists(char *dir_name) +boolean directoryExists(const char *dir_name) { if (dir_name == NULL) return FALSE; @@ -2838,7 +3105,7 @@ boolean directoryExists(char *dir_name) return success; } -boolean fileExists(char *filename) +boolean fileExists(const char *filename) { if (filename == NULL) return FALSE; @@ -2862,7 +3129,7 @@ boolean fileExists(char *filename) } #if 0 -static boolean fileHasPrefix(char *basename, char *prefix) +static boolean fileHasPrefix(const char *basename, const char *prefix) { static char *basename_lower = NULL; int basename_length, prefix_length; @@ -2885,7 +3152,7 @@ static boolean fileHasPrefix(char *basename, char *prefix) } #endif -static boolean fileHasSuffix(char *basename, char *suffix) +static boolean fileHasSuffix(const char *basename, const char *suffix) { static char *basename_lower = NULL; int basename_length, suffix_length; @@ -3683,8 +3950,8 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info) char *filename_base = UNDEFINED_FILENAME, *filename_local; int i, j; - DrawInitText("Loading artwork config", 120, FC_GREEN); - DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW); + DrawInitTextHead("Loading artwork config"); + DrawInitTextItem(ARTWORKINFO_FILENAME(artwork_info->type)); // always start with reliable default values for (i = 0; i < num_file_list_entries; i++) @@ -3769,6 +4036,11 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info, char *basename = file_list_entry->filename; char *filename = getCustomArtworkFilename(basename, artwork_info->type); + // mark all images from non-default graphics directory as "redefined" + if (artwork_info->type == ARTWORK_TYPE_GRAPHICS && + !strPrefix(filename, options.graphics_directory)) + file_list_entry->redefined = TRUE; + if (filename == NULL) { Warn("cannot find artwork file '%s'", basename); @@ -3837,8 +4109,8 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info, return; } - DrawInitText(init_text[artwork_info->type], 120, FC_GREEN); - DrawInitText(basename, 150, FC_YELLOW); + DrawInitTextHead(init_text[artwork_info->type]); + DrawInitTextItem(basename); if ((*listnode = artwork_info->load_artwork(filename)) != NULL) { @@ -3937,45 +4209,41 @@ void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info) // (now also added for Windows, to create files in user data directory) // ---------------------------------------------------------------------------- +char *getLogBasename(char *basename) +{ + return getStringCat2(basename, ".log"); +} + char *getLogFilename(char *basename) { return getPath2(getMainUserGameDataDir(), basename); } -void OpenLogFiles(void) +void OpenLogFile(void) { - int i; - InitMainUserDataDirectory(); - for (i = 0; i < NUM_LOGS; i++) + if ((program.log_file = fopen(program.log_filename, MODE_WRITE)) == NULL) { - if ((program.log_file[i] = fopen(program.log_filename[i], MODE_WRITE)) - == NULL) - { - program.log_file[i] = program.log_file_default[i]; // reset to default - - Warn("cannot open file '%s' for writing: %s", - program.log_filename[i], strerror(errno)); - } + program.log_file = program.log_file_default; // reset to default - // output should be unbuffered so it is not truncated in a crash - setbuf(program.log_file[i], NULL); + Warn("cannot open file '%s' for writing: %s", + program.log_filename, strerror(errno)); } + + // output should be unbuffered so it is not truncated in a crash + setbuf(program.log_file, NULL); } -void CloseLogFiles(void) +void CloseLogFile(void) { - int i; - - for (i = 0; i < NUM_LOGS; i++) - if (program.log_file[i] != program.log_file_default[i]) - fclose(program.log_file[i]); + if (program.log_file != program.log_file_default) + fclose(program.log_file); } -void DumpLogFile(int nr) +void DumpLogFile(void) { - FILE *log_file = fopen(program.log_filename[nr], MODE_READ); + FILE *log_file = fopen(program.log_filename, MODE_READ); if (log_file == NULL) return; @@ -3988,12 +4256,12 @@ void DumpLogFile(int nr) void NotifyUserAboutErrorFile(void) { -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WINDOWS) char *title_text = getStringCat2(program.program_title, " Error Message"); char *error_text = getStringCat2("The program was aborted due to an error; " "for details, see the following error file:" STRING_NEWLINE, - program.log_filename[LOG_ERR_ID]); + program.log_filename); MessageBox(NULL, error_text, title_text, MB_OK); #endif