<commit_before>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "buffer_utils.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__) || defined(__CYGWIN__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, nullptr);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr) + "/../share/kak";
}

void register_env_vars()
{
    static const struct {
        const char* name;
        String (*func)(StringView, const Context&);
    } env_vars[] = { {
            "bufname",
            [](StringView name, const Context& context)
            { return context.buffer().display_name(); }
        }, {
            "buffile",
            [](StringView name, const Context& context) -> String
            { return context.buffer().name(); }
        }, {
            "timestamp",
            [](StringView name, const Context& context)
            { return to_string(context.buffer().timestamp()); }
        }, {
            "selection",
            [](StringView name, const Context& context)
            { const Selection& sel = context.selections().main();
              return content(context.buffer(), sel); }
        }, {
            "selections",
            [](StringView name, const Context& context)
            { auto sels = context.selections_content();
              String res;
              for (size_t i = 0; i < sels.size(); ++i)
              {
                  res += escape(sels[i], ':', '\\');
                  if (i != sels.size() - 1)
                      res += ':';
              }
              return res; }
        }, {
            "runtime",
            [](StringView name, const Context& context)
            { return runtime_directory(); }
        }, {
            "opt_.+",
            [](StringView name, const Context& context)
            { return context.options()[name.substr(4_byte)].get_as_string(); }
        }, {
            "reg_.+",
            [](StringView name, const Context& context) -> String
            { return RegisterManager::instance()[name[4]].values(context)[0]; }
        }, {
            "client_env_.+",
            [](StringView name, const Context& context) -> String
            { return context.client().get_env_var(name.substr(11_byte)); }
        }, {
            "session",
            [](StringView name, const Context& context) -> String
            { return Server::instance().session(); }
        }, {
            "client",
            [](StringView name, const Context& context) -> String
            { return context.name(); }
        }, {
            "cursor_line",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().line + 1); }
        }, {
            "cursor_column",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().column + 1); }
        }, {
            "cursor_char_column",
            [](StringView name, const Context& context)
            { auto coord = context.selections().main().cursor();
              return to_string(context.buffer()[coord.line].char_count_to(coord.column) + 1); }
        }, {
            "selection_desc",
            [](StringView name, const Context& context)
            { auto& sel = context.selections().main();
                auto beg = sel.min();
                return to_string(beg.line + 1) + ':' + to_string(beg.column + 1) + '+' +
                       to_string((int)context.buffer().distance(beg, sel.max())+1); }
        }, {
            "window_width",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().column); }
        }, {
            "window_height",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().line); }
    } };

    ShellManager& shell_manager = ShellManager::instance();
    for (auto& env_var : env_vars)
        shell_manager.register_env_var(env_var.name, env_var.func);
}

void register_registers()
{
    using StringList = std::vector<String>;
    static const struct {
        char name;
        StringList (*func)(const Context&);
    } dyn_regs[] = {
        { '%', [](const Context& context) { return StringList{{context.buffer().display_name()}}; } },
        { '.', [](const Context& context) { return context.selections_content(); } },
        { '#', [](const Context& context) { return StringList{{to_string((int)context.selections().size())}}; } },
    };

    RegisterManager& register_manager = RegisterManager::instance();
    for (auto& dyn_reg : dyn_regs)
        register_manager.register_dynamic_register(dyn_reg.name, dyn_reg.func);

    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    if (not isatty(1))
        throw runtime_error("stdout is not a tty");

    if (not isatty(0))
    {
        // move stdin to another fd, and restore tty as stdin
        int fd = dup(0);
        int tty = open("/dev/tty", O_RDONLY);
        dup2(tty, 0);
        close(tty);
        create_fifo_buffer("*stdin*", fd);
    }

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    if (Server::has_instance())
        Server::instance().close_session();
    abort();
}

int run_client(const String& session, const String& init_command)
{
    try
    {
        EventManager event_manager;
        auto client = connect_to(session,
                                 std::unique_ptr<UserInterface>{new NCursesUI{}},
                                 get_env_vars(),
                                 init_command);
        while (true)
            event_manager.handle_next_events();
    }
    catch (peer_disconnected&)
    {
        fputs("disconnected from server\n", stderr);
        return -1;
    }
    catch (connection_failed& e)
    {
        fputs(e.what(), stderr);
        return -1;
    }
    return 0;
}

int kakoune(const ParametersParser& parser)
{
    if (parser.has_option("p"))
    {
        for (auto opt : { "c", "n", "s", "d", "e" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -p\n", opt);
                return -1;
            }
        }
        char buf[512];
        String command;
        while (ssize_t count = read(0, buf, 512))
        {
            if (count < 0)
            {
                fprintf(stderr, "error while reading stdin\n");
                return -1;
            }
            command += String{buf, buf + count};
        }
        try
        {
            send_command(parser.option_value("p"), command);
        }
        catch (connection_failed& e)
        {
            fputs(e.what(), stderr);
            return -1;
        }
        return 0;
    }

    String init_command;
    if (parser.has_option("e"))
        init_command = parser.option_value("e");

    if (parser.has_option("c"))
    {
        for (auto opt : { "n", "s", "d" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -c\n", opt);
                return -1;
            }
        }
        return run_client(parser.option_value("c"), init_command);
    }

    const bool daemon = parser.has_option("d");
    static bool terminate = false;
    if (daemon)
    {
        if (not parser.has_option("s"))
        {
            fputs("-d needs a session name to be specified with -s\n", stderr);
            return -1;
        }
        if (pid_t child = fork())
        {
            printf("Kakoune forked to background, for session '%s'\n"
                   "send SIGTERM to process %d for closing the session\n",
                   parser.option_value("s").c_str(), child);
            exit(0);
        }
        signal(SIGTERM, [](int) { terminate = true; });
    }

    EventManager        event_manager;
    GlobalOptions       global_options;
    GlobalHooks         global_hooks;
    GlobalKeymaps       global_keymaps;
    ShellManager        shell_manager;
    CommandManager      command_manager;
    BufferManager       buffer_manager;
    RegisterManager     register_manager;
    HighlighterRegistry highlighter_registry;
    DefinedHighlighters defined_highlighters;
    ColorRegistry       color_registry;
    ClientManager       client_manager;

    run_unit_tests();

    register_env_vars();
    register_registers();
    register_commands();
    register_highlighters();

    write_debug("*** This is the debug buffer, where debug info will be written ***");
    write_debug("pid: " + to_string(getpid()));

    Server server(parser.has_option("s") ? parser.option_value("s") : to_string(getpid()));
    write_debug("session: " + server.session());

    if (not parser.has_option("n")) try
    {
        Context initialisation_context;
        command_manager.execute("source " + runtime_directory() + "/kakrc",
                                initialisation_context);
    }
    catch (Kakoune::runtime_error& error)
    {
        write_debug("error while parsing kakrc:\n    "_str + error.what());
    }
    catch (Kakoune::client_removed&)
    {
        write_debug("error while parsing kakrc: asked to quit");
    }

    {
        Context empty_context;
        global_hooks.run_hook("KakBegin", "", empty_context);
    }

    if (parser.positional_count() != 0) try
    {
        // create buffers in reverse order so that the first given buffer
        // is the most recently created one.
        for (int i = parser.positional_count() - 1; i >= 0; --i)
        {
            const String& file = parser[i];
            if (not create_buffer_from_file(file))
                new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
        }
    }
    catch (Kakoune::runtime_error& error)
    {
         write_debug("error while opening command line files: "_str + error.what());
    }
    else
        new Buffer("*scratch*", Buffer::Flags::None);

    if (not daemon)
        create_local_client(init_command);

    while (not terminate and (not client_manager.empty() or daemon))
        event_manager.handle_next_events();

    {
        Context empty_context;
        global_hooks.run_hook("KakEnd", "", empty_context);
    }
    return 0;
}

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "");

    signal(SIGSEGV, signal_handler);
    signal(SIGFPE,  signal_handler);
    signal(SIGQUIT, signal_handler);
    signal(SIGTERM, signal_handler);

    std::vector<String> params;
    for (size_t i = 1; i < argc; ++i)
        params.push_back(argv[i]);

    const ParameterDesc param_desc{
        SwitchMap{ { "c", { true, "connect to given session" } },
                   { "e", { true, "execute argument on initialisation" } },
                   { "n", { false, "do not source kakrc files on startup" } },
                   { "s", { true, "set session name" } },
                   { "d", { false, "run as a headless session (requires -s)" } },
                   { "p", { true, "just send stdin as commands to the given session" } } }
    };
    try
    {
        kakoune(ParametersParser(params, param_desc));
    }
    catch (Kakoune::parameter_error& error)
    {
        printf("Error: %s\n"
               "Valid switches:\n"
               "%s",
               error.what(), generate_switches_doc(param_desc.switches).c_str());
       return -1;
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<commit_msg>Change # register to contain selection number<commit_after>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "buffer_utils.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__) || defined(__CYGWIN__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, nullptr);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr) + "/../share/kak";
}

