← index
libmx2/cmd/src/cmd.cpp
Source: libmx2/cmd/src/cmd.cpp
#include"ast.hpp"

#include"parser.hpp"

#include"scanner.hpp"

#include"types.hpp"

#include"string_buffer.hpp"

#include"html.hpp"

#include"command.hpp"

#include<iostream>

#include<string>

#include<fstream>

#include<optional>

#include<vector>

#include<memory>

#include<functional>

#include<unordered_map>

#include<sstream>

#include <iomanip>

#include<cctype>

#include<cstdio>

#include<readline/readline.h>

#include<readline/history.h>

#include"version_info.hpp"

#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

#include <signal.h>

#include <unistd.h>

#endif

#ifdef _WIN32

#include<windows.h>

#endif

#include<cstdlib>

#include"cmd_argz.hpp"


namespace arg {
	struct Args {
	    bool debug_output = false;
	    bool debug_syntax_highlight = false;
	    bool command_proc = false;
	    bool stdin_input = false;
	    bool debug_tokens = false;
	    std::string command_text;
	    std::string filename;
	    std::vector<std::string> arguments;
	};
}

arg::Args proc_custom_args(int &argc, char **argv) {
	arg::Args args;
	Argz<std::string> parser(argc, argv);
    parser.addOptionSingle('h', "Display help message")
        .addOptionDouble('H', "help", "Display help message")
        .addOptionSingle('v', "Display version")
        .addOptionDouble('V', "version", "Display version")     
        .addOptionSingle('i', "stdin input")
        .addOptionDouble('I', "stdin", "stdin input")
        .addOptionSingle('d', "debug output")
        .addOptionDouble('D', "debug", "debug output")  
        .addOptionSingle('s', "debug syntax highlight")
        .addOptionDouble('S', "syntax", "debug syntax highlight")
        .addOptionSingle('t', "debug tokens")
        .addOptionDouble('T', "tokens", "debug tokens")
        .addOptionSingleValue('c', "command")
        .addOptionDoubleValue('C', "command", "command")
        ;
    Argument<std::string> arg;
    int value = 0;
    try {
        while((value = parser.proc(arg)) != -1) {
            switch(value) {
                case 'h':
                case 'H':
                case 'v':
                case 'V':
                    std::cout << "MXCMD " << version_string << "\n(C) 1999-2025 LostSideDead Software\n\n";
                    parser.help(std::cout);
                    exit(EXIT_SUCCESS);
                    break;
                case 'i':
                case 'I':
                    args.stdin_input = true;;
                    break;
                case 'd':
                case 'D':
                    args.debug_output = true;
                    break;
                case 's':
                case 'S':
                    args.debug_syntax_highlight = true;
                    break;
                case 'c':
                case 'C':
                    args.command_proc = true;
                    args.command_text = arg.arg_value;
                    break;
                case 't':
                case 'T':
                    args.debug_tokens = true;
                    break;
                case '-':
                default:
                    args.arguments.push_back(arg.arg_value);
                    break;

                }
        }
    } catch (const ArgException<std::string>& e) {
        std::cerr << "mxcmd: Argument Exception" << e.text() << std::endl;
		return args;
    }
    cmd::argv.clear();
    for(size_t i = 1; i < args.arguments.size(); ++i) {
        cmd::argv.push_back(args.arguments.at(i));
    }
    return args;
}

#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

void sigint_handler(int sig) {
    if (program_running) {
        program_running = 0;
    } else {
          std::cout << "\nMXCMD: Interrupt signal received. Exiting...\n";
          exit(130);
    }
}
#endif


void dumpTokens(scan::Scanner &scan, std::ostream& out = std::cout) {
    out << "Idx | Type           | Value\n";
    out << "----+----------------+--------------------------\n";
    for (size_t i = 0; i < scan.size(); ++i) {
        std::ostringstream data;
        types::print_type_TokenType(data,scan[i].getTokenType());
        out << std::setw(3) << i << " | "
            << std::setw(14) << data.str() << " | "
            << scan[i].getTokenValue() << "\n";
    }
}

struct MultiLineState {
    bool needsMoreInput;
    int blockDepth;
    bool lineContinuation;
};

