<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////

#include "config.h"

#if BX_USE_TEXTCONFIG && defined(WIN32)

#ifdef WIN32

extern "C" {
#include <stdio.h>
#include <windows.h>
}
#include "win32res.h"
#include "siminterface.h"
#include "win32dialog.h"

HWND GetBochsWindow()
{
  HWND hwnd;

  hwnd = FindWindow("Bochs for Windows", NULL);
  if (hwnd == NULL) {
    hwnd = GetForegroundWindow();
  }
  return hwnd;
}

BOOL CreateImage(HWND hDlg, int sectors, const char *filename)
{
  if (sectors < 1) {
    MessageBox(hDlg, "The disk size is invalid.", "Invalid size", MB_ICONERROR);
    return FALSE;
  }
  if (lstrlen(filename) < 1) {
    MessageBox(hDlg, "You must type a file name for the new disk image.", "Bad filename", MB_ICONERROR);
    return FALSE;
  }
  int ret = SIM->create_disk_image (filename, sectors, 0);
  if (ret == -1) {  // already exists
    int answer = MessageBox(hDlg, "File exists.  Do you want to overwrite it?",
                            "File exists", MB_YESNO);
    if (answer == IDYES)
      ret = SIM->create_disk_image (filename, sectors, 1);
    else
      return FALSE;
  }
  if (ret == -2) {
    MessageBox(hDlg, "I could not create the disk image. Check for permission problems or available disk space.", "Failed", MB_ICONERROR);
    return FALSE;
  }
  return TRUE;
}

static BOOL CALLBACK LogAskProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  BxEvent *event;
  int level;

  switch (msg) {
    case WM_INITDIALOG:
      event = (BxEvent*)lParam;
      level = event->u.logmsg.level;
      SetWindowText(hDlg, SIM->get_log_level_name(level));
      SetWindowText(GetDlgItem(hDlg, IDASKDEV), event->u.logmsg.prefix);
      SetWindowText(GetDlgItem(hDlg, IDASKMSG), event->u.logmsg.msg);
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and don't ask again");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Kill simulation");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Abort (dump core)");
#if BX_DEBUGGER
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and return to debugger");
#endif
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_SETCURSEL, 2, 0);
      SetFocus(GetDlgItem(hDlg, IDASKLIST));
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDOK:
          EndDialog(hDlg, SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_GETCURSEL, 0, 0));
          break;
        case IDCANCEL:
          EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
          break;
    }
  }
  return FALSE;
}

static BOOL CALLBACK StringParamProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static bx_param_string_c *param;
  char buffer[20];

  switch (msg) {
    case WM_INITDIALOG:
      param = (bx_param_string_c *)lParam;
      SetWindowText(hDlg, param->get_name());
      SetWindowText(GetDlgItem(hDlg, IDSTRING), param->getptr());
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, -1);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDOK:
          GetWindowText(GetDlgItem(hDlg, IDSTRING), buffer, 20);
          param->set(buffer);
          EndDialog(hDlg, 1);
          break;
        case IDCANCEL:
          EndDialog(hDlg, -1);
          break;
    }
  }
  return FALSE;
}

static BOOL CALLBACK FloppyDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static bx_param_filename_c *param;
  static bx_param_enum_c *status;
  static bx_param_enum_c *disktype;
  static char origpath[MAX_PATH];
  char mesg[MAX_PATH];
  char path[MAX_PATH];
  char *title;
  int cap;

  switch (msg) {
    case WM_INITDIALOG:
      param = (bx_param_filename_c *)lParam;
      if (param->get_id() == BXP_FLOPPYA_PATH) {
        status = SIM->get_param_enum(BXP_FLOPPYA_STATUS);
        disktype = SIM->get_param_enum(BXP_FLOPPYA_DEVTYPE);
      } else {
        status = SIM->get_param_enum(BXP_FLOPPYB_STATUS);
        disktype = SIM->get_param_enum(BXP_FLOPPYB_DEVTYPE);
      }
      cap = disktype->get() - disktype->get_min();
      SetWindowText(GetDlgItem(hDlg, IDDEVTYPE), floppy_type_names[cap]);
      if (status->get() == BX_INSERTED) {
        SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_SETCHECK, BST_CHECKED, 0);
      }
      lstrcpy(origpath, param->getptr());
      title = param->get_label();
      if (!title) title = param->get_name();
      SetWindowText(hDlg, title);
      if (lstrlen(origpath) && lstrcmp(origpath, "none")) {
        SetWindowText(GetDlgItem(hDlg, IDPATH), origpath);
      }
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, -1);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDBROWSE:
          if (AskFilename(hDlg, param) > 0) {
            SetWindowText(GetDlgItem(hDlg, IDPATH), param->getptr());
            SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_SETCHECK, BST_CHECKED, 0);
          }
          break;
        case IDOK:
          if (SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_GETCHECK, 0, 0) == BST_CHECKED) {
            GetWindowText(GetDlgItem(hDlg, IDPATH), path, MAX_PATH);
            if (lstrlen(path)) {
              status->set(BX_INSERTED);
            } else {
              status->set(BX_EJECTED);
              lstrcpy(path, "none");
            }
          } else {
            status->set(BX_EJECTED);
            lstrcpy(path, "none");
          }
          param->set(path);
          EndDialog(hDlg, 1);
          break;
        case IDCANCEL:
          param->set(origpath);
          EndDialog(hDlg, -1);
          break;
        case IDCREATE:
          GetWindowText(GetDlgItem(hDlg, IDPATH), path, MAX_PATH);
          cap = disktype->get() - disktype->get_min();
          if (CreateImage(hDlg, floppy_type_n_sectors[cap], path)) {
            wsprintf(mesg, "Created a %s disk image called %s", floppy_type_names[cap], path);
            MessageBox(hDlg, mesg, "Image created", MB_OK);
          }
          break;
    }
  }
  return FALSE;
}

void LogAskDialog(BxEvent *event)
{
  event->retcode = DialogBoxParam(NULL, MAKEINTRESOURCE(ASK_DLG), GetBochsWindow(),
                                  (DLGPROC)LogAskProc, (LPARAM)event);
}

int AskFilename(HWND hwnd, bx_param_filename_c *param)
{
  OPENFILENAME ofn;
  int ret;
  DWORD errcode;
  char filename[MAX_PATH];
  char *title;
  char errtext[80];

  param->get(filename, MAX_PATH);
  title = param->get_label();
  if (!title) title = param->get_name();
  memset(&ofn, 0, sizeof(OPENFILENAME));
  ofn.lStructSize = sizeof(OPENFILENAME);
  ofn.hwndOwner = hwnd;
  ofn.lpstrFile   = filename;
  ofn.nMaxFile    = MAX_PATH;
  ofn.lpstrTitle = title;
  ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
  if (param->get_options()->get() & bx_param_filename_c::SAVE_FILE_DIALOG) {
    ofn.lpstrFilter = "Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0";
    ofn.lpstrDefExt = "prg";
    ofn.Flags |= OFN_OVERWRITEPROMPT;
    ret = GetSaveFileName(&ofn);
  } else {
    ofn.lpstrFilter = "Floppy image files (*.img)\0*.img\0All files (*.*)\0*.*\0";
    ofn.lpstrDefExt = "img";
    ofn.Flags |= OFN_FILEMUSTEXIST;
    ret = GetOpenFileName(&ofn);
  }
  param->set(filename);
  if (ret == 0) {
    errcode = CommDlgExtendedError();
    if (errcode == 0) {
      ret = -1;
    } else {
      wsprintf(errtext, "CommDlgExtendedError returns 0x%04x", errcode);
      MessageBox(hwnd, errtext, "Error", MB_ICONERROR);
    }
  }
  return ret;
}

int AskString(bx_param_string_c *param)
{
  return DialogBoxParam(NULL, MAKEINTRESOURCE(STRING_DLG), GetBochsWindow(),
                        (DLGPROC)StringParamProc, (LPARAM)param);
}

int FloppyDialog(bx_param_filename_c *param)
{
  return DialogBoxParam(NULL, MAKEINTRESOURCE(FLOPPY_DLG), GetBochsWindow(),
                        (DLGPROC)FloppyDlgProc, (LPARAM)param);
}