void register_env_vars()
{
    static const struct {
        const char* name;
        String (*func)(StringView, const Context&);
    } env_vars[] = { {
            "bufname",
            [](StringView name, const Context& context)
            { return context.buffer().display_name(); }
        }, {
            "buffile",
            [](StringView name, const Context& context) -> String
            { return context.buffer().name(); }
        }, {
            "timestamp",
            [](StringView name, const Context& context)
            { return to_string(context.buffer().timestamp()); }
        }, {
            "selection",
            [](StringView name, const Context& context)
            { const Selection& sel = context.selections().main();
              return content(context.buffer(), sel); }
        }, {
            "selections",
            [](StringView name, const Context& context)
            { auto sels = context.selections_content();
              String res;
              for (size_t i = 0; i < sels.size(); ++i)
              {
                  res += escape(sels[i], ':', '\\');
                  if (i != sels.size() - 1)
                      res += ':';
              }
              return res; }
        }, {
            "runtime",
            [](StringView name, const Context& context)
            { return runtime_directory(); }
        }, {
            "opt_.+",
            [](StringView name, const Context& context)
            { return context.options()[name.substr(4_byte)].get_as_string(); }
        }, {
            "reg_.+",
            [](StringView name, const Context& context) -> String
            { return RegisterManager::instance()[name[4]].values(context)[0]; }
        }, {
            "client_env_.+",
            [](StringView name, const Context& context) -> String
            { return context.client().get_env_var(name.substr(11_byte)); }
        }, {
            "session",
            [](StringView name, const Context& context) -> String
            { return Server::instance().session(); }
        }, {
            "client",
            [](StringView name, const Context& context) -> String
            { return context.name(); }
        }, {
            "cursor_line",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().line + 1); }
        }, {
            "cursor_column",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().column + 1); }
        }, {
            "cursor_char_column",
            [](StringView name, const Context& context)
            { auto coord = context.selections().main().cursor();
              return to_string(context.buffer()[coord.line].char_count_to(coord.column) + 1); }
        }, {
            "selection_desc",
            [](StringView name, const Context& context)
            { auto& sel = context.selections().main();
                auto beg = sel.min();
                return to_string(beg.line + 1) + ':' + to_string(beg.column + 1) + '+' +
                       to_string((int)context.buffer().distance(beg, sel.max())+1); }
        }, {
            "window_width",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().column); }
        }, {
            "window_height",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().line); }
    } };

    ShellManager& shell_manager = ShellManager::instance();
    for (auto& env_var : env_vars)
        shell_manager.register_env_var(env_var.name, env_var.func);
}

void register_registers()
{
    using StringList = std::vector<String>;
    static const struct {
        char name;
        StringList (*func)(const Context&);
    } dyn_regs[] = {
        { '%', [](const Context& context) { return StringList{{context.buffer().display_name()}}; } },
        { '.', [](const Context& context) { return context.selections_content(); } },
        { '#', [](const Context& context) {
            StringList res;
            for (size_t i = 1; i < context.selections().size(); ++i)
                res.push_back(to_string((int)i));
            return res;
        } }
    };

    RegisterManager& register_manager = RegisterManager::instance();
    for (auto& dyn_reg : dyn_regs)
        register_manager.register_dynamic_register(dyn_reg.name, dyn_reg.func);

    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    if (not isatty(1))
        throw runtime_error("stdout is not a tty");

    if (not isatty(0))
    {
        // move stdin to another fd, and restore tty as stdin
        int fd = dup(0);
        int tty = open("/dev/tty", O_RDONLY);
        dup2(tty, 0);
        close(tty);
        create_fifo_buffer("*stdin*", fd);
    }

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    if (Server::has_instance())
        Server::instance().close_session();
    abort();
}

int run_client(const String& session, const String& init_command)
{
    try
    {
        EventManager event_manager;
        auto client = connect_to(session,
                                 std::unique_ptr<UserInterface>{new NCursesUI{}},
                                 get_env_vars(),
                                 init_command);
        while (true)
            event_manager.handle_next_events();
    }
    catch (peer_disconnected&)
    {
        fputs("disconnected from server\n", stderr);
        return -1;
    }
    catch (connection_failed& e)
    {
        fputs(e.what(), stderr);
        return -1;
    }
    return 0;
}

