summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/IPC.h2
-rw-r--r--src/commands.cpp372
-rw-r--r--src/commands.h91
-rw-r--r--src/config.cpp5
-rw-r--r--src/config.h2
-rw-r--r--src/keybinds.cpp5
-rw-r--r--src/keybinds.h2
7 files changed, 470 insertions, 9 deletions
diff --git a/src/IPC.h b/src/IPC.h
index 0705c2b..e0bbcee 100644
--- a/src/IPC.h
+++ b/src/IPC.h
@@ -3,7 +3,7 @@
#include <sys/socket.h>
#include <sys/un.h>
-#include <commands.h>
+#include "commands.h"
#include "config.h"
#include "util.h"
diff --git a/src/commands.cpp b/src/commands.cpp
new file mode 100644
index 0000000..caa82eb
--- /dev/null
+++ b/src/commands.cpp
@@ -0,0 +1,372 @@
+#include "commands.h"
+#include "error.h"
+#include "util.h"
+
+#include <cctype>
+#include <filesystem>
+#include <iostream>
+#include <algorithm>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <cstring>
+#include <fstream>
+
+using std::cout, std::endl, std::string, std::vector;
+
+const void CommandsModule::echo(const CommandArg* argv)
+{
+ cout << argv[0].str << endl;
+}
+
+const void CommandsModule::loadFile(const CommandArg* argv)
+{
+ std::vector<Err> errs;
+
+ string path = cwd + "/" + std::string(argv[0].str);
+
+ std::ifstream file(path);
+ if(!file.good())
+ throw Err(CMD_ERR_NON_FATAL, "File '" + std::string(argv[0].str) + "' doesn't exist");
+
+ string prevCWD = cwd;
+ cwd = std::filesystem::path(path).parent_path();
+
+ cout << "Loading file '" << argv[0].str << "'" << endl;
+
+ int line = 0;
+ for(string cmd; std::getline(file, cmd);)
+ {
+ line++;
+ if(cmd.size() == 0)
+ continue;
+ if(cmd.at(0) == '#')
+ continue;
+ try
+ {
+ this->runCommand(cmd);
+ }
+ catch (Err e)
+ {
+ throw Err(e.code, "Error in file '" + std::string(argv[0].str) + "' (line " + std::to_string(line) + "): " + std::to_string(e.code) + "\n\tMessage: " + e.message);
+ }
+ }
+
+ cwd = prevCWD;
+}
+
+CommandsModule::CommandsModule()
+{
+ addCommand("echo", &CommandsModule::echo, 1, {STR_REST}, this);
+ addCommand("loadFile", &CommandsModule::loadFile, 1, {STR_REST}, this);
+ cwd = std::filesystem::current_path();
+}
+CommandsModule::~CommandsModule()
+{
+ for(Command c : commandList)
+ {
+ if(c.argc > 0)
+ delete[] c.argTypes;
+ }
+}
+
+void CommandsModule::addCommand(Command c)
+{
+ if(lookupCommand(c.name) != nullptr)
+ {
+ cout << "Duplicate command: " << c.name << endl;
+ }
+ commandList.push_back(c);
+}
+void CommandsModule::addCommand(std::string name, const void (*func)(const CommandArg *), const int argc, CommandArgType *argTypes)
+{
+ Command c = {name, nullptr, func, argc, argTypes, nullptr};
+ addCommand(c);
+}
+void CommandsModule::addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes)
+{
+ CommandArgType* argTypesArr = new CommandArgType[argc];
+ for(int i = 0; i < argc; i++)
+ {
+ argTypesArr[i] = argTypes[i];
+ }
+ addCommand(name, func, argc, argTypesArr);
+}
+
+struct NameMatches
+{
+ NameMatches(string s): s_{s} {}
+ bool operator()(Command c) { return (c.name == s_); }
+ string s_;
+};
+
+Command* CommandsModule::lookupCommand(string name)
+{
+ auto elem = std::find_if(commandList.begin(), commandList.end(), NameMatches(name));
+ if (elem != commandList.end())
+ {
+ int i = elem - commandList.begin();
+ return &(commandList[i]);
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+vector<string> CommandsModule::splitCommand(string command)
+{
+ vector<string> v;
+ string arg = "";
+ bool inQuotes = false;
+ bool escapeNext = true;
+ char quoteType;
+ for(int i = 0; i < command.size(); i++)
+ {
+ if(escapeNext)
+ {
+ arg += command[i];
+ escapeNext = false;
+ }
+ else if(command[i] == '\\')
+ {
+ escapeNext = true;
+ }
+ else if(inQuotes)
+ {
+ if(command[i] == quoteType)
+ {
+ if(arg != "")
+ {
+ v.push_back(arg);
+ arg = "";
+ }
+ inQuotes = false;
+ }
+ else
+ {
+ arg += command[i];
+ }
+ }
+ else
+ {
+ if(command[i] == ' ')
+ {
+ if(arg != "")
+ {
+ v.push_back(arg);
+ arg = "";
+ }
+ }
+ else if(command[i] == '"' || command[i] == '\'')
+ {
+ inQuotes = true;
+ quoteType = command[i];
+ }
+ else
+ {
+ arg += command[i];
+ }
+ }
+ }
+ if(arg != "")
+ v.push_back(arg);
+ return v;
+}
+
+CommandArg* CommandsModule::getCommandArgs(vector<string>& split, const CommandArgType* argTypes, const int argc)
+{
+ CommandArg* args = new CommandArg[argc];
+ for(int i = 1; i < argc + 1; i++)
+ {
+ switch(argTypes[i-1])
+ {
+ case STR: args[i-1].str = (char*)split[i].c_str(); break;
+ case NUM:
+ {
+ try
+ {
+ args[i-1].num = std::stoi(split[i]);
+ break;
+ }
+ catch(std::invalid_argument e)
+ {
+ delete[] args;
+ throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!");
+ }
+ }
+ case MOVDIR:
+ {
+ if(lowercase(split[i]) == "up")
+ args[i-1].dir = UP;
+ else if(lowercase(split[i]) == "down")
+ args[i-1].dir = DOWN;
+ else if(lowercase(split[i]) == "left")
+ args[i-1].dir = LEFT;
+ else if(lowercase(split[i]) == "right")
+ args[i-1].dir = RIGHT;
+ else
+ {
+ delete[] args;
+ throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a direction!");
+ }
+ break;
+ }
+ case STR_REST:
+ {
+ string rest = "";
+ for(int j = i; j < split.size(); j++)
+ {
+ rest += split[j];
+ if(j != split.size() - 1)
+ rest += " ";
+ }
+ args[i-1].str = new char[rest.size()];
+ strncpy(args[i-1].str, rest.c_str(), rest.size());
+ return args;
+ }
+ case NUM_ARR_REST:
+ {
+ int* rest = new int[split.size() - i];
+ for(int j = 0; j < split.size() - i; j++)
+ {
+ try
+ {
+ rest[j] = std::stoi(split[j + i]);
+ }
+ catch(std::invalid_argument e)
+ {
+ delete[] rest;
+ delete[] args;
+ throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!");
+ }
+ }
+ args[i-1].numArr = {rest, (int) split.size() - i};
+ return args;
+ }
+ default: cout << "UH OH SOMETHING IS VERY WRONG" << endl;
+ }
+ }
+ return args;
+}
+
+void CommandsModule::runCommand(string command)
+{
+ vector<string> split = splitCommand(command);
+ vector<string>::const_iterator start = split.begin();
+ int count = 0;
+ for(string s : split)
+ {
+ if(s == ";")
+ {
+ vector<string>::const_iterator end = start + count;
+ vector<string> partialCmd(start, end);
+ runCommand(partialCmd);
+ count = 0;
+ start = end + 1;
+ }
+ else
+ {
+ count++;
+ }
+ }
+ if(start != split.end())
+ {
+ vector<string> partialCmd(start, (vector<string>::const_iterator)split.end());
+ runCommand(partialCmd);
+ }
+}
+void CommandsModule::runCommand(vector<string> split)
+{
+ Command* cmd = lookupCommand(split[0]);
+ if(cmd == nullptr)
+ throw Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name");
+ if(cmd->argc > split.size() - 1)
+ throw Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments");
+ CommandArg* args;
+ try
+ {
+ args = getCommandArgs(split, cmd->argTypes, cmd->argc);
+ }
+ catch(Err e)
+ {
+ throw e;
+ }
+ try
+ {
+ if(cmd->module == nullptr)
+ cmd->staticFunc(args);
+ else
+ cmd->func(*cmd->module, args);
+ }
+ catch (Err e)
+ {
+ for(int i = 0; i < cmd->argc; i++)
+ {
+ if(cmd->argTypes[i] == STR_REST)
+ delete[] args[i].str;
+ }
+ delete[] args;
+ throw e;
+ }
+ for(int i = 0; i < cmd->argc; i++)
+ {
+ if(cmd->argTypes[i] == STR_REST)
+ delete[] args[i].str;
+ }
+ delete[] args;
+}
+
+vector<Err> CommandsModule::checkCommand(string command)
+{
+ vector<Err> errs;
+ vector<string> split = splitCommand(command);
+ vector<string>::const_iterator start = split.begin();
+ int count = 0;
+ for(string s : split)
+ {
+ if(s == ";")
+ {
+ vector<string>::const_iterator end = start + count;
+ vector<string> partialCmd(start, end);
+ errs.push_back(checkCommand(partialCmd));
+ count = 0;
+ start = end + 1;
+ }
+ else
+ {
+ count++;
+ }
+ }
+ if(start != split.end())
+ {
+ vector<string> partialCmd(start, (vector<string>::const_iterator)split.end());
+ errs.push_back(checkCommand(partialCmd));
+ }
+ return errs;
+}
+
+Err CommandsModule::checkCommand(vector<string> split)
+{
+ Command* cmd = lookupCommand(split[0]);
+ if(cmd == nullptr)
+ return Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name");
+ if(cmd->argc > split.size())
+ return Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments");
+ CommandArg* args;
+ try
+ {
+ args = getCommandArgs(split, cmd->argTypes, cmd->argc);
+ }
+ catch(Err e)
+ {
+ return e;
+ }
+ for(int i = 0; i < cmd->argc; i++)
+ {
+ if(cmd->argTypes[i] == STR_REST || cmd->argTypes[i] == NUM_ARR_REST)
+ delete[] args[i].str;
+ }
+ delete[] args;
+ return Err(NOERR, "");
+}
diff --git a/src/commands.h b/src/commands.h
new file mode 100644
index 0000000..4825f1c
--- /dev/null
+++ b/src/commands.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "error.h"
+
+#include <vector>
+#include <string>
+#include <any>
+#include <functional>
+
+enum MoveDir
+ {
+ UP,
+ RIGHT,
+ DOWN,
+ LEFT
+ };
+enum CommandArgType
+ {
+ STR,
+ NUM,
+ MOVDIR,
+ STR_REST,
+ NUM_ARR_REST
+ };
+
+struct NumArr
+{
+ int* arr;
+ int size;
+};
+typedef union
+{
+ char* str;
+ int num;
+ NumArr numArr;
+ MoveDir dir;
+} CommandArg;
+
+struct Command
+{
+ const std::string name;
+ const std::function<void(std::any&, const CommandArg* argv)> func;
+ const std::function<void(const CommandArg* argv)> staticFunc;
+ const int argc;
+ CommandArgType* argTypes;
+ std::any* module;
+};
+class CommandsModule
+{
+private:
+ std::vector<Command> commandList;
+ std::vector<std::string> splitCommand(std::string command);
+ CommandArg* getCommandArgs(std::vector<std::string>& args, const CommandArgType* argTypes, const int argc);
+ const void echo(const CommandArg* argv);
+ const void loadFile(const CommandArg* argv);
+ std::string cwd;
+public:
+ CommandsModule();
+ ~CommandsModule();
+ template <class T>
+ void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module);
+ void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, CommandArgType* argTypes);
+ template <class T>
+ void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes, T* module);
+ void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes);
+ void addCommand(Command c);
+ Command* lookupCommand(std::string name);
+ void runCommand(std::string command);
+ void runCommand(std::vector<std::string> split);
+ std::vector<Err> checkCommand(std::string command);
+ Err checkCommand(std::vector<std::string> split);
+};
+
+// YES I KNOW THIS IS BAD
+// but it needs to be done this way
+template <class T>
+void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module)
+{
+ Command c = {name, (const void*(std::any::*)(const CommandArg* argv)) func, nullptr, argc, argTypes, (std::any*)module};
+ addCommand(c);
+}
+template <class T>
+void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes, T* module)
+{
+ CommandArgType* argTypesArr = new CommandArgType[argc];
+ for(int i = 0; i < argc; i++)
+ {
+ argTypesArr[i] = argTypes[i];
+ }
+ addCommand(name, func, argc, argTypesArr, module);
+}
diff --git a/src/config.cpp b/src/config.cpp
index df195aa..925e6ea 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -1,7 +1,6 @@
#include "config.h"
-#include <commands.h>
-//TODO: FIX THIS
-#include <error.h>
+#include "commands.h"
+#include "error.h"
#include <X11/Xlib.h>
diff --git a/src/config.h b/src/config.h
index b04753f..55e4fd3 100644
--- a/src/config.h
+++ b/src/config.h
@@ -2,7 +2,7 @@
#include <X11/X.h>
#include <X11/keysym.h>
-#include <commands.h>
+#include "commands.h"
#include <string>
#include <vector>
diff --git a/src/keybinds.cpp b/src/keybinds.cpp
index 127a534..235f8c1 100644
--- a/src/keybinds.cpp
+++ b/src/keybinds.cpp
@@ -7,9 +7,8 @@
#include <vector>
#include <regex>
-#include <commands.h>
-//TODO: FIX THIS
-#include <error.h>
+#include "commands.h"
+#include "error.h"
#include "keybinds.h"
#include "util.h"
diff --git a/src/keybinds.h b/src/keybinds.h
index 5fd4fba..a742240 100644
--- a/src/keybinds.h
+++ b/src/keybinds.h
@@ -8,7 +8,7 @@
#include <X11/keysym.h>
#include <vector>
-#include <commands.h>
+#include "commands.h"
#include "config.h"
#include "util.h"