#endif // BX_USE_TEXTCONFIG && defined(WIN32)
<commit_msg>- fixed unterminated #if statement<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////

#include "config.h"

#if BX_USE_TEXTCONFIG && defined(WIN32)

extern "C" {
#include <stdio.h>
#include <windows.h>
}
#include "win32res.h"
#include "siminterface.h"
#include "win32dialog.h"

HWND GetBochsWindow()
{
  HWND hwnd;

  hwnd = FindWindow("Bochs for Windows", NULL);
  if (hwnd == NULL) {
    hwnd = GetForegroundWindow();
  }
  return hwnd;
}

BOOL CreateImage(HWND hDlg, int sectors, const char *filename)
{
  if (sectors < 1) {
    MessageBox(hDlg, "The disk size is invalid.", "Invalid size", MB_ICONERROR);
    return FALSE;
  }
  if (lstrlen(filename) < 1) {
    MessageBox(hDlg, "You must type a file name for the new disk image.", "Bad filename", MB_ICONERROR);
    return FALSE;
  }
  int ret = SIM->create_disk_image (filename, sectors, 0);
  if (ret == -1) {  // already exists
    int answer = MessageBox(hDlg, "File exists.  Do you want to overwrite it?",
                            "File exists", MB_YESNO);
    if (answer == IDYES)
      ret = SIM->create_disk_image (filename, sectors, 1);
    else
      return FALSE;
  }
  if (ret == -2) {
    MessageBox(hDlg, "I could not create the disk image. Check for permission problems or available disk space.", "Failed", MB_ICONERROR);
    return FALSE;
  }
  return TRUE;
}

static BOOL CALLBACK LogAskProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  BxEvent *event;
  int level;

  switch (msg) {
    case WM_INITDIALOG:
      event = (BxEvent*)lParam;
      level = event->u.logmsg.level;
      SetWindowText(hDlg, SIM->get_log_level_name(level));
      SetWindowText(GetDlgItem(hDlg, IDASKDEV), event->u.logmsg.prefix);
      SetWindowText(GetDlgItem(hDlg, IDASKMSG), event->u.logmsg.msg);
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and don't ask again");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Kill simulation");
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Abort (dump core)");
#if BX_DEBUGGER
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and return to debugger");
#endif
      SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_SETCURSEL, 2, 0);
      SetFocus(GetDlgItem(hDlg, IDASKLIST));
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDOK:
          EndDialog(hDlg, SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_GETCURSEL, 0, 0));
          break;
        case IDCANCEL:
          EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
          break;
    }
  }
  return FALSE;
}

static BOOL CALLBACK StringParamProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static bx_param_string_c *param;
  char buffer[20];

  switch (msg) {
    case WM_INITDIALOG:
      param = (bx_param_string_c *)lParam;
      SetWindowText(hDlg, param->get_name());
      SetWindowText(GetDlgItem(hDlg, IDSTRING), param->getptr());
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, -1);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDOK:
          GetWindowText(GetDlgItem(hDlg, IDSTRING), buffer, 20);
          param->set(buffer);
          EndDialog(hDlg, 1);
          break;
        case IDCANCEL:
          EndDialog(hDlg, -1);
          break;
    }
  }
  return FALSE;
}

static BOOL CALLBACK FloppyDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static bx_param_filename_c *param;
  static bx_param_enum_c *status;
  static bx_param_enum_c *disktype;
  static char origpath[MAX_PATH];
  char mesg[MAX_PATH];
  char path[MAX_PATH];
  char *title;
  int cap;

  switch (msg) {
    case WM_INITDIALOG:
      param = (bx_param_filename_c *)lParam;
      if (param->get_id() == BXP_FLOPPYA_PATH) {
        status = SIM->get_param_enum(BXP_FLOPPYA_STATUS);
        disktype = SIM->get_param_enum(BXP_FLOPPYA_DEVTYPE);
      } else {
        status = SIM->get_param_enum(BXP_FLOPPYB_STATUS);
        disktype = SIM->get_param_enum(BXP_FLOPPYB_DEVTYPE);
      }
      cap = disktype->get() - disktype->get_min();
      SetWindowText(GetDlgItem(hDlg, IDDEVTYPE), floppy_type_names[cap]);
      if (status->get() == BX_INSERTED) {
        SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_SETCHECK, BST_CHECKED, 0);
      }
      lstrcpy(origpath, param->getptr());
      title = param->get_label();
      if (!title) title = param->get_name();
      SetWindowText(hDlg, title);
      if (lstrlen(origpath) && lstrcmp(origpath, "none")) {
        SetWindowText(GetDlgItem(hDlg, IDPATH), origpath);
      }
      return FALSE;
    case WM_CLOSE:
      EndDialog(hDlg, -1);
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDBROWSE:
          if (AskFilename(hDlg, param) > 0) {
            SetWindowText(GetDlgItem(hDlg, IDPATH), param->getptr());
            SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_SETCHECK, BST_CHECKED, 0);
          }
          break;
        case IDOK:
          if (SendMessage(GetDlgItem(hDlg, IDSTATUS), BM_GETCHECK, 0, 0) == BST_CHECKED) {
            GetWindowText(GetDlgItem(hDlg, IDPATH), path, MAX_PATH);
            if (lstrlen(path)) {
              status->set(BX_INSERTED);
            } else {
              status->set(BX_EJECTED);
              lstrcpy(path, "none");
            }
          } else {
            status->set(BX_EJECTED);
            lstrcpy(path, "none");
          }
          param->set(path);
          EndDialog(hDlg, 1);
          break;
        case IDCANCEL:
          param->set(origpath);
          EndDialog(hDlg, -1);
          break;
        case IDCREATE:
          GetWindowText(GetDlgItem(hDlg, IDPATH), path, MAX_PATH);
          cap = disktype->get() - disktype->get_min();
          if (CreateImage(hDlg, floppy_type_n_sectors[cap], path)) {
            wsprintf(mesg, "Created a %s disk image called %s", floppy_type_names[cap], path);
            MessageBox(hDlg, mesg, "Image created", MB_OK);
          }
          break;
    }
  }
  return FALSE;
}

void LogAskDialog(BxEvent *event)
{
  event->retcode = DialogBoxParam(NULL, MAKEINTRESOURCE(ASK_DLG), GetBochsWindow(),
                                  (DLGPROC)LogAskProc, (LPARAM)event);
}

int AskFilename(HWND hwnd, bx_param_filename_c *param)
{
  OPENFILENAME ofn;
  int ret;
  DWORD errcode;
  char filename[MAX_PATH];
  char *title;
  char errtext[80];

  param->get(filename, MAX_PATH);
  title = param->get_label();
  if (!title) title = param->get_name();
  memset(&ofn, 0, sizeof(OPENFILENAME));
  ofn.lStructSize = sizeof(OPENFILENAME);
  ofn.hwndOwner = hwnd;
  ofn.lpstrFile   = filename;
  ofn.nMaxFile    = MAX_PATH;
  ofn.lpstrTitle = title;
  ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
  if (param->get_options()->get() & bx_param_filename_c::SAVE_FILE_DIALOG) {
    ofn.lpstrFilter = "Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0";
    ofn.lpstrDefExt = "prg";
    ofn.Flags |= OFN_OVERWRITEPROMPT;
    ret = GetSaveFileName(&ofn);
  } else {
    ofn.lpstrFilter = "Floppy image files (*.img)\0*.img\0All files (*.*)\0*.*\0";
    ofn.lpstrDefExt = "img";
    ofn.Flags |= OFN_FILEMUSTEXIST;
    ret = GetOpenFileName(&ofn);
  }
  param->set(filename);
  if (ret == 0) {
    errcode = CommDlgExtendedError();
    if (errcode == 0) {
      ret = -1;
    } else {
      wsprintf(errtext, "CommDlgExtendedError returns 0x%04x", errcode);
      MessageBox(hwnd, errtext, "Error", MB_ICONERROR);
    }
  }
  return ret;
}