int kakoune(const ParametersParser& parser)
{
    if (parser.has_option("p"))
    {
        for (auto opt : { "c", "n", "s", "d", "e" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -p\n", opt);
                return -1;
            }
        }
        char buf[512];
        String command;
        while (ssize_t count = read(0, buf, 512))
        {
            if (count < 0)
            {
                fprintf(stderr, "error while reading stdin\n");
                return -1;
            }
            command += String{buf, buf + count};
        }
        try
        {
            send_command(parser.option_value("p"), command);
        }
        catch (connection_failed& e)
        {
            fputs(e.what(), stderr);
            return -1;
        }
        return 0;
    }

    String init_command;
    if (parser.has_option("e"))
        init_command = parser.option_value("e");

    if (parser.has_option("c"))
    {
        for (auto opt : { "n", "s", "d" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -c\n", opt);
                return -1;
            }
        }
        return run_client(parser.option_value("c"), init_command);
    }

    const bool daemon = parser.has_option("d");
    static bool terminate = false;
    if (daemon)
    {
        if (not parser.has_option("s"))
        {
            fputs("-d needs a session name to be specified with -s\n", stderr);
            return -1;
        }
        if (pid_t child = fork())
        {
            printf("Kakoune forked to background, for session '%s'\n"
                   "send SIGTERM to process %d for closing the session\n",
                   parser.option_value("s").c_str(), child);
            exit(0);
        }
        signal(SIGTERM, [](int) { terminate = true; });
    }

    EventManager        event_manager;
    GlobalOptions       global_options;
    GlobalHooks         global_hooks;
    GlobalKeymaps       global_keymaps;
    ShellManager        shell_manager;
    CommandManager      command_manager;
    BufferManager       buffer_manager;
    RegisterManager     register_manager;
    HighlighterRegistry highlighter_registry;
    DefinedHighlighters defined_highlighters;
    ColorRegistry       color_registry;
    ClientManager       client_manager;

    run_unit_tests();

    register_env_vars();
    register_registers();
    register_commands();
    register_highlighters();

    write_debug("*** This is the debug buffer, where debug info will be written ***");
    write_debug("pid: " + to_string(getpid()));

    Server server(parser.has_option("s") ? parser.option_value("s") : to_string(getpid()));
    write_debug("session: " + server.session());

    if (not parser.has_option("n")) try
    {
        Context initialisation_context;
        command_manager.execute("source " + runtime_directory() + "/kakrc",
                                initialisation_context);
    }
    catch (Kakoune::runtime_error& error)
    {
        write_debug("error while parsing kakrc:\n    "_str + error.what());
    }
    catch (Kakoune::client_removed&)
    {
        write_debug("error while parsing kakrc: asked to quit");
    }

    {
        Context empty_context;
        global_hooks.run_hook("KakBegin", "", empty_context);
    }

    if (parser.positional_count() != 0) try
    {
        // create buffers in reverse order so that the first given buffer
        // is the most recently created one.
        for (int i = parser.positional_count() - 1; i >= 0; --i)
        {
            const String& file = parser[i];
            if (not create_buffer_from_file(file))
                new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
        }
    }
    catch (Kakoune::runtime_error& error)
    {
         write_debug("error while opening command line files: "_str + error.what());
    }
    else
        new Buffer("*scratch*", Buffer::Flags::None);

    if (not daemon)
        create_local_client(init_command);

    while (not terminate and (not client_manager.empty() or daemon))
        event_manager.handle_next_events();

    {
        Context empty_context;
        global_hooks.run_hook("KakEnd", "", empty_context);
    }
    return 0;
}

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "");

    signal(SIGSEGV, signal_handler);
    signal(SIGFPE,  signal_handler);
    signal(SIGQUIT, signal_handler);
    signal(SIGTERM, signal_handler);

    std::vector<String> params;
    for (size_t i = 1; i < argc; ++i)
        params.push_back(argv[i]);

    const ParameterDesc param_desc{
        SwitchMap{ { "c", { true, "connect to given session" } },
                   { "e", { true, "execute argument on initialisation" } },
                   { "n", { false, "do not source kakrc files on startup" } },
                   { "s", { true, "set session name" } },
                   { "d", { false, "run as a headless session (requires -s)" } },
                   { "p", { true, "just send stdin as commands to the given session" } } }
    };
    try
    {
        kakoune(ParametersParser(params, param_desc));
    }
    catch (Kakoune::parameter_error& error)
    {
        printf("Error: %s\n"
               "Valid switches:\n"
               "%s",
               error.what(), generate_switches_doc(param_desc.switches).c_str());
       return -1;
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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 3 of the License, or
    (at your option) any later version.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Main executable
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QtGui/QApplication>
#include "QGCCore.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "AutoTest.h"
#endif

/* SDL does ugly things to main() */
#ifdef main
#undef main
#endif

// Install a message handler so you do not need
// the MSFT debug tools installed to se
// qDebug(), qWarning(), qCritical and qAbort
#ifdef Q_OS_WIN
void msgHandler( QtMsgType type, const char* msg )
{
    const char symbols[] = { 'I', 'E', '!', 'X' };
    QString output = QString("[%1] %2").arg( symbols[type] ).arg( msg );
    std::cerr << output.toStdString() << std::endl;
    if( type == QtFatalMsg ) abort();
}

#endif

/**
 * @brief Starts the application
 *
 * @param argc Number of commandline arguments
 * @param argv Commandline arguments
 * @return exit code, 0 for normal exit and !=0 for error cases
 */

int main(int argc, char *argv[])
{
// install the message handler
#ifdef Q_OS_WIN
    qInstallMsgHandler( msgHandler );
#endif

    // The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
    qRegisterMetaType<QSerialPort::SerialPortError>();
    qRegisterMetaType<QAbstractSocket::SocketError>();

#ifdef QT_DEBUG
    if (argc > 1 && QString(argv[1]).compare("--unittest", Qt::CaseInsensitive) == 0) {
        // Strip off extra command line args so QTest doesn't complain
        for (int i=1; i<argc-1; i++)
        {
            argv[i] = argv[i+1];
        }

        // Run the test
        int failures = AutoTest::run(argc-1, argv);
        if (failures == 0)
        {
            qDebug() << "ALL TESTS PASSED";
        }
        else
        {
            qDebug() << failures << " TESTS FAILED!";
        }
        return failures;
    }
#endif

    QGCCore* core = NULL;
    int val;
    bool firstStart = true;

    do {
        if (core) {
            delete core;
            firstStart = false;
        }
        core = new QGCCore(firstStart, argc, argv);
        val = core->exec();
    } while (core->getRestartRequested());

    return val;
}
<commit_msg>Added --no-windows-assert-ui command line option<commit_after>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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 3 of the License, or
    (at your option) any later version.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Main executable
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QtGui/QApplication>
#include "QGCCore.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "AutoTest.h"
#include "CmdLineOptParser.h"
#ifdef Q_OS_WIN
#include <crtdbg.h>
#endif
#endif

/* SDL does ugly things to main() */
#ifdef main
#undef main
#endif

#ifdef Q_OS_WIN

/// @brief Message handler which is installed using qInstallMsgHandler so you do not need
/// the MSFT debug tools installed to see qDebug(), qWarning(), qCritical and qAbort
void msgHandler( QtMsgType type, const char* msg )
{
    const char symbols[] = { 'I', 'E', '!', 'X' };
    QString output = QString("[%1] %2").arg( symbols[type] ).arg( msg );
    std::cerr << output.toStdString() << std::endl;
    if( type == QtFatalMsg ) abort();
}

/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
    Q_UNUSED(reportType);

    std::cerr << message << std::endl;  // Output message to stderr
    *returnValue = 0;                   // Don't break into debugger
    return true;                        // We handled this fully ourselves
}

#endif

/**
 * @brief Starts the application
 *
 * @param argc Number of commandline arguments
 * @param argv Commandline arguments
 * @return exit code, 0 for normal exit and !=0 for error cases
 */

int main(int argc, char *argv[])
{
// install the message handler
#ifdef Q_OS_WIN
    qInstallMsgHandler( msgHandler );
#endif

    // The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
    qRegisterMetaType<QSerialPort::SerialPortError>();
    qRegisterMetaType<QAbstractSocket::SocketError>();

#ifdef QT_DEBUG
    // We parse a small set of command line options here prior to QGCCore in order to handle the ones
    // which need to be handled before a QApplication object is started.

    bool runUnitTests = false;          // Run unit test
    bool quietWindowsAsserts = false;   // Don't let asserts pop dialog boxes

    CmdLineOpt_t rgCmdLineOptions[] = {
        { "--unittest",             &runUnitTests },
        { "--no-windows-assert-ui", &quietWindowsAsserts },
        // Add additional command line option flags here
    };

    ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), true);

    if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
        _CrtSetReportHook(WindowsCrtReportHook);
