X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fmisc.c;h=7450c3a35fd4942d4e0a19a039738b9c997b2650;hb=9bda353724b6dc9176d0dfaf28ef9f1ff4084d4b;hp=f0858f4a20c5ee731339cd52073d05246cf3fd97;hpb=14ef59d8e791fc8a0d52978873555dc36d2d5ee0;p=rocksndiamonds.git diff --git a/src/libgame/misc.c b/src/libgame/misc.c index f0858f4a..7450c3a3 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); @@ -621,12 +620,12 @@ static unsigned int mainCounter(int mode) return current_ms - base_ms; } -void InitCounter() // set counter back to zero +void InitCounter(void) // set counter back to zero { mainCounter(INIT_COUNTER); } -unsigned int Counter() // get milliseconds since last call of InitCounter() +unsigned int Counter(void) // get milliseconds since last call of InitCounter() { return mainCounter(READ_COUNTER); } @@ -1085,11 +1084,31 @@ char *getBasePath(char *filename) } +// ---------------------------------------------------------------------------- +// various memory functions +// ---------------------------------------------------------------------------- + +void *getMemCopy(const void *m, size_t size) +{ + void *m_copy; + + if (m == NULL) + return NULL; + + m_copy = checked_malloc(size); + memcpy(m_copy, m, size); + + return m_copy; +} + + // ---------------------------------------------------------------------------- // 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; @@ -1102,7 +1121,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; @@ -1116,17 +1138,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 @@ -1139,7 +1161,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 @@ -1167,12 +1189,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)); } @@ -1216,6 +1238,18 @@ char *getStringCopyNStatic(const char *s, int n) return s_copy; } +char *getStringToUpper(const char *s) +{ + char *s_copy = checked_malloc(strlen(s) + 1); + char *s_ptr = s_copy; + + while (*s) + *s_ptr++ = toupper(*s++); + *s_ptr = '\0'; + + return s_copy; +} + char *getStringToLower(const char *s) { char *s_copy = checked_malloc(strlen(s) + 1); @@ -1228,14 +1262,224 @@ 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) +char **getSplitStringArray(const char *s, const char *separators, int max_tokens) +{ + const char *s_ptr, *s_last = s; + byte separator_table[256] = { FALSE }; + int num_tokens; + char **tokens = NULL; + + if (s == NULL) + return NULL; + + if (separators == NULL) + return NULL; + + if (max_tokens < 1) + max_tokens = INT_MAX; + + // if string is empty, return empty array + if (*s == '\0') + { + tokens = checked_malloc(sizeof(char *)); + tokens[0] = NULL; + + return tokens; + } + + // initialize separator table for all characters in separators string + for (s_ptr = separators; *s_ptr != '\0'; s_ptr++) + separator_table[*(byte *)s_ptr] = TRUE; + + // count number of tokens in string + for (num_tokens = 1, s_ptr = s; *s_ptr != '\0'; s_ptr++) + if (separator_table[*(byte *)s_ptr] && num_tokens < max_tokens) + num_tokens++; + + // allocate array for determined number of tokens + tokens = checked_malloc((num_tokens + 1) * sizeof(char *)); + + // copy all but last separated sub-strings to array + for (num_tokens = 0, s_ptr = s; *s_ptr != '\0'; s_ptr++) + { + if (separator_table[*(byte *)s_ptr] && num_tokens + 1 < max_tokens) + { + tokens[num_tokens++] = getStringCopyN(s_last, s_ptr - s_last); + s_last = s_ptr + 1; + } + } + + // copy last separated sub-string to array + tokens[num_tokens++] = getStringCopyN(s_last, s_ptr - s_last); + + // terminate array + tokens[num_tokens] = NULL; + + return tokens; +} + +int getStringArrayLength(char **s_array) +{ + int num_strings = 0; + + if (s_array == NULL) + return 0; + + while (s_array[num_strings] != NULL) + num_strings++; + + return num_strings; +} + +void freeStringArray(char **s_array) +{ + int i; + + if (s_array == NULL) + return; + + for (i = 0; s_array[i] != NULL; i++) + checked_free(s_array[i]); + + checked_free(s_array); +} + +char *getUnescapedString(const char *s) +{ + const char *s_ptr = s; + const char *octal_ptr; + char *s_unescaped; + char *s_unescaped_ptr; + + if (s == NULL) + return NULL; + + s_unescaped = checked_malloc(strlen(s) + 1); + s_unescaped_ptr = s_unescaped; + + while (*s_ptr != '\0') + { + if (*s_ptr == '\\') + { + s_ptr++; + + switch (*s_ptr) + { + case '\0': + Warn("getUnescapedString: trailing \\"); + goto out; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *s_unescaped_ptr = 0; + octal_ptr = s_ptr; + + while (s_ptr < octal_ptr + 3 && *s_ptr >= '0' && *s_ptr <= '7') + { + *s_unescaped_ptr = (*s_unescaped_ptr * 8) + (*s_ptr - '0'); + s_ptr++; + } + + s_unescaped_ptr++; + s_ptr--; + break; + + case 'b': + *s_unescaped_ptr++ = '\b'; + break; + + case 'f': + *s_unescaped_ptr++ = '\f'; + break; + + case 'n': + *s_unescaped_ptr++ = '\n'; + break; + + case 'r': + *s_unescaped_ptr++ = '\r'; + break; + + case 't': + *s_unescaped_ptr++ = '\t'; + break; + + case 'v': + *s_unescaped_ptr++ = '\v'; + break; + + default: + /* also handles \" and \\ */ + *s_unescaped_ptr++ = *s_ptr; + break; + } + } + else + { + *s_unescaped_ptr++ = *s_ptr; + } + + s_ptr++; + } + + out: + *s_unescaped_ptr = '\0'; + + return s_unescaped; +} + +char *chugString(char *s) +{ + if (s == NULL) + return NULL; + + char *start; + + for (start = (char *)s; *start && isspace(*start); start++) + ; + + memmove(s, start, strlen(start) + 1); + + return s; +} + +char *chompString(char *s) +{ + if (s == NULL) + return NULL; + + int len = strlen(s); + + while (len--) + { + if (isspace(s[len])) + s[len] = '\0'; + else + break; + } + + return s; +} + +char *stripString(char *s) +{ + return chugString(chompString(s)); +} + +boolean strEqual(const char *s1, const char *s2) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : @@ -1243,7 +1487,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 : @@ -1251,7 +1495,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 : @@ -1259,7 +1503,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 : @@ -1267,7 +1511,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 : @@ -1275,7 +1519,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 : @@ -1284,7 +1528,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); @@ -1294,7 +1538,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); @@ -1304,7 +1548,7 @@ boolean strSuffixLower(char *s, char *suffix) return match; } -boolean isURL(char *s) +boolean isURL(const char *s) { while (*s && *s >= 'a' && *s <= 'z') s++; @@ -1561,12 +1805,17 @@ void GetOptions(int argc, char *argv[], 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")) @@ -1678,6 +1927,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 @@ -3043,7 +3317,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; @@ -3071,7 +3345,7 @@ boolean directoryExists(char *dir_name) return success; } -boolean fileExists(char *filename) +boolean fileExists(const char *filename) { if (filename == NULL) return FALSE; @@ -3095,7 +3369,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; @@ -3118,7 +3392,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; @@ -4175,45 +4449,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 + program.log_file = program.log_file_default; // reset to default - Warn("cannot open file '%s' for writing: %s", - program.log_filename[i], strerror(errno)); - } - - // 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; @@ -4231,7 +4501,7 @@ void NotifyUserAboutErrorFile(void) 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