<commit_before>#include "ncurses.hh"

#include "display_buffer.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"
#include "event_manager.hh"

#include <map>

#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>

namespace Kakoune
{

static void set_attribute(int attribute, bool on)
{
    if (on)
        attron(attribute);
    else
        attroff(attribute);
}

static int nc_color(Color color)
{
    switch (color)
    {
    case Color::Black:   return COLOR_BLACK;
    case Color::Red:     return COLOR_RED;
    case Color::Green:   return COLOR_GREEN;
    case Color::Yellow:  return COLOR_YELLOW;
    case Color::Blue:    return COLOR_BLUE;
    case Color::Magenta: return COLOR_MAGENTA;
    case Color::Cyan:    return COLOR_CYAN;
    case Color::White:   return COLOR_WHITE;

    case Color::Default:
    default:
        return -1;
    }
}

static int get_color_pair(Color fg_color, Color bg_color)
{
    static std::map<std::pair<Color, Color>, int> colorpairs;
    static int next_pair = 1;

    std::pair<Color, Color> colorpair(fg_color, bg_color);

    auto it = colorpairs.find(colorpair);
    if (it != colorpairs.end())
        return it->second;
    else
    {
        init_pair(next_pair, nc_color(fg_color), nc_color(bg_color));
        colorpairs[colorpair] = next_pair;
        return next_pair++;
    }
}

static void set_color(Color fg_color, Color bg_color)
{
    static int current_pair = -1;

    if (current_pair != -1)
        attroff(COLOR_PAIR(current_pair));

    if (fg_color != Color::Default or bg_color != Color::Default)
    {
        current_pair = get_color_pair(fg_color, bg_color);
        attron(COLOR_PAIR(current_pair));
    }
}

void on_term_resize(int)
{
    ungetch(KEY_RESIZE);
    EventManager::instance().force_signal(0);
}

void on_sigint(int)
{
    ungetch(CTRL('c'));
    EventManager::instance().force_signal(0);
}

NCursesUI::NCursesUI()
    : m_stdin_watcher{0, [this](FDWatcher&){ if (m_input_callback) m_input_callback(); }}
{
    //setlocale(LC_CTYPE, "");
    initscr();
    cbreak();
    noecho();
    nonl();
    intrflush(stdscr, false);
    keypad(stdscr, true);
    curs_set(0);
    start_color();
    use_default_colors();
    ESCDELAY=25;

    m_menu_fg = get_color_pair(Color::Blue, Color::Cyan);
    m_menu_bg = get_color_pair(Color::Cyan, Color::Blue);

    signal(SIGWINCH, on_term_resize);
    signal(SIGINT, on_sigint);

    update_dimensions();
}

NCursesUI::~NCursesUI()
{
    endwin();
    signal(SIGWINCH, SIG_DFL);
    signal(SIGINT, SIG_DFL);
}

static void redraw(WINDOW* menu_win, WINDOW* info_win)
{
    wnoutrefresh(stdscr);
    if (menu_win)
    {
        redrawwin(menu_win);
        wnoutrefresh(menu_win);
    }
    if (info_win)
    {
        redrawwin(info_win);
        wnoutrefresh(info_win);
    }
    doupdate();
}
using Utf8Policy = utf8::InvalidBytePolicy::Pass;
using Utf8Iterator = utf8::utf8_iterator<String::iterator, Utf8Policy>;
void addutf8str(WINDOW* win, Utf8Iterator begin, Utf8Iterator end)
{
    assert(begin <= end);
    while (begin != end)
        waddch(win, *begin++);
}

static DisplayCoord window_size(WINDOW* win)
{
    DisplayCoord size;
    getmaxyx(win, (int&)size.line, (int&)size.column);
    return size;
}

static DisplayCoord window_pos(WINDOW* win)
{
    DisplayCoord pos;
    getbegyx(win, (int&)pos.line, (int&)pos.column);
    return pos;
}

void NCursesUI::update_dimensions()
{
    m_dimensions = window_size(stdscr);
    --m_dimensions.line;
}

void NCursesUI::draw(const DisplayBuffer& display_buffer,
                     const String& mode_line)
{
    LineCount line_index = 0;
    for (const DisplayLine& line : display_buffer.lines())
    {
        move((int)line_index, 0);
        clrtoeol();
        CharCount col_index = 0;
        for (const DisplayAtom& atom : line)
        {
            set_attribute(A_UNDERLINE, atom.attribute & Underline);
            set_attribute(A_REVERSE, atom.attribute & Reverse);
            set_attribute(A_BLINK, atom.attribute & Blink);
            set_attribute(A_BOLD, atom.attribute & Bold);

            set_color(atom.fg_color, atom.bg_color);

            String content = atom.content.content();
            if (content[content.length()-1] == '\n' and
                content.char_length() - 1 < m_dimensions.column - col_index)
            {
                addutf8str(stdscr, Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
                addch(' ');
            }
            else
            {
                Utf8Iterator begin(content.begin()), end(content.end());
                if (end - begin > m_dimensions.column - col_index)
                    end = begin + (m_dimensions.column - col_index);
                addutf8str(stdscr, begin, end);
                col_index += end - begin;
            }
        }
        ++line_index;
    }

    set_attribute(A_UNDERLINE, 0);
    set_attribute(A_REVERSE, 0);
    set_attribute(A_BLINK, 0);
    set_attribute(A_BOLD, 0);
    set_color(Color::Blue, Color::Black);
    for (;line_index < m_dimensions.line; ++line_index)
    {
        move((int)line_index, 0);
        clrtoeol();
        addch('~');
    }

    set_color(Color::Cyan, Color::Default);
    draw_status();
    CharCount status_len = mode_line.char_length();
    // only draw mode_line if it does not overlap one status line
    if (m_dimensions.column - m_status_line.char_length() > status_len + 1)
    {
        move((int)m_dimensions.line, (int)(m_dimensions.column - status_len));
        addutf8str(stdscr, Utf8Iterator(mode_line.begin()),
                   Utf8Iterator(mode_line.end()));
    }
    redraw(m_menu_win, m_info_win);
}

struct getch_iterator
{
    int operator*() { return getch(); }
    getch_iterator& operator++() { return *this; }
    getch_iterator& operator++(int) { return *this; }
};

bool NCursesUI::is_key_available()
{
    timeout(0);
    const int c = getch();
    if (c != ERR)
        ungetch(c);
    timeout(-1);
    return c != ERR;
}

Key NCursesUI::get_key()
{
    const int c = getch();
    if (c > 0 and c < 27)
    {
        return {Key::Modifiers::Control, Codepoint(c) - 1 + 'a'};
    }
    else if (c == 27)
    {
        timeout(0);
        const Codepoint new_c = getch();
        timeout(-1);
        if (new_c != ERR)
            return {Key::Modifiers::Alt, new_c};
        else
            return Key::Escape;
    }
    else if (c == KEY_RESIZE)
    {
        int fd = open("/dev/tty", O_RDWR);
        winsize ws;
        if (fd != -1 and ioctl(fd, TIOCGWINSZ, (void*)&ws) == 0)
        {
            close(fd);
            resizeterm(ws.ws_row, ws.ws_col);
            update_dimensions();
        }
        return Key::Invalid;
    }
    else switch (c)
    {
    case KEY_BACKSPACE: case 127: return Key::Backspace;
    case KEY_UP: return Key::Up;
    case KEY_DOWN: return Key::Down;
    case KEY_LEFT: return Key::Left;
    case KEY_RIGHT: return Key::Right;
    case KEY_PPAGE: return Key::PageUp;
    case KEY_NPAGE: return Key::PageDown;
    case KEY_BTAB: return Key::BackTab;
    }

    if (c >= 0 and c < 256)
    {
       ungetch(c);
       return utf8::codepoint(getch_iterator{});
    }
    return Key::Invalid;
}

void NCursesUI::draw_status()
{
    move((int)m_dimensions.line, 0);
    clrtoeol();
    if (m_status_cursor == -1)
       addutf8str(stdscr, m_status_line.begin(), m_status_line.end());
    else
    {
        auto cursor_it = utf8::advance(m_status_line.begin(), m_status_line.end(),
                                       (int)m_status_cursor);
        auto end = m_status_line.end();
        addutf8str(stdscr, m_status_line.begin(), cursor_it);
        set_attribute(A_REVERSE, 1);
        addch((cursor_it == end) ? ' ' : utf8::codepoint<Utf8Policy>(cursor_it));
        set_attribute(A_REVERSE, 0);
        if (cursor_it != end)
            addutf8str(stdscr, utf8::next(cursor_it), end);
    }
}

void NCursesUI::print_status(const String& status, CharCount cursor_pos)
{
    m_status_line   = status;
    m_status_cursor = cursor_pos;
    draw_status();
    redraw(m_menu_win, m_info_win);
}

void NCursesUI::menu_show(const memoryview<String>& choices,
                          const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_menu == nullptr);
    assert(m_menu_win == nullptr);
    assert(m_choices.empty());
    assert(m_items.empty());

    DisplayCoord maxsize = window_size(stdscr);
    maxsize.column -= anchor.column;

    m_choices.reserve(choices.size());
    CharCount longest = 0;
    for (auto& choice : choices)
    {
        m_choices.push_back(choice.substr(0_char, std::min((int)maxsize.column-1, 200)));
        m_items.emplace_back(new_item(m_choices.back().c_str(), ""));
        longest = std::max(longest, m_choices.back().char_length());
    }
    m_items.push_back(nullptr);
    longest += 1;

    int columns = (style == MenuStyle::Prompt) ? (int)(maxsize.column / longest) : 1;
    int lines = std::min(10, (int)ceilf((float)m_choices.size()/columns));

    DisplayCoord pos = { anchor.line+1, anchor.column };
    if (pos.line + lines >= maxsize.line)
        pos.line = anchor.line - lines;
    DisplayCoord size = { lines, columns == 1 ? longest : maxsize.column };

    m_menu = new_menu(&m_items[0]);
    m_menu_win = newwin((int)size.line, (int)size.column,
                        (int)pos.line,  (int)pos.column);
    set_menu_win(m_menu, m_menu_win);
    set_menu_format(m_menu, lines, columns);
    set_menu_mark(m_menu, nullptr);
    set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
    set_menu_back(m_menu, COLOR_PAIR(m_menu_bg));
    post_menu(m_menu);
}

void NCursesUI::menu_select(int selected)
{
    // last item in m_items is the nullptr, hence the - 1
    if (selected >= 0 and selected < m_items.size() - 1)
    {
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
        set_current_item(m_menu, m_items[selected]);
    }
    else
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_bg));
}

void NCursesUI::menu_hide()
{
    if (not m_menu)
        return;
    unpost_menu(m_menu);
    free_menu(m_menu);
    for (auto item : m_items)
       if (item)
           free_item(item);
    m_menu = nullptr;
    delwin(m_menu_win);
    m_menu_win = nullptr;
    m_items.clear();
    m_choices.clear();
}

static DisplayCoord compute_needed_size(const String& str)
{
    DisplayCoord res{1,0};
    CharCount line_len = 0;
    for (Utf8Iterator begin{str.begin()}, end{str.end()}; begin != end; ++begin)
    {
        if (*begin == '\n')
        {
            line_len = 0;
            ++res.line;
        }
        else
        {
            ++line_len;
            res.column = std::max(res.column, line_len);
        }
    }
    return res;
}