#endif
    }

    if (runUnitTests) {
        // Run the test
        int failures = AutoTest::run(argc-1, argv);
        if (failures == 0)
        {
            qDebug() << "ALL TESTS PASSED";
        }
        else
        {
            qDebug() << failures << " TESTS FAILED!";
        }
        return failures;
    }
#endif

    QGCCore* core = NULL;
    int val;
    bool firstStart = true;

    do {
        if (core) {
            delete core;
            firstStart = false;
        }
        core = new QGCCore(firstStart, argc, argv);
        val = core->exec();
    } while (core->getRestartRequested());

    return val;
}
<|endoftext|>


<commit_before>
#include <ugdk/system/engine.h>
#include <ugdk/action/3D/camera.h>
#include <ugdk/action/3D/scene3d.h>
#include <ugdk/action/3D/component/body.h>

#include <shipsbattle/objects/ship.h>
#include <shipsbattle/components/spacedust.h>
#include <shipsbattle/components/playercontroller.h>
#include <shipsbattle/components/subsystems/typedefs.h>
#include <shipsbattle/components/hull.h>
#include <shipsbattle/components/subsystems/subhull.h>

#include <shipsbattle/components/timedlife.h>

#include <btBulletDynamicsCommon.h>
#include <OgreSceneManager.h>
#include <OgreOverlaySystem.h>

#include <OgreMeshManager.h>
#include <OgreHardwareBufferManager.h>
#include <OgreSubMesh.h>

#include <memory>
#include <iostream>
#include <sstream>

#define AREA_RANGE 200.0

using std::weak_ptr;
using std::shared_ptr;
using std::unique_ptr;
using std::make_shared;
using std::stringstream;
using std::cout;
using std::endl;
using shipsbattle::objects::Ship;
using shipsbattle::components::SpaceDust;
using shipsbattle::components::PlayerController;
using namespace shipsbattle::components::subsystems::DecaymentFunctions;

ugdk::action::mode3d::Scene3D *ourscene;

void CreateHUD(Ship& pla, Ship& enemy) {
    Ogre::OverlayManager* overlay_mgr = Ogre::OverlayManager::getSingletonPtr();
    std::string over_name = "SBHUD";
    Ogre::Overlay* hud = overlay_mgr->create(over_name);
    hud->setZOrder(600);

    Ogre::TextAreaOverlayElement* plaHullStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/PlaHullStats"));
    plaHullStats->setMetricsMode(Ogre::GMM_PIXELS);
    plaHullStats->setPosition(10, 0);
    plaHullStats->setDimensions(350, 30);
    plaHullStats->setFontName("testeFont");
    plaHullStats->setCharHeight(16);
    plaHullStats->setColour(Ogre::ColourValue::Black);
    plaHullStats->setCaption("PLAYER HULL STATS");
    Ogre::TextAreaOverlayElement* plaArmorStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/PlaArmorStats"));
    plaArmorStats->setMetricsMode(Ogre::GMM_PIXELS);
    plaArmorStats->setPosition(10, 30);
    plaArmorStats->setDimensions(350, 30);
    plaArmorStats->setFontName("testeFont");
    plaArmorStats->setCharHeight(16);
    plaArmorStats->setColour(Ogre::ColourValue::Blue);
    plaArmorStats->setCaption("PLAYER ARMOR STATS");

    Ogre::TextAreaOverlayElement* enemyHullStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/EnemyHullStats"));
    enemyHullStats->setMetricsMode(Ogre::GMM_PIXELS);
    enemyHullStats->setPosition(10, 60);
    enemyHullStats->setDimensions(350, 30);
    enemyHullStats->setFontName("testeFont");
    enemyHullStats->setCharHeight(16);
    enemyHullStats->setColour(Ogre::ColourValue::Black);
    enemyHullStats->setCaption("ENEMY HULL STATS");
    Ogre::TextAreaOverlayElement* enemyArmorStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/EnemyArmorStats"));
    enemyArmorStats->setMetricsMode(Ogre::GMM_PIXELS);
    enemyArmorStats->setPosition(10, 90);
    enemyArmorStats->setDimensions(350, 30);
    enemyArmorStats->setFontName("testeFont");
    enemyArmorStats->setCharHeight(16);
    enemyArmorStats->setColour(Ogre::ColourValue::Blue);
    enemyArmorStats->setCaption("ENEMY ARMOR STATS");

    Ogre::OverlayContainer* panel = static_cast<Ogre::OverlayContainer*>(overlay_mgr->createOverlayElement("Panel", over_name + "/Panel"));
    panel->setMetricsMode(Ogre::GMM_PIXELS);
    panel->setPosition(450, 0.0);
    panel->setDimensions(350, 120);
    panel->setMaterialName("BaseWhite");
    panel->addChild(plaHullStats);
    panel->addChild(plaArmorStats);
    panel->addChild(enemyHullStats);
    panel->addChild(enemyArmorStats);
    hud->add2D(panel);
    hud->show();

    ourscene->AddTask(ugdk::system::Task(
    [&pla, &enemy, plaHullStats, plaArmorStats, enemyHullStats, enemyArmorStats](double dt) {

        auto func = [](Ship& ship, Ogre::TextAreaOverlayElement* hullStats, Ogre::TextAreaOverlayElement* armorStats) {
            if (ship.valid()) {
                auto hull = ship.hull()->GetSubHull("MainHull");
                double hullPerc = 100.0 * hull->hitpoints() / hull->max_hitpoints();
                double armorPerc = 100.0 * hull->armor_rating() / hull->max_armor_rating();
                stringstream ssh;
                ssh.precision(2);
                ssh.setf(std::ios::fixed, std::ios::floatfield);
                ssh << ship->name() << " HULL: " << hullPerc << "% (" << hull->hitpoints() << "/" << hull->max_hitpoints() << ")";
                hullStats->setCaption(ssh.str());
                stringstream ssa;
                ssa.precision(2);
                ssa.setf(std::ios::fixed, std::ios::floatfield);
                ssa << ship->name() << " ARMOR: " << armorPerc << "% (" << hull->armor_rating() << "/" << hull->max_armor_rating() << ")";
                armorStats->setCaption(ssa.str());
            }
            else {
                hullStats->setCaption("HULL: DESTROYED");
                armorStats->setCaption("ARMOR: DESTROYED");
            }
        };

        func(pla, plaHullStats, plaArmorStats);
        func(enemy, enemyHullStats, enemyArmorStats);
    }));
}