int AskString(bx_param_string_c *param)
{
  return DialogBoxParam(NULL, MAKEINTRESOURCE(STRING_DLG), GetBochsWindow(),
                        (DLGPROC)StringParamProc, (LPARAM)param);
}

int FloppyDialog(bx_param_filename_c *param)
{
  return DialogBoxParam(NULL, MAKEINTRESOURCE(FLOPPY_DLG), GetBochsWindow(),
                        (DLGPROC)FloppyDlgProc, (LPARAM)param);
}

#endif // BX_USE_TEXTCONFIG && defined(WIN32)
<|endoftext|>


<commit_before>#include "menu.h"
#include "config.h"
#include <string>
#include <iostream>

Menu::Menu() {
  ui_xml = R"RAW(
<interface>
  <menu id='juci-menu'>

      <item>
        <attribute name='label' translatable='yes'>_About</attribute>
        <attribute name='action'>app.about</attribute>
      </item>

      <item>
        <attribute name='label' translatable='yes'>_Preferences</attribute>
        <attribute name='action'>app.preferences</attribute>
      </item>

      <item>
        <attribute name='label' translatable='yes'>_Quit</attribute>
        <attribute name='action'>app.quit</attribute>
      </item>

  </menu>

  <menu id='window-menu'>
    <submenu>
      <attribute name='label' translatable='yes'>_File</attribute>

        <item>
          <attribute name='label' translatable='yes'>_New _File</attribute>
          <attribute name='action'>app.new_file</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_New _Folder</attribute>
          <attribute name='action'>app.new_folder</attribute>
        </item>
        <submenu>
          <attribute name='label' translatable='yes'>_New _Project</attribute>
          <item>
            <attribute name='label' translatable='no'>C</attribute>
            <attribute name='action'>app.new_project_c</attribute>
          </item>
          <item>
            <attribute name='label' translatable='no'>C++</attribute>
            <attribute name='action'>app.new_project_cpp</attribute>
          </item>
        </submenu>

        <item>
          <attribute name='label' translatable='yes'>_Open _File</attribute>
          <attribute name='action'>app.open_file</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Open _Folder</attribute>
          <attribute name='action'>app.open_folder</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Save</attribute>
          <attribute name='action'>app.save</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Save _As</attribute>
          <attribute name='action'>app.save_as</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Print</attribute>
          <attribute name='action'>app.print</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Edit</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Undo</attribute>
          <attribute name='action'>app.edit_undo</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Redo</attribute>
          <attribute name='action'>app.edit_redo</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Cut</attribute>
          <attribute name='action'>app.edit_cut</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Copy</attribute>
          <attribute name='action'>app.edit_copy</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Paste</attribute>
          <attribute name='action'>app.edit_paste</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Find</attribute>
          <attribute name='action'>app.edit_find</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Source</attribute>

        <submenu>
          <attribute name='label' translatable='yes'>_Spell _Check</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Spell _Check _Buffer</attribute>
            <attribute name='action'>app.source_spellcheck</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Clear _Spelling _Errors</attribute>
            <attribute name='action'>app.source_spellcheck_clear</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Go _to _Next _Spelling _Error</attribute>
            <attribute name='action'>app.source_spellcheck_next_error</attribute>
          </item>
        </submenu>

        <submenu>
          <attribute name='label' translatable='yes'>_Git</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Go _to _Next _Diff</attribute>
            <attribute name='action'>app.source_git_next_diff</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Show _Diff</attribute>
            <attribute name='action'>app.source_git_show_diff</attribute>
          </item>
        </submenu>

        <submenu>
          <attribute name='label' translatable='yes'>_Indentation</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Set _Current _Buffer _Tab</attribute>
            <attribute name='action'>app.source_indentation_set_buffer_tab</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Auto-Indent _Current _Buffer</attribute>
            <attribute name='action'>app.source_indentation_auto_indent_buffer</attribute>
          </item>
        </submenu>

        <item>
          <attribute name='label' translatable='yes'>_Go _to _Line</attribute>
          <attribute name='action'>app.source_goto_line</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Center _Cursor</attribute>
          <attribute name='action'>app.source_center_cursor</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Find _Symbol (Ctags)</attribute>
          <attribute name='action'>app.source_find_symbol_ctags</attribute>
        </item>

        <submenu>
          <attribute name='label' translatable='yes'>_Comments</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Toggle _Comments</attribute>
            <attribute name='action'>app.source_comments_toggle</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Add _Documentation (not yet implemented)</attribute>
            <attribute name='action'>app.source_comments_add_documentation</attribute>
          </item>
        </submenu>
        <item>
          <attribute name='label' translatable='yes'>_Find _Documentation</attribute>
          <attribute name='action'>app.source_find_documentation</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go to Declaration</attribute>
          <attribute name='action'>app.source_goto_declaration</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Implementation</attribute>
          <attribute name='action'>app.source_goto_implementation</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Usage</attribute>
          <attribute name='action'>app.source_goto_usage</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Method</attribute>
          <attribute name='action'>app.source_goto_method</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Rename</attribute>
          <attribute name='action'>app.source_rename</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Implement _Method</attribute>
          <attribute name='action'>app.source_implement_method</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go to Next Diagnostic</attribute>
          <attribute name='action'>app.source_goto_next_diagnostic</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Apply Fix-Its</attribute>
          <attribute name='action'>app.source_apply_fix_its</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Project</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
          <attribute name='action'>app.project_set_run_arguments</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Compile _and _Run</attribute>
          <attribute name='action'>app.compile_and_run</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Compile</attribute>
          <attribute name='action'>app.compile</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Run _Command</attribute>
          <attribute name='action'>app.run_command</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Kill _Last _Process</attribute>
          <attribute name='action'>app.kill_last_running</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Force _Kill _Last _Process</attribute>
          <attribute name='action'>app.force_kill_last_running</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Debug</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
          <attribute name='action'>app.debug_set_run_arguments</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Start/_Continue</attribute>
          <attribute name='action'>app.debug_start_continue</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Stop</attribute>
          <attribute name='action'>app.debug_stop</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Kill</attribute>
          <attribute name='action'>app.debug_kill</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Step _Over</attribute>
          <attribute name='action'>app.debug_step_over</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Step _Into</attribute>
          <attribute name='action'>app.debug_step_into</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Step _Out</attribute>
          <attribute name='action'>app.debug_step_out</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Backtrace</attribute>
          <attribute name='action'>app.debug_backtrace</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Show _Variables</attribute>
          <attribute name='action'>app.debug_show_variables</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Run Command</attribute>
          <attribute name='action'>app.debug_run_command</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Toggle _Breakpoint</attribute>
          <attribute name='action'>app.debug_toggle_breakpoint</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go _to _Stop</attribute>
          <attribute name='action'>app.debug_goto_stop</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Window</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Next _Tab</attribute>
          <attribute name='action'>app.next_tab</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Previous _Tab</attribute>
          <attribute name='action'>app.previous_tab</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Close _Tab</attribute>
          <attribute name='action'>app.close_tab</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Toggle _Split</attribute>
          <attribute name='action'>app.window_toggle_split</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Clear _Terminal</attribute>
          <attribute name='action'>app.window_clear_terminal</attribute>
        </item>

    </submenu>
  </menu>
</interface>
)RAW";
}

void Menu::add_action(const std::string &name, std::function<void()> action) {
  auto g_application=g_application_get_default();
  auto gio_application=Glib::wrap(g_application, true);
  auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);

  actions[name]=application->add_action(name, action);
}

void Menu::set_keys() {
  auto g_application=g_application_get_default();
  auto gio_application=Glib::wrap(g_application, true);
  auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);

  for(auto &key: Config::get().menu.keys) {
    if(key.second.size()>0 && actions.find(key.first)!=actions.end())
      application->set_accel_for_action("app."+key.first, key.second);
  }
}

void Menu::build() {
  builder = Gtk::Builder::create();

  try {
    builder->add_from_string(ui_xml);
    auto object = Menu::get().builder->get_object("juci-menu");
    juci_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
    object = Menu::get().builder->get_object("window-menu");
    window_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
  }
  catch (const Glib::Error &ex) {
    std::cerr << "building menu failed: " << ex.what();
  }
}
<commit_msg>Close Tab in menu is now in same section as Next/Previous Tab<commit_after>#include "menu.h"
#include "config.h"
#include <string>
#include <iostream>

