aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/adrift/scutils.cpp
diff options
context:
space:
mode:
authorPaul Gilbert2019-09-02 20:57:19 -0700
committerPaul Gilbert2019-09-25 20:13:26 -0700
commit60c860c6a6c37b95ab8265d658cbcc144d51153b (patch)
treee21dac197fcd374bb8d348873c91230141e1fddf /engines/glk/adrift/scutils.cpp
parentc893c5a60b8298aa99ae1a47dea51c6f04c419bc (diff)
downloadscummvm-rg350-60c860c6a6c37b95ab8265d658cbcc144d51153b.tar.gz
scummvm-rg350-60c860c6a6c37b95ab8265d658cbcc144d51153b.tar.bz2
scummvm-rg350-60c860c6a6c37b95ab8265d658cbcc144d51153b.zip
GLK: ADRIFT: Skeleton sub-engine commit
Diffstat (limited to 'engines/glk/adrift/scutils.cpp')
-rw-r--r--engines/glk/adrift/scutils.cpp462
1 files changed, 462 insertions, 0 deletions
diff --git a/engines/glk/adrift/scutils.cpp b/engines/glk/adrift/scutils.cpp
new file mode 100644
index 0000000000..98e10651e7
--- /dev/null
+++ b/engines/glk/adrift/scutils.cpp
@@ -0,0 +1,462 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/adrift/scare.h"
+#include "glk/adrift/scprotos.h"
+#include "glk/glk.h"
+#include "glk/events.h"
+#include "common/debug.h"
+#include "common/str.h"
+#include "common/textconsole.h"
+
+namespace Glk {
+namespace Adrift {
+
+/*
+ * Module notes:
+ *
+ * o Implement smarter selective module tracing.
+ */
+
+/*
+ * sc_trace()
+ *
+ * Debugging trace function; printf wrapper that writes to stderr.
+ */
+void sc_trace (const sc_char *format, ...) {
+ va_list ap;
+ assert(format);
+
+ va_start (ap, format);
+ Common::String s = Common::String::format(format, ap);
+ va_end (ap);
+ debug("%s", s.c_str());
+}
+
+
+/*
+ * sc_error()
+ * sc_fatal()
+ *
+ * Error reporting functions. sc_error() prints a message and continues.
+ * sc_fatal() prints a message, then calls abort().
+ */
+void sc_error (const sc_char *format, ...) {
+ va_list ap;
+ assert(format);
+
+ va_start(ap, format);
+ Common::String s = Common::String::format(format, ap);
+ va_end(ap);
+ warning("%s", s.c_str());
+}
+
+void sc_fatal (const sc_char *format, ...) {
+ va_list ap;
+ assert(format);
+
+ va_start(ap, format);
+ Common::String s = Common::String::format(format, ap);
+ va_end(ap);
+ error("%s", s.c_str());
+}
+
+
+/* Unique non-heap address for zero size malloc() and realloc() requests. */
+static void *sc_zero_allocation = &sc_zero_allocation;
+
+/*
+ * sc_malloc()
+ * sc_realloc()
+ * sc_free()
+ *
+ * Non-failing wrappers around malloc functions. Newly allocated memory is
+ * cleared to zero. In ANSI/ISO C, zero byte allocations are implementation-
+ * defined, so we have to take special care to get predictable behavior.
+ */
+void *
+sc_malloc (size_t size)
+{
+ void *allocated;
+
+ if (size == 0)
+ return sc_zero_allocation;
+
+ allocated = malloc (size);
+ if (!allocated)
+ sc_fatal ("sc_malloc: requested %lu bytes\n", (sc_uint) size);
+ else if (allocated == sc_zero_allocation)
+ sc_fatal ("sc_malloc: zero-byte allocation address returned\n");
+
+ memset (allocated, 0, size);
+ return allocated;
+}
+
+void *
+sc_realloc (void *pointer, size_t size)
+{
+ void *allocated;
+
+ if (size == 0)
+ {
+ sc_free (pointer);
+ return sc_zero_allocation;
+ }
+
+ if (pointer == sc_zero_allocation)
+ pointer = NULL;
+
+ allocated = realloc (pointer, size);
+ if (!allocated)
+ sc_fatal ("sc_realloc: requested %lu bytes\n", (sc_uint) size);
+ else if (allocated == sc_zero_allocation)
+ sc_fatal ("sc_realloc: zero-byte allocation address returned\n");
+
+ if (!pointer)
+ memset (allocated, 0, size);
+ return allocated;
+}
+
+void
+sc_free (void *pointer)
+{
+ if (sc_zero_allocation != &sc_zero_allocation)
+ sc_fatal ("sc_free: write to zero-byte allocation address detected\n");
+
+ if (pointer && pointer != sc_zero_allocation)
+ free (pointer);
+}
+
+
+/*
+ * sc_strncasecmp()
+ * sc_strcasecmp()
+ *
+ * Strncasecmp and strcasecmp are not ANSI functions, so here are local
+ * definitions to do the same jobs.
+ */
+sc_int
+sc_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n)
+{
+ sc_int index_;
+ assert (s1 && s2);
+
+ for (index_ = 0; index_ < n; index_++)
+ {
+ sc_int diff;
+
+ diff = sc_tolower (s1[index_]) - sc_tolower (s2[index_]);
+ if (diff < 0 || diff > 0)
+ return diff < 0 ? -1 : 1;
+ }
+
+ return 0;
+}
+
+sc_int
+sc_strcasecmp (const sc_char *s1, const sc_char *s2)
+{
+ sc_int s1len, s2len, result;
+ assert (s1 && s2);
+
+ s1len = strlen (s1);
+ s2len = strlen (s2);
+
+ result = sc_strncasecmp (s1, s2, s1len < s2len ? s1len : s2len);
+ if (result < 0 || result > 0)
+ return result;
+ else
+ return s1len < s2len ? -1 : s1len > s2len ? 1 : 0;
+}
+
+
+/*
+ * sc_platform_rand()
+ * sc_congruential_rand()
+ * sc_set_random_handler()
+ *
+ * Internal random number generation functions. We offer two: one is a self-
+ * seeding wrapper around the platform's rand(), which should generate good
+ * random numbers but with a sequence that is platform-dependent; the other
+ * is a linear congruential generator with a long period that is guaranteed
+ * to return the same sequence for all platforms. The default is the first,
+ * with the latter intended for predictability of game actions.
+ */
+static sc_int
+sc_platform_rand (sc_uint new_seed)
+{
+ static sc_bool is_seeded = FALSE;
+
+ /* If reseeding, seed with the value supplied, note seeded, and return 0. */
+ if (new_seed > 0) {
+ g_vm->setRandomNumberSeed(new_seed);
+ is_seeded = TRUE;
+ return 0;
+ }
+ else
+ {
+ /* If not explicitly seeded yet, generate a seed from time(). */
+ if (!is_seeded)
+ {
+ //srand ((sc_uint) time (NULL));
+ is_seeded = TRUE;
+ }
+
+ /* Return the next rand() number in the sequence. */
+ return g_vm->getRandomNumber(0xffffff);
+ }
+}
+
+static sc_int
+sc_congruential_rand (sc_uint new_seed)
+{
+ static sc_bool is_seeded = FALSE;
+ static sc_uint rand_state = 1;
+
+ /* If reseeding, seed with the value supplied, and note seeded. */
+ if (new_seed > 0)
+ {
+ rand_state = new_seed;
+ is_seeded = TRUE;
+ return 0;
+ }
+ else
+ {
+ /* If not explicitly seeded yet, generate a seed from time(). */
+ if (!is_seeded)
+ {
+ rand_state = (sc_uint)g_vm->_events->getTotalPlayTicks();
+ is_seeded = TRUE;
+ }
+
+ /*
+ * Advance random state, using constants from Park & Miller (1988).
+ * To keep the values the same for both 32 and 64 bit longs, mask out
+ * any bits above the bottom 32.
+ */
+ rand_state = (rand_state * 16807 + 2147483647) & 0xffffffff;
+
+ /*
+ * Discard the lowest bit as a way to map 32-bits unsigned to a 32-bit
+ * positive signed.
+ */
+ return rand_state >> 1;
+ }
+}
+
+
+/* Function pointer for the actual random number generator in use. */
+static sc_int (*sc_rand_function) (sc_uint) = sc_platform_rand;
+
+/*
+ * sc_set_congruential_random()
+ * sc_set_platform_random()
+ * sc_is_congruential_random()
+ * sc_seed_random()
+ * sc_rand()
+ * sc_randomint()
+ *
+ * Public interface to random functions; control and reseed the random
+ * handler in use, generate a random number, and a convenience function to
+ * generate a random value within a given range.
+ */
+void
+sc_set_congruential_random (void)
+{
+ sc_rand_function = sc_congruential_rand;
+}
+
+void
+sc_set_platform_random (void)
+{
+ sc_rand_function = sc_platform_rand;
+}
+
+sc_bool
+sc_is_congruential_random (void)
+{
+ return sc_rand_function == sc_congruential_rand;
+}
+
+void
+sc_seed_random (sc_uint new_seed)
+{
+ /* Ignore zero values of new_seed by simply using 1 instead. */
+ sc_rand_function (new_seed > 0 ? new_seed : 1);
+}
+
+sc_int
+sc_rand (void)
+{
+ sc_int retval;
+
+ /* Passing zero indicates this is not a seed operation. */
+ retval = sc_rand_function (0);
+ return retval;
+}
+
+sc_int
+sc_randomint (sc_int low, sc_int high)
+{
+ /*
+ * If the range is invalid, just return the low value given. This mimics
+ * Adrift under the same conditions, and also guards against division by
+ * zero in the mod operation.
+ */
+ return (high < low) ? low : low + sc_rand () % (high - low + 1);
+}
+
+
+/* Miscellaneous general ascii constants. */
+static const sc_char NUL = '\0';
+static const sc_char SPACE = ' ';
+
+/*
+ * sc_strempty()
+ *
+ * Return TRUE if a string is either zero-length or contains only whitespace.
+ */
+sc_bool
+sc_strempty (const sc_char *string)
+{
+ sc_int index_;
+ assert (string);
+
+ /* Scan for any non-space character. */
+ for (index_ = 0; string[index_] != NUL; index_++)
+ {
+ if (!sc_isspace (string[index_]))
+ return FALSE;
+ }
+
+ /* None found, so string is empty. */
+ return TRUE;
+}
+
+
+/*
+ * sc_trim_string()
+ *
+ * Trim leading and trailing whitespace from a string. Modifies the string
+ * in place, and returns the string address for convenience.
+ */
+sc_char *
+sc_trim_string (sc_char *string)
+{
+ sc_int index_;
+ assert (string);
+
+ for (index_ = strlen (string) - 1;
+ index_ >= 0 && sc_isspace (string[index_]); index_--)
+ string[index_] = NUL;
+
+ for (index_ = 0; sc_isspace (string[index_]);)
+ index_++;
+ memmove (string, string + index_, strlen (string) - index_ + 1);
+
+ return string;
+}
+
+
+/*
+ * sc_normalize_string()
+ *
+ * Trim a string, and set all runs of whitespace to a single space character.
+ * Modifies the string in place, and returns the string address for
+ * convenience.
+ */
+sc_char *
+sc_normalize_string (sc_char *string)
+{
+ sc_int index_;
+ assert (string);
+
+ /* Trim all leading and trailing spaces. */
+ string = sc_trim_string (string);
+
+ /* Compress multiple whitespace runs into a single space character. */
+ for (index_ = 0; string[index_] != NUL; index_++)
+ {
+ if (sc_isspace (string[index_]))
+ {
+ sc_int cursor;
+
+ string[index_] = SPACE;
+ for (cursor = index_ + 1; sc_isspace (string[cursor]);)
+ cursor++;
+ memmove (string + index_ + 1,
+ string + cursor, strlen (string + cursor) + 1);
+ }
+ }
+
+ return string;
+}
+
+
+/*
+ * sc_compare_word()
+ *
+ * Return TRUE if the first word in the string is word, case insensitive.
+ */
+sc_bool
+sc_compare_word (const sc_char *string, const sc_char *word, sc_int length)
+{
+ assert (string && word);
+
+ /* Return TRUE if string starts with word, then space or string end. */
+ return sc_strncasecmp (string, word, length) == 0
+ && (string[length] == NUL || sc_isspace (string[length]));
+}
+
+
+/*
+ * sc_hash()
+ *
+ * Hash a string, hashpjw algorithm, from 'Compilers, principles, techniques,
+ * and tools', page 436, unmodulo'ed and somewhat restyled.
+ */
+sc_uint
+sc_hash (const sc_char *string)
+{
+ sc_int index_;
+ sc_uint hash;
+ assert (string);
+
+ hash = 0;
+ for (index_ = 0; string[index_] != NUL; index_++)
+ {
+ sc_uint temp;
+
+ hash = (hash << 4) + string[index_];
+ temp = hash & 0xf0000000;
+ if (temp != 0)
+ {
+ hash = hash ^ (temp >> 24);
+ hash = hash ^ temp;
+ }
+ }
+
+ return hash;
+}
+
+} // End of namespace Adrift
+} // End of namespace Glk