summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/libutil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/libutil.cc')
-rw-r--r--stone_soup/crawl-ref/source/libutil.cc730
1 files changed, 0 insertions, 730 deletions
diff --git a/stone_soup/crawl-ref/source/libutil.cc b/stone_soup/crawl-ref/source/libutil.cc
deleted file mode 100644
index 734ae2dc0a..0000000000
--- a/stone_soup/crawl-ref/source/libutil.cc
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * File: libutil.cc
- * Summary: Functions that may be missing from some systems
- * Written by: ?
- *
- * Modified for Crawl Reference by $Author$ on $Date$
- *
- * Change History (most recent first):
- *
- * <1> 2001/Nov/01 BWR Created
- *
- */
-
-#include "AppHdr.h"
-#include "defines.h"
-#include "libutil.h"
-#include "externs.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <string.h>
-
-#ifdef WIN32CONSOLE
- #include <windows.h>
-
- #ifdef WINMM_PLAY_SOUNDS
- #include <mmsystem.h>
- #endif
-#endif
-
-#ifdef REGEX_PCRE
- // Statically link pcre on Windows
- #ifdef WIN32CONSOLE
- #define PCRE_STATIC
- #endif
-
- #include <pcre.h>
-#endif
-
-#ifdef REGEX_POSIX
- // Do we still need to include sys/types.h?
- #include <sys/types.h>
- #include <regex.h>
-#endif
-
-// Should return true if the filename contains nothing that
-// the shell can do damage with.
-bool shell_safe(const char *file)
-{
- int match = strcspn(file, "`$*?|><");
- return !(match >= 0 && file[match]);
-}
-
-void play_sound( const char *file )
-{
-#if defined(WINMM_PLAY_SOUNDS)
- // Check whether file exists, is readable, etc.?
- if (file && *file)
- sndPlaySound(file, SND_ASYNC | SND_NODEFAULT);
-#elif defined(SOUND_PLAY_COMMAND)
- char command[255];
- command[0] = '\0';
- if (file && *file && (strlen(file) + strlen(SOUND_PLAY_COMMAND) < 255)
- && shell_safe(file))
- {
- snprintf(command, sizeof command, SOUND_PLAY_COMMAND, file);
- system(command);
- }
-#endif
-}
-
-void get_input_line( char *const buff, int len )
-{
- buff[0] = '\0'; // just in case
-
-#if defined(UNIX)
- get_input_line_from_curses( buff, len ); // implemented in libunix.cc
-#elif defined(MAC) || defined(WIN32CONSOLE)
- getstr( buff, len ); // implemented in libmac.cc
-#else
- fgets( buff, len, stdin ); // much safer than gets()
-#endif
-
- buff[ len - 1 ] = '\0'; // just in case
-
- // Removing white space from the end in order to get rid of any
- // newlines or carriage returns that any of the above might have
- // left there (ie fgets especially). -- bwr
- const int end = strlen( buff );
- int i;
-
- for (i = end - 1; i >= 0; i++)
- {
- if (isspace( buff[i] ))
- buff[i] = '\0';
- else
- break;
- }
-}
-
-#ifdef DOS
-static int getch_ck() {
- int c = getch();
- if (!c) {
- switch (c = getch()) {
- case 'O': return CK_END;
- case 'P': return CK_DOWN;
- case 'I': return CK_PGUP;
- case 'H': return CK_UP;
- case 'G': return CK_HOME;
- case 'K': return CK_LEFT;
- case 'Q': return CK_PGDN;
- case 'M': return CK_RIGHT;
- case 119: return CK_CTRL_HOME;
- case 141: return CK_CTRL_UP;
- case 132: return CK_CTRL_PGUP;
- case 116: return CK_CTRL_RIGHT;
- case 118: return CK_CTRL_PGDN;
- case 145: return CK_CTRL_DOWN;
- case 117: return CK_CTRL_END;
- case 115: return CK_CTRL_LEFT;
- case 'S': return CK_DELETE;
- }
- }
- return c;
-}
-#endif
-
-// Hacky wrapper around getch() that returns CK_ codes for keys
-// we want to use in cancelable_get_line() and menus.
-int c_getch() {
-#if defined(DOS) || defined(LINUX) || defined(WIN32CONSOLE)
- return getch_ck();
-#else
- return getch();
-#endif
-}
-
-// cprintf that knows how to wrap down lines (primitive, but what the heck)
-int wrapcprintf( int wrapcol, const char *s, ... )
-{
- char buf[1000]; // Hard max
- va_list args;
- va_start(args, s);
-
- // XXX: If snprintf isn't available, vsnprintf probably isn't, either.
- int len = vsnprintf(buf, sizeof buf, s, args), olen = len;
- va_end(args);
-
- char *run = buf;
- while (len > 0)
- {
- int x = wherex(), y = wherey();
-
- if (x > wrapcol) // Somebody messed up!
- return 0;
-
- int avail = wrapcol - x + 1;
- int c = 0;
- if (len > avail) {
- c = run[avail];
- run[avail] = 0;
- }
- cprintf("%s", run);
-
- if (len > avail)
- run[avail] = c;
-
- if ((len -= avail) > 0)
- gotoxy(1, y + 1);
- run += avail;
- }
- return (olen);
-}
-
-#define WX(x) ( ((x) - 1) % maxcol + 1 )
-#define WY(x,y) ( (y) + ((x) - 1) / maxcol )
-#define WC(x,y) WX(x), WY(x,y)
-#define GOTOXY(x,y) gotoxy( WC(x,y) )
-bool cancelable_get_line( char *buf, int len, int maxcol,
- input_history *mh )
-{
- if (len <= 0) return false;
-
- buf[0] = 0;
-
- char *cur = buf;
- int start = wherex(), line = wherey();
- int length = 0, pos = 0;
-
- if (mh)
- mh->go_end();
-
- for ( ; ; ) {
- int ch = c_getch();
-
- switch (ch) {
- case CK_ESCAPE:
- return false;
- case CK_UP:
- case CK_DOWN:
- {
- if (!mh)
- break;
- const std::string *text = ch == CK_UP? mh->prev() : mh->next();
- if (text)
- {
- int olen = length;
- length = text->length();
- if (length >= len)
- length = len - 1;
- memcpy(buf, text->c_str(), length);
- buf[length] = 0;
- GOTOXY(start, line);
-
- int clear = length < olen? olen - length : 0;
- wrapcprintf(maxcol, "%s%*s", buf, clear, "");
-
- pos = length;
- cur = buf + pos;
- GOTOXY(start + pos, line);
- }
- break;
- }
- case CK_ENTER:
- buf[length] = 0;
- if (mh && length)
- mh->new_input(buf);
- return true;
- case CONTROL('K'):
- {
- // Kill to end of line
- int erase = length - pos;
- if (erase)
- {
- length = pos;
- buf[length] = 0;
- wrapcprintf( maxcol, "%*s", erase, "" );
- GOTOXY(start + pos, line);
- }
- break;
- }
- case CK_DELETE:
- if (pos < length) {
- char *c = cur;
- while (c - buf < length) {
- *c = c[1];
- c++;
- }
- --length;
-
- GOTOXY( start + pos, line );
- buf[length] = 0;
- wrapcprintf( maxcol, "%s ", cur );
- GOTOXY( start + pos, line );
- }
- break;
- case CK_BKSP:
- if (pos) {
- --cur;
- char *c = cur;
- while (*c) {
- *c = c[1];
- c++;
- }
- --pos;
- --length;
-
- GOTOXY( start + pos, line );
- buf[length] = 0;
- wrapcprintf( maxcol, "%s ", cur );
- GOTOXY( start + pos, line );
- }
- break;
- case CK_LEFT:
- if (pos) {
- --pos;
- cur = buf + pos;
- GOTOXY( start + pos, line );
- }
- break;
- case CK_RIGHT:
- if (pos < length) {
- ++pos;
- cur = buf + pos;
- GOTOXY( start + pos, line );
- }
- break;
- case CK_HOME:
- case CONTROL('A'):
- pos = 0;
- cur = buf + pos;
- GOTOXY( start + pos, line );
- break;
- case CK_END:
- case CONTROL('E'):
- pos = length;
- cur = buf + pos;
- GOTOXY( start + pos, line );
- break;
- default:
- if (isprint(ch) && length < len - 1) {
- if (pos < length) {
- char *c = buf + length - 1;
- while (c >= cur) {
- c[1] = *c;
- c--;
- }
- }
- *cur++ = (char) ch;
- ++length;
- ++pos;
- putch(ch);
- if (pos < length) {
- buf[length] = 0;
- wrapcprintf( maxcol, "%s", cur );
- }
- GOTOXY(start + pos, line);
- }
- break;
- }
- }
-}
-#undef GOTOXY
-#undef WC
-#undef WX
-#undef WY
-
-// also used with macros
-std::string & trim_string( std::string &str )
-{
- // OK, this is really annoying. Borland C++ seems to define
- // basic_string::erase to take iterators, and basic_string::remove
- // to take size_t or integer. This is ass-backwards compared to
- // nearly all other C++ compilers. Crap. (GDL)
- //
- // Borland 5.5 does this correctly now... leaving the old code
- // around for now in case anyone needs it. -- bwr
-// #ifdef __BCPLUSPLUS__
-// str.remove( 0, str.find_first_not_of( " \t\n\r" ) );
-// str.remove( str.find_last_not_of( " \t\n\r" ) + 1 );
-// #else
- str.erase( 0, str.find_first_not_of( " \t\n\r" ) );
- str.erase( str.find_last_not_of( " \t\n\r" ) + 1 );
-// #endif
-
- return (str);
-}
-
-std::vector<std::string> split_string(const char *sep, std::string s)
-{
- std::vector<std::string> segments;
-
- std::string::size_type pos;
- while ((pos = s.find(sep, 0)) != std::string::npos) {
- if (pos > 0)
- segments.push_back(s.substr(0, pos));
- s.erase(0, pos + 1);
- }
- if (s.length() > 0)
- segments.push_back(s);
-
- for (int i = 0, count = segments.size(); i < count; ++i)
- trim_string(segments[i]);
- return segments;
-}
-
-// The old school way of doing short delays via low level I/O sync.
-// Good for systems like old versions of Solaris that don't have usleep.
-#ifdef NEED_USLEEP
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/unistd.h>
-
-void usleep(unsigned long time)
-{
- struct timeval timer;
-
- timer.tv_sec = (time / 1000000L);
- timer.tv_usec = (time % 1000000L);
-
- select(0, NULL, NULL, NULL, &timer);
-}
-#endif
-
-// Not the greatest version of snprintf, but a functional one that's
-// a bit safer than raw sprintf(). Note that this doesn't do the
-// special behaviour for size == 0, largely because the return value
-// in that case varies depending on which standard is being used (SUSv2
-// returns an unspecified value < 1, whereas C99 allows str == NULL
-// and returns the number of characters that would have been written). -- bwr
-#ifdef NEED_SNPRINTF
-
-#include <string.h>
-
-int snprintf( char *str, size_t size, const char *format, ... )
-{
- va_list argp;
- va_start( argp, format );
-
- char buff[ 10 * size ]; // hopefully enough
-
- vsprintf( buff, format, argp );
- strncpy( str, buff, size );
- str[ size - 1 ] = '\0';
-
- int ret = strlen( str );
- if ((unsigned int) ret == size - 1 && strlen( buff ) >= size)
- ret = -1;
-
- va_end( argp );
-
- return (ret);
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////
-// Pattern matching
-
-inline int pm_lower(int ch, bool icase) {
- return icase? tolower(ch) : ch;
-}
-
-// Determines whether the pattern specified by 'pattern' matches the given
-// text. A pattern is a simple glob, with the traditional * and ? wildcards.
-static bool glob_match( const char *pattern, const char *text, bool icase )
-{
- char p, t;
- bool special;
-
- for (;;)
- {
- p = pm_lower(*pattern++, icase);
- t = pm_lower(*text++, icase);
- special = true;
-
- if (!p) return t == 0;
- if (p == '\\' && *pattern)
- {
- p = pm_lower(*pattern++, icase);
- special = false;
- }
-
- if (p == '*' && special)
- // Try to match exactly at the current text position...
- return !*pattern || glob_match(pattern, text - 1, icase)? true :
- // Or skip one character in the text and try the wildcard
- // match again. If this is the end of the text, the match has
- // failed.
- t? glob_match(pattern - 1, text, icase) : false;
- else if (!t || (p != t && (p != '?' || !special)))
- return false;
- }
-}
-
-#if defined(REGEX_PCRE)
-////////////////////////////////////////////////////////////////////
-// Perl Compatible Regular Expressions
-
-void *compile_pattern(const char *pattern, bool icase) {
- const char *error;
- int erroffset;
- int flags = icase? PCRE_CASELESS : 0;
- return pcre_compile(pattern,
- flags,
- &error,
- &erroffset,
- NULL);
-}
-
-void free_compiled_pattern(void *cp) {
- if (cp)
- pcre_free(cp);
-}
-
-bool pattern_match(void *compiled_pattern, const char *text, int length)
-{
- int ovector[42];
- int pcre_rc = pcre_exec(static_cast<pcre *>(compiled_pattern),
- NULL,
- text,
- length,
- 0,
- 0,
- ovector,
- sizeof(ovector) / sizeof(*ovector));
- return (pcre_rc >= 0);
-}
-
-////////////////////////////////////////////////////////////////////
-#elif defined(REGEX_POSIX)
-////////////////////////////////////////////////////////////////////
-// POSIX regular expressions
-
-void *compile_pattern(const char *pattern, bool icase) {
- regex_t *re = new regex_t;
- if (!re)
- return NULL;
-
- int flags = REG_EXTENDED | REG_NOSUB;
- if (icase)
- flags |= REG_ICASE;
- int rc = regcomp(re, pattern, flags);
- // Nonzero return code == failure
- if (rc) {
- delete re;
- return NULL;
- }
- return re;
-}
-
-void free_compiled_pattern(void *cp) {
- if (cp) {
- regex_t *re = static_cast<regex_t *>( cp );
- regfree(re);
- delete re;
- }
-}
-
-bool pattern_match(void *compiled_pattern, const char *text, int length)
-{
- regex_t *re = static_cast<regex_t *>( compiled_pattern );
- return !regexec(re, text, 0, NULL, 0);
-}
-
-////////////////////////////////////////////////////////////////////
-#else
-////////////////////////////////////////////////////////////////////
-// Basic glob
-
-struct glob_info
-{
- std::string s;
- bool ignore_case;
-};
-
-void *compile_pattern(const char *pattern, bool icase)
-{
- // If we're using simple globs, we need to box the pattern with '*'
- std::string s = std::string("*") + pattern + "*";
- glob_info *gi = new glob_info;
- if (gi) {
- gi->s = s;
- gi->ignore_case = icase;
- }
- return gi;
-}
-
-void free_compiled_pattern(void *compiled_pattern)
-{
- delete static_cast<glob_info *>( compiled_pattern );
-}
-
-bool pattern_match(void *compiled_pattern, const char *text, int length)
-{
- glob_info *gi = static_cast<glob_info *>( compiled_pattern );
- return glob_match(gi->s.c_str(), text, gi->ignore_case);
-}
-////////////////////////////////////////////////////////////////////
-
-#endif
-
-
-
-////////////////////////////////////////////////////////////////////
-// formatted_string
-//
-
-formatted_string::formatted_string(const std::string &s)
- : ops()
-{
- ops.push_back( s );
-}
-
-formatted_string::operator std::string() const
-{
- std::string s;
- for (int i = 0, size = ops.size(); i < size; ++i)
- {
- if (ops[i] == FSOP_TEXT)
- s += ops[i].text;
- }
- return s;
-}
-
-inline void cap(int &i, int max)
-{
- if (i < 0 && -i <= max)
- i += max;
- if (i >= max)
- i = max - 1;
- if (i < 0)
- i = 0;
-}
-
-std::string formatted_string::tostring(int s, int e) const
-{
- std::string st;
-
- int size = ops.size();
- cap(s, size);
- cap(e, size);
-
- for (int i = s; i <= e && i < size; ++i)
- {
- if (ops[i] == FSOP_TEXT)
- st += ops[i].text;
- }
- return st;
-}
-
-void formatted_string::display(int s, int e) const
-{
- int size = ops.size();
- if (!size)
- return ;
-
- cap(s, size);
- cap(e, size);
-
- for (int i = s; i <= e && i < size; ++i)
- ops[i].display();
-}
-
-void formatted_string::gotoxy(int x, int y)
-{
- ops.push_back( fs_op(x, y) );
-}
-
-void formatted_string::textcolor(int color)
-{
- ops.push_back(color);
-}
-
-void formatted_string::cprintf(const char *s, ...)
-{
- char buf[1000];
- va_list args;
- va_start(args, s);
- vsnprintf(buf, sizeof buf, s, args);
- va_end(args);
-
- cprintf(std::string(buf));
-}
-
-void formatted_string::cprintf(const std::string &s)
-{
- ops.push_back(s);
-}
-
-void formatted_string::fs_op::display() const
-{
- switch (type)
- {
- case FSOP_CURSOR:
- {
- int cx = (x == -1? wherex() : x);
- int cy = (y == -1? wherey() : y);
- ::gotoxy(cx, cy);
- break;
- }
- case FSOP_COLOUR:
- ::textcolor(x);
- break;
- case FSOP_TEXT:
- ::cprintf("%s", text.c_str());
- break;
- }
-}
-
-/////////////////////////////////////////////////////////////
-// input_history
-//
-
-input_history::input_history(size_t size)
- : history(), pos(), maxsize(size)
-{
- if (maxsize < 2)
- maxsize = 2;
-
- pos = history.end();
-}
-
-void input_history::new_input(const std::string &s)
-{
- history.remove(s);
-
- if (history.size() == maxsize)
- history.pop_front();
-
- history.push_back(s);
-
- // Force the iterator to the end (also revalidates it)
- go_end();
-}
-
-const std::string *input_history::prev()
-{
- if (history.empty())
- return NULL;
-
- if (pos == history.begin())
- pos = history.end();
-
- return &*--pos;
-}
-
-const std::string *input_history::next()
-{
- if (history.empty())
- return NULL;
-
- if (pos == history.end() || ++pos == history.end())
- pos = history.begin();
-
- return &*pos;
-}
-
-void input_history::go_end()
-{
- pos = history.end();
-}
-
-void input_history::clear()
-{
- history.clear();
- go_end();
-}