static int countWord(const std::string& input, const std::string& word) {
    int count = 0;
    size_t pos = 0;
    while ((pos = input.find(word, pos)) != std::string::npos) {
        bool validStart = (pos == 0 || !std::isalnum(static_cast<unsigned char>(input[pos - 1])));
        bool validEnd = (pos + word.length() >= input.length() || 
                        !std::isalnum(static_cast<unsigned char>(input[pos + word.length()])));
        if (validStart && validEnd) {
            count++;
        }
        pos += word.length();
    }
    return count;
}

static bool endsWithBackslash(const std::string& input) {
    if (input.empty()) return false;
    size_t lastNonSpace = input.find_last_not_of(" \t\n\r");
    if (lastNonSpace != std::string::npos && input[lastNonSpace] == '\\') {
        return true;
    }
    return false;
}

static MultiLineState checkMultiLineState(const std::string& input) {
    MultiLineState state;
    state.needsMoreInput = false;
    state.blockDepth = 0;
    state.lineContinuation = false;
    
    if (input.empty()) {
        return state;
    }
    
    if (endsWithBackslash(input)) {
        state.lineContinuation = true;
        state.needsMoreInput = true;
        return state;
    }
    
    int forCount = countWord(input, "for");
    int whileCount = countWord(input, "while");
    int ifCount = countWord(input, "if");
    int defineCount = countWord(input, "define");
    
    int doneCount = countWord(input, "done");
    int fiCount = countWord(input, "fi");
    int endCount = countWord(input, "end");
    
    int loopDepth = (forCount + whileCount) - doneCount;
    int ifDepth = ifCount - fiCount;
    int defineDepth = defineCount - endCount;
    
    state.blockDepth = loopDepth + ifDepth + defineDepth;
    
    if (state.blockDepth > 0) {
        state.needsMoreInput = true;
    }
    
    return state;
}

static bool astContainsExecCommand(const std::shared_ptr<cmd::Node> &node) {
    if (!node) {
        return false;
    }

    if (auto command = std::dynamic_pointer_cast<cmd::Command>(node)) {
        if (command->name == "exec") {
            return true;
        }
        for (const auto &arg : command->args) {
            if (arg.cmdNode && astContainsExecCommand(arg.cmdNode)) {
                return true;
            }
        }
        return false;
    }

    if (auto pipeline = std::dynamic_pointer_cast<cmd::Pipeline>(node)) {
        for (const auto &pipelineCommand : pipeline->commands) {
            if (astContainsExecCommand(pipelineCommand)) {
                return true;
            }
        }
        return false;
    }

    if (auto sequence = std::dynamic_pointer_cast<cmd::Sequence>(node)) {
        for (const auto &child : sequence->commands) {
            if (astContainsExecCommand(child)) {
                return true;
            }
        }
        return false;
    }

    if (auto redirection = std::dynamic_pointer_cast<cmd::Redirection>(node)) {
        return astContainsExecCommand(redirection->command);
    }

    if (auto logicalAnd = std::dynamic_pointer_cast<cmd::LogicalAnd>(node)) {
        return astContainsExecCommand(logicalAnd->left) || astContainsExecCommand(logicalAnd->right);
    }

    if (auto logicalOr = std::dynamic_pointer_cast<cmd::LogicalOr>(node)) {
        return astContainsExecCommand(logicalOr->left) || astContainsExecCommand(logicalOr->right);
    }

    if (auto logicalNot = std::dynamic_pointer_cast<cmd::LogicalNot>(node)) {
        return astContainsExecCommand(logicalNot->operand);
    }

    if (auto ifStatement = std::dynamic_pointer_cast<cmd::IfStatement>(node)) {
        for (const auto &branch : ifStatement->branches) {
            if (astContainsExecCommand(branch.condition) || astContainsExecCommand(branch.action)) {
                return true;
            }
        }
        return astContainsExecCommand(ifStatement->elseAction);
    }

    if (auto whileStatement = std::dynamic_pointer_cast<cmd::WhileStatement>(node)) {
        return astContainsExecCommand(whileStatement->condition) || astContainsExecCommand(whileStatement->body);
    }

    if (auto forStatement = std::dynamic_pointer_cast<cmd::ForStatement>(node)) {
        for (const auto &value : forStatement->values) {
            if (value.cmdNode && astContainsExecCommand(value.cmdNode)) {
                return true;
            }
        }
        return astContainsExecCommand(forStatement->body);
    }

    if (auto commandDefinition = std::dynamic_pointer_cast<cmd::CommandDefinition>(node)) {
        return astContainsExecCommand(commandDefinition->body);
    }

    if (auto variableAssignment = std::dynamic_pointer_cast<cmd::VariableAssignment>(node)) {
        return astContainsExecCommand(variableAssignment->value);
    }

    if (auto commandSubstitution = std::dynamic_pointer_cast<cmd::CommandSubstitution>(node)) {
        return astContainsExecCommand(commandSubstitution->command);
    }

    return false;
}