static DisplayCoord compute_pos(const DisplayCoord& anchor,
                                const DisplayCoord& size,
                                WINDOW* opt_window_to_avoid = nullptr)
{
    DisplayCoord scrsize = window_size(stdscr);
    DisplayCoord pos = { anchor.line+1, anchor.column };
    if (pos.line + size.line >= scrsize.line)
        pos.line = anchor.line - size.line;

    if (opt_window_to_avoid)
    {
        DisplayCoord winbeg = window_pos(opt_window_to_avoid);
        DisplayCoord winend = winbeg + window_size(opt_window_to_avoid);

        DisplayCoord end = pos + size;

        // check intersection
        if (not (end.line < winbeg.line or end.column < winbeg.column or
                 pos.line > winend.line or pos.column > winend.column))
        {
            pos.line = std::min(winbeg.line, anchor.line) - size.line;
            // if above does not work, try below
            if (pos.line < 0)
                pos.line = std::max(winend.line, anchor.line);
        }
    }

    return pos;
}

void NCursesUI::info_show(const String& content, const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_info_win == nullptr);

    DisplayCoord size = compute_needed_size(content);
    if (style == MenuStyle::Prompt)
        size.column = window_size(stdscr).column - anchor.column;

    DisplayCoord pos = compute_pos(anchor, size, m_menu_win);

    m_info_win = newwin((int)size.line, (int)size.column,
                        (int)pos.line,  (int)pos.column);

    wbkgd(m_info_win, COLOR_PAIR(get_color_pair(Color::Black, Color::Yellow)));
    wmove(m_info_win, 0, 0);
    addutf8str(m_info_win, Utf8Iterator(content.begin()),
               Utf8Iterator(content.end()));
}

void NCursesUI::info_hide()
{
    if (not m_info_win)
        return;
    delwin(m_info_win);
    m_info_win = nullptr;
}

DisplayCoord NCursesUI::dimensions()
{
    return m_dimensions;
}

void NCursesUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

}
<commit_msg>NCurses: redraw after menu/info window is modified<commit_after>#include "ncurses.hh"

#include "display_buffer.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"
#include "event_manager.hh"

#include <map>

#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>

namespace Kakoune
{

static void set_attribute(int attribute, bool on)
{
    if (on)
        attron(attribute);
    else
        attroff(attribute);
}

static int nc_color(Color color)
{
    switch (color)
    {
    case Color::Black:   return COLOR_BLACK;
    case Color::Red:     return COLOR_RED;
    case Color::Green:   return COLOR_GREEN;
    case Color::Yellow:  return COLOR_YELLOW;
    case Color::Blue:    return COLOR_BLUE;
    case Color::Magenta: return COLOR_MAGENTA;
    case Color::Cyan:    return COLOR_CYAN;
    case Color::White:   return COLOR_WHITE;

    case Color::Default:
    default:
        return -1;
    }
}

static int get_color_pair(Color fg_color, Color bg_color)
{
    static std::map<std::pair<Color, Color>, int> colorpairs;
    static int next_pair = 1;

    std::pair<Color, Color> colorpair(fg_color, bg_color);

    auto it = colorpairs.find(colorpair);
    if (it != colorpairs.end())
        return it->second;
    else
    {
        init_pair(next_pair, nc_color(fg_color), nc_color(bg_color));
        colorpairs[colorpair] = next_pair;
        return next_pair++;
    }
}

static void set_color(Color fg_color, Color bg_color)
{
    static int current_pair = -1;

    if (current_pair != -1)
        attroff(COLOR_PAIR(current_pair));

    if (fg_color != Color::Default or bg_color != Color::Default)
    {
        current_pair = get_color_pair(fg_color, bg_color);
        attron(COLOR_PAIR(current_pair));
    }
}

void on_term_resize(int)
{
    ungetch(KEY_RESIZE);
    EventManager::instance().force_signal(0);
}

void on_sigint(int)
{
    ungetch(CTRL('c'));
    EventManager::instance().force_signal(0);
}

NCursesUI::NCursesUI()
    : m_stdin_watcher{0, [this](FDWatcher&){ if (m_input_callback) m_input_callback(); }}
{
    //setlocale(LC_CTYPE, "");
    initscr();
    cbreak();
    noecho();
    nonl();
    intrflush(stdscr, false);
    keypad(stdscr, true);
    curs_set(0);
    start_color();
    use_default_colors();
    ESCDELAY=25;

    m_menu_fg = get_color_pair(Color::Blue, Color::Cyan);
    m_menu_bg = get_color_pair(Color::Cyan, Color::Blue);

    signal(SIGWINCH, on_term_resize);
    signal(SIGINT, on_sigint);

    update_dimensions();
}

NCursesUI::~NCursesUI()
{
    endwin();
    signal(SIGWINCH, SIG_DFL);
    signal(SIGINT, SIG_DFL);
}

static void redraw(WINDOW* menu_win, WINDOW* info_win)
{
    wnoutrefresh(stdscr);
    if (menu_win)
    {
        redrawwin(menu_win);
        wnoutrefresh(menu_win);
    }
    if (info_win)
    {
        redrawwin(info_win);
        wnoutrefresh(info_win);
    }
    doupdate();
}
using Utf8Policy = utf8::InvalidBytePolicy::Pass;
using Utf8Iterator = utf8::utf8_iterator<String::iterator, Utf8Policy>;
void addutf8str(WINDOW* win, Utf8Iterator begin, Utf8Iterator end)
{
    assert(begin <= end);
    while (begin != end)
        waddch(win, *begin++);
}

static DisplayCoord window_size(WINDOW* win)
{
    DisplayCoord size;
    getmaxyx(win, (int&)size.line, (int&)size.column);
    return size;
}

static DisplayCoord window_pos(WINDOW* win)
{
    DisplayCoord pos;
    getbegyx(win, (int&)pos.line, (int&)pos.column);
    return pos;
}

void NCursesUI::update_dimensions()
{
    m_dimensions = window_size(stdscr);
    --m_dimensions.line;
}

void NCursesUI::draw(const DisplayBuffer& display_buffer,
                     const String& mode_line)
{
    LineCount line_index = 0;
    for (const DisplayLine& line : display_buffer.lines())
    {
        move((int)line_index, 0);
        clrtoeol();
        CharCount col_index = 0;
        for (const DisplayAtom& atom : line)
        {
            set_attribute(A_UNDERLINE, atom.attribute & Underline);
            set_attribute(A_REVERSE, atom.attribute & Reverse);
            set_attribute(A_BLINK, atom.attribute & Blink);
            set_attribute(A_BOLD, atom.attribute & Bold);

            set_color(atom.fg_color, atom.bg_color);

            String content = atom.content.content();
            if (content[content.length()-1] == '\n' and
                content.char_length() - 1 < m_dimensions.column - col_index)
            {
                addutf8str(stdscr, Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
                addch(' ');
            }
            else
            {
                Utf8Iterator begin(content.begin()), end(content.end());
                if (end - begin > m_dimensions.column - col_index)
                    end = begin + (m_dimensions.column - col_index);
                addutf8str(stdscr, begin, end);
                col_index += end - begin;
            }
        }
        ++line_index;
    }

    set_attribute(A_UNDERLINE, 0);
    set_attribute(A_REVERSE, 0);
    set_attribute(A_BLINK, 0);
    set_attribute(A_BOLD, 0);
    set_color(Color::Blue, Color::Black);
    for (;line_index < m_dimensions.line; ++line_index)
    {
        move((int)line_index, 0);
        clrtoeol();
        addch('~');
    }

    set_color(Color::Cyan, Color::Default);
    draw_status();
    CharCount status_len = mode_line.char_length();
    // only draw mode_line if it does not overlap one status line
    if (m_dimensions.column - m_status_line.char_length() > status_len + 1)
    {
        move((int)m_dimensions.line, (int)(m_dimensions.column - status_len));
        addutf8str(stdscr, Utf8Iterator(mode_line.begin()),
                   Utf8Iterator(mode_line.end()));
    }
    redraw(m_menu_win, m_info_win);
}

struct getch_iterator
{
    int operator*() { return getch(); }
    getch_iterator& operator++() { return *this; }
    getch_iterator& operator++(int) { return *this; }
};

bool NCursesUI::is_key_available()
{
    timeout(0);
    const int c = getch();
    if (c != ERR)
        ungetch(c);
    timeout(-1);
    return c != ERR;
}

Key NCursesUI::get_key()
{
    const int c = getch();
    if (c > 0 and c < 27)
    {
        return {Key::Modifiers::Control, Codepoint(c) - 1 + 'a'};
    }
    else if (c == 27)
    {
        timeout(0);
        const Codepoint new_c = getch();
        timeout(-1);
        if (new_c != ERR)
            return {Key::Modifiers::Alt, new_c};
        else
            return Key::Escape;
    }
    else if (c == KEY_RESIZE)
    {
        int fd = open("/dev/tty", O_RDWR);
        winsize ws;
        if (fd != -1 and ioctl(fd, TIOCGWINSZ, (void*)&ws) == 0)
        {
            close(fd);
            resizeterm(ws.ws_row, ws.ws_col);
            update_dimensions();
        }
        return Key::Invalid;
    }
    else switch (c)
    {
    case KEY_BACKSPACE: case 127: return Key::Backspace;
    case KEY_UP: return Key::Up;
    case KEY_DOWN: return Key::Down;
    case KEY_LEFT: return Key::Left;
    case KEY_RIGHT: return Key::Right;
    case KEY_PPAGE: return Key::PageUp;
    case KEY_NPAGE: return Key::PageDown;
    case KEY_BTAB: return Key::BackTab;
    }

    if (c >= 0 and c < 256)
    {
       ungetch(c);
       return utf8::codepoint(getch_iterator{});
    }
    return Key::Invalid;
}

void NCursesUI::draw_status()
{
    move((int)m_dimensions.line, 0);
    clrtoeol();
    if (m_status_cursor == -1)
       addutf8str(stdscr, m_status_line.begin(), m_status_line.end());
    else
    {
        auto cursor_it = utf8::advance(m_status_line.begin(), m_status_line.end(),
                                       (int)m_status_cursor);
        auto end = m_status_line.end();
        addutf8str(stdscr, m_status_line.begin(), cursor_it);
        set_attribute(A_REVERSE, 1);
        addch((cursor_it == end) ? ' ' : utf8::codepoint<Utf8Policy>(cursor_it));
        set_attribute(A_REVERSE, 0);
        if (cursor_it != end)
            addutf8str(stdscr, utf8::next(cursor_it), end);
    }
}

void NCursesUI::print_status(const String& status, CharCount cursor_pos)
{
    m_status_line   = status;
    m_status_cursor = cursor_pos;
    draw_status();
    redraw(m_menu_win, m_info_win);
}

void NCursesUI::menu_show(const memoryview<String>& choices,
                          const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_menu == nullptr);
    assert(m_menu_win == nullptr);
    assert(m_choices.empty());
    assert(m_items.empty());

    DisplayCoord maxsize = window_size(stdscr);
    maxsize.column -= anchor.column;

    m_choices.reserve(choices.size());
    CharCount longest = 0;
    for (auto& choice : choices)
    {
        m_choices.push_back(choice.substr(0_char, std::min((int)maxsize.column-1, 200)));
        m_items.emplace_back(new_item(m_choices.back().c_str(), ""));
        longest = std::max(longest, m_choices.back().char_length());
    }
    m_items.push_back(nullptr);
    longest += 1;

    int columns = (style == MenuStyle::Prompt) ? (int)(maxsize.column / longest) : 1;
    int lines = std::min(10, (int)ceilf((float)m_choices.size()/columns));

    DisplayCoord pos = { anchor.line+1, anchor.column };
    if (pos.line + lines >= maxsize.line)
        pos.line = anchor.line - lines;
    DisplayCoord size = { lines, columns == 1 ? longest : maxsize.column };

    m_menu = new_menu(&m_items[0]);
    m_menu_win = newwin((int)size.line, (int)size.column,
                        (int)pos.line,  (int)pos.column);
    set_menu_win(m_menu, m_menu_win);
    set_menu_format(m_menu, lines, columns);
    set_menu_mark(m_menu, nullptr);
    set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
    set_menu_back(m_menu, COLOR_PAIR(m_menu_bg));
    post_menu(m_menu);
    redraw(m_menu_win, m_info_win);
}

void NCursesUI::menu_select(int selected)
{
    // last item in m_items is the nullptr, hence the - 1
    if (selected >= 0 and selected < m_items.size() - 1)
    {
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
        set_current_item(m_menu, m_items[selected]);
    }
    else
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_bg));
    redraw(m_menu_win, m_info_win);
}