Menu::Menu() {
  ui_xml = R"RAW(
<interface>
  <menu id='juci-menu'>

      <item>
        <attribute name='label' translatable='yes'>_About</attribute>
        <attribute name='action'>app.about</attribute>
      </item>

      <item>
        <attribute name='label' translatable='yes'>_Preferences</attribute>
        <attribute name='action'>app.preferences</attribute>
      </item>

      <item>
        <attribute name='label' translatable='yes'>_Quit</attribute>
        <attribute name='action'>app.quit</attribute>
      </item>

  </menu>

  <menu id='window-menu'>
    <submenu>
      <attribute name='label' translatable='yes'>_File</attribute>

        <item>
          <attribute name='label' translatable='yes'>_New _File</attribute>
          <attribute name='action'>app.new_file</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_New _Folder</attribute>
          <attribute name='action'>app.new_folder</attribute>
        </item>
        <submenu>
          <attribute name='label' translatable='yes'>_New _Project</attribute>
          <item>
            <attribute name='label' translatable='no'>C</attribute>
            <attribute name='action'>app.new_project_c</attribute>
          </item>
          <item>
            <attribute name='label' translatable='no'>C++</attribute>
            <attribute name='action'>app.new_project_cpp</attribute>
          </item>
        </submenu>

        <item>
          <attribute name='label' translatable='yes'>_Open _File</attribute>
          <attribute name='action'>app.open_file</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Open _Folder</attribute>
          <attribute name='action'>app.open_folder</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Save</attribute>
          <attribute name='action'>app.save</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Save _As</attribute>
          <attribute name='action'>app.save_as</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Print</attribute>
          <attribute name='action'>app.print</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Edit</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Undo</attribute>
          <attribute name='action'>app.edit_undo</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Redo</attribute>
          <attribute name='action'>app.edit_redo</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Cut</attribute>
          <attribute name='action'>app.edit_cut</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Copy</attribute>
          <attribute name='action'>app.edit_copy</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Paste</attribute>
          <attribute name='action'>app.edit_paste</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Find</attribute>
          <attribute name='action'>app.edit_find</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Source</attribute>

        <submenu>
          <attribute name='label' translatable='yes'>_Spell _Check</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Spell _Check _Buffer</attribute>
            <attribute name='action'>app.source_spellcheck</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Clear _Spelling _Errors</attribute>
            <attribute name='action'>app.source_spellcheck_clear</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Go _to _Next _Spelling _Error</attribute>
            <attribute name='action'>app.source_spellcheck_next_error</attribute>
          </item>
        </submenu>

        <submenu>
          <attribute name='label' translatable='yes'>_Git</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Go _to _Next _Diff</attribute>
            <attribute name='action'>app.source_git_next_diff</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Show _Diff</attribute>
            <attribute name='action'>app.source_git_show_diff</attribute>
          </item>
        </submenu>

        <submenu>
          <attribute name='label' translatable='yes'>_Indentation</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Set _Current _Buffer _Tab</attribute>
            <attribute name='action'>app.source_indentation_set_buffer_tab</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Auto-Indent _Current _Buffer</attribute>
            <attribute name='action'>app.source_indentation_auto_indent_buffer</attribute>
          </item>
        </submenu>

        <item>
          <attribute name='label' translatable='yes'>_Go _to _Line</attribute>
          <attribute name='action'>app.source_goto_line</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Center _Cursor</attribute>
          <attribute name='action'>app.source_center_cursor</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Find _Symbol (Ctags)</attribute>
          <attribute name='action'>app.source_find_symbol_ctags</attribute>
        </item>

        <submenu>
          <attribute name='label' translatable='yes'>_Comments</attribute>
          <item>
            <attribute name='label' translatable='yes'>_Toggle _Comments</attribute>
            <attribute name='action'>app.source_comments_toggle</attribute>
          </item>
          <item>
            <attribute name='label' translatable='yes'>_Add _Documentation (not yet implemented)</attribute>
            <attribute name='action'>app.source_comments_add_documentation</attribute>
          </item>
        </submenu>
        <item>
          <attribute name='label' translatable='yes'>_Find _Documentation</attribute>
          <attribute name='action'>app.source_find_documentation</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go to Declaration</attribute>
          <attribute name='action'>app.source_goto_declaration</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Implementation</attribute>
          <attribute name='action'>app.source_goto_implementation</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Usage</attribute>
          <attribute name='action'>app.source_goto_usage</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Go to Method</attribute>
          <attribute name='action'>app.source_goto_method</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Rename</attribute>
          <attribute name='action'>app.source_rename</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Implement _Method</attribute>
          <attribute name='action'>app.source_implement_method</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go to Next Diagnostic</attribute>
          <attribute name='action'>app.source_goto_next_diagnostic</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Apply Fix-Its</attribute>
          <attribute name='action'>app.source_apply_fix_its</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Project</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
          <attribute name='action'>app.project_set_run_arguments</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Compile _and _Run</attribute>
          <attribute name='action'>app.compile_and_run</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Compile</attribute>
          <attribute name='action'>app.compile</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Run _Command</attribute>
          <attribute name='action'>app.run_command</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Kill _Last _Process</attribute>
          <attribute name='action'>app.kill_last_running</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Force _Kill _Last _Process</attribute>
          <attribute name='action'>app.force_kill_last_running</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Debug</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
          <attribute name='action'>app.debug_set_run_arguments</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Start/_Continue</attribute>
          <attribute name='action'>app.debug_start_continue</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Stop</attribute>
          <attribute name='action'>app.debug_stop</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Kill</attribute>
          <attribute name='action'>app.debug_kill</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Step _Over</attribute>
          <attribute name='action'>app.debug_step_over</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Step _Into</attribute>
          <attribute name='action'>app.debug_step_into</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Step _Out</attribute>
          <attribute name='action'>app.debug_step_out</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Backtrace</attribute>
          <attribute name='action'>app.debug_backtrace</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Show _Variables</attribute>
          <attribute name='action'>app.debug_show_variables</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Run Command</attribute>
          <attribute name='action'>app.debug_run_command</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Toggle _Breakpoint</attribute>
          <attribute name='action'>app.debug_toggle_breakpoint</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Go _to _Stop</attribute>
          <attribute name='action'>app.debug_goto_stop</attribute>
        </item>

    </submenu>

    <submenu>
      <attribute name='label' translatable='yes'>_Window</attribute>

        <item>
          <attribute name='label' translatable='yes'>_Next _Tab</attribute>
          <attribute name='action'>app.next_tab</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Previous _Tab</attribute>
          <attribute name='action'>app.previous_tab</attribute>
        </item>
        <item>
          <attribute name='label' translatable='yes'>_Close _Tab</attribute>
          <attribute name='action'>app.close_tab</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Toggle _Split</attribute>
          <attribute name='action'>app.window_toggle_split</attribute>
        </item>

        <item>
          <attribute name='label' translatable='yes'>_Clear _Terminal</attribute>
          <attribute name='action'>app.window_clear_terminal</attribute>
        </item>

    </submenu>
  </menu>
</interface>
)RAW";
}

void Menu::add_action(const std::string &name, std::function<void()> action) {
  auto g_application=g_application_get_default();
  auto gio_application=Glib::wrap(g_application, true);
  auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);

  actions[name]=application->add_action(name, action);
}

void Menu::set_keys() {
  auto g_application=g_application_get_default();
  auto gio_application=Glib::wrap(g_application, true);
  auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);

  for(auto &key: Config::get().menu.keys) {
    if(key.second.size()>0 && actions.find(key.first)!=actions.end())
      application->set_accel_for_action("app."+key.first, key.second);
  }
}

void Menu::build() {
  builder = Gtk::Builder::create();

  try {
    builder->add_from_string(ui_xml);
    auto object = Menu::get().builder->get_object("juci-menu");
    juci_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
    object = Menu::get().builder->get_object("window-menu");
    window_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
  }
  catch (const Glib::Error &ex) {
    std::cerr << "building menu failed: " << ex.what();
  }
}
<|endoftext|>