void createSphere(const std::string& name, const float r, const int nRings=16, const int nSegments=16) {
    Ogre::MeshPtr pSphere = Ogre::MeshManager::getSingleton().createManual(Ogre::String(name), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    Ogre::SubMesh *pSphereVertex = pSphere->createSubMesh();

    pSphere->sharedVertexData = new Ogre::VertexData();
    Ogre::VertexData* vertexData = pSphere->sharedVertexData;

    // define the vertex format
    Ogre::VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
    size_t currOffset = 0;
    // positions
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
    // normals
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
    // two dimensional texture coordinates
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);

    // allocate the vertex buffer
    vertexData->vertexCount = (nRings + 1) * (nSegments + 1);
    Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
    Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
    binding->setBinding(0, vBuf);
    float* pVertex = static_cast<float*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));

    // allocate index buffer
    pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
    pSphereVertex->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
    Ogre::HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
    unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));

    float fDeltaRingAngle = (Ogre::Math::PI / nRings);
    float fDeltaSegAngle = (2 * Ogre::Math::PI / nSegments);
    unsigned short wVerticeIndex = 0;

    // Generate the group of rings for the sphere
    for (int ring = 0; ring <= nRings; ring++) {
        float r0 = r * sinf(ring * fDeltaRingAngle);
        float y0 = r * cosf(ring * fDeltaRingAngle);

        // Generate the group of segments for the current ring
        for (int seg = 0; seg <= nSegments; seg++) {
            float x0 = r0 * sinf(seg * fDeltaSegAngle);
            float z0 = r0 * cosf(seg * fDeltaSegAngle);

            // Add one vertex to the strip which makes up the sphere
            *pVertex++ = x0;
            *pVertex++ = y0;
            *pVertex++ = z0;

            Ogre::Vector3 vNormal = Ogre::Vector3(x0, y0, z0).normalisedCopy();
            *pVertex++ = vNormal.x;
            *pVertex++ = vNormal.y;
            *pVertex++ = vNormal.z;

            *pVertex++ = (float)seg / (float)nSegments;
            *pVertex++ = (float)ring / (float)nRings;

            if (ring != nRings) {
                // each vertex (except the last) has six indices pointing to it
                *pIndices++ = wVerticeIndex + nSegments + 1;
                *pIndices++ = wVerticeIndex;
                *pIndices++ = wVerticeIndex + nSegments;
                *pIndices++ = wVerticeIndex + nSegments + 1;
                *pIndices++ = wVerticeIndex + 1;
                *pIndices++ = wVerticeIndex;
                wVerticeIndex++;
            }
        }; // end for seg
    } // end for ring

    // Unlock
    vBuf->unlock();
    iBuf->unlock();
    // Generate face list
    pSphereVertex->useSharedVertices = true;

    // the original code was missing this line:
    pSphere->_setBounds(Ogre::AxisAlignedBox(Ogre::Vector3(-r, -r, -r), Ogre::Vector3(r, r, r)), false);
    pSphere->_setBoundingSphereRadius(r);
    // this line makes clear the mesh is loaded (avoids memory leaks)
    pSphere->load();

    //material
    Ogre::MaterialPtr mMat = Ogre::MaterialManager::getSingleton().create("AmmoSphere", "General", true);
    mMat->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(1.0, 0.1, 0));
    mMat->getTechnique(0)->getPass(0)->setEmissive(Ogre::ColourValue(1.0, 0.1, 0));
    pSphereVertex->setMaterialName("AmmoSphere");
}

Ship createShip(const std::string& name) {
    return Ship(*ourscene, name, "AerOmar.mesh");
}

void AddSubHull(Ship& ship, const std::string& name, double radius, double x, double y, double z) {
    shipsbattle::components::Hull* hull = ship.hull();
    shipsbattle::components::subsystems::SubHull* sh = new shipsbattle::components::subsystems::SubHull(name);
    sh->SetVolume(radius, btVector3(x, y, z));
    hull->AddSubHull(std::shared_ptr<shipsbattle::components::subsystems::SubHull>(sh));
}