void NCursesUI::menu_hide()
{
    if (not m_menu)
        return;
    unpost_menu(m_menu);
    free_menu(m_menu);
    for (auto item : m_items)
       if (item)
           free_item(item);
    m_menu = nullptr;
    delwin(m_menu_win);
    m_menu_win = nullptr;
    m_items.clear();
    m_choices.clear();
    redraw(m_menu_win, m_info_win);
}

static DisplayCoord compute_needed_size(const String& str)
{
    DisplayCoord res{1,0};
    CharCount line_len = 0;
    for (Utf8Iterator begin{str.begin()}, end{str.end()}; begin != end; ++begin)
    {
        if (*begin == '\n')
        {
            line_len = 0;
            ++res.line;
        }
        else
        {
            ++line_len;
            res.column = std::max(res.column, line_len);
        }
    }
    return res;
}

static DisplayCoord compute_pos(const DisplayCoord& anchor,
                                const DisplayCoord& size,
                                WINDOW* opt_window_to_avoid = nullptr)
{
    DisplayCoord scrsize = window_size(stdscr);
    DisplayCoord pos = { anchor.line+1, anchor.column };
    if (pos.line + size.line >= scrsize.line)
        pos.line = anchor.line - size.line;

    if (opt_window_to_avoid)
    {
        DisplayCoord winbeg = window_pos(opt_window_to_avoid);
        DisplayCoord winend = winbeg + window_size(opt_window_to_avoid);

        DisplayCoord end = pos + size;

        // check intersection
        if (not (end.line < winbeg.line or end.column < winbeg.column or
                 pos.line > winend.line or pos.column > winend.column))
        {
            pos.line = std::min(winbeg.line, anchor.line) - size.line;
            // if above does not work, try below
            if (pos.line < 0)
                pos.line = std::max(winend.line, anchor.line);
        }
    }

    return pos;
}

void NCursesUI::info_show(const String& content, const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_info_win == nullptr);

    DisplayCoord size = compute_needed_size(content);
    if (style == MenuStyle::Prompt)
        size.column = window_size(stdscr).column - anchor.column;

    DisplayCoord pos = compute_pos(anchor, size, m_menu_win);

    m_info_win = newwin((int)size.line, (int)size.column,
                        (int)pos.line,  (int)pos.column);

    wbkgd(m_info_win, COLOR_PAIR(get_color_pair(Color::Black, Color::Yellow)));
    wmove(m_info_win, 0, 0);
    addutf8str(m_info_win, Utf8Iterator(content.begin()),
               Utf8Iterator(content.end()));
    redraw(m_menu_win, m_info_win);
}

void NCursesUI::info_hide()
{
    if (not m_info_win)
        return;
    delwin(m_info_win);
    m_info_win = nullptr;
    redraw(m_menu_win, m_info_win);
}

DisplayCoord NCursesUI::dimensions()
{
    return m_dimensions;
}

void NCursesUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

}
<|endoftext|>


<commit_before>// Run
// Author: Matthew Raso-Barnett  08/10/2009

#include <iostream>
#include <sstream>
#include <cassert>
#include <stdexcept>

#include "Run.h"
#include "ConfigFile.h"
#include "FieldManager.h"
#include "Particle.h"
#include "Data.h"
#include "Clock.h"

#include "TFile.h"
#include "TRandom.h"

#include "Algorithms.h"
#include "Units.h"

using namespace std;

//#define VERBOSE_MODE

ClassImp(Run)

//_____________________________________________________________________________
Run::Run()
        :TNamed(),
         fRunConfig(),
         fData()
{
// -- Default constructor
   Info("Run", "Default Constructor");
   fExperiment = NULL;
}

//_____________________________________________________________________________
Run::Run(const RunConfig& runConfig)
        :TNamed(),
         fRunConfig(runConfig),
         fData()
{
// -- constructor
   Info("Run", "Constructor");
   this->SetName(this->GetRunConfig().RunName().c_str());
   fExperiment = new Experiment();
}

//_____________________________________________________________________________
Run::Run(const Run& other)
        :TNamed(other),
         fRunConfig(other.fRunConfig),
         fData(other.fData),
         fExperiment(other.fExperiment)
{
// -- Copy Constructor
   Info("RunManager", "Copy Constructor");
}

//_____________________________________________________________________________
Run& Run::operator=(const Run& other)
{
// --assignment operator
   if(this!=&other) {
      TNamed::operator=(other);
      fRunConfig = other.fRunConfig;
      fData = other.fData;
      // deallocate previous memory if necessary
      if (fExperiment != NULL) delete fExperiment; fExperiment = NULL;
      fExperiment = other.fExperiment;
   }
   return *this;
}

//______________________________________________________________________________
Run::~Run()
{
// -- Destructor
   Info("Run", "Destructor");
   if(fExperiment) delete fExperiment;
}