<commit_before>#include "ppr.hxx"
#include <list>

namespace miniml
{

Ptr<String> Ppr::string() const
{
  SStream stream;
  stream << this;
  return ptr<String>(stream.str());
}

void PprString::output(OStream &out, unsigned indent) const
{
  out << String(indent, ' ') << m_val;
}

void PprIndent::output(OStream &out, unsigned indent) const
{
  m_child->output(out, indent + m_indent);
}

void PprHCat::output(OStream &out, unsigned indent) const
{
  out << String(indent, ' ');
  for (auto child: *m_children) {
    child->output(out, 0);
  }
}

void PprVCat::output(OStream &out, unsigned indent) const
{
  for (auto child: *m_children) {
    child->output(out, indent);
    out << std::endl;
  }
}

namespace
{
  template <typename T>
  Ptr<T> cat(Ptr<Ppr> a, Ptr<Ppr> b)
  {
    return std::shared_ptr<T>(new T {a, b});
  }
}

namespace ppr
{
  Ptr<Ppr> string(const String &str)
  {
    return ptr<PprString>(str);
  }

  Ptr<Ppr> string(const Char *str)
  {
    return ptr<PprString>(String(str));
  }

  Ptr<Ppr> indent(Ptr<Ppr> ppr, unsigned ind)
  {
    return ptr<PprIndent>(ppr, ind);
  }

  Ptr<Ppr> parens_if(bool b, const Ptr<Ppr> ppr)
  {
    if (b)
      return '('_p * ppr * ')'_p;
    else
      return ppr;
  }
}

Ptr<Ppr> operator>>(Ptr<Ppr> ppr, unsigned ind)
{
  return ppr::indent(ppr, ind * Ppr::default_indent);
}

Ptr<Ppr> operator*(Ptr<Ppr> left, Ptr<Ppr> right)
{
  return cat<PprHCat>(left, right);
}

Ptr<Ppr> operator+(Ptr<Ppr> top, Ptr<Ppr> bottom)
{
  return cat<PprVCat>(top, bottom);
}

Ptr<Ppr> operator""_p(const Char *str, size_t len)
{
  return ptr<PprString>(String(str));
}

Ptr<Ppr> operator""_p(Char c)
{
  return ptr<PprString>(String(1, c));
}

Ptr<Ppr> operator+(Ptr<Ppr> p)
{
  return ' '_p * p;
}

}
<commit_msg>fix Ppr::string()<commit_after>#include "ppr.hxx"
#include <list>

namespace miniml
{

Ptr<String> Ppr::string() const
{
  SStream stream;
  stream << *this;
  return ptr<String>(stream.str());
}

void PprString::output(OStream &out, unsigned indent) const
{
  out << String(indent, ' ') << m_val;
}

void PprIndent::output(OStream &out, unsigned indent) const
{
  m_child->output(out, indent + m_indent);
}

void PprHCat::output(OStream &out, unsigned indent) const
{
  out << String(indent, ' ');
  for (auto child: *m_children) {
    child->output(out, 0);
  }
}

void PprVCat::output(OStream &out, unsigned indent) const
{
  for (auto child: *m_children) {
    child->output(out, indent);
    out << std::endl;
  }
}

namespace
{
  template <typename T>
  Ptr<T> cat(Ptr<Ppr> a, Ptr<Ppr> b)
  {
    return std::shared_ptr<T>(new T {a, b});
  }
}

namespace ppr
{
  Ptr<Ppr> string(const String &str)
  {
    return ptr<PprString>(str);
  }

  Ptr<Ppr> string(const Char *str)
  {
    return ptr<PprString>(String(str));
  }

  Ptr<Ppr> indent(Ptr<Ppr> ppr, unsigned ind)
  {
    return ptr<PprIndent>(ppr, ind);
  }

  Ptr<Ppr> parens_if(bool b, const Ptr<Ppr> ppr)
  {
    if (b)
      return '('_p * ppr * ')'_p;
    else
      return ppr;
  }
}

Ptr<Ppr> operator>>(Ptr<Ppr> ppr, unsigned ind)
{
  return ppr::indent(ppr, ind * Ppr::default_indent);
}

Ptr<Ppr> operator*(Ptr<Ppr> left, Ptr<Ppr> right)
{
  return cat<PprHCat>(left, right);
}

Ptr<Ppr> operator+(Ptr<Ppr> top, Ptr<Ppr> bottom)
{
  return cat<PprVCat>(top, bottom);
}

Ptr<Ppr> operator""_p(const Char *str, size_t len)
{
  return ptr<PprString>(String(str));
}

Ptr<Ppr> operator""_p(Char c)
{
  return ptr<PprString>(String(1, c));
}

Ptr<Ppr> operator+(Ptr<Ppr> p)
{
  return ' '_p * p;
}

}
<|endoftext|>


<commit_before>#include <Wire.h>
#include <DS1307RTC.h>
#include <core.h>
#include "thermostat.h"
#include "rtc.h"

tmElements_t _rtcNow;

tmElementsPtr_t rtcNow() {
  if (!RTC.read(_rtcNow)) {
    Serial.println(F("Read RTC failed!"));
    Serial.println();
  }

  return &_rtcNow;
}

void setRtc(tmElements_t &now) {
  if (!RTC.write(now)) {
    Serial.println(F("Set DS1307 time failed"));
    Serial.println();
  }

  Serial.print(F("Set RTC to "));
  Serial.print(1970 + now.Year);
  Serial.print('-');
  Serial.print(now.Month);
  Serial.print('-');
  Serial.print(now.Day);
  Serial.print(' ');
  Serial.print(now.Hour);
  Serial.print(' ');
  Serial.print(now.Minute);
  Serial.print(' ');
  Serial.print(now.Second);
  Serial.println();
}

void setupRTC() {
  _rtcNow.Year = 2016 - 1970;
  _rtcNow.Month = 11;
  _rtcNow.Day = 22;
  _rtcNow.Hour = 15;
  _rtcNow.Minute = 50;
  _rtcNow.Second = 0;
  _rtcNow.Wday = 3;

  if (!RTC.read(_rtcNow)) {
    if (RTC.chipPresent()) {
      // RTC maybe not inited
      Serial.println(F("DS1307 not inited, set time to 2016-11-25 15:50:00"));
      setRtc(_rtcNow);

      return;
    }

    Serial.println(F("DS1307 read error!  Please check the circuitry."));
    Serial.println();
  }
}

struct Node {
  alarmFunc fn;
  tmElements_t when;
  Node *next;

  Node(tmElements_t aWhen, alarmFunc aFn) : fn(aFn), when(aWhen), next(NULL) {}
};

struct Queue {
  Node *head;

  void add(Node *);
  void remove(Node *);

  Queue() : head(NULL) {}
};

void Queue::add(Node *node) {
  if (head == NULL) {
    head = node;
    return;
  }

  for (Node *p = head; ; p = p->next) {
    if (p->next == NULL) {
      p->next = node;
      break;
    }
  }
}

void Queue::remove(Node *node) {
  for (Node *p = head, *prev = NULL; p != NULL; prev = p, p = p->next) {
    if (p == node) {
      if (prev == NULL) {
        head = p->next;
      } else {
        prev->next = p->next;
      }
      delete node;
      break;
    }
  }
}

Queue alarms;

void checkAlarm() {
  tmElementsPtr_t now = rtcNow();
  for (Node *p = alarms.head; p != NULL; p = p->next) {
    if (p->when.Month != 255 && p->when.Month != now->Month) {
      continue;
    }

    if (p->when.Day != 255 && p->when.Day != now->Day) {
      continue;
    }

    if (p->when.Wday != 255 && p->when.Wday != now->Wday) {
      continue;
    }

    if (p->when.Hour != 255 && p->when.Wday != now->Hour) {
      continue;
    }

    if (p->when.Minute != 255 && p->when.Minute != now->Minute) {
      continue;
    }

    p->fn(now);
  }
}

void *defineRtcAlarm(tmElements_t when, alarmFunc fn) {
  static bool rtcHosted = false;
  if (!rtcHosted) {
    rtcHosted = true;
    core::clock::interval(30 * 1000, &checkAlarm); // check alarm every 30 seconds.
  }

  Node *node = new Node(when, fn);
  alarms.add(node);
  return node;
}