#ifndef _WIN32

struct ExecCallbackScope {
    explicit ExecCallbackScope(bool enableCallback) {
        if (enableCallback) {
            cmd::AstExecutor::getExecutor().setUpdateCallback(
                [](const std::string &chunk) {
                    std::cout << chunk;
                    std::cout.flush();
                    fflush(stdout);
                }
            );
        } else {
            cmd::AstExecutor::getExecutor().setUpdateCallback(nullptr);
        }
    }

    ~ExecCallbackScope() {
        cmd::AstExecutor::getExecutor().setUpdateCallback(nullptr);
    }
};
#endif


#ifdef _WIN32

#include <conio.h>

static char *win_readline(const char *prompt) {
    if (prompt) { printf("%s", prompt); fflush(stdout); }

    std::string line;
    int cursor = 0;
    int hist_pos = history_length;
    std::string saved_line;
    auto redraw_tail = [&]() {
        int tail = (int)line.size() - cursor;
        for (int i = cursor; i < (int)line.size(); i++) putchar(line[i]);
        putchar(' ');                                   // erase the extra char

        for (int i = 0; i < tail + 1; i++) putchar('\b'); // back to cursor

        fflush(stdout);
    };
    auto replace_line = [&](const std::string &old_line) {
        for (int i = 0; i < (int)old_line.size(); i++) putchar('\b');
        for (char c : line) putchar(c);
        int diff = (int)old_line.size() - (int)line.size();
        for (int i = 0; i < diff; i++) putchar(' ');
        for (int i = 0; i < diff; i++) putchar('\b');
        cursor = (int)line.size();
        fflush(stdout);
    };

    while (true) {
        int c = _getch();
        if (c == 0 || c == 224) {
            int ext = _getch();
            switch (ext) {
                case 72: { 
                    if (hist_pos > 0) {
                        if (hist_pos == history_length) saved_line = line;
                        hist_pos--;
                        HIST_ENTRY *e = history_get(history_base + hist_pos);
                        std::string old = line;
                        line = e ? e->line : "";
                        replace_line(old);
                    }
                    break;
                }
                case 80: { 
                    if (hist_pos < history_length) {
                        hist_pos++;
                        std::string old = line;
                        if (hist_pos == history_length) line = saved_line;
                        else { HIST_ENTRY *e = history_get(history_base + hist_pos); line = e ? e->line : ""; }
                        replace_line(old);
                    }
                    break;
                }
                case 75: 
                    if (cursor > 0) { cursor--; putchar('\b'); fflush(stdout); }
                    break;
                case 77: 
                    if (cursor < (int)line.size()) { putchar(line[cursor]); cursor++; fflush(stdout); }
                    break;
                case 71: 
                    while (cursor > 0) { putchar('\b'); cursor--; } fflush(stdout);
                    break;
                case 79: 
                    while (cursor < (int)line.size()) { putchar(line[cursor]); cursor++; } fflush(stdout);
                    break;
                case 83: 
                    if (cursor < (int)line.size()) { line.erase(cursor, 1); redraw_tail(); }
                    break;
            }
        } else if (c == '\r' || c == '\n') {
            printf("\n"); fflush(stdout);
            break;
        } else if (c == 8 || c == 127) {
            if (cursor > 0 && !line.empty()) {
                cursor--;
                line.erase(cursor, 1);
                putchar('\b');
                redraw_tail();
            }
        } else if (c == 3) {
            printf("\n"); fflush(stdout);
            return nullptr;
        } else if (c == 4) {
            if (line.empty()) { printf("\n"); fflush(stdout); return nullptr; }
        } else if (c == 21) {
            while (cursor > 0) { putchar('\b'); cursor--; }
            for (int i = 0; i < (int)line.size(); i++) putchar(' ');
            for (int i = 0; i < (int)line.size(); i++) putchar('\b');
            line.clear(); cursor = 0; fflush(stdout);
        } else if (c >= 32 && c < 256) {
            line.insert(cursor, 1, static_cast<char>(c));
            cursor++;
            for (int i = cursor - 1; i < (int)line.size(); i++) putchar(line[i]);
            for (int i = cursor; i < (int)line.size(); i++) putchar('\b');
            fflush(stdout);
        }
    }
    char *result = static_cast<char *>(malloc(line.size() + 1));
    if (result) memcpy(result, line.c_str(), line.size() + 1);
    return result;
}
#endif


