summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/macro.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/macro.cc')
-rw-r--r--stone_soup/crawl-ref/source/macro.cc731
1 files changed, 0 insertions, 731 deletions
diff --git a/stone_soup/crawl-ref/source/macro.cc b/stone_soup/crawl-ref/source/macro.cc
deleted file mode 100644
index 13838a947c..0000000000
--- a/stone_soup/crawl-ref/source/macro.cc
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * File: macro.cc
- * Summary: Crude macro-capability
- * Written by: Juho Snellman <jsnell@lyseo.edu.ouka.fi>
- *
- * Change History (most recent first):
- *
- * <3> 6/25/02 JS Completely rewritten
- * <2> 6/13/99 BWR SysEnv.crawl_dir support
- * <1> -/--/-- JS Created
- */
-
-/*
- * The macro-implementation works like this:
- * - For generic game code, #define getch() getchm().
- * - getchm() works by reading characters from an internal
- * buffer. If none are available, new characters are read into
- * the buffer with getch_mul().
- * - getch_mul() reads at least one character, but will read more
- * if available (determined using kbhit(), which should be defined
- * in the platform specific libraries).
- * - Before adding the characters read into the buffer, any macros
- * in the sequence are replaced (see macro_add_buf_long for the
- * details).
- *
- * (When the above text mentions characters, it actually means int).
- */
-
-#include "AppHdr.h"
-
-#ifdef USE_MACROS
-#define MACRO_CC
-#include "macro.h"
-
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <map>
-#include <deque>
-#include <vector>
-
-#include <stdio.h> // for snprintf
-#include <ctype.h> // for tolower
-
-#include "externs.h"
-#include "stuff.h"
-
-// for trim_string:
-#include "initfile.h"
-
-typedef std::deque<int> keyseq;
-typedef std::deque<int> keybuf;
-typedef std::map<keyseq,keyseq> macromap;
-
-static macromap Keymaps[KC_CONTEXT_COUNT];
-static macromap Macros;
-
-static macromap *all_maps[] =
-{
- &Keymaps[KC_DEFAULT],
- &Keymaps[KC_LEVELMAP],
- &Keymaps[KC_TARGETING],
- &Macros,
-};
-
-static keybuf Buffer;
-
-#define USERFUNCBASE -10000
-static std::vector<std::string> userfunctions;
-
-inline int userfunc_index(int key)
-{
- int index = (key <= USERFUNCBASE? USERFUNCBASE - key : -1);
- return (index < 0 || index >= (int) userfunctions.size()? -1 : index);
-}
-
-static int userfunc_index(const keyseq &seq)
-{
- if (seq.empty())
- return (-1);
-
- return userfunc_index(seq.front());
-}
-
-bool is_userfunction(int key)
-{
- return (userfunc_index(key) != -1);
-}
-
-static bool is_userfunction(const keyseq &seq)
-{
- return (userfunc_index(seq) != -1);
-}
-
-const char *get_userfunction(int key)
-{
- int index = userfunc_index(key);
- return (index == -1? NULL : userfunctions[index].c_str());
-}
-
-static const char *get_userfunction(const keyseq &seq)
-{
- int index = userfunc_index(seq);
- return (index == -1? NULL : userfunctions[index].c_str());
-}
-
-static bool userfunc_referenced(int index, const macromap &mm)
-{
- for (macromap::const_iterator i = mm.begin(); i != mm.end(); i++)
- {
- if (userfunc_index(i->second) == index)
- return (true);
- }
- return (false);
-}
-
-static bool userfunc_referenced(int index)
-{
- for (unsigned i = 0; i < sizeof(all_maps) / sizeof(*all_maps); ++i)
- {
- macromap *m = all_maps[i];
- if (userfunc_referenced(index, *m))
- return (true);
- }
- return (false);
-}
-
-// Expensive function to discard unused function names
-static void userfunc_collectgarbage(void)
-{
- for (int i = userfunctions.size() - 1; i >= 0; --i)
- {
- if (!userfunctions.empty() && !userfunc_referenced(i))
- userfunctions[i].clear();
- }
-}
-
-static int userfunc_getindex(const std::string &fname)
-{
- if (fname.length() == 0)
- return (-1);
-
- userfunc_collectgarbage();
-
- // Pass 1 to see if we have this string already
- for (int i = 0, count = userfunctions.size(); i < count; ++i)
- {
- if (userfunctions[i] == fname)
- return (i);
- }
-
- // Pass 2 to hunt for gaps
- for (int i = 0, count = userfunctions.size(); i < count; ++i)
- {
- if (userfunctions[i].empty())
- {
- userfunctions[i] = fname;
- return (i);
- }
- }
-
- userfunctions.push_back(fname);
- return (userfunctions.size() - 1);
-}
-
-/*
- * Returns the name of the file that contains macros.
- */
-static std::string get_macro_file()
-{
- std::string s;
-
- if (SysEnv.crawl_dir)
- s = SysEnv.crawl_dir;
-
- return (s + "macro.txt");
-}
-
-static void buf2keyseq(const char *buff, keyseq &k)
-{
- // Sanity check
- if (!buff)
- return;
-
- // convert c_str to keyseq
-
- // Check for user functions
- if (*buff == '=' && buff[1] == '=' && buff[2] == '=' && buff[3])
- {
- int index = userfunc_getindex(buff + 3);
- if (index != -1)
- k.push_back( USERFUNCBASE - index );
- }
- else
- {
- const int len = strlen( buff );
- for (int i = 0; i < len; i++)
- k.push_back( buff[i] );
- }
-}
-
-/*
- * Takes as argument a string, and returns a sequence of keys described
- * by the string. Most characters produce their own ASCII code. There
- * are two special cases:
- * \\ produces the ASCII code of a single \
- * \{123} produces 123 (decimal)
- */
-static keyseq parse_keyseq( std::string s )
-{
- int state = 0;
- keyseq v;
- int num;
-
- if (s.find("===") == 0)
- {
- buf2keyseq(s.c_str(), v);
- return (v);
- }
-
- for (std::string::iterator i = s.begin(); i != s.end(); i++)
- {
- char c = *i;
-
- switch (state)
- {
- case 0: // Normal state
- if (c == '\\') {
- state = 1;
- } else {
- v.push_back(c);
- }
- break;
-
- case 1: // Last char is a '\'
- if (c == '\\') {
- state = 0;
- v.push_back(c);
- } else if (c == '{') {
- state = 2;
- num = 0;
- }
- // XXX Error handling
- break;
-
- case 2: // Inside \{}
- if (c == '}') {
- v.push_back(num);
- state = 0;
- } else if (c >= '0' && c <= '9') {
- num = num * 10 + c - '0';
- }
- // XXX Error handling
- break;
- }
- }
-
- return (v);
-}
-
-/*
- * Serializes a key sequence into a string of the format described
- * above.
- */
-static std::string vtostr( const keyseq &seq )
-{
- std::string s;
-
- const keyseq *v = &seq;
- keyseq dummy;
- if (is_userfunction(seq))
- {
- // Laboriously reconstruct the original user input
- std::string newseq = std::string("==") + get_userfunction(seq);
- buf2keyseq(newseq.c_str(), dummy);
- dummy.push_front('=');
-
- v = &dummy;
- }
-
- for (keyseq::const_iterator i = v->begin(); i != v->end(); i++)
- {
- if (*i <= 32 || *i > 127) {
- char buff[10];
-
- snprintf( buff, sizeof(buff), "\\{%d}", *i );
- s += std::string( buff );
-
- // Removing the stringstream code because its highly
- // non-portable. For starters, people and compilers
- // are supposed to be using the <sstream> implementation
- // (with the ostringstream class) not the old <strstream>
- // version, but <sstream> is not as available as it should be.
- //
- // The strstream implementation isn't very standard
- // either: some compilers require the "ends" marker,
- // others don't (and potentially fatal errors can
- // happen if you don't have it correct for the system...
- // ie its hard to make portable). It also isn't a very
- // good implementation to begin with.
- //
- // Everyone should have snprintf()... we supply a version
- // in libutil.cc to make sure of that! -- bwr
- //
- // std::ostrstream ss;
- // ss << "\\{" << *i << "}" << ends;
- // s += ss.str();
- } else if (*i == '\\') {
- s += "\\\\";
- } else {
- s += *i;
- }
- }
-
- return (s);
-}
-
-/*
- * Add a macro (suprise, suprise).
- */
-static void macro_add( macromap &mapref, keyseq key, keyseq action )
-{
- mapref[key] = action;
-}
-
-static void macro_add( macromap &mapref, keyseq key, const char *buff )
-{
- keyseq act;
- buf2keyseq(buff, act);
- if (!act.empty())
- macro_add( mapref, key, act );
-}
-
-/*
- * Remove a macro.
- */
-static void macro_del( macromap &mapref, keyseq key )
-{
- mapref.erase( key );
-}
-
-
-/*
- * Adds keypresses from a sequence into the internal keybuffer. Ignores
- * macros.
- */
-static void macro_buf_add( keyseq actions )
-{
- for (keyseq::iterator i = actions.begin(); i != actions.end(); i++)
- Buffer.push_back(*i);
-}
-
-/*
- * Adds a single keypress into the internal keybuffer.
- */
-void macro_buf_add( int key )
-{
- Buffer.push_back( key );
-}
-
-
-/*
- * Adds keypresses from a sequence into the internal keybuffer. Does some
- * O(N^2) analysis to the sequence to replace macros.
- */
-static void macro_buf_add_long( keyseq actions, macromap &keymap = Keymaps[KC_DEFAULT] )
-{
- keyseq tmp;
-
- // debug << "Adding: " << vtostr(actions) << endl;
- // debug.flush();
-
- // Check whether any subsequences of the sequence are macros.
- // The matching starts from as early as possible, and is
- // as long as possible given the first constraint. I.e from
- // the sequence "abcdef" and macros "ab", "bcde" and "de"
- // "ab" and "de" are recognized as macros.
-
- while (actions.size() > 0)
- {
- tmp = actions;
-
- while (tmp.size() > 0)
- {
- keyseq result = keymap[tmp];
-
- // Found a macro. Add the expansion (action) of the
- // macro into the buffer.
- if (result.size() > 0) {
- macro_buf_add( result );
- break;
- }
-
- // Didn't find a macro. Remove a key from the end
- // of the sequence, and try again.
- tmp.pop_back();
- }
-
- if (tmp.size() == 0) {
- // Didn't find a macro. Add the first keypress of the sequence
- // into the buffer, remove it from the sequence, and try again.
- macro_buf_add( actions.front() );
- actions.pop_front();
-
- } else {
- // Found a macro, which has already been added above. Now just
- // remove the macroed keys from the sequence.
- for (unsigned int i = 0; i < tmp.size(); i++)
- actions.pop_front();
- }
- }
-}
-
-/*
- * Command macros are only applied from the immediate front of the
- * buffer, and only when the game is expecting a command.
- */
-static void macro_buf_apply_command_macro( void )
-{
- keyseq tmp = Buffer;
-
- // find the longest match from the start of the buffer and replace it
- while (tmp.size() > 0)
- {
- keyseq result = Macros[tmp];
-
- if (result.size() > 0)
- {
- // Found macro, remove match from front:
- for (unsigned int i = 0; i < tmp.size(); i++)
- Buffer.pop_front();
-
- // Add macro to front:
- for (keyseq::reverse_iterator k = result.rbegin(); k != result.rend(); k++)
- Buffer.push_front(*k);
-
- break;
- }
-
- tmp.pop_back();
- }
-}
-
-/*
- * Removes the earlies keypress from the keybuffer, and returns its
- * value. If buffer was empty, returns -1;
- */
-static int macro_buf_get( void )
-{
- if (Buffer.size() == 0)
- return (-1);
-
- int key = Buffer.front();
- Buffer.pop_front();
-
- return (key);
-}
-
-static void write_map(std::ofstream &f, const macromap &mp, const char *key)
-{
- for (macromap::const_iterator i = mp.begin(); i != mp.end(); i++)
- {
- // Need this check, since empty values are added into the
- // macro struct for all used keyboard commands.
- if (i->second.size())
- {
- f << key << vtostr((*i).first) << std::endl
- << "A:" << vtostr((*i).second) << std::endl << std::endl;
- }
- }
-}
-
-/*
- * Saves macros into the macrofile, overwriting the old one.
- */
-void macro_save( void )
-{
- std::ofstream f;
- f.open( get_macro_file().c_str() );
-
- f << "# WARNING: This file is entirely auto-generated." << std::endl
- << std::endl << "# Key Mappings:" << std::endl;
- for (int mc = KC_DEFAULT; mc < KC_CONTEXT_COUNT; ++mc) {
- char keybuf[30] = "K:";
- if (mc)
- snprintf(keybuf, sizeof keybuf, "K%d:", mc);
- write_map(f, Keymaps[mc], keybuf);
- }
-
- f << "# Command Macros:" << std::endl;
- write_map(f, Macros, "M:");
-
- f.close();
-}
-
-/*
- * Reads as many keypresses as are available (waiting for at least one),
- * and returns them as a single keyseq.
- */
-static keyseq getch_mul( int (*rgetch)() = NULL )
-{
- keyseq keys;
- int a;
-
- if (!rgetch)
- rgetch = getch;
-
- keys.push_back( a = rgetch() );
-
- // The a == 0 test is legacy code that I don't dare to remove. I
- // have a vague recollection of it being a kludge for conio support.
- while ((kbhit() || a == 0)) {
- keys.push_back( a = rgetch() );
- }
-
- return (keys);
-}
-
-/*
- * Replacement for getch(). Returns keys from the key buffer if available.
- * If not, adds some content to the buffer, and returns some of it.
- */
-int getchm( int (*rgetch)() )
-{
- return getchm( KC_DEFAULT, rgetch );
-}
-
-int getchm(KeymapContext mc, int (*rgetch)())
-{
- int a;
-
- // Got data from buffer.
- if ((a = macro_buf_get()) != -1)
- return (a);
-
- // Read some keys...
- keyseq keys = getch_mul(rgetch);
- // ... and add them into the buffer
- macro_buf_add_long( keys, Keymaps[mc] );
-
- return (macro_buf_get());
-}
-
-/*
- * Replacement for getch(). Returns keys from the key buffer if available.
- * If not, adds some content to the buffer, and returns some of it.
- */
-int getch_with_command_macros( void )
-{
- if (Buffer.size() == 0)
- {
- // Read some keys...
- keyseq keys = getch_mul();
- // ... and add them into the buffer (apply keymaps)
- macro_buf_add_long( keys );
- }
-
- // Apply longest matching macro at front of buffer:
- macro_buf_apply_command_macro();
-
- return (macro_buf_get());
-}
-
-/*
- * Flush the buffer. Later we'll probably want to give the player options
- * as to when this happens (ex. always before command input, casting failed).
- */
-void flush_input_buffer( int reason )
-{
- if (Options.flush_input[ reason ])
- Buffer.clear();
-}
-
-void macro_add_query( void )
-{
- unsigned char input;
- bool keymap = false;
- KeymapContext keymc = KC_DEFAULT;
-
- mesclr();
- mpr( "Command (m)acro or keymap [(k) default, (x) level-map or "
- "(t)argeting]? ", MSGCH_PROMPT );
- input = getch();
- if (input == 0)
- input = getch();
-
- input = tolower( input );
- if (input == 'k')
- {
- keymap = true;
- keymc = KC_DEFAULT;
- }
- else if (input == 'x')
- {
- keymap = true;
- keymc = KC_LEVELMAP;
- }
- else if (input == 't')
- {
- keymap = true;
- keymc = KC_TARGETING;
- }
- else if (input == 'm')
- keymap = false;
- else
- {
- mpr( "Aborting." );
- return;
- }
-
- // reference to the appropriate mapping
- macromap &mapref = (keymap ? Keymaps[keymc] : Macros);
-
- snprintf( info, INFO_SIZE, "Input %s%s trigger key: ",
- keymap?
- (keymc == KC_DEFAULT? "default " :
- keymc == KC_LEVELMAP? "level-map " :
- "targeting ") :
- "",
- (keymap ? "keymap" : "macro") );
-
- mpr( info, MSGCH_PROMPT );
- keyseq key = getch_mul();
-
- cprintf( "%s" EOL, (vtostr( key )).c_str() ); // echo key to screen
-
- if (mapref[key].size() > 0)
- {
- snprintf( info, INFO_SIZE, "Current Action: %s",
- (vtostr( mapref[key] )).c_str() );
-
- mpr( info, MSGCH_WARN );
- mpr( "Do you wish to (r)edefine, (c)lear, or (a)bort?", MSGCH_PROMPT );
-
- input = getch();
- if (input == 0)
- input = getch();
-
- input = tolower( input );
- if (input == 'a' || input == ESCAPE)
- {
- mpr( "Aborting." );
- return;
- }
- else if (input == 'c')
- {
- mpr( "Cleared." );
- macro_del( mapref, key );
- return;
- }
- }
-
- mpr( "Input Macro Action: ", MSGCH_PROMPT );
-
- // Using getch_mul() here isn't very useful... We'd like the
- // flexibility to define multicharacter macros without having
- // to resort to editing files and restarting the game. -- bwr
- // keyseq act = getch_mul();
-
- char buff[4096];
- get_input_line(buff, sizeof buff);
-
- if (Options.macro_meta_entry)
- {
- macro_add( mapref, key, parse_keyseq(buff) );
- }
- else
- {
- macro_add( mapref, key, buff );
- }
-
- redraw_screen();
-}
-
-
-/*
- * Initializes the macros.
- */
-int macro_init( void )
-{
- std::string s;
- std::ifstream f;
- keyseq key, action;
- bool keymap = false;
- KeymapContext keymc = KC_DEFAULT;
-
- f.open( get_macro_file().c_str() );
-
- while (f >> s)
- {
- trim_string(s); // remove white space from ends
-
- if (s[0] == '#') {
- continue; // skip comments
-
- } else if (s.substr(0, 2) == "K:") {
- key = parse_keyseq(s.substr(2));
- keymap = true;
- keymc = KC_DEFAULT;
-
- } else if (s.length() >= 3 && s[0] == 'K' && s[2] == ':') {
- keymc = KeymapContext( KC_DEFAULT + s[1] - '0' );
- if (keymc >= KC_DEFAULT && keymc < KC_CONTEXT_COUNT) {
- key = parse_keyseq(s.substr(3));
- keymap = true;
- }
-
- } else if (s.substr(0, 2) == "M:") {
- key = parse_keyseq(s.substr(2));
- keymap = false;
-
- } else if (s.substr(0, 2) == "A:") {
- action = parse_keyseq(s.substr(2));
- macro_add( (keymap ? Keymaps[keymc] : Macros), key, action );
- }
- }
-
- return (0);
-}
-
-#ifdef CLUA_BINDINGS
-void macro_userfn(const char *keys, const char *regname)
-{
- // TODO: Implement.
- // Converting 'keys' to a key sequence is the difficulty. Doing it portably
- // requires a mapping of key names to whatever getch() spits back, unlikely
- // to happen in a hurry.
-}
-#endif
-
-#endif