void removeRtcAlarm(void *handle) {
  alarms.remove((Node*)handle);
}
<commit_msg>Fix rtc alarm<commit_after>#include <Wire.h>
#include <DS1307RTC.h>
#include <core.h>
#include "thermostat.h"
#include "rtc.h"

tmElements_t _rtcNow;

tmElementsPtr_t rtcNow() {
  if (!RTC.read(_rtcNow)) {
    Serial.println(F("Read RTC failed!"));
    Serial.println();
  }

  return &_rtcNow;
}

void setRtc(tmElements_t &now) {
  if (!RTC.write(now)) {
    Serial.println(F("Set DS1307 time failed"));
    Serial.println();
  }

  Serial.print(F("Set RTC to "));
  Serial.print(1970 + now.Year);
  Serial.print('-');
  Serial.print(now.Month);
  Serial.print('-');
  Serial.print(now.Day);
  Serial.print(' ');
  Serial.print(now.Hour);
  Serial.print(' ');
  Serial.print(now.Minute);
  Serial.print(' ');
  Serial.print(now.Second);
  Serial.println();
}

void setupRTC() {
  _rtcNow.Year = 2016 - 1970;
  _rtcNow.Month = 11;
  _rtcNow.Day = 22;
  _rtcNow.Hour = 15;
  _rtcNow.Minute = 50;
  _rtcNow.Second = 0;
  _rtcNow.Wday = 3;

  if (!RTC.read(_rtcNow)) {
    if (RTC.chipPresent()) {
      // RTC maybe not inited
      Serial.println(F("DS1307 not inited, set time to 2016-11-25 15:50:00"));
      setRtc(_rtcNow);

      return;
    }

    Serial.println(F("DS1307 read error!  Please check the circuitry."));
    Serial.println();
  }
}

struct Node {
  alarmFunc fn;
  tmElements_t when;
  Node *next;

  Node(tmElements_t aWhen, alarmFunc aFn) : fn(aFn), when(aWhen), next(NULL) {}
};

struct Queue {
  Node *head;

  void add(Node *);
  void remove(Node *);

  Queue() : head(NULL) {}
};

void Queue::add(Node *node) {
  if (head == NULL) {
    head = node;
    return;
  }

  for (Node *p = head; ; p = p->next) {
    if (p->next == NULL) {
      p->next = node;
      break;
    }
  }
}

void Queue::remove(Node *node) {
  for (Node *p = head, *prev = NULL; p != NULL; prev = p, p = p->next) {
    if (p == node) {
      if (prev == NULL) {
        head = p->next;
      } else {
        prev->next = p->next;
      }
      delete node;
      break;
    }
  }
}

Queue alarms;

void checkAlarm() {
  Serial.println("checkAlarm");
  tmElementsPtr_t now = rtcNow();
  for (Node *p = alarms.head; p != NULL; p = p->next) {
    if (p->when.Month != 255 && p->when.Month != now->Month) {
      continue;
    }

    if (p->when.Day != 255 && p->when.Day != now->Day) {
      continue;
    }

    if (p->when.Wday != 255 && p->when.Wday != now->Wday) {
      continue;
    }

    if (p->when.Hour != 255 && p->when.Hour != now->Hour) {
      continue;
    }

    if (p->when.Minute != 255 && p->when.Minute != now->Minute) {
      continue;
    }

    p->fn(now);
  }
}

void *defineRtcAlarm(tmElements_t when, alarmFunc fn) {
  static bool rtcHosted = false;
  if (!rtcHosted) {
    rtcHosted = true;
    Serial.println("Host RTC alarm");
    core::clock::interval(30 * 1000, &checkAlarm); // check alarm every 30 seconds.
  }

  Node *node = new Node(when, fn);
  alarms.add(node);
  return node;
}

void removeRtcAlarm(void *handle) {
  alarms.remove((Node*)handle);
}
<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    const int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    const int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    const int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, const int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

auto adjust_thread_number(const int n_bits,
                          const uint64_t remaining_sequences,
                          uint64_t n_threads) -> uint64_t {
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int channels_16 {16};
  constexpr unsigned int bit_mode_16 {16};
  auto channels{channels_16};

  assert(remaining_sequences > 0);
  assert(n_threads > 0);
  assert((n_bits == bit_mode_16) || (n_bits == bit_mode_16 / 2));

  if (n_bits == bit_mode_16) {
    channels = channels_8;
  }

  if (remaining_sequences <= (channels - 1) * n_threads) {
    n_threads = (remaining_sequences + channels - 1) / channels;
  }

  return n_threads;
}

// arguments: bits, master_length, thr
// static_assert(adjust_thread_number( 8, 32, 10) == 2);
// static_assert(adjust_thread_number( 8, 32,  3) == 2);
// static_assert(adjust_thread_number( 8, 31,  2) == 2);
// static_assert(adjust_thread_number( 8, 17,  2) == 2);
// static_assert(adjust_thread_number( 8, 16,  2) == 1);
// static_assert(adjust_thread_number( 8,  1,  2) == 1);
// static_assert(adjust_thread_number( 8, 32,  1) == 1);
// static_assert(adjust_thread_number(16, 17, 10) == 3);
// static_assert(adjust_thread_number(16, 17,  3) == 3);
// static_assert(adjust_thread_number(16, 16,  3) == 2);
// static_assert(adjust_thread_number(16, 15,  2) == 2);
// static_assert(adjust_thread_number(16,  1,  3) == 1);
// static_assert(adjust_thread_number(16, 17,  1) == 1);

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  thr = adjust_thread_number(bits, master_length, thr);

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<commit_msg>replace implicit 'float to int' truncation with a simple decrement<commit_after>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    const int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    const int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    const int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, const int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

auto adjust_thread_number(const int n_bits,
                          const uint64_t remaining_sequences,
                          uint64_t n_threads) -> uint64_t {
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int channels_16 {16};
  constexpr unsigned int bit_mode_16 {16};
  auto channels{channels_16};

  assert(remaining_sequences > 0);
  assert(n_threads > 0);
  assert((n_bits == bit_mode_16) || (n_bits == bit_mode_16 / 2));

  if (n_bits == bit_mode_16) {
    channels = channels_8;
  }

  while (remaining_sequences <= (n_threads - 1) * channels) {
    --n_threads;
  }

  return n_threads;
}

// arguments: bits, master_length, thr
// static_assert(adjust_thread_number( 8, 32, 10) == 2);
// static_assert(adjust_thread_number( 8, 32,  3) == 2);
// static_assert(adjust_thread_number( 8, 31,  2) == 2);
// static_assert(adjust_thread_number( 8, 17,  2) == 2);
// static_assert(adjust_thread_number( 8, 16,  2) == 1);
// static_assert(adjust_thread_number( 8,  1,  2) == 1);
// static_assert(adjust_thread_number( 8, 32,  1) == 1);
// static_assert(adjust_thread_number(16, 17, 10) == 3);
// static_assert(adjust_thread_number(16, 17,  3) == 3);
// static_assert(adjust_thread_number(16, 16,  3) == 2);
// static_assert(adjust_thread_number(16, 15,  2) == 2);
// static_assert(adjust_thread_number(16,  1,  3) == 1);
// static_assert(adjust_thread_number(16, 17,  1) == 1);

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  thr = adjust_thread_number(bits, master_length, thr);

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<|endoftext|>


<commit_before>#ifndef PLUGIN_MANAGER_HPP
#define PLUGIN_MANAGER_HPP

/// COMPONENT
#include <csapex/utility/constructor.hpp>
#include <csapex/plugin/plugin_locator.h>
#include <csapex/plugin/plugin_constructor.hpp>

/// SYSTEM
#include <csapex/utility/slim_signal.hpp>
#include <class_loader/class_loader.h>
#include <set>
#include <tinyxml.h>
#include <mutex>

namespace csapex
{

template <class M>
class PluginManagerImp
{
    template <class>
    friend class PluginManager;

protected:
    typedef PluginConstructor<M> PluginConstructorM;
    typedef std::map<std::string, PluginConstructorM> Constructors;

protected:
    PluginManagerImp(const std::string& full_name)
        : plugins_loaded_(false), full_name_(full_name)
    {
    }