int main(int argc, char* argv[]) {
    ugdk::system::Configuration config;
    config.base_path = "assets/";
    config.windows_list.front().title = "Ships Battle";
    config.ogre_plugins.push_back("Plugin_ParticleFX");
    ugdk::system::Initialize(config);

    // create 3D scene
    ourscene = new ugdk::action::mode3d::Scene3D(btVector3(0.0, 0.0, 0.0));
    ourscene->manager()->setAmbientLight(Ogre::ColourValue(.7, .7, .7));
    // set some basic stuff our "space" scenes will need.
    ourscene->ShowFrameStats();
    ourscene->manager()->setSkyBox(true, "Backgrounds/Nebula1");

    // prepare our simple test mesh for projectiles
    createSphere("Ammo", 0.1);

    // create Player ship
    Ship player = createShip("Player");
    player->AddComponent(make_shared<SpaceDust>());
    player->AddComponent(make_shared<PlayerController>());
    ourscene->camera()->AttachTo(*player);
    ourscene->camera()->SetParameters(Ogre::Vector3::ZERO, 100);
    ourscene->camera()->SetDistance(10);

    //AerOmar bounding box size: (3.07287, 1.06726, 6.79639) - bounding sphere radius: 3.88078
    AddSubHull(player, "BallOrigin", 0.5, 0, 0, 0);
    //AddSubHull(player, "BallUno", 1.0, 0, 0, 1.0);
    //AddSubHull(player, "BallBottom", 0.1, 0, 0, 0.25);
    AddSubHull(player, "BallFront", 0.2, 0, 0, 3.7);

    // create Enemy ship
    Ship enemy = createShip("Enemy");
    enemy.body()->Translate(0, 0, 80);
    AddSubHull(enemy, "Butt", 0.2, 0.0, 0.0, -3.6);
    player->component<PlayerController>()->set_target( enemy.hull()->GetSubHull("Butt").get() );
    //enemy->AddComponent(std::make_shared<shipsbattle::components::TimedLife>(15.0));

    CreateHUD(player, enemy);
    ourscene->event_handler().AddListener<ugdk::input::KeyPressedEvent>(
        [&player,&enemy](const ugdk::input::KeyPressedEvent& ev) -> void {
        if (ev.scancode == ugdk::input::Scancode::I) {
            player.hull()->TakeDamage(-100, 0.2, 5.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::O) {
            player.hull()->TakeDamage(100, 0.2, 1.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::P) {
            player.hull()->TakeDamage(100, 0.2, 0.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::SPACE) {
            enemy.hull()->TakeDamage(-500.0, 0.0, 1.0, btVector3(0, 0, 0), CONSTANT);
        }
    });

    // push scene
    ugdk::system::PushScene(unique_ptr<ugdk::action::Scene>(ourscene));

    ugdk::system::Run();
    ugdk::system::Release();
    return 0;
}
<commit_msg>Updated main to use Navigation to set initial player target; Main also uses old AerOmar model (new one at this point is wrong); Updated main to create a bigger window for the game and fixed hud for it;<commit_after>
#include <ugdk/system/engine.h>
#include <ugdk/action/3D/camera.h>
#include <ugdk/action/3D/scene3d.h>
#include <ugdk/action/3D/component/body.h>

#include <shipsbattle/objects/ship.h>
#include <shipsbattle/components/spacedust.h>
#include <shipsbattle/components/playercontroller.h>
#include <shipsbattle/components/subsystems/typedefs.h>
#include <shipsbattle/components/hull.h>
#include <shipsbattle/components/subsystems/subhull.h>
#include <shipsbattle/components/navigation.h>
#include <shipsbattle/components/timedlife.h>

#include <btBulletDynamicsCommon.h>
#include <OgreSceneManager.h>
#include <OgreOverlaySystem.h>

#include <OgreMeshManager.h>
#include <OgreHardwareBufferManager.h>
#include <OgreSubMesh.h>

#include <memory>
#include <iostream>
#include <sstream>

#define AREA_RANGE 200.0

using std::weak_ptr;
using std::shared_ptr;
using std::unique_ptr;
using std::make_shared;
using std::stringstream;
using std::cout;
using std::endl;
using shipsbattle::objects::Ship;
using shipsbattle::components::SpaceDust;
using shipsbattle::components::PlayerController;
using shipsbattle::components::Navigation;
using namespace shipsbattle::components::subsystems::DecaymentFunctions;

ugdk::action::mode3d::Scene3D *ourscene;

void CreateHUD(Ship& pla, Ship& enemy) {
    Ogre::OverlayManager* overlay_mgr = Ogre::OverlayManager::getSingletonPtr();
    std::string over_name = "SBHUD";
    Ogre::Overlay* hud = overlay_mgr->create(over_name);
    hud->setZOrder(600);

    Ogre::TextAreaOverlayElement* plaHullStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/PlaHullStats"));
    plaHullStats->setMetricsMode(Ogre::GMM_PIXELS);
    plaHullStats->setPosition(10, 0);
    plaHullStats->setDimensions(350, 30);
    plaHullStats->setFontName("testeFont");
    plaHullStats->setCharHeight(16);
    plaHullStats->setColour(Ogre::ColourValue::Black);
    plaHullStats->setCaption("PLAYER HULL STATS");
    Ogre::TextAreaOverlayElement* plaArmorStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/PlaArmorStats"));
    plaArmorStats->setMetricsMode(Ogre::GMM_PIXELS);
    plaArmorStats->setPosition(10, 30);
    plaArmorStats->setDimensions(350, 30);
    plaArmorStats->setFontName("testeFont");
    plaArmorStats->setCharHeight(16);
    plaArmorStats->setColour(Ogre::ColourValue::Blue);
    plaArmorStats->setCaption("PLAYER ARMOR STATS");

    Ogre::TextAreaOverlayElement* enemyHullStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/EnemyHullStats"));
    enemyHullStats->setMetricsMode(Ogre::GMM_PIXELS);
    enemyHullStats->setPosition(10, 60);
    enemyHullStats->setDimensions(350, 30);
    enemyHullStats->setFontName("testeFont");
    enemyHullStats->setCharHeight(16);
    enemyHullStats->setColour(Ogre::ColourValue::Black);
    enemyHullStats->setCaption("ENEMY HULL STATS");
    Ogre::TextAreaOverlayElement* enemyArmorStats = static_cast<Ogre::TextAreaOverlayElement*>(overlay_mgr->createOverlayElement("TextArea", over_name + "/EnemyArmorStats"));
    enemyArmorStats->setMetricsMode(Ogre::GMM_PIXELS);
    enemyArmorStats->setPosition(10, 90);
    enemyArmorStats->setDimensions(350, 30);
    enemyArmorStats->setFontName("testeFont");
    enemyArmorStats->setCharHeight(16);
    enemyArmorStats->setColour(Ogre::ColourValue::Blue);
    enemyArmorStats->setCaption("ENEMY ARMOR STATS");

    Ogre::OverlayContainer* panel = static_cast<Ogre::OverlayContainer*>(overlay_mgr->createOverlayElement("Panel", over_name + "/Panel"));
    panel->setMetricsMode(Ogre::GMM_PIXELS);
    panel->setPosition(674, 0.0);
    panel->setDimensions(350, 120);
    panel->setMaterialName("BaseWhite");
    panel->addChild(plaHullStats);
    panel->addChild(plaArmorStats);
    panel->addChild(enemyHullStats);
    panel->addChild(enemyArmorStats);
    hud->add2D(panel);
    hud->show();

    ourscene->AddTask(ugdk::system::Task(
    [&pla, &enemy, plaHullStats, plaArmorStats, enemyHullStats, enemyArmorStats](double dt) {

        auto func = [](Ship& ship, Ogre::TextAreaOverlayElement* hullStats, Ogre::TextAreaOverlayElement* armorStats) {
            if (ship.valid()) {
                auto hull = ship.hull()->GetSubHull("MainHull");
                double hullPerc = 100.0 * hull->hitpoints() / hull->max_hitpoints();
                double armorPerc = 100.0 * hull->armor_rating() / hull->max_armor_rating();
                stringstream ssh;
                ssh.precision(2);
                ssh.setf(std::ios::fixed, std::ios::floatfield);
                ssh << ship->name() << " HULL: " << hullPerc << "% (" << hull->hitpoints() << "/" << hull->max_hitpoints() << ")";
                hullStats->setCaption(ssh.str());
                stringstream ssa;
                ssa.precision(2);
                ssa.setf(std::ios::fixed, std::ios::floatfield);
                ssa << ship->name() << " ARMOR: " << armorPerc << "% (" << hull->armor_rating() << "/" << hull->max_armor_rating() << ")";
                armorStats->setCaption(ssa.str());
            }
            else {
                hullStats->setCaption("HULL: DESTROYED");
                armorStats->setCaption("ARMOR: DESTROYED");
            }
        };

        func(pla, plaHullStats, plaArmorStats);
        func(enemy, enemyHullStats, enemyArmorStats);
    }));
}

void createSphere(const std::string& name, const float r, const int nRings=16, const int nSegments=16) {
    Ogre::MeshPtr pSphere = Ogre::MeshManager::getSingleton().createManual(Ogre::String(name), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    Ogre::SubMesh *pSphereVertex = pSphere->createSubMesh();

    pSphere->sharedVertexData = new Ogre::VertexData();
    Ogre::VertexData* vertexData = pSphere->sharedVertexData;

    // define the vertex format
    Ogre::VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
    size_t currOffset = 0;
    // positions
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
    // normals
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
    // two dimensional texture coordinates
    vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
    currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);

    // allocate the vertex buffer
    vertexData->vertexCount = (nRings + 1) * (nSegments + 1);
    Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
    Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
    binding->setBinding(0, vBuf);
    float* pVertex = static_cast<float*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));

    // allocate index buffer
    pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
    pSphereVertex->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
    Ogre::HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
    unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));

    float fDeltaRingAngle = (Ogre::Math::PI / nRings);
    float fDeltaSegAngle = (2 * Ogre::Math::PI / nSegments);
    unsigned short wVerticeIndex = 0;

    // Generate the group of rings for the sphere
    for (int ring = 0; ring <= nRings; ring++) {
        float r0 = r * sinf(ring * fDeltaRingAngle);
        float y0 = r * cosf(ring * fDeltaRingAngle);

        // Generate the group of segments for the current ring
        for (int seg = 0; seg <= nSegments; seg++) {
            float x0 = r0 * sinf(seg * fDeltaSegAngle);
            float z0 = r0 * cosf(seg * fDeltaSegAngle);

            // Add one vertex to the strip which makes up the sphere
            *pVertex++ = x0;
            *pVertex++ = y0;
            *pVertex++ = z0;

            Ogre::Vector3 vNormal = Ogre::Vector3(x0, y0, z0).normalisedCopy();
            *pVertex++ = vNormal.x;
            *pVertex++ = vNormal.y;
            *pVertex++ = vNormal.z;

            *pVertex++ = (float)seg / (float)nSegments;
            *pVertex++ = (float)ring / (float)nRings;

            if (ring != nRings) {
                // each vertex (except the last) has six indices pointing to it
                *pIndices++ = wVerticeIndex + nSegments + 1;
                *pIndices++ = wVerticeIndex;
                *pIndices++ = wVerticeIndex + nSegments;
                *pIndices++ = wVerticeIndex + nSegments + 1;
                *pIndices++ = wVerticeIndex + 1;
                *pIndices++ = wVerticeIndex;
                wVerticeIndex++;
            }
        }; // end for seg
    } // end for ring

    // Unlock
    vBuf->unlock();
    iBuf->unlock();
    // Generate face list
    pSphereVertex->useSharedVertices = true;

    // the original code was missing this line:
    pSphere->_setBounds(Ogre::AxisAlignedBox(Ogre::Vector3(-r, -r, -r), Ogre::Vector3(r, r, r)), false);
    pSphere->_setBoundingSphereRadius(r);
    // this line makes clear the mesh is loaded (avoids memory leaks)
    pSphere->load();

    //material
    Ogre::MaterialPtr mMat = Ogre::MaterialManager::getSingleton().create("AmmoSphere", "General", true);
    mMat->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(1.0, 0.1, 0));
    mMat->getTechnique(0)->getPass(0)->setEmissive(Ogre::ColourValue(1.0, 0.1, 0));
    pSphereVertex->setMaterialName("AmmoSphere");
}

