diff options
Diffstat (limited to 'engines/sci/scicore/tools.cpp')
-rw-r--r-- | engines/sci/scicore/tools.cpp | 798 |
1 files changed, 798 insertions, 0 deletions
diff --git a/engines/sci/scicore/tools.cpp b/engines/sci/scicore/tools.cpp new file mode 100644 index 0000000000..8167da33b4 --- /dev/null +++ b/engines/sci/scicore/tools.cpp @@ -0,0 +1,798 @@ +/*************************************************************************** + tools.c Copyright (C) 1999,2000,2001,2002 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CJR) [jameson@linuxgames.com] + +***************************************************************************/ + +#define _GNU_SOURCE /* For FNM_CASEFOLD in fnmatch.h */ + +#include <stdlib.h> +#include "sci/include/engine.h" + +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#ifdef _MSC_VER +# include <sys/timeb.h> +# include <windows.h> +# include <sys/types.h> +# include <sys/stat.h> +#endif + +#ifdef _WIN32 +# include <windows.h> +# include <mmsystem.h> + +void usleep (long usec); + +# ifdef sleep +# undef sleep +# endif + +# define sleep(x) \ + do { \ + if (x == 0) { \ + Sleep(0); \ + } else { \ + if (timeBeginPeriod(1) != TIMERR_NOERROR) \ + fprintf(stderr, "timeBeginPeriod(1) failed\n"); \ + Sleep(x); \ + if (timeEndPeriod(1) != TIMERR_NOERROR) \ + fprintf(stderr, "timeEndPeriod(1) failed\n"); \ + } \ + } while (0); +#endif + +#if !defined(HAVE_FNMATCH) && !defined(_WIN32) +# include <beos/fnmatch.h> +#endif + +#ifdef _DREAMCAST +# include <kos/thread.h> +#endif + +#ifdef __BEOS__ +# include <be/kernel/OS.h> +#endif + +#ifdef HAVE_MEMFROB +void *memfrob(void *s, size_t n); +#endif + +int script_debug_flag = 0; /* Defaulting to running mode */ +int sci_debug_flags = 0; /* Special flags */ + +#ifndef con_file +# define con_file 0 +#endif + +#define MEMTEST_HARDNESS 31 + +int +memtest(const char *file, int line) +{ + /* va_list argp; -- unused */ + int i; + void *blocks[MEMTEST_HARDNESS + 1]; + fprintf(stderr,"Memtesting in %s, L%d\n", file, line); + + for (i = 0; i < MEMTEST_HARDNESS; i++) { + blocks[i] = sci_malloc(1 + i); +#ifdef HAVE_MEMFROB + memfrob(blocks[i], 1 + i); +#else + memset(blocks[i], 42, 1 + i); +#endif + } + for (i = 0; i < MEMTEST_HARDNESS; i++) + free(blocks[i]); + + for (i = 0; i < MEMTEST_HARDNESS; i++) { + blocks[i] = sci_malloc(5 + i*5); +#ifdef HAVE_MEMFROB + memfrob(blocks[i], 5 + i*5); +#else + memset(blocks[i], 42, 5 + i*5); +#endif + } + for (i = 0; i < MEMTEST_HARDNESS; i++) + free(blocks[i]); + + for (i = 0; i < MEMTEST_HARDNESS; i++) { + blocks[i] = sci_malloc(5 + i*100); +#ifdef HAVE_MEMFROB + memfrob(blocks[i], 5 + i*100); +#else + memset(blocks[i], 42, 5 + i*100); +#endif + } + for (i = 0; i < MEMTEST_HARDNESS; i++) + free(blocks[i]); + + for (i = 0; i < MEMTEST_HARDNESS; i++) { + blocks[i] = sci_malloc(5 + i*1000); +#ifdef HAVE_MEMFROB + memfrob(blocks[i], 5 + i * 1000); +#else + memset(blocks[i], 42, 5 + i * 1000); +#endif + } + for (i = 0; i < MEMTEST_HARDNESS; i++) + free(blocks[i]); + fprintf(stderr,"Memtest succeeded!\n"); + return 0; +} + +void * +memdup(void *src, int size) +{ + void *b = malloc(size); + memcpy(b, src, size); + return b; +} + +int sci_ffs(int _mask) +{ + int retval = 0; + + if (!_mask) return 0; + retval++; + while (! (_mask & 1)) + { + retval++; + _mask >>= 1; + } + + return retval; +} + + +/******************** Debug functions ********************/ + +void +_SCIkvprintf(FILE *file, const char *format, va_list args) +{ + vfprintf(file, format, args); + if (con_file) vfprintf(con_file, format, args); +} + +void +_SCIkprintf(FILE *file, const char *format, ...) +{ + va_list args; + + va_start(args, format); + _SCIkvprintf(file, format, args); + va_end (args); +} + + +void +_SCIkwarn(state_t *s, const char *file, int line, int area, const char *format, ...) +{ + va_list args; + + if (area == SCIkERROR_NR) + _SCIkprintf(stderr, "ERROR: "); + else + _SCIkprintf(stderr, "Warning: "); + + va_start(args, format); + _SCIkvprintf(stderr, format, args); + va_end(args); + fflush(NULL); + + if (sci_debug_flags & _DEBUG_FLAG_BREAK_ON_WARNINGS) script_debug_flag=1; +} + +void +_SCIkdebug(state_t *s, const char *file, int line, int area, const char *format, ...) +{ + va_list args; + + if (s->debug_mode & (1 << area)) { + _SCIkprintf(stdout, " kernel: (%s L%d): ", file, line); + va_start(args, format); + _SCIkvprintf(stdout, format, args); + va_end(args); + fflush(NULL); + } +} + +void +_SCIGNUkdebug(const char *funcname, state_t *s, const char *file, int line, int area, const char *format, ...) +{ + va_list xargs; + int error = ((area == SCIkWARNING_NR) || (area == SCIkERROR_NR)); + + if (error || (s->debug_mode & (1 << area))) { /* Is debugging enabled for this area? */ + + _SCIkprintf(stderr, "FSCI: "); + + if (area == SCIkERROR_NR) + _SCIkprintf(stderr, "ERROR in %s ", funcname); + else if (area == SCIkWARNING_NR) + _SCIkprintf(stderr, "%s: Warning ", funcname); + else _SCIkprintf(stderr, funcname); + + _SCIkprintf(stderr, "(%s L%d): ", file, line); + + va_start(xargs, format); + _SCIkvprintf(stderr, format, xargs); + va_end(xargs); + + } +} + + +#if defined(HAVE_GETTIMEOFDAY) +void +sci_gettime(long *seconds, long *useconds) +{ + struct timeval tv; + + assert(!gettimeofday(&tv, NULL)); + *seconds = tv.tv_sec; + *useconds = tv.tv_usec; +} +#elif defined (_WIN32) + +/*WARNING(Incorrect)*/ +/* Warning: This function only retrieves the amount of mseconds since the start of +** the Win32 kernel; it does /not/ provide the number of seconds since the epoch! +** There are no known cases where this causes problems, though. */ +void sci_gettime(long *seconds, long *useconds) +{ + DWORD tm; + + if (TIMERR_NOERROR != timeBeginPeriod(1)) + { + fprintf(stderr, "timeBeginPeriod(1) failed in sci_gettime\n"); + } + + tm = timeGetTime(); + + if (TIMERR_NOERROR != timeEndPeriod(1)) + { + fprintf(stderr, "timeEndPeriod(1) failed in sci_gettime\n"); + } + + *seconds = tm/1000; + *useconds = (tm%1000)*1000; +} +#else +# error "You need to provide a microsecond resolution sci_gettime implementation for your platform!" +#endif + + +void +sci_get_current_time(GTimeVal *val) +{ + long foo, bar; + sci_gettime(&foo, &bar); + val->tv_sec = foo; + val->tv_usec = bar; +} + + +/************* Directory entities *************/ +#if defined(_WIN32) +/******** Dir: Win32 CODE ********/ + +void +sci_init_dir(sci_dir_t *dir) +{ + dir->search = -1; +} + +char * +sci_find_first(sci_dir_t *dir, const char *mask) +{ + dir->search = _findfirst(mask, &(dir->fileinfo)); + + if (dir->search != -1) + { + if (dir->fileinfo.name == NULL) + { + return NULL; + } + + if (strcmp(dir->fileinfo.name, ".") == 0 || + strcmp(dir->fileinfo.name, "..") == 0) + { + if (sci_find_next(dir) == NULL) + { + return NULL; + } + } + + return dir->fileinfo.name; + } + else + { + switch (errno) + { + case ENOENT: + { +#ifdef _DEBUG + printf("_findfirst errno = ENOENT: no match\n"); + + if (mask) + printf(" in: %s\n", mask); + else + printf(" - searching in undefined directory\n"); +#endif + break; + } + case EINVAL: + { + printf("_findfirst errno = EINVAL: invalid filename\n"); + break; + } + default: + printf("_findfirst errno = unknown (%d)", errno); + } + } + + return NULL; +} + +char * +sci_find_next(sci_dir_t *dir) +{ + if (dir->search == -1) + return NULL; + + if (_findnext(dir->search, &(dir->fileinfo)) < 0) { + _findclose(dir->search); + dir->search = -1; + return NULL; + } + + if (strcmp(dir->fileinfo.name, ".") == 0 || + strcmp(dir->fileinfo.name, "..") == 0) + { + if (sci_find_next(dir) == NULL) + { + return NULL; + } + } + + return dir->fileinfo.name; +} + +void +sci_finish_find(sci_dir_t *dir) +{ + if(dir->search != -1) { + _findclose(dir->search); + dir->search = -1; + } +} + +#else /* !_WIN32 */ +/******** Dir: UNIX CODE ********/ + +void +sci_init_dir(sci_dir_t *dir) +{ + dir->dir = NULL; + dir->mask_copy = NULL; +} + +char * +sci_find_first(sci_dir_t *dir, const char *mask) +{ + if (dir->dir) + closedir(dir->dir); + + if (!(dir->dir = opendir("."))) { + sciprintf("%s, L%d: opendir(\".\") failed!\n", __FILE__, __LINE__); + return NULL; + } + + dir->mask_copy = sci_strdup(mask); + + return sci_find_next(dir); +} + +#ifndef FNM_CASEFOLD +#define FNM_CASEFOLD 0 +#warning "File searches will not be case-insensitive!" +#endif + +char * +sci_find_next(sci_dir_t *dir) +{ + struct dirent *match; + + while ((match = readdir(dir->dir))) { + if (match->d_name[0] == '.') + continue; + + if (!fnmatch(dir->mask_copy, match->d_name, FNM_CASEFOLD)) + return match->d_name; + } + + sci_finish_find(dir); + return NULL; +} + +void +sci_finish_find(sci_dir_t *dir) +{ + if (dir->dir) { + closedir(dir->dir); + dir->dir = NULL; + free(dir->mask_copy); + dir->mask_copy = NULL; + } +} + +#endif /* !_WIN32 */ + +/************* /Directory entities *************/ + + +int +sci_mkpath(const char *path) +{ + const char *path_position = path; + char *next_separator = NULL; + + if (chdir(G_DIR_SEPARATOR_S)) { /* Go to root */ + sciprintf("Error: Could not change to root directory '%s'!\n", + G_DIR_SEPARATOR_S); + return -1; + } + + do { + if (next_separator) + *next_separator = G_DIR_SEPARATOR_S[0]; + next_separator = (char *)strchr(path_position, G_DIR_SEPARATOR_S[0]); + + if (next_separator) + *next_separator = 0; + + if (*path_position) { /* Unless we're at the first slash... */ + if (chdir(path_position)) { + if (scimkdir(path_position, 0700) || chdir(path_position)) { + sciprintf("Error: Could not create subdirectory '%s' in", + path_position); + if (next_separator) + *next_separator = G_DIR_SEPARATOR_S[0]; + sciprintf(" '%s'!\n", path); + return -2; + } + } + } + path_position = next_separator + 1; + + } while (next_separator); + + return 0; +} + + + +char * +sci_get_homedir(void) +{ +#ifdef _WIN32 + char *_path_buf = (char*)malloc(MAX_PATH); + char *dr = getenv("HOMEDRIVE"); + char *path = getenv("HOMEPATH"); + + if (!dr || !path) + return getenv("WINDIR"); + + strncpy(_path_buf, dr, 4); + strncat(_path_buf, path, MAX_PATH - 4); + + return _path_buf; +#elif defined(__unix__) || !defined(X_DISPLAY_MISSING) || defined (__BEOS__) || defined(MACOSX) + return getenv("HOME"); +#elif defined(_DREAMCAST) + return NULL; +#elif defined(__amigaos4__) + return "/PROGDIR/"; +#else +# error Please add a $HOME policy for your platform! +#endif +} + + +sci_queue_t * +sci_init_queue(sci_queue_t *queue) +{ + queue->start = queue->end = NULL; + return queue; +} + +sci_queue_t * +sci_add_to_queue(sci_queue_t *queue, void *data, int type) +{ + sci_queue_node_t *node = (sci_queue_node_t*)sci_malloc(sizeof(sci_queue_node_t)); + + node->next = NULL; + node->data = data; + node->type = type; + + if (queue->start) + queue->start->next = node; + + queue->start = node; + + if (!queue->end) + queue->end = node; + + return queue; +} + +void * +sci_get_from_queue(sci_queue_t *queue, int *type) +{ + sci_queue_node_t *node = queue->end; + if (node) { + void *retval = node->data; + if (type) + *type = node->type; + + queue->end = node->next; + + if (queue->end == NULL) /* Queue empty? */ + queue->start = NULL; + + free(node); + return retval; + } + return NULL; +} + + +/*-- Yielding to the scheduler --*/ + +#ifdef HAVE_SCHED_YIELD +# include <sched.h> + +void +sci_sched_yield(void) +{ + sched_yield(); +} + +#elif defined (_DREAMCAST) + +void +sci_sched_yield() +{ + thd_pass(); +} + +#elif defined (__BEOS__) + +void +sci_sched_yield() +{ + snooze(0); +} + +#elif defined (_WIN32) + +void +sci_sched_yield() +{ + sleep(1); +} + +#else + +void +sci_sched_yield() +{ +} + +#endif /* !HAVE_SCHED_YIELD */ + + +char * +_fcaseseek(const char *fname, sci_dir_t *dir) +/* Expects *dir to be uninitialized and the caller to + ** free it afterwards */ +{ + char *buf, *iterator; + char _buf[14]; + char *retval = NULL, *name; + +#ifdef _MSC_VER + return fname; +#endif + + if (strchr(fname, G_DIR_SEPARATOR)) { + fprintf(stderr, "_fcaseseek() does not support subdirs\n"); + BREAKPOINT(); + } + + if (strlen(fname) > 12) /* not a DOS file? */ + buf = (char*)sci_malloc(strlen(fname) + 1); + else + buf = _buf; + + sci_init_dir(dir); + + /* Replace all letters with '?' chars */ + strcpy(buf, fname); + iterator = buf; + while (*iterator) { + if (isalpha(*iterator)) + *iterator = '?'; + iterator++; + } + + name = sci_find_first(dir, buf); + + while (name && !retval) { + if (!strcasecmp(fname, name)) + retval = name; + else + name = sci_find_next(dir); + } + + if (strlen(fname) > 12) + free(buf); + + return retval; +} + + +FILE * +sci_fopen(const char *fname, const char *mode) +{ + sci_dir_t dir; + char *name = _fcaseseek(fname, &dir); + FILE *file = NULL; + + if (name) + file = fopen(name, mode); + else if (strchr(mode, 'w')) + file = fopen(fname, mode); + + sci_finish_find(&dir); /* Free memory */ + + return file; +} + +int +sci_open(const char *fname, int flags) +{ + sci_dir_t dir; + char *name; + int file = SCI_INVALID_FD; + char *separator_position; + char *path; + char *caller_cwd; + + sci_init_dir(&dir); + + separator_position = (char *)strrchr(fname, G_DIR_SEPARATOR); + if (separator_position) + { + path = (char *) malloc(separator_position-fname+1); + path[separator_position-fname] = 0; + strncpy(path, fname, separator_position-fname); + chdir(path); + free(path); + } + + name = _fcaseseek(separator_position ? separator_position + 1 : fname, &dir); + if (name) + file = open(name, flags); + + sci_finish_find(&dir); /* Free memory */ + + caller_cwd = sci_getcwd(); + chdir(caller_cwd); + free(caller_cwd); + + return file; +} + +char * +sci_getcwd(void) +{ + int size = 0; + char *cwd = NULL; + + while (size < 8192) { + size += 256; + cwd = (char*)sci_malloc(size); + if (getcwd(cwd, size-1)) + return cwd; + + sci_free(cwd); + } + + fprintf(stderr,"Could not determine current working directory!\n"); + return NULL; +} + +#ifdef _DREAMCAST + +int +sci_fd_size(int fd) +{ + return fs_total(fd); +} + +int +sci_file_size(const char *fname) +{ + int fd = fs_open(fname, O_RDONLY); + int retval = -1; + + if (fd != 0) { + retval = sci_fd_size(fd); + fs_close(fd); + } + + return retval; +} + +#else + +int +sci_fd_size(int fd) +{ + struct stat fd_stat; + if (fstat(fd, &fd_stat)) return -1; + return fd_stat.st_size; +} + +int +sci_file_size(const char *fname) +{ + struct stat fn_stat; + if (stat(fname, &fn_stat)) return -1; + return fn_stat.st_size; +} + +#endif + +/* Simple heuristic to work around array handling peculiarity in SQ4: +It uses StrAt() to read the individual elements, so we must determine +whether a string is really a string or an array. */ +int is_print_str(char *str) +{ + int printable = 0; + int len = strlen(str); + + if (len == 0) return 1; + + while (*str) + { + if (isprint(*str)) printable++; + str++; + } + + return ((float) printable / (float) len >= 0.5); +} |