    PluginManagerImp(const PluginManagerImp& rhs);
    PluginManagerImp& operator = (const PluginManagerImp& rhs);

public:
    virtual ~PluginManagerImp() {
    }

protected:
    void registerConstructor(PluginConstructorM constructor) {
        available_classes[constructor.getType()] = constructor;
    }

    void enumerateXmlFiles()
    {
    }

    void load(csapex::PluginLocator* locator) {
        std::vector<std::string> xml_files = locator->enumerateXmlFiles<M>();
        std::vector<std::string> library_paths = locator->enumerateLibraryPaths();

        library_paths_.insert(library_paths_.end(), library_paths.begin(), library_paths.end());

        for(std::vector<std::string>::const_iterator manifest = xml_files.begin(); manifest != xml_files.end(); ++manifest) {
            processManifest(locator, *manifest);
        }

        plugins_loaded_ = true;
    }

    bool processManifest(csapex::PluginLocator* locator, const std::string& xml_file)
    {
        TiXmlDocument document;
        document.LoadFile(xml_file);
        TiXmlElement * config = document.RootElement();
        if (config == nullptr) {
            std::cerr << "[Plugin] Cannot load the file " << xml_file << std::endl;
            return false;
        }
        if (config->ValueStr() != "library") {
            std::cerr << "[Plugin] Manifest root is not <library>" << std::endl;
            return false;
        }

        TiXmlElement* library = config;
        while (library != nullptr) {

            std::string library_name = library->Attribute("path");
            if (library_name.size() == 0) {
                std::cerr << "[Plugin] Item in row" << library->Row() << " does not contain a path attribute" << std::endl;
                continue;
            }

            if(!locator->isLibraryIgnored(library_name)) {
                loadLibrary(library_name, library);
            }

            library_to_locator_[library_name] = locator;

            library = library->NextSiblingElement( "library" );
        }

        return true;
    }

    void loadLibrary(const std::string& library_name, TiXmlElement* library)  {
        if(!containsPlugins(library)) {
        }

        TiXmlElement* class_element = library->FirstChildElement("class");
        while (class_element) {
            loadClass(library_name, class_element);

            class_element = class_element->NextSiblingElement( "class" );
        }
    }

    void loadClass(const std::string& library_name, TiXmlElement* class_element) {
        std::string base_class_type = class_element->Attribute("base_class_type");
        std::string derived_class = class_element->Attribute("type");

        std::string lookup_name;
        if(class_element->Attribute("name") != nullptr) {
            lookup_name = class_element->Attribute("name");
        } else {
            lookup_name = derived_class;
        }

        if(base_class_type == full_name_){
            std::string description = readString(class_element, "description");
            std::string icon = readString(class_element, "icon");
            std::string tags = readString(class_element, "tags");

            PluginConstructorM constructor;
            constructor.setType(lookup_name);
            constructor.setDescription(description);
            constructor.setIcon(icon);
            constructor.setTags(tags);

            std::function< std::shared_ptr<M>(M*)> make_shared_ptr = [](M* p) { return std::shared_ptr<M>(p); };

            constructor.setConstructor([this, lookup_name]() {
                return createInstance(lookup_name);
            });
            constructor.setLibraryName(library_name);

            registerConstructor(constructor);

            plugin_to_library_[lookup_name] = library_name;
        }
    }

    std::shared_ptr<M> createInstance(const std::string& lookup_name)
    {
        auto loader = getLoader(plugin_to_library_.at(lookup_name));
        try {
            M* raw_ptr = loader->template createUnmanagedInstance<M>(lookup_name);
            return std::shared_ptr<M>(raw_ptr);

        } catch(const std::exception& e) {
            std::cerr << "cannot create instance of " << lookup_name << ": " << e.what() << std::endl;
            return nullptr;
        }
    }

    std::shared_ptr<class_loader::ClassLoader> getLoader(const std::string& library_name)
    {
        std::string library_path = library_name + ".so";

        auto pos = loaders_.find(library_path);
        if(pos == loaders_.end()) {
            try {
                auto loader = std::make_shared<class_loader::ClassLoader>(library_path);
                library_to_locator_[library_name]->setLibraryLoaded(library_name, library_path);

                loaders_[library_path] = loader;

                return loader;

            } catch(const class_loader::ClassLoaderException& e) {
                std::cerr << "cannot load library " << library_name << ": " << e.what() << std::endl;
                library_to_locator_[library_name]->setLibraryError(library_name, e.what());
            }

            return nullptr;

        } else {
            return pos->second;
        }
    }

    std::string readString(TiXmlElement* class_element, const std::string& name) {
        TiXmlElement* description = class_element->FirstChildElement(name);
        std::string description_str;
        if(description) {
            description_str = description->GetText() ? description->GetText() : "";
        }

        return description_str;
    }

    bool containsPlugins(TiXmlElement* library)
    {
        TiXmlElement* class_element = library->FirstChildElement("class");
        while (class_element) {
            std::string base_class_type = class_element->Attribute("base_class_type");
            if(base_class_type == full_name_) {
                return true;
            }
            class_element = class_element->NextSiblingElement( "class" );
        }

        return false;
    }

protected:
    csapex::slim_signal::Signal<void(const std::string&)> loaded;

protected:
    bool plugins_loaded_;

    std::map< std::string, std::shared_ptr<class_loader::ClassLoader> > loaders_;
    std::map< std::string, std::string > plugin_to_library_;

    std::vector<std::string> library_paths_;
    std::map<std::string, csapex::PluginLocator*> library_to_locator_;

    std::string full_name_;
    Constructors available_classes;
};

template <typename T>
struct PluginManagerGroup
{
    enum Group {
        value = 10
    };
};

class PluginManagerLocker
{
public:
    static std::mutex& getMutex()
    {
        static PluginManagerLocker instance;
        return instance.mutex;
    }

private:
    PluginManagerLocker()
    {}

private:
    std::mutex mutex;
};

template <class M>
class PluginManager
{
protected:
    typedef PluginManagerImp<M> Parent;

public:
    typedef typename Parent::PluginConstructorM Constructor;
    typedef typename Parent::Constructors Constructors;

    PluginManager(const std::string& full_name)
    {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        if(i_count == 0) {
            ++i_count;
            instance = new Parent(full_name);
        }
        instance->loaded.connect(loaded);
    }

    virtual ~PluginManager()
    {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        --i_count;
        if(i_count == 0) {
            delete instance;
        }
    }

    virtual bool pluginsLoaded() const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->plugins_loaded_;
    }

    virtual void load(csapex::PluginLocator* locator) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());

        instance->load(locator);
    }

    const Constructors& getConstructors() const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes;
    }
    const Constructor& getConstructor(unsigned index) const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        typename Constructors::iterator it = instance->available_classes.begin();
        std::advance(it, index);
        return it->second;
    }
    const Constructor& getConstructor(const std::string& key) const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes.at(key);
    }
    Constructor& getConstructor(const std::string& key) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes.at(key);
    }

    Constructor* getConstructorNoThrow(const std::string& key) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        auto pos = instance->available_classes.find(key);
        if(pos != instance->available_classes.end()) {
            return &pos->second;
        } else {
            return nullptr;
        }
    }

public:
    csapex::slim_signal::Signal<void(const std::string&)> loaded;

protected:
    static int i_count;
    static Parent* instance;
};

template <class M>
int PluginManager<M>::i_count = 0;
template <class M>
typename PluginManager<M>::Parent* PluginManager<M>::instance(nullptr);

}

#endif // PLUGIN_MANAGER_HPP
<commit_msg>plugin loader fix<commit_after>#ifndef PLUGIN_MANAGER_HPP
#define PLUGIN_MANAGER_HPP

/// COMPONENT
#include <csapex/utility/constructor.hpp>
#include <csapex/plugin/plugin_locator.h>
#include <csapex/plugin/plugin_constructor.hpp>

/// SYSTEM
#include <csapex/utility/slim_signal.hpp>
#include <class_loader/class_loader.h>
#include <set>
#include <tinyxml.h>
#include <mutex>