//_____________________________________________________________________________
Bool_t Run::Initialise()
{
   // -- Initialise the Run. Build the Experiment Object which loads the Geometry and fields
   // -- into memory. Build the Data Object which loads the data files and initial particles.
   // -- Finally check Run parameters in the RunConfig object for further instructions.
   cout << "-------------------------------------------" << endl;
   cout << "Initialising: " << this->GetName() << endl;
   cout << "-------------------------------------------" << endl;
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Setup the Clock
   if (Clock::Instance()->Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to initialise the Clock");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Build Geometry
   ///////////////////////////////////////////////////////////////////////////////////////
   if (fExperiment->Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to Build the Experiment");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Initialise the DataFile and load initial particles
   ///////////////////////////////////////////////////////////////////////////////////////
   if (this->GetData().Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to Load the Initial Particle Distribution from File");
      return kFALSE;
   }
   // -- Create any observers selected by user
   this->GetData().CreateObservers(this->GetRunConfig(), this->GetExperiment());
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Check Run Parameters
   // Run Time
   if (this->GetRunConfig().RunTime() <= 0.0) {
      Error("Initialise","No RunTime set");
      return kFALSE;
   }
   // Max Step Time
   if (this->GetRunConfig().MaxStepTime() <= 0.0) {
      Error("Initialise","No maxsteptime set!");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   cout << "-------------------------------------------" << endl;
   cout << "Run successfully initialised" << endl;
   cout << "Particles to propagate: " << this->GetData().InitialParticles() << endl;
   cout << "RunTime(s): " << this->GetRunConfig().RunTime() << endl;
   cout << "MaxStepTime(s): " << this->GetRunConfig().MaxStepTime() << endl;
   cout << "WallLosses: " << this->GetRunConfig().WallLossesOn() << endl;
   cout << "-------------------------------------------" << endl;
   return kTRUE;
}

//_____________________________________________________________________________
Bool_t Run::Start()
{
// -- Propagate the particles stored in the Run's Data, specified by configFile
   cout << "-------------------------------------------" << endl;
   cout << "Starting Simulation of " << this->GetRunConfig().RunName() << endl;
   cout << "Total Particles: " << this->GetData().InitialParticles() << endl;
   cout << "-------------------------------------------" << endl;
   Int_t totalParticles = this->GetData().InitialParticles();
   ///////////////////////////////////////////////////////////////////////
   // Loop over all particles stored in InitialParticles Tree
   for (Int_t index = 0; index < totalParticles; index++) {
      // Get Particle from list
      Particle* particle = this->GetData().RetrieveParticle(index);
      assert(particle != NULL);
      // Reset the clock
      Clock::Instance()->Reset();
      // Determine whether we are restoring to the start of a previously propagated track.
      // If so we want to set the Random Generator's seed back to what it was at the start of this
      // particle's propagation. This seed is stored (currently) in the particle itself. Otherwise
      // just store the seed in the new particle.
      if (particle->GetRandomSeed() == 0) {
         // Particle is 'new', store current random seed in particle
         particle->SetRandomSeed(gRandom->GetSeed());
      } else {
         // Particle is 'restored' -> seed must be restored too
         gRandom->SetSeed(particle->GetRandomSeed());
      }
      ///////////////////////////////////////////////////////////////////////
      // Attempt to Propagate track
      try {
         Bool_t propagated = particle->Propagate(this);
         if (!propagated) {
            Error("Start", "Propagation Failed to Begin.");
            return kFALSE;
         }
      } catch (...) {
         // Serious tracking errors (eg: particle cannot be located correctly) will be thrown
         #ifdef VERBOSE_MODE
            cout << "-------------------------------------------" << endl;
            Error("Start","Exception thrown by particle %i. Propagation Failed.", index);
            cout << "-------------------------------------------" << endl << endl;
         #endif
         // Add this particle to special tree for errorneous particles
         particle->SaveState(this);
         delete particle;
         continue;
      }
      ///////////////////////////////////////////////////////////////////////
      // Add Final Particle State to data tree
      particle->SaveState(this);
      // Print Progress Bar to Screen
      #ifndef VERBOSE_MODE
         Algorithms::ProgressBar::PrintProgress(index, totalParticles, 2);
      #endif
      // Delete Particle
//      delete particle;
   }
   ///////////////////////////////////////////////////////////////////////
   cout << "-------------------------------------------" << endl;
   cout << "Propagation Results: " << endl;
   cout << "Total Particles: " << this->GetData().FinalParticles() << endl;
   cout << "Number Still Propagating: " << this->GetData().PropagatingParticles() << endl;
   cout << "Number Detected: " << this->GetData().DetectedParticles() << endl;
   cout << "Number Absorbed by Boundary: " << this->GetData().AbsorbedParticles() << endl;
   cout << "Number Decayed: " << this->GetData().DecayedParticles() << endl;
   cout << "Number Lost To Outer Geometry: " << this->GetData().LostParticles() << endl;
   cout << "Number With Anomalous Behaviour: " << this->GetData().AnomalousParticles() << endl;
   cout << "-------------------------------------------" << endl;
   return kTRUE;
}

//_____________________________________________________________________________
Bool_t Run::Finish()
{
   // -- Clean up the Run before exporting it to file
   // Check that Data 'checks out'
   if (this->GetData().ChecksOut() == kFALSE) {
      Error("Finish", "Number of initial states doesn't match final states.");
      return kFALSE;
   }
   // Write the Particle Tree to file
   this->GetData().ExportData();
   // Write the geometry out to file
   fExperiment->ExportGeometry(*this);
   // Delete the experiment
   if (fExperiment) delete fExperiment; fExperiment = NULL;
   return kTRUE;
}

<commit_msg>Fix setting Run name in constructor<commit_after>// Run
// Author: Matthew Raso-Barnett  08/10/2009

#include <iostream>
#include <sstream>
#include <cassert>
#include <stdexcept>

#include "Run.h"
#include "ConfigFile.h"
#include "FieldManager.h"
#include "Particle.h"
#include "Data.h"
#include "Clock.h"

#include "TFile.h"
#include "TRandom.h"

#include "Algorithms.h"
#include "Units.h"

using namespace std;

//#define VERBOSE_MODE

ClassImp(Run)

//_____________________________________________________________________________
Run::Run()
        :TNamed(),
         fRunConfig(),
         fData()
{
// -- Default constructor
   Info("Run", "Default Constructor");
   fExperiment = NULL;
}

//_____________________________________________________________________________
Run::Run(const RunConfig& runConfig)
        :TNamed(runConfig.RunName().c_str(), "The Run"),
         fRunConfig(runConfig),
         fData()
{
// -- constructor
   Info("Run", "Constructor");
   this->SetName(this->GetRunConfig().RunName().c_str());
   fExperiment = new Experiment();
}

//_____________________________________________________________________________
Run::Run(const Run& other)
        :TNamed(other),
         fRunConfig(other.fRunConfig),
         fData(other.fData),
         fExperiment(other.fExperiment)
{
// -- Copy Constructor
   Info("RunManager", "Copy Constructor");
}

//_____________________________________________________________________________
Run& Run::operator=(const Run& other)
{
// --assignment operator
   if(this!=&other) {
      TNamed::operator=(other);
      fRunConfig = other.fRunConfig;
      fData = other.fData;
      // deallocate previous memory if necessary
      if (fExperiment != NULL) delete fExperiment; fExperiment = NULL;
      fExperiment = other.fExperiment;
   }
   return *this;
}

//______________________________________________________________________________
Run::~Run()
{
// -- Destructor
   Info("Run", "Destructor");
   if(fExperiment) delete fExperiment;
}

//_____________________________________________________________________________
Bool_t Run::Initialise()
{
   // -- Initialise the Run. Build the Experiment Object which loads the Geometry and fields
   // -- into memory. Build the Data Object which loads the data files and initial particles.
   // -- Finally check Run parameters in the RunConfig object for further instructions.
   cout << "-------------------------------------------" << endl;
   cout << "Initialising: " << this->GetName() << endl;
   cout << "-------------------------------------------" << endl;
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Setup the Clock
   if (Clock::Instance()->Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to initialise the Clock");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Build Geometry
   ///////////////////////////////////////////////////////////////////////////////////////
   if (fExperiment->Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to Build the Experiment");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Initialise the DataFile and load initial particles
   ///////////////////////////////////////////////////////////////////////////////////////
   if (this->GetData().Initialise(this->GetRunConfig()) == kFALSE) {
      Error("Initialise","Failed to Load the Initial Particle Distribution from File");
      return kFALSE;
   }
   // -- Create any observers selected by user
   this->GetData().CreateObservers(this->GetRunConfig(), this->GetExperiment());
   ///////////////////////////////////////////////////////////////////////////////////////
   // -- Check Run Parameters
   // Run Time
   if (this->GetRunConfig().RunTime() <= 0.0) {
      Error("Initialise","No RunTime set");
      return kFALSE;
   }
   // Max Step Time
   if (this->GetRunConfig().MaxStepTime() <= 0.0) {
      Error("Initialise","No maxsteptime set!");
      return kFALSE;
   }
   ///////////////////////////////////////////////////////////////////////////////////////
   cout << "-------------------------------------------" << endl;
   cout << "Run successfully initialised" << endl;
   cout << "Particles to propagate: " << this->GetData().InitialParticles() << endl;
   cout << "RunTime(s): " << this->GetRunConfig().RunTime() << endl;
   cout << "MaxStepTime(s): " << this->GetRunConfig().MaxStepTime() << endl;
   cout << "WallLosses: " << this->GetRunConfig().WallLossesOn() << endl;
   cout << "-------------------------------------------" << endl;
   return kTRUE;
}

//_____________________________________________________________________________
Bool_t Run::Start()
{
// -- Propagate the particles stored in the Run's Data, specified by configFile
   cout << "-------------------------------------------" << endl;
   cout << "Starting Simulation of " << this->GetRunConfig().RunName() << endl;
   cout << "Total Particles: " << this->GetData().InitialParticles() << endl;
   cout << "-------------------------------------------" << endl;
   Int_t totalParticles = this->GetData().InitialParticles();
   ///////////////////////////////////////////////////////////////////////
   // Loop over all particles stored in InitialParticles Tree
   for (Int_t index = 0; index < totalParticles; index++) {
      // Get Particle from list
      Particle* particle = this->GetData().RetrieveParticle(index);
      assert(particle != NULL);
      // Reset the clock
      Clock::Instance()->Reset();
      // Determine whether we are restoring to the start of a previously propagated track.
      // If so we want to set the Random Generator's seed back to what it was at the start of this
      // particle's propagation. This seed is stored (currently) in the particle itself. Otherwise
      // just store the seed in the new particle.
      if (particle->GetRandomSeed() == 0) {
         // Particle is 'new', store current random seed in particle
         particle->SetRandomSeed(gRandom->GetSeed());
      } else {
         // Particle is 'restored' -> seed must be restored too
         gRandom->SetSeed(particle->GetRandomSeed());
      }
      ///////////////////////////////////////////////////////////////////////
      // Attempt to Propagate track
      try {
         Bool_t propagated = particle->Propagate(this);
         if (!propagated) {
            Error("Start", "Propagation Failed to Begin.");
            return kFALSE;
         }
      } catch (...) {
         // Serious tracking errors (eg: particle cannot be located correctly) will be thrown
         #ifdef VERBOSE_MODE
            cout << "-------------------------------------------" << endl;
            Error("Start","Exception thrown by particle %i. Propagation Failed.", index);
            cout << "-------------------------------------------" << endl << endl;
         #endif
         // Add this particle to special tree for errorneous particles
         particle->SaveState(this);
         delete particle;
         continue;
      }
      ///////////////////////////////////////////////////////////////////////
      // Add Final Particle State to data tree
      particle->SaveState(this);
      // Print Progress Bar to Screen
      #ifndef VERBOSE_MODE
         Algorithms::ProgressBar::PrintProgress(index, totalParticles, 2);
      #endif
      // Delete Particle
//      delete particle;
   }
   ///////////////////////////////////////////////////////////////////////
   cout << "-------------------------------------------" << endl;
   cout << "Propagation Results: " << endl;
   cout << "Total Particles: " << this->GetData().FinalParticles() << endl;
   cout << "Number Still Propagating: " << this->GetData().PropagatingParticles() << endl;
   cout << "Number Detected: " << this->GetData().DetectedParticles() << endl;
   cout << "Number Absorbed by Boundary: " << this->GetData().AbsorbedParticles() << endl;
   cout << "Number Decayed: " << this->GetData().DecayedParticles() << endl;
   cout << "Number Lost To Outer Geometry: " << this->GetData().LostParticles() << endl;
   cout << "Number With Anomalous Behaviour: " << this->GetData().AnomalousParticles() << endl;
   cout << "-------------------------------------------" << endl;
   return kTRUE;
}

//_____________________________________________________________________________
Bool_t Run::Finish()
{
   // -- Clean up the Run before exporting it to file
   // Check that Data 'checks out'
   if (this->GetData().ChecksOut() == kFALSE) {
      Error("Finish", "Number of initial states doesn't match final states.");
      return kFALSE;
   }
   // Write the Particle Tree to file
   this->GetData().ExportData();
   // Write the geometry out to file
   fExperiment->ExportGeometry(*this);
   // Delete the experiment
   if (fExperiment) delete fExperiment; fExperiment = NULL;
   return kTRUE;
}

<|endoftext|>


<commit_before>//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Sergey Gorbunov <sergey.gorbunov@cern.ch>             *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/** @file   AliHLTTPCFastTransform.cxx
    @author Sergey Gorbubnov
    @date
    @brief
*/

#include "AliHLTTPCFastTransform.h"
#include "AliTPCTransform.h"
#include "AliTPCParam.h"
#include "AliTPCcalibDB.h"

#include <iostream>
#include <iomanip>

using namespace std;

ClassImp(AliHLTTPCFastTransform); //ROOT macro for the implementation of ROOT specific class methods

AliHLTTPCFastTransform* AliHLTTPCFastTransform::fgInstance = 0;

void AliHLTTPCFastTransform::Terminate()
{
  //
  // Singleton implementation
  // Deletes the instance of this class and sets the terminated flag, instances cannot be requested anymore
  // This function can be called several times.
  //

  if( fgInstance ){
    delete fgInstance;
    fgInstance = 0;
  }
}

AliHLTTPCFastTransform::AliHLTTPCFastTransform()
:
  fOrigTransform(0),
  fLastTimeStamp(-1),
  fLastTimeBin(600),
  fTimeBorder1(100),
  fTimeBorder2(500)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
  for( Int_t i=0; i<72; i++)
    for( Int_t j=0; j<100; j++ ) fRows[i][j] = 0;
  Init();
}

AliHLTTPCFastTransform::~AliHLTTPCFastTransform()
{
  // see header file for class documentation
  for( Int_t i=0; i<72; i++)
    for( Int_t j=0; j<100; j++ ) delete fRows[i][j];

  if( fgInstance == this ) fgInstance = 0;
}

Int_t  AliHLTTPCFastTransform::Init( AliTPCTransform *transform, Int_t TimeStamp )
{
  // Initialisation

  if( !transform ){
    AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
    if(!pCalib ) return 1;
    transform = pCalib->GetTransform();
  }

  if( fOrigTransform != transform ){
    fOrigTransform = transform;
    fLastTimeStamp = -1;
  }

  SetCurrentTimeStamp( TimeStamp );
  return 0;
}

void AliHLTTPCFastTransform::SetCurrentTimeStamp( Int_t TimeStamp )
{
  // Set the current time stamp
  if( fLastTimeStamp>=0 && TMath::Abs(fLastTimeStamp - TimeStamp ) <60 ) return;

  if( !fOrigTransform ) return;

  if( TimeStamp>=0 ){
    fOrigTransform->SetCurrentTimeStamp( TimeStamp );
    fLastTimeStamp = TimeStamp;
  } else fLastTimeStamp = fOrigTransform->GetCurrentTimeStamp();

  AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
  if(!pCalib ) return ;

  AliTPCParam *par = pCalib->GetParameters();
  if( !par ) return ;

  // find last calibrated time bin

  Int_t nTimeBins = par->GetMaxTBin();
  Int_t is[]={0};
  bool sign = 0;
  for( fLastTimeBin=0; fLastTimeBin<nTimeBins; fLastTimeBin++){
    Double_t xx[]={0,0,fLastTimeBin};
    fOrigTransform->Transform(xx,is,0,1);
    bool s = (xx[2]>=0);
    if( fLastTimeBin==0 ) sign = s;
    else if( sign!=s ){
      fLastTimeBin--;
      break;
    }
  }
  fTimeBorder1 = 60;
  fTimeBorder2 = fLastTimeBin - 100;

  for( Int_t i=0; i<72; i++ )
    for( Int_t j=0; j<100; j++ ) if( fRows[i][j] ) InitRow(i,j);
}

Int_t AliHLTTPCFastTransform::InitRow( Int_t iSector, Int_t iRow )
{
  // see header file for class documentation

  if( iSector<0 || iSector>=72 || iRow<0 || iRow>=100 || !fOrigTransform) return 1;

  AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
  if(!pCalib ) return 1;

  AliTPCParam *par = pCalib->GetParameters();
  if( !par ) return 1;

  Int_t nPads = par->GetNPads(iSector,iRow);

  if( !fRows[iSector][iRow] ){
    fRows[iSector][iRow] = new AliHLTTPCFastTransform::AliRowTransform;
  }

  fRows[iSector][iRow]->fSpline[0].Init(         0.5, nPads-1+0.5, 15, 0,  fTimeBorder1,         5);
  fRows[iSector][iRow]->fSpline[1].Init(         0.5, nPads-1+0.5, 15, fTimeBorder1, fTimeBorder2,         10);
  fRows[iSector][iRow]->fSpline[2].Init(         0.5, nPads-1+0.5, 15, fTimeBorder2, fLastTimeBin,         5);

  for( Int_t i=0; i<3; i++){
    Int_t is[]={iSector};
    for( Int_t j=0; j<fRows[iSector][iRow]->fSpline[i].GetNPoints(); j++){
      Float_t pad, time;
      fRows[iSector][iRow]->fSpline[i].GetAB(j,pad,time);
      Double_t xx[]={iRow,pad,time};
      fOrigTransform->Transform(xx,is,0,1);
      fRows[iSector][iRow]->fSpline[i].Fill(j,xx);
    }
  }
  return 0;
}

Int_t AliHLTTPCFastTransform::GetRowSize( Int_t iSec, Int_t iRow ) const
{
  // see header file for class documentation
  Int_t s = sizeof(AliHLTTPCFastTransform::AliRowTransform);
  if( fRows[iSec][iRow] ) for( Int_t i=0; i<3; i++) s+=fRows[iSec][iRow]->fSpline[i].GetMapSize();
  return s;
}

Int_t AliHLTTPCFastTransform::GetSize() const
{
  // see header file for class documentation
  Int_t s = sizeof(AliHLTTPCFastTransform);
  for( Int_t i=0; i<72; i++ )
    for( Int_t j=0; j<100; j++ ) if( fRows[i][j] ){
	s+= sizeof(AliHLTTPCFastTransform::AliRowTransform);
	for( Int_t k=0; k<3; k++) fRows[i][j]->fSpline[i].GetMapSize();
      }
  return s;
}
<commit_msg>coverity fix<commit_after>//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Sergey Gorbunov <sergey.gorbunov@cern.ch>             *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/** @file   AliHLTTPCFastTransform.cxx
    @author Sergey Gorbubnov
    @date
    @brief
*/

#include "AliHLTTPCFastTransform.h"
#include "AliTPCTransform.h"
#include "AliTPCParam.h"
#include "AliTPCcalibDB.h"

#include <iostream>
#include <iomanip>

using namespace std;

ClassImp(AliHLTTPCFastTransform); //ROOT macro for the implementation of ROOT specific class methods

AliHLTTPCFastTransform* AliHLTTPCFastTransform::fgInstance = 0;

void AliHLTTPCFastTransform::Terminate()
{
  //
  // Singleton implementation
  // Deletes the instance of this class and sets the terminated flag, instances cannot be requested anymore
  // This function can be called several times.
  //

  if( fgInstance ){
    delete fgInstance;
    fgInstance = 0;
  }
}

AliHLTTPCFastTransform::AliHLTTPCFastTransform()
:
  fOrigTransform(0),
  fLastTimeStamp(-1),
  fLastTimeBin(600),
  fTimeBorder1(100),
  fTimeBorder2(500)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
  for( Int_t i=0; i<72; i++)
    for( Int_t j=0; j<100; j++ ) fRows[i][j] = 0;
  Init();
}

AliHLTTPCFastTransform::~AliHLTTPCFastTransform()
{
  // see header file for class documentation
  for( Int_t i=0; i<72; i++)
    for( Int_t j=0; j<100; j++ ) delete fRows[i][j];

  if( fgInstance == this ) fgInstance = 0;
}

Int_t  AliHLTTPCFastTransform::Init( AliTPCTransform *transform, Int_t TimeStamp )
{
  // Initialisation

  if( !transform ){
    AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
    if(!pCalib ) return 1;
    transform = pCalib->GetTransform();
  }

  if( fOrigTransform != transform ){
    fOrigTransform = transform;
    fLastTimeStamp = -1;
  }

  SetCurrentTimeStamp( TimeStamp );
  return 0;
}

void AliHLTTPCFastTransform::SetCurrentTimeStamp( Int_t TimeStamp )
{
  // Set the current time stamp
  if( fLastTimeStamp>=0 && TMath::Abs(fLastTimeStamp - TimeStamp ) <60 ) return;

  if( !fOrigTransform ) return;

  if( TimeStamp>=0 ){
    fOrigTransform->SetCurrentTimeStamp( TimeStamp );
    fLastTimeStamp = TimeStamp;
  } else fLastTimeStamp = fOrigTransform->GetCurrentTimeStamp();

  AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
  if(!pCalib ) return ;

  AliTPCParam *par = pCalib->GetParameters();
  if( !par ) return ;

  // find last calibrated time bin

  Int_t nTimeBins = par->GetMaxTBin();
  Int_t is[]={0};
  bool sign = 0;
  for( fLastTimeBin=0; fLastTimeBin<nTimeBins; fLastTimeBin++){
    Double_t xx[]={0,0,fLastTimeBin};
    fOrigTransform->Transform(xx,is,0,1);
    bool s = (xx[2]>=0);
    if( fLastTimeBin==0 ) sign = s;
    else if( sign!=s ){
      fLastTimeBin--;
      break;
    }
  }
  fTimeBorder1 = 60;
  fTimeBorder2 = fLastTimeBin - 100;

  for( Int_t i=0; i<72; i++ )
    for( Int_t j=0; j<100; j++ ) if( fRows[i][j] ) InitRow(i,j);
}

Int_t AliHLTTPCFastTransform::InitRow( Int_t iSector, Int_t iRow )
{
  // see header file for class documentation

  if( iSector<0 || iSector>=72 || iRow<0 || iRow>=100 || !fOrigTransform) return 1;

  AliTPCcalibDB* pCalib=AliTPCcalibDB::Instance();
  if(!pCalib ) return 1;

  AliTPCParam *par = pCalib->GetParameters();
  if( !par ) return 1;

  Int_t nPads = par->GetNPads(iSector,iRow);

  if( !fRows[iSector][iRow] ){
    fRows[iSector][iRow] = new AliHLTTPCFastTransform::AliRowTransform;
  }

  fRows[iSector][iRow]->fSpline[0].Init(         0.5, nPads-1+0.5, 15, 0,  fTimeBorder1,         5);
  fRows[iSector][iRow]->fSpline[1].Init(         0.5, nPads-1+0.5, 15, fTimeBorder1, fTimeBorder2,         10);
  fRows[iSector][iRow]->fSpline[2].Init(         0.5, nPads-1+0.5, 15, fTimeBorder2, fLastTimeBin,         5);

  for( Int_t i=0; i<3; i++){
    Int_t is[]={iSector};
    for( Int_t j=0; j<fRows[iSector][iRow]->fSpline[i].GetNPoints(); j++){
      Float_t pad, time;
      fRows[iSector][iRow]->fSpline[i].GetAB(j,pad,time);
      Double_t xx[]={iRow,pad,time};
      fOrigTransform->Transform(xx,is,0,1);
      fRows[iSector][iRow]->fSpline[i].Fill(j,xx);
    }
  }
  return 0;
}

Int_t AliHLTTPCFastTransform::GetRowSize( Int_t iSec, Int_t iRow ) const
{
  // see header file for class documentation
  Int_t s = sizeof(AliHLTTPCFastTransform::AliRowTransform);
  if( fRows[iSec][iRow] ) for( Int_t i=0; i<3; i++) s+=fRows[iSec][iRow]->fSpline[i].GetMapSize();
  return s;
}

Int_t AliHLTTPCFastTransform::GetSize() const
{
  // see header file for class documentation
  Int_t s = sizeof(AliHLTTPCFastTransform);
  for( Int_t i=0; i<72; i++ )
    for( Int_t j=0; j<100; j++ ) if( fRows[i][j] ){
	s+= sizeof(AliHLTTPCFastTransform::AliRowTransform);
	for( Int_t k=0; k<3; k++) fRows[i][j]->fSpline[k].GetMapSize();
      }
  return s;
}
<|endoftext|>


<commit_before>#ifndef keymap_manager_hh_INCLUDED
#define keymap_manager_hh_INCLUDED

#include "keys.hh"
#include "utils.hh"

#include <unordered_map>

namespace Kakoune
{

enum class KeymapMode : int
{
    None,
    Normal,
    Insert,
    Prompt,
    Menu
};

class KeymapManager
{
public:
    KeymapManager(KeymapManager& parent) : m_parent(&parent) {}

    void map_key(Key key, KeymapMode mode, std::vector<Key> mapping);
    void unmap_key(Key key, KeymapMode mode);

    bool is_mapped(Key key, KeymapMode mode) const;
    memoryview<Key> get_mapping(Key key, KeymapMode mode) const;
private:
    KeymapManager()
        : m_parent(nullptr) {}
    // the only one allowed to construct a root map manager
    friend class GlobalKeymaps;

    KeymapManager* m_parent;

    using Keymap = std::unordered_map<std::pair<Key, KeymapMode>, std::vector<Key>>;
    Keymap m_mapping;
};

class GlobalKeymaps : public KeymapManager,
                      public Singleton<GlobalKeymaps>
{
};

}

#endif // keymap_manager_hh_INCLUDED

<commit_msg>minor style tweak<commit_after>#ifndef keymap_manager_hh_INCLUDED
#define keymap_manager_hh_INCLUDED

#include "keys.hh"
#include "utils.hh"

#include <unordered_map>

namespace Kakoune
{

enum class KeymapMode : int
{
    None,
    Normal,
    Insert,
    Prompt,
    Menu
};

class KeymapManager
{
public:
    KeymapManager(KeymapManager& parent) : m_parent(&parent) {}

    void map_key(Key key, KeymapMode mode, std::vector<Key> mapping);
    void unmap_key(Key key, KeymapMode mode);

    bool is_mapped(Key key, KeymapMode mode) const;
    memoryview<Key> get_mapping(Key key, KeymapMode mode) const;
private:
    KeymapManager()
        : m_parent(nullptr) {}
    // the only one allowed to construct a root map manager
    friend class GlobalKeymaps;

    KeymapManager* m_parent;

    using KeyList = std::vector<Key>;
    using Keymap = std::unordered_map<std::pair<Key, KeymapMode>, KeyList>;
    Keymap m_mapping;
};

class GlobalKeymaps : public KeymapManager,
                      public Singleton<GlobalKeymaps>
{
};

}

#endif // keymap_manager_hh_INCLUDED

<|endoftext|>


<commit_before>/*
 * Copyright 2014 Matthew Harvey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "day_command.hpp"
#include "command.hpp"
#include "help_line.hpp"
#include "reporting_command.hpp"
#include "time_point.hpp"
#include <ostream>
#include <sstream>
#include <string>
#include <vector>

using std::ostream;
using std::ostringstream;
using std::string;
using std::vector;

namespace swx
{

namespace
{
	int const k_max_days_ago = 9;

	string days_ago_pluralized(int days)
	{
		if (days == 1)
		{
			return "yesterday";
		}
		ostringstream oss;
		oss << days << " days ago";
		return oss.str();
	}
}

DayCommand::DayCommand
(	string const& p_command_word,
	vector<string> const& p_aliases,
	TimeLog& p_time_log
):
	ReportingCommand
	(	p_command_word,
		p_aliases,
		"Print summary of today's activities",
		vector<HelpLine>
		{	HelpLine("Print summary of time spent on all activities today"),
			HelpLine
			(	"Print summary of time spent on ACTIVITY today",
				"ACTIVITY"
			)
		},
		p_time_log
	)
{
	string const s("Instead of today's activities, print the activities from ");
	for (int i = 1; i <= k_max_days_ago; ++i)
	{
		add_boolean_option
		(	static_cast<char>(i + '0'),
			s + days_ago_pluralized(i)
		);
	}
}

DayCommand::~DayCommand()
{
}

Command::ErrorMessages
DayCommand::do_process
(	ParsedArguments const& p_args,
	ostream& p_ordinary_ostream
)
{
	ErrorMessages ret;
	TimePoint const n = now();

	int days_ago = 0;
	for (int i = 1; i <= k_max_days_ago; ++i)
	{
		if (p_args.has_flag(static_cast<char>(i + '0'))) days_ago = i;
	}
	auto const b = day_begin(n, -days_ago);
	auto const e = day_end(n, -days_ago);
	print_report
	(	p_ordinary_ostream,
		p_args.single_character_flags(),
		p_args.ordinary_args(),
		&b,
		&e
	);
	return ret;
}

}  // namespace swx
<commit_msg>Adjust help output for "day" command.<commit_after>/*
 * Copyright 2014 Matthew Harvey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "day_command.hpp"
#include "command.hpp"
#include "help_line.hpp"
#include "reporting_command.hpp"
#include "time_point.hpp"
#include <ostream>
#include <sstream>
#include <string>
#include <vector>

using std::ostream;
using std::ostringstream;
using std::string;
using std::vector;

namespace swx
{

namespace
{
	int const k_max_days_ago = 9;

	string days_ago_pluralized(int days)
	{
		if (days == 1)
		{
			return "yesterday";
		}
		ostringstream oss;
		oss << days << " days ago";
		return oss.str();
	}
}

DayCommand::DayCommand
(	string const& p_command_word,
	vector<string> const& p_aliases,
	TimeLog& p_time_log
):
	ReportingCommand
	(	p_command_word,
		p_aliases,
		"Print summary of a single day's activities",
		vector<HelpLine>
		{	HelpLine("Print summary of time spent on all activities today"),
			HelpLine
			(	"Print summary of time spent on ACTIVITY today",
				"ACTIVITY"
			)
		},
		p_time_log
	)
{
	string const s("Instead of today's activities, print the activities from ");
	for (int i = 1; i <= k_max_days_ago; ++i)
	{
		add_boolean_option
		(	static_cast<char>(i + '0'),
			s + days_ago_pluralized(i)
		);
	}
}

DayCommand::~DayCommand()
{
}

Command::ErrorMessages
DayCommand::do_process
(	ParsedArguments const& p_args,
	ostream& p_ordinary_ostream
)
{
	ErrorMessages ret;
	TimePoint const n = now();

	int days_ago = 0;
	for (int i = 1; i <= k_max_days_ago; ++i)
	{
		if (p_args.has_flag(static_cast<char>(i + '0'))) days_ago = i;
	}
	auto const b = day_begin(n, -days_ago);
	auto const e = day_end(n, -days_ago);
	print_report
	(	p_ordinary_ostream,
		p_args.single_character_flags(),
		p_args.ordinary_args(),
		&b,
		&e
	);
	return ret;
}

}  // namespace swx
<|endoftext|>


<commit_before>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// stackwalker.cc: Generic stackwalker.
//
// See stackwalker.h for documentation.
//
// Author: Mark Mentovai

#include <cassert>

#include "google_breakpad/processor/stackwalker.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/code_module.h"
#include "google_breakpad/processor/code_modules.h"
#include "google_breakpad/processor/minidump.h"
#include "google_breakpad/processor/source_line_resolver_interface.h"
#include "google_breakpad/processor/stack_frame.h"
#include "google_breakpad/processor/symbol_supplier.h"
#include "processor/linked_ptr.h"
#include "processor/scoped_ptr.h"
#include "processor/stack_frame_info.h"
#include "processor/stackwalker_ppc.h"
#include "processor/stackwalker_x86.h"

namespace google_breakpad {

Stackwalker::Stackwalker(const SystemInfo *system_info,
                         MemoryRegion *memory,
                         const CodeModules *modules,
                         SymbolSupplier *supplier,
                         SourceLineResolverInterface *resolver)
    : system_info_(system_info),
      memory_(memory),
      modules_(modules),
      supplier_(supplier),
      resolver_(resolver) {
}

bool Stackwalker::Walk(CallStack *stack) {
  assert(stack);
  stack->Clear();

  // stack_frame_info parallels the CallStack.  The vector is passed to the
  // GetCallerFrame function.  It contains information that may be helpful
  // for stackwalking.
  vector< linked_ptr<StackFrameInfo> > stack_frame_info;

  // Begin with the context frame, and keep getting callers until there are
  // no more.

  // Take ownership of the pointer returned by GetContextFrame.
  scoped_ptr<StackFrame> frame(GetContextFrame());

  while (frame.get()) {
    // frame already contains a good frame with properly set instruction and
    // frame_pointer fields.  The frame structure comes from either the
    // context frame (above) or a caller frame (below).

    linked_ptr<StackFrameInfo> frame_info;

    // Resolve the module information, if a module map was provided.
    if (modules_) {
      const CodeModule *module =
          modules_->GetModuleForAddress(frame->instruction);
      if (module) {
        frame->module = module;
        if (resolver_ &&
            !resolver_->HasModule(frame->module->code_file()) &&
            supplier_) {
          string symbol_file;
          SymbolSupplier::SymbolResult symbol_result =
              supplier_->GetSymbolFile(module, system_info_, &symbol_file);

          switch (symbol_result) {
            case SymbolSupplier::FOUND:
              resolver_->LoadModule(frame->module->code_file(), symbol_file);
              break;
            case SymbolSupplier::NOT_FOUND:
              break;  // nothing to do
            case SymbolSupplier::INTERRUPT:
              return false;
          }
        }
        frame_info.reset(resolver_->FillSourceLineInfo(frame.get()));
      }
    }

    // Add the frame to the call stack.  Relinquish the ownership claim
    // over the frame, because the stack now owns it.
    stack->frames_.push_back(frame.release());

    // Add the frame info to the parallel stack.
    stack_frame_info.push_back(frame_info);
    frame_info.reset(NULL);

    // Get the next frame and take ownership.
    frame.reset(GetCallerFrame(stack, stack_frame_info));
  }

  return true;
}

// static
Stackwalker* Stackwalker::StackwalkerForCPU(
    const SystemInfo *system_info,
    MinidumpContext *context,
    MemoryRegion *memory,
    const CodeModules *modules,
    SymbolSupplier *supplier,
    SourceLineResolverInterface *resolver) {
  Stackwalker *cpu_stackwalker = NULL;

  u_int32_t cpu = context->GetContextCPU();
  switch (cpu) {
    case MD_CONTEXT_X86:
      cpu_stackwalker = new StackwalkerX86(system_info,
                                           context->GetContextX86(),
                                           memory, modules, supplier,
                                           resolver);
      break;

    case MD_CONTEXT_PPC:
      cpu_stackwalker = new StackwalkerPPC(system_info,
                                           context->GetContextPPC(),
                                           memory, modules, supplier,
                                           resolver);
      break;
  }

  return cpu_stackwalker;
}

}  // namespace google_breakpad
<commit_msg>Minidump without context crashes the processor (#153).  r=bryner<commit_after>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// stackwalker.cc: Generic stackwalker.
//
// See stackwalker.h for documentation.
//
// Author: Mark Mentovai

#include <cassert>

#include "google_breakpad/processor/stackwalker.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/code_module.h"
#include "google_breakpad/processor/code_modules.h"
#include "google_breakpad/processor/minidump.h"
#include "google_breakpad/processor/source_line_resolver_interface.h"
#include "google_breakpad/processor/stack_frame.h"
#include "google_breakpad/processor/symbol_supplier.h"
#include "processor/linked_ptr.h"
#include "processor/scoped_ptr.h"
#include "processor/stack_frame_info.h"
#include "processor/stackwalker_ppc.h"
#include "processor/stackwalker_x86.h"

namespace google_breakpad {

Stackwalker::Stackwalker(const SystemInfo *system_info,
                         MemoryRegion *memory,
                         const CodeModules *modules,
                         SymbolSupplier *supplier,
                         SourceLineResolverInterface *resolver)
    : system_info_(system_info),
      memory_(memory),
      modules_(modules),
      supplier_(supplier),
      resolver_(resolver) {
}

bool Stackwalker::Walk(CallStack *stack) {
  assert(stack);
  stack->Clear();

  // stack_frame_info parallels the CallStack.  The vector is passed to the
  // GetCallerFrame function.  It contains information that may be helpful
  // for stackwalking.
  vector< linked_ptr<StackFrameInfo> > stack_frame_info;

  // Begin with the context frame, and keep getting callers until there are
  // no more.

  // Take ownership of the pointer returned by GetContextFrame.
  scoped_ptr<StackFrame> frame(GetContextFrame());

  while (frame.get()) {
    // frame already contains a good frame with properly set instruction and
    // frame_pointer fields.  The frame structure comes from either the
    // context frame (above) or a caller frame (below).

    linked_ptr<StackFrameInfo> frame_info;

    // Resolve the module information, if a module map was provided.
    if (modules_) {
      const CodeModule *module =
          modules_->GetModuleForAddress(frame->instruction);
      if (module) {
        frame->module = module;
        if (resolver_ &&
            !resolver_->HasModule(frame->module->code_file()) &&
            supplier_) {
          string symbol_file;
          SymbolSupplier::SymbolResult symbol_result =
              supplier_->GetSymbolFile(module, system_info_, &symbol_file);

          switch (symbol_result) {
            case SymbolSupplier::FOUND:
              resolver_->LoadModule(frame->module->code_file(), symbol_file);
              break;
            case SymbolSupplier::NOT_FOUND:
              break;  // nothing to do
            case SymbolSupplier::INTERRUPT:
              return false;
          }
        }
        frame_info.reset(resolver_->FillSourceLineInfo(frame.get()));
      }
    }

    // Add the frame to the call stack.  Relinquish the ownership claim
    // over the frame, because the stack now owns it.
    stack->frames_.push_back(frame.release());

    // Add the frame info to the parallel stack.
    stack_frame_info.push_back(frame_info);
    frame_info.reset(NULL);

    // Get the next frame and take ownership.
    frame.reset(GetCallerFrame(stack, stack_frame_info));
  }

  return true;
}

// static
Stackwalker* Stackwalker::StackwalkerForCPU(
    const SystemInfo *system_info,
    MinidumpContext *context,
    MemoryRegion *memory,
    const CodeModules *modules,
    SymbolSupplier *supplier,
    SourceLineResolverInterface *resolver) {
  if (!context)
    return NULL;

  Stackwalker *cpu_stackwalker = NULL;

  u_int32_t cpu = context->GetContextCPU();
  switch (cpu) {
    case MD_CONTEXT_X86:
      cpu_stackwalker = new StackwalkerX86(system_info,
                                           context->GetContextX86(),
                                           memory, modules, supplier,
                                           resolver);
      break;

    case MD_CONTEXT_PPC:
      cpu_stackwalker = new StackwalkerPPC(system_info,
                                           context->GetContextPPC(),
                                           memory, modules, supplier,
                                           resolver);
      break;
  }

  return cpu_stackwalker;
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.

#include <signal.h>

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

#include "ScopedLocalRef.h"
#include "UniquePtr.h"
#include "jni.h"
#include "logging.h"
#include "toStringArray.h"

// Determine whether or not the specified method is public.
static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
  ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz,
      method_id, JNI_FALSE));
  if (reflected.get() == NULL) {
    fprintf(stderr, "Unable to get reflected method\n");
    return false;
  }
  // We now have a Method instance.  We need to call its
  // getModifiers() method.
  ScopedLocalRef<jclass> method(env,
      env->FindClass("java/lang/reflect/Method"));
  if (method.get() == NULL) {
    fprintf(stderr, "Unable to find class Method\n");
    return false;
  }
  static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
  jmethodID get_modifiers = env->GetMethodID(method.get(),
                                             "getModifiers",
                                             "()I");
  if (get_modifiers == NULL) {
    fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
    return false;
  }
  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
  if ((modifiers & PUBLIC) == 0) {
    return false;
  }
  return true;
}

static void InvokeMain(JNIEnv* env, int argc, char** argv) {
  // We want to call main() with a String array with our arguments in
  // it.  Create an array and populate it.  Note argv[0] is not
  // included.
  ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
  if (args.get() == NULL) {
    return;
  }

  // Find [class].main(String[]).

  // Convert "com.android.Blah" to "com/android/Blah".
  std::string class_name(argv[0]);
  std::replace(class_name.begin(), class_name.end(), '.', '/');

  ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
  if (klass.get() == NULL) {
    fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
    return;
  }

  jmethodID method = env->GetStaticMethodID(klass.get(),
                                            "main",
                                            "([Ljava/lang/String;)V");
  if (method == NULL) {
    fprintf(stderr, "Unable to find static main(String[]) in '%s'\n",
            class_name.c_str());
    return;
  }

  // Make sure the method is public.  JNI doesn't prevent us from
  // calling a private method, so we have to check it explicitly.
  if (!IsMethodPublic(env, klass.get(), method)) {
    fprintf(stderr, "Sorry, main() is not public\n");
    return;
  }

  // Invoke main().
  env->CallStaticVoidMethod(klass.get(), method, args.get());
}

// Parse arguments.  Most of it just gets passed through to the VM.
// The JNI spec defines a handful of standard arguments.
int main(int argc, char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  // Skip over argv[0].
  argv++;
  argc--;

  // If we're adding any additional stuff, e.g. function hook specifiers,
  // add them to the count here.
  //
  // We're over-allocating, because this includes the options to the VM
  // plus the options to the program.
  int option_count = argc;
  UniquePtr<JavaVMOption[]> options(new JavaVMOption[option_count]());

  // Copy options over.  Everything up to the name of the class starts
  // with a '-' (the function hook stuff is strictly internal).
  //
  // [Do we need to catch & handle "-jar" here?]
  bool need_extra = false;
  int curr_opt, arg_idx;
  for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) {
    if (argv[arg_idx][0] != '-' && !need_extra) {
      break;
    }
    options[curr_opt++].optionString = argv[arg_idx];

    // Some options require an additional argument.
    need_extra = false;
    if (strcmp(argv[arg_idx], "-classpath") == 0 ||
        strcmp(argv[arg_idx], "-cp") == 0) {
      // others?
      need_extra = true;
    }
  }

  if (need_extra) {
    fprintf(stderr, "VM requires value after last option flag\n");
    return EXIT_FAILURE;
  }

  // Make sure they provided a class name.  We do this after VM init
  // so that things like "-Xrunjdwp:help" have the opportunity to emit
  // a usage statement.
  if (arg_idx == argc) {
    fprintf(stderr, "Class name required\n");
    return EXIT_FAILURE;
  }

  // insert additional internal options here

  DCHECK_LE(curr_opt, option_count);

  JavaVMInitArgs init_args;
  init_args.version = JNI_VERSION_1_6;
  init_args.options = options.get();
  init_args.nOptions = curr_opt;
  init_args.ignoreUnrecognized = JNI_FALSE;

  // Start VM.  The current thread becomes the main thread of the VM.
  JavaVM* vm = NULL;
  JNIEnv* env = NULL;
  if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) {
    fprintf(stderr, "VM init failed (check log file)\n");
    return EXIT_FAILURE;
  }

  InvokeMain(env, argc - arg_idx, &argv[arg_idx]);
  int rc = env->ExceptionCheck() ? EXIT_FAILURE : EXIT_SUCCESS;
  if (rc == EXIT_FAILURE) {
    env->ExceptionDescribe();
  }

  if (vm->DetachCurrentThread() != JNI_OK) {
    fprintf(stderr, "Warning: unable to detach main thread\n");
    rc = EXIT_FAILURE;
  }

  if (vm->DestroyJavaVM() != 0) {
    fprintf(stderr, "Warning: VM did not shut down cleanly\n");
    rc = EXIT_FAILURE;
  }

  return rc;
}
<commit_msg>Fix oatexec to not print uncaught exceptions twice.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.

#include <signal.h>

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

#include "ScopedLocalRef.h"
#include "UniquePtr.h"
#include "jni.h"
#include "logging.h"
#include "toStringArray.h"

// Determine whether or not the specified method is public.
static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
  ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz,
      method_id, JNI_FALSE));
  if (reflected.get() == NULL) {
    fprintf(stderr, "Unable to get reflected method\n");
    return false;
  }
  // We now have a Method instance.  We need to call its
  // getModifiers() method.
  ScopedLocalRef<jclass> method(env,
      env->FindClass("java/lang/reflect/Method"));
  if (method.get() == NULL) {
    fprintf(stderr, "Unable to find class Method\n");
    return false;
  }
  static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
  jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
  if (get_modifiers == NULL) {
    fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
    return false;
  }
  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
  if ((modifiers & PUBLIC) == 0) {
    return false;
  }
  return true;
}

static int InvokeMain(JNIEnv* env, int argc, char** argv) {
  // We want to call main() with a String array with our arguments in
  // it.  Create an array and populate it.  Note argv[0] is not
  // included.
  ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
  if (args.get() == NULL) {
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Find [class].main(String[]).

  // Convert "com.android.Blah" to "com/android/Blah".
  std::string class_name(argv[0]);
  std::replace(class_name.begin(), class_name.end(), '.', '/');

  ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
  if (klass.get() == NULL) {
    fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  jmethodID method = env->GetStaticMethodID(klass.get(), "main", "([Ljava/lang/String;)V");
  if (method == NULL) {
    fprintf(stderr, "Unable to find static main(String[]) in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Make sure the method is public.  JNI doesn't prevent us from
  // calling a private method, so we have to check it explicitly.
  if (!IsMethodPublic(env, klass.get(), method)) {
    fprintf(stderr, "Sorry, main() is not public in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Invoke main().
  env->CallStaticVoidMethod(klass.get(), method, args.get());
  return EXIT_SUCCESS;
}

// Parse arguments.  Most of it just gets passed through to the VM.
// The JNI spec defines a handful of standard arguments.
int main(int argc, char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  // Skip over argv[0].
  argv++;
  argc--;

  // If we're adding any additional stuff, e.g. function hook specifiers,
  // add them to the count here.
  //
  // We're over-allocating, because this includes the options to the VM
  // plus the options to the program.
  int option_count = argc;
  UniquePtr<JavaVMOption[]> options(new JavaVMOption[option_count]());

  // Copy options over.  Everything up to the name of the class starts
  // with a '-' (the function hook stuff is strictly internal).
  //
  // [Do we need to catch & handle "-jar" here?]
  bool need_extra = false;
  int curr_opt, arg_idx;
  for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) {
    if (argv[arg_idx][0] != '-' && !need_extra) {
      break;
    }
    options[curr_opt++].optionString = argv[arg_idx];

    // Some options require an additional argument.
    need_extra = false;
    if (strcmp(argv[arg_idx], "-classpath") == 0 || strcmp(argv[arg_idx], "-cp") == 0) {
      // others?
      need_extra = true;
    }
  }

  if (need_extra) {
    fprintf(stderr, "VM requires value after last option flag\n");
    return EXIT_FAILURE;
  }

  // Make sure they provided a class name.  We do this after VM init
  // so that things like "-Xrunjdwp:help" have the opportunity to emit
  // a usage statement.
  if (arg_idx == argc) {
    fprintf(stderr, "Class name required\n");
    return EXIT_FAILURE;
  }

  // insert additional internal options here

  DCHECK_LE(curr_opt, option_count);

  JavaVMInitArgs init_args;
  init_args.version = JNI_VERSION_1_6;
  init_args.options = options.get();
  init_args.nOptions = curr_opt;
  init_args.ignoreUnrecognized = JNI_FALSE;

  // Start VM.  The current thread becomes the main thread of the VM.
  JavaVM* vm = NULL;
  JNIEnv* env = NULL;
  if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) {
    fprintf(stderr, "VM init failed (check log file)\n");
    return EXIT_FAILURE;
  }

  int rc = InvokeMain(env, argc - arg_idx, &argv[arg_idx]);

  if (vm->DetachCurrentThread() != JNI_OK) {
    fprintf(stderr, "Warning: unable to detach main thread\n");
    rc = EXIT_FAILURE;
  }

  if (vm->DestroyJavaVM() != 0) {
    fprintf(stderr, "Warning: VM did not shut down cleanly\n");
    rc = EXIT_FAILURE;
  }

  return rc;
}
<|endoftext|>


<commit_before>#define BUILDING_NODE_EXTENSION 1
#include <node.h>

#include "amf.h"
#include "deserializer.h"
#include "utils.h"

using namespace AMF;
using namespace v8;

// TODO: clean up obj ref hacks to make it more readable; temp stack var is ugly
// TODO: way better error messages
// TODO: die() takes formatstr
// TODO: trigger GC to make sure no leaks

Deserializer::Deserializer() {
}

Deserializer::~Deserializer() {
}

void Deserializer::Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("deserialize"),
      Persistent<Function>::New(FunctionTemplate::New(Run)->GetFunction()));
}

Handle<Value> Deserializer::Run(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1) {
    die("Need exactly one argument");
  }

  std::auto_ptr<Deserializer> obj(new Deserializer());
  obj->init(args[0]->ToString());
  return scope.Close(obj->readValue(obj->buffer_->getRegion()));
}

void Deserializer::init(Handle<String> payload) {
  buffer_.reset(new ReadBuffer(payload));
}

Handle<Value> Deserializer::readValue(ReadBuffer::Region* region) {
  uint8_t marker = AMF3_UNDEFINED;
  region->readUInt8(&marker);
  switch (marker) {
    case AMF3_UNDEFINED:
      return Undefined();
    case AMF3_NULL:
      return Null();
    case AMF3_FALSE:
      return False();
    case AMF3_TRUE:
      return True();
    case AMF3_INTEGER:
      return readInteger(region);
    case AMF3_DOUBLE:
      return readDouble(region);
    case AMF3_STRING:
      return readUTF8(region);
    case AMF3_ARRAY:
      return readArray(region);
    case AMF3_OBJECT:
      return readObject(region);
    case AMF3_DATE:
      return readDate(region);
    default:
      die("Unsupported AMF3 marker");
  }
  return Undefined();
}

Handle<Integer> Deserializer::readInteger(ReadBuffer::Region* region) {
  int32_t v;
  if (!region->readInt29(&v)) {
    die("Integer expected but not found at position");
  }
  return Integer::New(v);
}

Handle<Number> Deserializer::readDouble(ReadBuffer::Region* region) {
  double v;
  if (!region->readDouble(&v)) {
    // TODO: make die take varargs and format string
    die("Double expected but not found at position");
  }
  return Number::New(v);
}

Handle<String> Deserializer::readUTF8(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("String expected but no length information found");
  }

  int32_t len;
  if (n & 1) {
    len = n >> 1;
    // index string unless empty
    if (len == 0) {
      return String::New("");
    }
    strRefs_.push_back(region->copy(len));
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= strRefs_.size()) {
      die("No string reference at index!");
    }
    ReadRegion temp = strRefs_[refIndex].copy();
    region = &temp;
    len = region->length();
  }

  uint8_t* str = NULL;
  if (!region->read(&str, len)) {
    die("String expected but not long enough");
  }
  Handle<String> s = String::New(reinterpret_cast<char*>(str), len);
  return s;
}

Handle<Array> Deserializer::readArray(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Array length not found");
  }

  if (n & 1) {
    int32_t len = n >> 1;
    objRefs_.push_back(makeRef(region->copy(), len));
    return readArrayWithLength(region, len);
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ObjRef ref = objRefs_[refIndex];
    return readArrayWithLength(&ref.region, ref.attr);
  }
}

Handle<Array> Deserializer::readArrayWithLength(
    ReadBuffer::Region* region, int32_t len) {
  // Skip the associative portion of the array: unsupported in Javascript
  while (readUTF8(region)->Length() != 0) {
    readValue(region);
  }

  Handle<Array> a = Array::New(len);
  for (int i = 0; i < len; i++) {
    a->Set(i, readValue(region));
  }
  return a;
}

inline bool isObjectReferenceFlag(int32_t n) {
  return ((n & 1) == 0);
}

inline bool isTraitReferenceFlag(int32_t n) {
  return ((n & 3) == 1);
}

inline bool isTraitDeclarationFlag(int32_t n) {
  return((n & 7) == 3);
}

inline bool isExternalizableTraitFlag(int32_t n) {
  return ((n & 7) == 7);
}

Handle<Object> Deserializer::readObject(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Object attributes not found");
  }

  if (isObjectReferenceFlag(n)) {
    // Reconstruct object reference ad re-parse it.
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ObjRef ref = objRefs_[refIndex];
    return readObjectWithFlag(&ref.region, ref.attr);
  } else {
    objRefs_.push_back(makeRef(region->copy(), n));
    return readObjectWithFlag(region, n);
  }
}

Handle<Object> Deserializer::readObjectWithFlag(
    ReadBuffer::Region* region, int32_t n) {
  if (isObjectReferenceFlag(n)) {
    die("Fatal error - obect reference flag passed to readObjectWithFlag");
  } else if (isExternalizableTraitFlag(n)) {
    die("Externalizable traits not supported!");
  } else if (isTraitDeclarationFlag(n)) {
    Traits traits;
    traits.dynamic = (n & 8) ? true : false;
    (void)readUTF8(region);  // classname
    int32_t num_props = n >> 4;
    for (int i = 0; i < num_props; i++) {
      traits.props.push_back(readUTF8(region));
    }
    traitRefs_.push_back(traits);
    return readObjectFromRegionAndTraits(region, traits);
  } else if (isTraitReferenceFlag(n)) {
    uint32_t refIndex = n >> 2;
    if (refIndex >= traitRefs_.size()) {
      die("No trait reference at index!");
    }
    Traits traits = traitRefs_[refIndex];
    return readObjectFromRegionAndTraits(region, traits);
  } else {
    die("Unrecognized flag!");
  }
}

void Deserializer::readObjectDynamicProps(
    ReadBuffer::Region* region, Handle<Object> o) {
  Handle<String> key;
  while (!(key = readUTF8(region)).IsEmpty() && key->Length() != 0) {
    o->Set(key, readValue(region));
  }
}

Handle<Object> Deserializer::readObjectFromRegion(ReadBuffer::Region* region) {
  Handle<Object> o = Object::New();
  (void)readUTF8(region);  // object's class name
  readObjectDynamicProps(region, o);
  return o;
}

Handle<Object> Deserializer::readObjectFromRegionAndTraits(
    ReadBuffer::Region* region, const Traits& traits) {
  Handle<Object> o = Object::New();
  for (Handle<String> key : traits.props) {
    o->Set(key, readValue(region));
  }
  if (traits.dynamic) {
    readObjectDynamicProps(region, o);
  }
  return o;
}

Handle<Value> Deserializer::readDate(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Object attributes not found");
  }
  if (n & 1) {
    objRefs_.push_back(makeRef(region->copy(8), 0));
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ReadRegion temp = objRefs_[refIndex].region.copy();
    region = &temp;
  }
  double time;
  if (!region->readDouble(&time)) {
    die("Time expected");
  }
  return Date::New(time);
}

Deserializer::ObjRef::ObjRef() : attr(0) { }

Deserializer::ObjRef Deserializer::makeRef(
    ReadBuffer::Region region, int32_t attr) {
  ObjRef ref;
  ref.region = region;
  ref.attr = attr;
  return ref;
}

Deserializer::Traits::Traits() : dynamic(false) { }

<commit_msg>Fix compiler warnings. node-gyp, y u no support C++11?<commit_after>#define BUILDING_NODE_EXTENSION 1
#include <node.h>

#include "amf.h"
#include "deserializer.h"
#include "utils.h"

using namespace AMF;
using namespace v8;

// TODO: clean up obj ref hacks to make it more readable; temp stack var is ugly
// TODO: way better error messages
// TODO: die() takes formatstr
// TODO: trigger GC to make sure no leaks

Deserializer::Deserializer() {
}

Deserializer::~Deserializer() {
}

void Deserializer::Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("deserialize"),
      Persistent<Function>::New(FunctionTemplate::New(Run)->GetFunction()));
}

Handle<Value> Deserializer::Run(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1) {
    die("Need exactly one argument");
  }

  std::auto_ptr<Deserializer> obj(new Deserializer());
  obj->init(args[0]->ToString());
  return scope.Close(obj->readValue(obj->buffer_->getRegion()));
}

void Deserializer::init(Handle<String> payload) {
  buffer_.reset(new ReadBuffer(payload));
}

Handle<Value> Deserializer::readValue(ReadBuffer::Region* region) {
  uint8_t marker = AMF3_UNDEFINED;
  region->readUInt8(&marker);
  switch (marker) {
    case AMF3_UNDEFINED:
      return Undefined();
    case AMF3_NULL:
      return Null();
    case AMF3_FALSE:
      return False();
    case AMF3_TRUE:
      return True();
    case AMF3_INTEGER:
      return readInteger(region);
    case AMF3_DOUBLE:
      return readDouble(region);
    case AMF3_STRING:
      return readUTF8(region);
    case AMF3_ARRAY:
      return readArray(region);
    case AMF3_OBJECT:
      return readObject(region);
    case AMF3_DATE:
      return readDate(region);
    default:
      die("Unsupported AMF3 marker");
  }
  return Undefined();
}

Handle<Integer> Deserializer::readInteger(ReadBuffer::Region* region) {
  int32_t v;
  if (!region->readInt29(&v)) {
    die("Integer expected but not found at position");
  }
  return Integer::New(v);
}

Handle<Number> Deserializer::readDouble(ReadBuffer::Region* region) {
  double v;
  if (!region->readDouble(&v)) {
    // TODO: make die take varargs and format string
    die("Double expected but not found at position");
  }
  return Number::New(v);
}

Handle<String> Deserializer::readUTF8(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("String expected but no length information found");
  }

  int32_t len;
  if (n & 1) {
    len = n >> 1;
    // index string unless empty
    if (len == 0) {
      return String::New("");
    }
    strRefs_.push_back(region->copy(len));
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= strRefs_.size()) {
      die("No string reference at index!");
    }
    ReadRegion temp = strRefs_[refIndex].copy();
    region = &temp;
    len = region->length();
  }

  uint8_t* str = NULL;
  if (!region->read(&str, len)) {
    die("String expected but not long enough");
  }
  Handle<String> s = String::New(reinterpret_cast<char*>(str), len);
  return s;
}

Handle<Array> Deserializer::readArray(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Array length not found");
  }

  if (n & 1) {
    int32_t len = n >> 1;
    objRefs_.push_back(makeRef(region->copy(), len));
    return readArrayWithLength(region, len);
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ObjRef ref = objRefs_[refIndex];
    return readArrayWithLength(&ref.region, ref.attr);
  }
}

Handle<Array> Deserializer::readArrayWithLength(
    ReadBuffer::Region* region, int32_t len) {
  // Skip the associative portion of the array: unsupported in Javascript
  while (readUTF8(region)->Length() != 0) {
    readValue(region);
  }

  Handle<Array> a = Array::New(len);
  for (int i = 0; i < len; i++) {
    a->Set(i, readValue(region));
  }
  return a;
}

inline bool isObjectReferenceFlag(int32_t n) {
  return ((n & 1) == 0);
}

inline bool isTraitReferenceFlag(int32_t n) {
  return ((n & 3) == 1);
}

inline bool isTraitDeclarationFlag(int32_t n) {
  return((n & 7) == 3);
}

inline bool isExternalizableTraitFlag(int32_t n) {
  return ((n & 7) == 7);
}

Handle<Object> Deserializer::readObject(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Object attributes not found");
  }

  if (isObjectReferenceFlag(n)) {
    // Reconstruct object reference ad re-parse it.
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ObjRef ref = objRefs_[refIndex];
    return readObjectWithFlag(&ref.region, ref.attr);
  } else {
    objRefs_.push_back(makeRef(region->copy(), n));
    return readObjectWithFlag(region, n);
  }
}

Handle<Object> Deserializer::readObjectWithFlag(
    ReadBuffer::Region* region, int32_t n) {
  if (isObjectReferenceFlag(n)) {
    die("Fatal error - obect reference flag passed to readObjectWithFlag");
  } else if (isExternalizableTraitFlag(n)) {
    die("Externalizable traits not supported!");
  } else if (isTraitDeclarationFlag(n)) {
    Traits traits;
    traits.dynamic = (n & 8) ? true : false;
    (void)readUTF8(region);  // classname
    int32_t num_props = n >> 4;
    for (int i = 0; i < num_props; i++) {
      traits.props.push_back(readUTF8(region));
    }
    traitRefs_.push_back(traits);
    return readObjectFromRegionAndTraits(region, traits);
  } else if (isTraitReferenceFlag(n)) {
    uint32_t refIndex = n >> 2;
    if (refIndex >= traitRefs_.size()) {
      die("No trait reference at index!");
    }
    Traits traits = traitRefs_[refIndex];
    return readObjectFromRegionAndTraits(region, traits);
  } else {
    die("Unrecognized flag!");
  }
  return Object::New();  // workaround compiler warning. We'll never get here.
}

void Deserializer::readObjectDynamicProps(
    ReadBuffer::Region* region, Handle<Object> o) {
  Handle<String> key;
  while (!(key = readUTF8(region)).IsEmpty() && key->Length() != 0) {
    o->Set(key, readValue(region));
  }
}

Handle<Object> Deserializer::readObjectFromRegion(ReadBuffer::Region* region) {
  Handle<Object> o = Object::New();
  (void)readUTF8(region);  // object's class name
  readObjectDynamicProps(region, o);
  return o;
}

Handle<Object> Deserializer::readObjectFromRegionAndTraits(
    ReadBuffer::Region* region, const Traits& traits) {
  Handle<Object> o = Object::New();
  for (uint i = 0; i < traits.props.size(); i++) {
    o->Set(traits.props[i], readValue(region));
  }
  if (traits.dynamic) {
    readObjectDynamicProps(region, o);
  }
  return o;
}

Handle<Value> Deserializer::readDate(ReadBuffer::Region* region) {
  int32_t n = 0;
  if (!region->readInt29(&n)) {
    die("Object attributes not found");
  }
  if (n & 1) {
    objRefs_.push_back(makeRef(region->copy(8), 0));
  } else {
    uint32_t refIndex = n >> 1;
    if (refIndex >= objRefs_.size()) {
      die("No object reference at index!");
    }
    ReadRegion temp = objRefs_[refIndex].region.copy();
    region = &temp;
  }
  double time;
  if (!region->readDouble(&time)) {
    die("Time expected");
  }
  return Date::New(time);
}

Deserializer::ObjRef::ObjRef() : attr(0) { }

Deserializer::ObjRef Deserializer::makeRef(
    ReadBuffer::Region region, int32_t attr) {
  ObjRef ref;
  ref.region = region;
  ref.attr = attr;
  return ref;
}

Deserializer::Traits::Traits() : dynamic(false) { }

<|endoftext|>