Ship createShip(const std::string& name) {
    return Ship(*ourscene, name, "AerOmarOld.mesh");
}

void AddSubHull(Ship& ship, const std::string& name, double radius, double x, double y, double z) {
    shipsbattle::components::Hull* hull = ship.hull();
    shipsbattle::components::subsystems::SubHull* sh = new shipsbattle::components::subsystems::SubHull(name);
    sh->SetVolume(radius, btVector3(x, y, z));
    hull->AddSubHull(std::shared_ptr<shipsbattle::components::subsystems::SubHull>(sh));
}

int main(int argc, char* argv[]) {
    ugdk::system::Configuration config;
    config.base_path = "assets/";
    config.windows_list.front().title = "Ships Battle";
    config.windows_list.front().size = ugdk::math::Integer2D(1024, 768);
    config.ogre_plugins.push_back("Plugin_ParticleFX");
    ugdk::system::Initialize(config);

    // create 3D scene
    ourscene = new ugdk::action::mode3d::Scene3D(btVector3(0.0, 0.0, 0.0));
    ourscene->manager()->setAmbientLight(Ogre::ColourValue(.7, .7, .7));
    // set some basic stuff our "space" scenes will need.
    ourscene->ShowFrameStats();
    ourscene->manager()->setSkyBox(true, "Backgrounds/Nebula1");

    // prepare our simple test mesh for projectiles
    createSphere("Ammo", 0.1);

    // create Player ship
    Ship player = createShip("Player");
    player->AddComponent(make_shared<SpaceDust>());
    player->AddComponent(make_shared<PlayerController>());
    ourscene->camera()->AttachTo(*player);
    ourscene->camera()->SetParameters(Ogre::Vector3::ZERO, 100);
    ourscene->camera()->SetDistance(10);

    //AerOmar bounding box size: (3.07287, 1.06726, 6.79639) - bounding sphere radius: 3.88078
    AddSubHull(player, "BallOrigin", 0.5, 0, 0, 0);
    //AddSubHull(player, "BallUno", 1.0, 0, 0, 1.0);
    //AddSubHull(player, "BallBottom", 0.1, 0, 0, 0.25);
    AddSubHull(player, "BallFront", 0.2, 0, 0, 3.7);

    // create Enemy ship
    Ship enemy = createShip("Enemy");
    enemy.body()->Translate(0, 0, 80);
    AddSubHull(enemy, "Butt", 0.2, 0.0, 0.0, -3.6);
    player->component<Navigation>()->ToggleTarget("Enemy", true);
    //enemy->AddComponent(std::make_shared<shipsbattle::components::TimedLife>(15.0));

    CreateHUD(player, enemy);
    ourscene->event_handler().AddListener<ugdk::input::KeyPressedEvent>(
        [&player,&enemy](const ugdk::input::KeyPressedEvent& ev) -> void {
        if (ev.scancode == ugdk::input::Scancode::I) {
            player.hull()->TakeDamage(-100, 0.2, 5.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::O) {
            player.hull()->TakeDamage(100, 0.2, 1.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::P) {
            player.hull()->TakeDamage(100, 0.2, 0.0, btVector3(0, 0, 3.9), CONSTANT);
        }
        else if (ev.scancode == ugdk::input::Scancode::SPACE) {
            enemy.hull()->TakeDamage(-500.0, 0.0, 1.0, btVector3(0, 0, 0), CONSTANT);
        }
    });

    // push scene
    ugdk::system::PushScene(unique_ptr<ugdk::action::Scene>(ourscene));

    ugdk::system::Run();
    ugdk::system::Release();
    return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: LinkSequence.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2006-01-31 18:16:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <string.h>

#ifndef NE_XML_H
#include <ne_xml.h>
#endif

#ifndef _LINKSEQUENCE_HXX_
#include "LinkSequence.hxx"
#endif

using namespace webdav_ucp;
using namespace com::sun::star;

//////////////////////////////////////////////////////////////////////////

struct LinkSequenceParseContext
{
    ucb::Link * pLink;
    bool hasSource;
    bool hasDestination;

    LinkSequenceParseContext()
    : pLink( 0 ), hasSource( false ), hasDestination( false ) {}
    ~LinkSequenceParseContext() { delete pLink; }
};

#define STATE_TOP (1)

#define STATE_LINK (STATE_TOP)
#define STATE_DST  (STATE_TOP + 1)
#define STATE_SRC  (STATE_TOP + 2)

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_startelement_callback(
    void *userdata,
    int parent,
    const char *nspace,
    const char *name,
    const char **atts )
{
    if ( ( name != 0 ) &&
         ( ( nspace == 0 ) || ( strcmp( nspace, "" ) == 0 ) ) )
    {
        switch ( parent )
        {
            case NE_XML_STATEROOT:
                if ( strcmp( name, "link" ) == 0 )
                    return STATE_LINK;
                break;

            case STATE_LINK:
                if ( strcmp( name, "dst" ) == 0 )
                    return STATE_DST;
                else if ( strcmp( name, "src" ) == 0 )
                    return STATE_SRC;
                break;
        }
    }
    return NE_XML_DECLINE;
}

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_chardata_callback(
    void *userdata,
    int state,
    const char *buf,
    size_t len )
{
    LinkSequenceParseContext * pCtx
                    = static_cast< LinkSequenceParseContext * >( userdata );
    if ( !pCtx->pLink )
        pCtx->pLink = new ucb::Link;

    switch ( state )
    {
        case STATE_DST:
            pCtx->pLink->Destination
                = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
            pCtx->hasDestination = true;
            break;

        case STATE_SRC:
            pCtx->pLink->Source
                = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
            pCtx->hasSource = true;
            break;
    }
    return 0; // zero to continue, non-zero to abort parsing
}

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_endelement_callback(
    void *userdata,
    int state,
    const char *nspace,
    const char *name )
{
    LinkSequenceParseContext * pCtx
                    = static_cast< LinkSequenceParseContext * >( userdata );
    if ( !pCtx->pLink )
        pCtx->pLink = new ucb::Link;

    switch ( state )
    {
        case STATE_LINK:
            if ( !pCtx->hasDestination || !pCtx->hasSource )
                return 1; // abort
            break;
    }
    return 0; // zero to continue, non-zero to abort parsing
}

//////////////////////////////////////////////////////////////////////////
// static
bool LinkSequence::createFromXML( const rtl::OString & rInData,
                                  uno::Sequence< ucb::Link > & rOutData )
{
    const sal_Int32 TOKEN_LENGTH = 7; // </link>
    bool success = true;

    // rInData may contain multiple <link>...</link> tags.
    sal_Int32 nCount = 0;
    sal_Int32 nStart = 0;
    sal_Int32 nEnd   = rInData.indexOf( "</link>" );
    while ( nEnd > -1 )
    {
        ne_xml_parser * parser = ne_xml_create();
        if ( !parser )
        {
            success = false;
            break;
        }

        LinkSequenceParseContext aCtx;
        ne_xml_push_handler( parser,
                             LinkSequence_startelement_callback,
                             LinkSequence_chardata_callback,
                             LinkSequence_endelement_callback,
                             &aCtx );

        ne_xml_parse( parser,
                      rInData.getStr() + nStart,
                      nEnd - nStart + TOKEN_LENGTH );

        success = !!ne_xml_valid( parser );

        ne_xml_destroy( parser );

        if ( !success )
            break;

        if ( aCtx.pLink )
        {
            nCount++;
            if ( nCount > rOutData.getLength() )
                rOutData.realloc( rOutData.getLength() + 1 );

            rOutData[ nCount - 1 ] = *aCtx.pLink;
        }

        nStart = nEnd + TOKEN_LENGTH + 1;
        nEnd   = rInData.indexOf( "</link>", nStart );
    }

    return success;
}

//////////////////////////////////////////////////////////////////////////
// static
bool LinkSequence::toXML( const uno::Sequence< ucb::Link > & rInData,
                          rtl::OUString & rOutData )
{
    // <link><src>value</src><dst>value</dst></link><link><src>....

    sal_Int32 nCount = rInData.getLength();
    if ( nCount )
    {
        rtl::OUString aPre( rtl::OUString::createFromAscii( "<link><src>" ) );
        rtl::OUString aMid( rtl::OUString::createFromAscii( "</src><dst>" ) );
        rtl::OUString aEnd( rtl::OUString::createFromAscii( "</dst></link>" ) );

        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
               rOutData += aPre;
               rOutData += rInData[ n ].Source;
               rOutData += aMid;
               rOutData += rInData[ n ].Destination;
               rOutData += aEnd;
        }
        return true;
    }
    return false;
}
<commit_msg>INTEGRATION: CWS nfslockproblem (1.6.32); FILE MERGED 2006/02/01 08:20:08 abi 1.6.32.2: RESYNC: (1.6-1.7); FILE MERGED 2006/01/26 16:21:12 kso 1.6.32.1: #i61178# - conditional compile time support for neon 0.25.x            (neon API has again changed incompatible).<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: LinkSequence.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2006-02-09 14:25:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <string.h>

#ifndef NE_XML_H
#include <ne_xml.h>
#endif

#ifndef _LINKSEQUENCE_HXX_
#include "LinkSequence.hxx"
#endif

using namespace webdav_ucp;
using namespace com::sun::star;

//////////////////////////////////////////////////////////////////////////

struct LinkSequenceParseContext
{
    ucb::Link * pLink;
    bool hasSource;
    bool hasDestination;

    LinkSequenceParseContext()
    : pLink( 0 ), hasSource( false ), hasDestination( false ) {}
    ~LinkSequenceParseContext() { delete pLink; }
};

#define STATE_TOP (1)

#define STATE_LINK (STATE_TOP)
#define STATE_DST  (STATE_TOP + 1)
#define STATE_SRC  (STATE_TOP + 2)

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_startelement_callback(
    void *userdata,
    int parent,
    const char *nspace,
    const char *name,
    const char **atts )
{
    if ( ( name != 0 ) &&
         ( ( nspace == 0 ) || ( strcmp( nspace, "" ) == 0 ) ) )
    {
        switch ( parent )
        {
            case NE_XML_STATEROOT:
                if ( strcmp( name, "link" ) == 0 )
                    return STATE_LINK;
                break;

            case STATE_LINK:
                if ( strcmp( name, "dst" ) == 0 )
                    return STATE_DST;
                else if ( strcmp( name, "src" ) == 0 )
                    return STATE_SRC;
                break;
        }
    }
    return NE_XML_DECLINE;
}

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_chardata_callback(
    void *userdata,
    int state,
    const char *buf,
    size_t len )
{
    LinkSequenceParseContext * pCtx
                    = static_cast< LinkSequenceParseContext * >( userdata );
    if ( !pCtx->pLink )
        pCtx->pLink = new ucb::Link;

    switch ( state )
    {
        case STATE_DST:
            pCtx->pLink->Destination
                = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
            pCtx->hasDestination = true;
            break;

        case STATE_SRC:
            pCtx->pLink->Source
                = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
            pCtx->hasSource = true;
            break;
    }
    return 0; // zero to continue, non-zero to abort parsing
}

//////////////////////////////////////////////////////////////////////////
extern "C" int LinkSequence_endelement_callback(
    void *userdata,
    int state,
    const char *nspace,
    const char *name )
{
    LinkSequenceParseContext * pCtx
                    = static_cast< LinkSequenceParseContext * >( userdata );
    if ( !pCtx->pLink )
        pCtx->pLink = new ucb::Link;

    switch ( state )
    {
        case STATE_LINK:
            if ( !pCtx->hasDestination || !pCtx->hasSource )
                return 1; // abort
            break;
    }
    return 0; // zero to continue, non-zero to abort parsing
}

//////////////////////////////////////////////////////////////////////////
// static
bool LinkSequence::createFromXML( const rtl::OString & rInData,
                                  uno::Sequence< ucb::Link > & rOutData )
{
    const sal_Int32 TOKEN_LENGTH = 7; // </link>
    bool success = true;

    // rInData may contain multiple <link>...</link> tags.
    sal_Int32 nCount = 0;
    sal_Int32 nStart = 0;
    sal_Int32 nEnd   = rInData.indexOf( "</link>" );
    while ( nEnd > -1 )
    {
        ne_xml_parser * parser = ne_xml_create();
        if ( !parser )
        {
            success = false;
            break;
        }

        LinkSequenceParseContext aCtx;
        ne_xml_push_handler( parser,
                             LinkSequence_startelement_callback,
                             LinkSequence_chardata_callback,
                             LinkSequence_endelement_callback,
                             &aCtx );

        ne_xml_parse( parser,
                      rInData.getStr() + nStart,
                      nEnd - nStart + TOKEN_LENGTH );

#ifdef NEONTWOFIVE
    success = !ne_xml_failed( parser );
#else
        success = !!ne_xml_valid( parser );
#endif

        ne_xml_destroy( parser );

        if ( !success )
            break;

        if ( aCtx.pLink )
        {
            nCount++;
            if ( nCount > rOutData.getLength() )
                rOutData.realloc( rOutData.getLength() + 1 );

            rOutData[ nCount - 1 ] = *aCtx.pLink;
        }

        nStart = nEnd + TOKEN_LENGTH + 1;
        nEnd   = rInData.indexOf( "</link>", nStart );
    }

    return success;
}

//////////////////////////////////////////////////////////////////////////
// static
bool LinkSequence::toXML( const uno::Sequence< ucb::Link > & rInData,
                          rtl::OUString & rOutData )
{
    // <link><src>value</src><dst>value</dst></link><link><src>....

    sal_Int32 nCount = rInData.getLength();
    if ( nCount )
    {
        rtl::OUString aPre( rtl::OUString::createFromAscii( "<link><src>" ) );
        rtl::OUString aMid( rtl::OUString::createFromAscii( "</src><dst>" ) );
        rtl::OUString aEnd( rtl::OUString::createFromAscii( "</dst></link>" ) );

        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
               rOutData += aPre;
               rOutData += rInData[ n ].Source;
               rOutData += aMid;
               rOutData += rInData[ n ].Destination;
               rOutData += aEnd;
        }
        return true;
    }
    return false;
}
<|endoftext|>