namespace csapex
{

template <class M>
class PluginManagerImp
{
    template <class>
    friend class PluginManager;

protected:
    typedef PluginConstructor<M> PluginConstructorM;
    typedef std::map<std::string, PluginConstructorM> Constructors;

protected:
    PluginManagerImp(const std::string& full_name)
        : plugins_loaded_(false), full_name_(full_name)
    {
    }

    PluginManagerImp(const PluginManagerImp& rhs);
    PluginManagerImp& operator = (const PluginManagerImp& rhs);

public:
    virtual ~PluginManagerImp() {
    }

protected:
    void registerConstructor(PluginConstructorM constructor) {
        available_classes[constructor.getType()] = constructor;
    }

    void enumerateXmlFiles()
    {
    }

    void load(csapex::PluginLocator* locator) {
        std::vector<std::string> xml_files = locator->enumerateXmlFiles<M>();
        std::vector<std::string> library_paths = locator->enumerateLibraryPaths();

        library_paths_.insert(library_paths_.end(), library_paths.begin(), library_paths.end());

        for(std::vector<std::string>::const_iterator manifest = xml_files.begin(); manifest != xml_files.end(); ++manifest) {
            processManifest(locator, *manifest);
        }

        plugins_loaded_ = true;
    }

    bool processManifest(csapex::PluginLocator* locator, const std::string& xml_file)
    {
        TiXmlDocument document;
        document.LoadFile(xml_file);
        TiXmlElement * config = document.RootElement();
        if (config == nullptr) {
            std::cerr << "[Plugin] Cannot load the file " << xml_file << std::endl;
            return false;
        }
        if (config->ValueStr() != "library") {
            std::cerr << "[Plugin] Manifest root is not <library>" << std::endl;
            return false;
        }

        TiXmlElement* library = config;
        while (library != nullptr) {

            std::string library_name = library->Attribute("path");
            if (library_name.size() == 0) {
                std::cerr << "[Plugin] Item in row" << library->Row() << " does not contain a path attribute" << std::endl;
                continue;
            }

            if(!locator->isLibraryIgnored(library_name)) {
                loadLibrary(library_name, library);
            }

            library_to_locator_[library_name] = locator;

            library = library->NextSiblingElement( "library" );
        }

        return true;
    }

    void loadLibrary(const std::string& library_name, TiXmlElement* library)  {
        if(!containsPlugins(library)) {
        }

        TiXmlElement* class_element = library->FirstChildElement("class");
        while (class_element) {
            loadClass(library_name, class_element);

            class_element = class_element->NextSiblingElement( "class" );
        }
    }

    void loadClass(const std::string& library_name, TiXmlElement* class_element) {
        std::string base_class_type = class_element->Attribute("base_class_type");
        std::string derived_class = class_element->Attribute("type");

        std::string lookup_name;
        if(class_element->Attribute("name") != nullptr) {
            lookup_name = class_element->Attribute("name");
        } else {
            lookup_name = derived_class;
        }

        if(base_class_type == full_name_){
            std::string description = readString(class_element, "description");
            std::string icon = readString(class_element, "icon");
            std::string tags = readString(class_element, "tags");

            PluginConstructorM constructor;
            constructor.setType(lookup_name);
            constructor.setDescription(description);
            constructor.setIcon(icon);
            constructor.setTags(tags);

            std::function< std::shared_ptr<M>(M*)> make_shared_ptr = [](M* p) { return std::shared_ptr<M>(p); };

            constructor.setConstructor([this, lookup_name]() {
                return createInstance(lookup_name);
            });
            constructor.setLibraryName(library_name);

            registerConstructor(constructor);

            plugin_to_library_[lookup_name] = library_name;
        }
    }

    std::shared_ptr<M> createInstance(const std::string& lookup_name)
    {
        auto loader = getLoader(plugin_to_library_.at(lookup_name));
        if(!loader) {
            return nullptr;
        }
        try {
            M* raw_ptr = loader->template createUnmanagedInstance<M>(lookup_name);
            return std::shared_ptr<M>(raw_ptr);

        } catch(const std::exception& e) {
            std::cerr << "cannot create instance of " << lookup_name << ": " << e.what() << std::endl;
            return nullptr;
        }
    }

    std::shared_ptr<class_loader::ClassLoader> getLoader(const std::string& library_name)
    {
        std::string library_path = library_name + ".so";

        auto pos = loaders_.find(library_path);
        if(pos == loaders_.end()) {
            try {
                auto loader = std::make_shared<class_loader::ClassLoader>(library_path);
                library_to_locator_[library_name]->setLibraryLoaded(library_name, library_path);

                loaders_[library_path] = loader;

                return loader;

            } catch(const class_loader::ClassLoaderException& e) {
                std::cerr << "cannot load library " << library_name << ": " << e.what() << std::endl;
                library_to_locator_[library_name]->setLibraryError(library_name, e.what());
            }

            return nullptr;

        } else {
            return pos->second;
        }
    }

    std::string readString(TiXmlElement* class_element, const std::string& name) {
        TiXmlElement* description = class_element->FirstChildElement(name);
        std::string description_str;
        if(description) {
            description_str = description->GetText() ? description->GetText() : "";
        }

        return description_str;
    }

    bool containsPlugins(TiXmlElement* library)
    {
        TiXmlElement* class_element = library->FirstChildElement("class");
        while (class_element) {
            std::string base_class_type = class_element->Attribute("base_class_type");
            if(base_class_type == full_name_) {
                return true;
            }
            class_element = class_element->NextSiblingElement( "class" );
        }

        return false;
    }

protected:
    csapex::slim_signal::Signal<void(const std::string&)> loaded;

protected:
    bool plugins_loaded_;

    std::map< std::string, std::shared_ptr<class_loader::ClassLoader> > loaders_;
    std::map< std::string, std::string > plugin_to_library_;

    std::vector<std::string> library_paths_;
    std::map<std::string, csapex::PluginLocator*> library_to_locator_;

    std::string full_name_;
    Constructors available_classes;
};

template <typename T>
struct PluginManagerGroup
{
    enum Group {
        value = 10
    };
};

class PluginManagerLocker
{
public:
    static std::mutex& getMutex()
    {
        static PluginManagerLocker instance;
        return instance.mutex;
    }

private:
    PluginManagerLocker()
    {}

private:
    std::mutex mutex;
};

template <class M>
class PluginManager
{
protected:
    typedef PluginManagerImp<M> Parent;

public:
    typedef typename Parent::PluginConstructorM Constructor;
    typedef typename Parent::Constructors Constructors;

    PluginManager(const std::string& full_name)
    {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        if(i_count == 0) {
            ++i_count;
            instance = new Parent(full_name);
        }
        instance->loaded.connect(loaded);
    }

    virtual ~PluginManager()
    {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        --i_count;
        if(i_count == 0) {
            delete instance;
        }
    }

    virtual bool pluginsLoaded() const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->plugins_loaded_;
    }

    virtual void load(csapex::PluginLocator* locator) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());

        instance->load(locator);
    }

    const Constructors& getConstructors() const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes;
    }
    const Constructor& getConstructor(unsigned index) const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        typename Constructors::iterator it = instance->available_classes.begin();
        std::advance(it, index);
        return it->second;
    }
    const Constructor& getConstructor(const std::string& key) const {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes.at(key);
    }
    Constructor& getConstructor(const std::string& key) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        return instance->available_classes.at(key);
    }

    Constructor* getConstructorNoThrow(const std::string& key) {
        std::unique_lock<std::mutex> lock(PluginManagerLocker::getMutex());
        auto pos = instance->available_classes.find(key);
        if(pos != instance->available_classes.end()) {
            return &pos->second;
        } else {
            return nullptr;
        }
    }

public:
    csapex::slim_signal::Signal<void(const std::string&)> loaded;

protected:
    static int i_count;
    static Parent* instance;
};

template <class M>
int PluginManager<M>::i_count = 0;
template <class M>
typename PluginManager<M>::Parent* PluginManager<M>::instance(nullptr);

}

#endif // PLUGIN_MANAGER_HPP
<|endoftext|>