void execute_command(const std::string &text) {
    fflush(stdout);
    try {
        cmd::AstExecutor &executor = cmd::AstExecutor::getExecutor();
        scan::TString string_buffer(text);
        scan::Scanner scanner(string_buffer);
        cmd::Parser parser(scanner);
        auto ast = parser.parse();
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

        program_running = 1;
#endif

#ifndef _WIN32

    ExecCallbackScope callbackScope(astContainsExecCommand(ast));
#endif

        executor.execute(std::cin, std::cout, ast);
        fflush(stdout);
        exit(0);
    } catch (const scan::ScanExcept &e) {
        std::cerr << "Scan error: " << e.why() << std::endl;
        exit(EXIT_FAILURE);
    } catch (const std::exception &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    } catch(const cmd::AstFailure &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    } catch (const state::StateException &e) {
        std::cerr << "State error: " << e.what() << std::endl;;
        exit(EXIT_FAILURE);
    } catch(const cmd::Exit_Exception  &e) {
        std::cout << "\nExit: " << e.getCode() << std::endl;
        exit(e.getCode());
    }
    catch (...) {
        std::cerr << "Unknown error occurred." << std::endl;
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char **argv) {
#ifdef WINDOWS_MODE

    cmd::AstExecutor::getExecutor().windows_mode = true;
#endif


    std::setvbuf(stdout, nullptr, _IONBF, 0);
    std::setvbuf(stderr, nullptr, _IONBF, 0);
    std::cout << std::unitbuf;
    std::cerr << std::unitbuf;

#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

    struct sigaction sa;
    sa.sa_handler = sigint_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, nullptr);
#endif

    arg::Args args = proc_custom_args(argc, argv);
    if(args.command_proc) {
        if(args.command_text.empty()) {
            std::cerr << "mx: No command provided.\n";
            exit(EXIT_FAILURE);
        }
        execute_command(args.command_text);
        exit(EXIT_SUCCESS);
    }
    std::cout << "MXCMD " << version_string << "\n(C) 1999-2025 LostSideDead Software\n\n";
    cmd::app_name = argv[0];

#ifdef _WIN32

cmd::AstExecutor::getExecutor().getRegistry().registerTypedCommand("exec", 
    [](const std::vector<cmd::Argument>& args, std::istream& input, std::ostream &output) {
        std::ostringstream all_args;
        for(auto &arg : args) {
            try {
                all_args << getVar(arg) << " ";
            } catch(const std::runtime_error &) {
                all_args << arg.value << " ";
            }
        }
        std::string command_str = all_args.str();
        
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.bInheritHandle = TRUE;
        sa.lpSecurityDescriptor = NULL;
        
        HANDLE hStdOutRead, hStdOutWrite;
        if (!CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 0)) {
            output << "exec: failed to create output pipe" << std::endl;
            return 1;
        }
        SetHandleInformation(hStdOutRead, HANDLE_FLAG_INHERIT, 0); 
        
        HANDLE hStdInRead, hStdInWrite;
        if (!CreatePipe(&hStdInRead, &hStdInWrite, &sa, 0)) {
            CloseHandle(hStdOutRead);
            CloseHandle(hStdOutWrite);
            output << "exec: failed to create input pipe" << std::endl;
            return 1;
        }
        SetHandleInformation(hStdInWrite, HANDLE_FLAG_INHERIT, 0); 
        
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.hStdInput = hStdInRead;
        si.hStdOutput = hStdOutWrite;
        si.hStdError = hStdOutWrite;
        si.dwFlags |= STARTF_USESTDHANDLES;
        
        PROCESS_INFORMATION pi;
        ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
        
        std::vector<std::string> envVars;
        
        
        LPCH env = GetEnvironmentStrings();
        if (env) {
            LPCH current = env;
            while (*current) {
                std::string envVar(current);
                
        
                if (envVar.substr(0, 18) != "PYTHONUNBUFFERED=" &&
                    envVar.substr(0, 5) != "TERM=" &&
                    envVar.substr(0, 8) != "COLUMNS=" &&
                    envVar.substr(0, 6) != "LINES=" &&
                    envVar.substr(0, 10) != "_STDBUF_O=" &&
                    envVar.substr(0, 10) != "_STDBUF_E=") {
                    envVars.push_back(envVar);
                }
                current += envVar.length() + 1;
            }
            FreeEnvironmentStrings(env);
        }
        
        
        envVars.push_back("PYTHONUNBUFFERED=1");
        envVars.push_back("TERM=dumb");           // Force dumb terminal

        envVars.push_back("COLUMNS=80");          // Set terminal width

        envVars.push_back("LINES=24");            // Set terminal height

        envVars.push_back("_STDBUF_O=0");         // Force unbuffered stdout

        envVars.push_back("_STDBUF_E=0");         // Force unbuffered stderr

        envVars.push_back("MSYS=enable_pcon");    // Enable pseudo console in MSYS2

        envVars.push_back("CYGWIN=disable_pcon"); // Disable pseudo console buffering in Cygwin

        
        
        std::string envBlock;
        for (const auto& var : envVars) {
            envBlock += var + '\0';
        }
        envBlock += '\0';
        
        
        std::string cmdLine;
        std::string bashPath;
        char *opt = getenv("MSYS2_BASH_PATH");
        
        if(cmd::cmd_type.find("wsl.exe") != std::string::npos) {
            cmdLine = "wsl.exe -e bash -c \"" + command_str + "\"";
        } else {
            if (opt != nullptr && std::filesystem::exists(opt)) {
                bashPath = opt;
            } else if (std::filesystem::exists("C:\\msys64\\usr\\bin\\bash.exe")) {
                bashPath = "C:\\msys64\\usr\\bin\\bash.exe";
            } else if (std::filesystem::exists("C:\\msys64\\mingw64\\bin\\bash.exe")) {
                bashPath = "C:\\msys64\\mingw64\\bin\\bash.exe";
            } else if (std::filesystem::exists("C:\\Program Files\\Git\\bin\\bash.exe")) {
                bashPath = "C:\\Program Files\\Git\\bin\\bash.exe";
            }
            
            if (!bashPath.empty() && std::filesystem::exists(bashPath)) {
                if (bashPath.find("msys64") != std::string::npos) {
                    cmdLine = "\"" + bashPath + "\" -c \"stdbuf -o0 -e0 " + command_str + "\"";
                } else {
                    cmdLine = "\"" + bashPath + "\" -c \"" + command_str + "\"";
                }
            } else {
                std::string shell = cmd::cmd_type;
                if (shell.empty() || shell.find("wsl.exe") != std::string::npos) {
                    shell = "cmd.exe /c";
                }
                cmdLine = shell + " " + command_str;
            }
        }
        
        if (!CreateProcess(NULL, const_cast<LPSTR>(cmdLine.c_str()), NULL, NULL, TRUE, 
                        CREATE_NO_WINDOW, 
                        const_cast<LPSTR>(envBlock.c_str()), 
                        NULL, &si, &pi)) {
            CloseHandle(hStdOutRead);
            CloseHandle(hStdOutWrite);
            CloseHandle(hStdInRead);
            CloseHandle(hStdInWrite);
            output << "exec: failed to create process" << std::endl;
            return 1;
        }
        
        CloseHandle(hStdOutWrite);
        CloseHandle(hStdInRead);
        CloseHandle(hStdInWrite);
        
        
        DWORD bytesRead;
        char buffer[64]; 
        DWORD bytesAvailable;
        
        while (true) {
            DWORD exitCode;
            if (GetExitCodeProcess(pi.hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
                while (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable > 0) {
                    DWORD toRead = std::min(bytesAvailable, static_cast<DWORD>(sizeof(buffer) - 1));
                    if (ReadFile(hStdOutRead, buffer, toRead, &bytesRead, NULL) && bytesRead > 0) {
                        buffer[bytesRead] = '\0';
                        printf("%s", buffer);
                        fflush(stdout);
                    }
                }
                break;
            }
            
            if (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable > 0) {
                DWORD toRead = std::min(bytesAvailable, static_cast<DWORD>(sizeof(buffer) - 1));
                if (ReadFile(hStdOutRead, buffer, toRead, &bytesRead, NULL) && bytesRead > 0) {
                    buffer[bytesRead] = '\0';
                    printf("%s", buffer);
                    fflush(stdout);
                }
            } else {
                Sleep(1); 
            }
        }
        
        DWORD finalExitCode = 0;
        GetExitCodeProcess(pi.hProcess, &finalExitCode);
        CloseHandle(hStdOutRead);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        fflush(stdout);
        
        return static_cast<int>(finalExitCode);
    });
#endif

    if(argc == 1) {
        bool active = true;
        bool debug_cmd = false;
        try {
            cmd::AstExecutor &executor = cmd::AstExecutor::getExecutor();
#ifdef _WIN32

            rl_variable_bind("bell-style", "none");
#endif

            using_history();
            read_history(".cmd_history");
#ifdef _WIN32

            auto prompt_readline = [](const char *p) -> char* { return win_readline(p); };
#else

            auto prompt_readline = [](const char *p) -> char* { return readline(p); };
#endif

            std::ostringstream input_stream;
            std::string multiLineBuffer;
            bool isMultiLineInput = false;
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

            signal(SIGINT, sigint_handler);
#endif

            while(active) {
                try {
                    std::string prompt = executor.getPath() + " $> ";
                    const char *activePrompt = isMultiLineInput ? ".. " : prompt.c_str();
                    char* line = prompt_readline(activePrompt);
                    if (line == nullptr) {
                        std::cout << std::endl;  
                        write_history(".cmd_history");
                        break;
                    }

                    if (line[0] != '\0') {
                        std::string command_data;
                        std::string inputLine = line;
                        free(line);

                        bool lineContinuation = false;
                        if (!inputLine.empty()) {
                            size_t lastNonSpace = inputLine.find_last_not_of(" \t");
                            if (lastNonSpace != std::string::npos && inputLine[lastNonSpace] == '\\') {
                                lineContinuation = true;
                                inputLine = inputLine.substr(0, lastNonSpace);
                            }
                        }

                        if (isMultiLineInput) {
                            multiLineBuffer += "\n" + inputLine;
                            MultiLineState state = checkMultiLineState(multiLineBuffer);
                            if (lineContinuation || state.needsMoreInput) {
                                continue;
                            }
                            command_data = multiLineBuffer;
                            isMultiLineInput = false;
                            multiLineBuffer.clear();
                        } else {
                            MultiLineState state = checkMultiLineState(inputLine);
                            if (lineContinuation || state.needsMoreInput) {
                                isMultiLineInput = true;
                                multiLineBuffer = inputLine;
                                continue;
                            }
                            command_data = inputLine;
                        }

                        add_history(command_data.c_str());

                        if(!command_data.empty() && command_data[0] == '{') {
                            std::string iline;
                            input_stream.str("");
                            while(true) {
                                char *in_line = prompt_readline("... ");
                                iline = in_line;
                                if(in_line != nullptr) {
                                    free(in_line);
                                    auto pos = iline.find("}");
                                    if(pos != std::string::npos) {
                                        std::string left;
                                        left = iline.substr(0, pos);
                                        input_stream << left << "\n";
                                        break;
                                    } else {
                                        add_history(iline.c_str());
                                        input_stream << iline << "\n";
                                    }
                                }
                            }
                            scan::TString string_buffer(input_stream.str());
                            scan::Scanner scanner(string_buffer);
                            cmd::Parser parser(scanner);
                            auto ast = parser.parse();
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

                            program_running = 1;
#endif

#ifndef _WIN32

                            ExecCallbackScope callbackScope(astContainsExecCommand(ast));
#endif

                            executor.execute(std::cin, std::cout, ast);
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

                            program_running = 0;
#endif

                            if(debug_cmd) {
                                ast->print(std::cout);
                            }
                            continue;
                        }

                        if(command_data == "wsl_on") {

#ifdef _WIN32

                            if(!std::filesystem::exists("C:\\Windows\\System32\\wsl.exe")) {
                                std::cerr << "WSL executable not found. Please ensure WSL is installed." << std::endl;
                                continue;
                            } else {
                                std::cout << "WSL mode enabled. Use 'wsl_off' to disable." << std::endl;
                                cmd::cmd_type = "wsl.exe";
                                continue;
                            }
#else

                            std::cerr << "WSL mode is not available on this platform." << std::endl;
                            continue;
#endif


                        } else if(command_data == "wsl_off") {
#ifdef _WIN32

                            cmd::cmd_type = "cmd.exe /c ";
                            std::cout << "WSL mode disabled. Using default command shell." << std::endl;
                            continue;
#else

                            std::cerr << "WSL mode is not available on this platform." << std::endl;    
                            continue;
#endif


                        } else if(command_data == "clear" || command_data == "cls") {
                            std::cout << "\033[2J\033[1;1H"; 
                            continue;
                        } else if(command_data == "exit" || command_data == "quit" || command_data == "q") {
                            active = false;
                            continue;
                        } else if(command_data == "@debug_on") {
                            debug_cmd = true;
                            std::cout << "Debugging commands on." << std::endl;
                            continue;
                        } else if(command_data == "@debug_off") {
                            debug_cmd = false;
                            std::cout << "Debugging commands off." << std::endl;
                            continue;
                        }
                    
                        scan::TString string_buffer(command_data);
                        scan::Scanner scanner(string_buffer);
                        cmd::Parser parser(scanner);
                        auto ast = parser.parse();
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

                        program_running = 1;
#endif

#ifndef _WIN32

                        ExecCallbackScope callbackScope(astContainsExecCommand(ast));
#endif

                        executor.execute(std::cin, std::cout, ast);

#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

                        program_running = 1;
#endif

                        if(debug_cmd) {
                            ast->print(std::cout);
                        }
                    }
                } catch (const scan::ScanExcept &e) {
                    std::cerr << "Scan error: " << e.why() << std::endl;
                } catch (const std::exception &e) {
                    std::cerr << "Exception: " << e.what() << std::endl;
                } catch(const cmd::AstFailure &e) {
                    std::cerr << "Exception: " << e.what() << std::endl;
                } catch (const state::StateException &e) {
                    std::cerr << "State error: " << e.what() << std::endl;;
                } catch(const cmd::Exit_Exception  &e) {
                    std::cout << "\nExit: " << e.getCode() << std::endl;
                }
                 catch (...) {
                    std::cerr << "Unknown error occurred." << std::endl;
                }
            }
            write_history(".cmd_history");
        } catch (const scan::ScanExcept &e) {
            std::cerr << "Scan error: " << e.why() << std::endl;
        } catch (const std::exception &e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        } catch (const cmd::AstFailure &e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        } catch (...) {
            std::cerr << "Unknown error occurred." << std::endl;
        }

    } else if(argc >= 2  && args.stdin_input == false) {

        cmd::AstExecutor &executor = cmd::AstExecutor::getExecutor();
        bool debug_cmd = false;
        bool debug_html = false;
        bool debug_tokens = false;
            std::ostringstream stream;
            std::fstream file;
            if(args.debug_output) {
                debug_cmd = true;
            }
            if(args.debug_syntax_highlight) {
                debug_html = true;
            }
            if(args.debug_tokens) {
                debug_tokens = true;
            }
            if(args.arguments.size() == 0) {
                std::cerr << "mx: No script file name provided.\n";
                return EXIT_FAILURE;
            }
            std::string app_name = args.arguments[0];
            file.open(app_name, std::ios::in);
            if(!file.is_open()) {
                std::cerr << "Error loading file: " << app_name << "\n";;
                return EXIT_FAILURE;
            }
            stream << file.rdbuf();
            std::string fileContent = stream.str();
            
            if(!fileContent.empty()) {
                fileContent.erase(
                    std::remove(fileContent.begin(), fileContent.end(), '\r'),
                        fileContent.end()
                );
            }

            if (fileContent.size() >= 2 && fileContent[0] == '#' && fileContent[1] == '!') {
                size_t newlinePos = fileContent.find('\n');
                if (newlinePos != std::string::npos) {
                    fileContent = fileContent.substr(newlinePos + 1);
                }
            }

            std::atomic<bool> exec_interrupt = false;
            executor.setInterrupt(&exec_interrupt);
            try {
                scan::TString string_buffer(fileContent); 
                scan::Scanner scanner(string_buffer);
                cmd::Parser parser(scanner);
                auto ast = parser.parse();

                if(debug_tokens) {
                    std::ofstream out_file("debug.tokens.txt");
                    std::cout << "Debug Tokens Information written to: debug.tokens.txt\n\n";
                    dumpTokens(scanner, out_file);
                }

    #if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
                program_running = 1;
    #endif
                executor.setPath(std::filesystem::path(app_name).parent_path().string());
    #ifndef _WIN32
                ExecCallbackScope callbackScope(astContainsExecCommand(ast));
    #endif
                executor.execute(std::cin, std::cout, ast);

                std::cout.flush();
                std::cout << std::flush;
                if(debug_cmd)  {
                    std::ofstream html_file("debug.html");
                    html::gen_html(html_file, ast);
                    std::cout << "Debug Information written to: debug.html\n\n";
                }
                if(debug_html) {
                    std::ofstream html_file("debug.syntax.html");
                    html::gen_html_color(html_file, ast);
                    std::cout << "Debug Syntax Information written to: debug.syntax.html\n\n";
                }
                
            } catch(const scan::ScanExcept &e) {
                std::cerr << "Scan Error: " << e.why() << std::endl;
                return EXIT_FAILURE;
            } catch(const std::exception &e) {
                std::cerr << "Exception: " << e.what() << std::endl;
                return EXIT_FAILURE;
            } catch(const cmd::AstFailure &e) {
                std::cerr << "Failure: " << e.what() << std::endl;
                return EXIT_FAILURE;   
            } catch(const state::StateException &e) {
                std::cerr << "State Exception: " << e.what() << std::endl;
            } catch(const cmd::Exit_Exception &e) {
                std::cout << "\nExit: " << e.getCode() << std::endl;
                return e.getCode();
            }
            catch(...) {
                std::cerr << "Fatal Error has occoured.\n";
                throw;
                return EXIT_FAILURE;
            }
        } else if(argc == 2 && args.stdin_input) {
            try {
            cmd::AstExecutor &executor = cmd::AstExecutor::getExecutor();
            std::ostringstream stream;
            stream << std::cin.rdbuf();
            scan::TString string_buffer(stream.str());
            scan::Scanner scanner(string_buffer);
            cmd::Parser parser(scanner);
            auto ast = parser.parse();
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

            program_running = 1;
#endif

#ifndef _WIN32

            ExecCallbackScope callbackScope(astContainsExecCommand(ast));
#endif

            executor.execute(std::cin, std::cout, ast);
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)

            program_running = 0;
#endif    

        } catch(const scan::ScanExcept &e) {
            std::cerr << "Scan Error: " << e.why() << std::endl;
            return EXIT_FAILURE;
        } catch(const std::exception &e) {
            std::cerr << "Exception: " << e.what() << std::endl;
            return EXIT_FAILURE;
        } catch(cmd::AstFailure &e) {
            std::cerr << "Failure: " << e.what() << std::endl;
            return EXIT_FAILURE;
        } catch(state::StateException &e) {
            std::cerr << "State Exception: " << e.what() << std::endl;
            return EXIT_FAILURE;
        } catch(cmd::Exit_Exception &e) {
            std::cout << "\nExit: " << e.getCode() << std::endl;
            return e.getCode();
        }
        catch(...) {
            std::cerr << "Unknown Error has Occoured..\n";
            return EXIT_FAILURE;
        }
    }
    return EXIT_SUCCESS;
}