<commit_before>
// Copyright 2014 Toggl Desktop developers.

#include "../src/error.h"

#include <string>

#include "./const.h"

namespace toggl {

bool IsNetworkingError(const error err) {
    std::string value(err);
    if (value.find(kCannotConnectError) != std::string::npos) {
        return true;
    }
    if (value.find("Cannot establish proxy connection") != std::string::npos) {
        return true;
    }
    if (value.find("certificate verify failed") != std::string::npos) {
        return true;
    }
    if (value.find("Proxy Authentication Required") != std::string::npos) {
        return true;
    }
    if (value.find("Cannot assign requested address") != std::string::npos) {
        return true;
    }
    if (value.find("Certificate validation error") != std::string::npos) {
        return true;
    }
    if (value.find("Unacceptable certificate from www.toggl.com")
            != std::string::npos) {
        return true;
    }
    if (value.find("Host not found") != std::string::npos) {
        return true;
    }
    if (value.find("Cannot upgrade to WebSocket connection")
            != std::string::npos) { // NOLINT
        return true;
    }
    if (value.find("No message received") != std::string::npos) {
        return true;
    }
    if (value.find("Connection refused") != std::string::npos) {
        return true;
    }
    if (value.find("Connection timed out") != std::string::npos) {
        return true;
    }
    if (value.find("connect timed out") != std::string::npos) {
        return true;
    }
    if (value.find("SSL connection unexpectedly closed") != std::string::npos) {
        return true;
    }
    if (value.find("Network is down") != std::string::npos) {
        return true;
    }
    if (value.find("Network is unreachable") != std::string::npos) {
        return true;
    }
    if (value.find("Host is down") != std::string::npos) {
        return true;
    }
    if (value.find("No route to host") != std::string::npos) {
        return true;
    }
    if ((value.find("I/O error: 1") != std::string::npos)
            && (value.find(":443") != std::string::npos)) {
        return true;
    }
    if (value.find("The request timed out") != std::string::npos) {
        return true;
    }
    if (value.find("Could not connect to the server") != std::string::npos) {
        return true;
    }
    if (value.find("Connection reset by peer") != std::string::npos) {
        return true;
    }
    if (value.find("The Internet connection appears to be offline")
            != std::string::npos) {
        return true;
    }
    if (value.find("Timeout") != std::string::npos) {
        return true;
    }
    if (value.find("SSL Exception") != std::string::npos) {
        return true;
    }
    if (value.find("An internal server error occurred.") != std::string::npos) {
        return true;
    }
    return false;
}

bool IsUserError(const error err) {
    if (noError == err) {
        return false;
    }
    std::string value(err);
    if (value.find(kPaymentRequiredError) != std::string::npos) {
        return true;
    }
    if (value.find("Access to file denied") != std::string::npos) {
        return true;
    }
    if (value.find(kBadRequestError) != std::string::npos) {
        return true;
    }
    if (value.find(kUnauthorizedError) != std::string::npos) {
        return true;
    }
    if (value.find("So short time entries, perhaps accidentally?")
            != std::string::npos) {
        return true;
    }
    if (value.find("Cannot write file") != std::string::npos) {
        return true;
    }
    if (value.find("is suspended") != std::string::npos) {
        return true;
    }
    if (value.find("Request to server failed with status code: 403")
            != std::string::npos) {
        return true;
    }
    if (value.find("This version of the app is not supported")
            != std::string::npos) {
        return true;
    }
    if (value.find("Stop time must be after start time")
            != std::string::npos) {
        return true;
    }
    if (value.find("Invalid e-mail or password") != std::string::npos) {
        return true;
    }
    if (value.find("Maximum length for description") != std::string::npos) {
        return true;
    }
    if (value.find("Start time year must be between 2010 and 2100")
            != std::string::npos) {
        return true;
    }
    if (value.find("Missing workspace ID") != std::string::npos) {
        return true;
    }
    if (value.find(kEndpointGoneError) != std::string::npos) {
        return true;
    }
    if (value.find("Password should be at least") != std::string::npos) {
        return true;
    }
    if (value.find("User with this email already exists") !=
            std::string::npos) {
        return true;
    }
    if (value.find("Invalid e-mail") != std::string::npos) {
        return true;
    }
    if (value.find(kCannotAccessWorkspaceError) != std::string::npos) {
        return true;
    }
    return false;
}

}  // namespace toggl
<commit_msg>Treat 'SSL context exception' as user error (lib)<commit_after>
// Copyright 2014 Toggl Desktop developers.

#include "../src/error.h"

#include <string>

#include "./const.h"

namespace toggl {

bool IsNetworkingError(const error err) {
    std::string value(err);
    if (value.find(kCannotConnectError) != std::string::npos) {
        return true;
    }
    if (value.find("Cannot establish proxy connection") != std::string::npos) {
        return true;
    }
    if (value.find("certificate verify failed") != std::string::npos) {
        return true;
    }
    if (value.find("Proxy Authentication Required") != std::string::npos) {
        return true;
    }
    if (value.find("Cannot assign requested address") != std::string::npos) {
        return true;
    }
    if (value.find("Certificate validation error") != std::string::npos) {
        return true;
    }
    if (value.find("Unacceptable certificate from www.toggl.com")
            != std::string::npos) {
        return true;
    }
    if (value.find("Host not found") != std::string::npos) {
        return true;
    }
    if (value.find("Cannot upgrade to WebSocket connection")
            != std::string::npos) { // NOLINT
        return true;
    }
    if (value.find("No message received") != std::string::npos) {
        return true;
    }
    if (value.find("Connection refused") != std::string::npos) {
        return true;
    }
    if (value.find("Connection timed out") != std::string::npos) {
        return true;
    }
    if (value.find("connect timed out") != std::string::npos) {
        return true;
    }
    if (value.find("SSL connection unexpectedly closed") != std::string::npos) {
        return true;
    }
    if (value.find("Network is down") != std::string::npos) {
        return true;
    }
    if (value.find("Network is unreachable") != std::string::npos) {
        return true;
    }
    if (value.find("Host is down") != std::string::npos) {
        return true;
    }
    if (value.find("No route to host") != std::string::npos) {
        return true;
    }
    if ((value.find("I/O error: 1") != std::string::npos)
            && (value.find(":443") != std::string::npos)) {
        return true;
    }
    if (value.find("The request timed out") != std::string::npos) {
        return true;
    }
    if (value.find("Could not connect to the server") != std::string::npos) {
        return true;
    }
    if (value.find("Connection reset by peer") != std::string::npos) {
        return true;
    }
    if (value.find("The Internet connection appears to be offline")
            != std::string::npos) {
        return true;
    }
    if (value.find("Timeout") != std::string::npos) {
        return true;
    }
    if (value.find("SSL Exception") != std::string::npos) {
        return true;
    }
    if (value.find("An internal server error occurred.") != std::string::npos) {
        return true;
    }
    return false;
}

bool IsUserError(const error err) {
    if (noError == err) {
        return false;
    }
    std::string value(err);
    if (value.find(kPaymentRequiredError) != std::string::npos) {
        return true;
    }
    if (value.find("SSL context exception") != std::string::npos) {
        return true;
    }
    if (value.find("Access to file denied") != std::string::npos) {
        return true;
    }
    if (value.find(kBadRequestError) != std::string::npos) {
        return true;
    }
    if (value.find(kUnauthorizedError) != std::string::npos) {
        return true;
    }
    if (value.find("So short time entries, perhaps accidentally?")
            != std::string::npos) {
        return true;
    }
    if (value.find("Cannot write file") != std::string::npos) {
        return true;
    }
    if (value.find("is suspended") != std::string::npos) {
        return true;
    }
    if (value.find("Request to server failed with status code: 403")
            != std::string::npos) {
        return true;
    }
    if (value.find("This version of the app is not supported")
            != std::string::npos) {
        return true;
    }
    if (value.find("Stop time must be after start time")
            != std::string::npos) {
        return true;
    }
    if (value.find("Invalid e-mail or password") != std::string::npos) {
        return true;
    }
    if (value.find("Maximum length for description") != std::string::npos) {
        return true;
    }
    if (value.find("Start time year must be between 2010 and 2100")
            != std::string::npos) {
        return true;
    }
    if (value.find("Missing workspace ID") != std::string::npos) {
        return true;
    }
    if (value.find(kEndpointGoneError) != std::string::npos) {
        return true;
    }
    if (value.find("Password should be at least") != std::string::npos) {
        return true;
    }
    if (value.find("User with this email already exists") !=
            std::string::npos) {
        return true;
    }
    if (value.find("Invalid e-mail") != std::string::npos) {
        return true;
    }
    if (value.find(kCannotAccessWorkspaceError) != std::string::npos) {
        return true;
    }
    return false;
}

}  // namespace toggl
<|endoftext|>


<commit_before>#include <mruby.h>

#include <Fl/Fl.h>
#include <Fl/Fl_draw.h>

#include "macros.h"
#include "helpers.h"

// FLTK.event_key(key=nil)
// Gets which key on the keyboard was last pushed.
// If a key is given, returns true if the given key was held down (or pressed) during the last event.
mrb_value mrb_fltk_event_key_module_method( mrb_state *mrb, mrb_value self ) {
  mrb_value key;
  mrb_get_args( mrb, "i", &key );

  if( mrb_nil_p( key ) ) {
    return mrb_fixnum_value( Fl::event_key() );
  } else {
    if( Fl::event_key( mrb_fixnum( key ) ) ) {
      return mrb_true_value();
    } else {
      return mrb_false_value();
    }
  }
}

// FLTK.run
mrb_value mrb_fltk_run_module_method( mrb_state *mrb, mrb_value self ) {
  return mrb_fixnum_value( Fl::run() );
}

void mrb_fltk_module_init( mrb_state *mrb ) {
  ARENA_SAVE;

  struct RClass *mrb_fltk_module = mrb_define_module( mrb, "FLTK" );

  // Fl_Align
  DEFINE_FIXNUM_CONSTANT( ALIGN_CENTER, FL_ALIGN_CENTER, mrb_fltk_module );                         // Align the label horizontally in the middle.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP, FL_ALIGN_TOP, mrb_fltk_module );                               // Align the label at the top of the widget. Inside labels appear below the top, outside labels are drawn on top of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM, FL_ALIGN_BOTTOM, mrb_fltk_module );                         // Align the label at the bottom of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT, FL_ALIGN_LEFT, mrb_fltk_module );                             // Align the label at the left of the widget. Inside labels appear left-justified starting at the left side of the widget, outside labels are right-justified and drawn to the left of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT, FL_ALIGN_RIGHT, mrb_fltk_module );                           // Align the label to the right of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_INSIDE, FL_ALIGN_INSIDE, mrb_fltk_module );                         // Draw the label inside of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TEXT_OVER_IMAGE, FL_ALIGN_TEXT_OVER_IMAGE, mrb_fltk_module );       // If the label contains an image, draw the text on top of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_OVER_TEXT, FL_ALIGN_IMAGE_OVER_TEXT, mrb_fltk_module );       // If the label contains an image, draw the text below the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_CLIP, FL_ALIGN_CLIP, mrb_fltk_module );                             // All parts of the label that are lager than the widget will not be drawn .
  DEFINE_FIXNUM_CONSTANT( ALIGN_WRAP, FL_ALIGN_WRAP, mrb_fltk_module );                             // Wrap text that does not fit the width of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_NEXT_TO_TEXT, FL_ALIGN_IMAGE_NEXT_TO_TEXT, mrb_fltk_module ); // If the label contains an image, draw the text to the right of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TEXT_NEXT_TO_IMAGE, FL_ALIGN_TEXT_NEXT_TO_IMAGE, mrb_fltk_module ); // If the label contains an image, draw the text to the left of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_BACKDROP, FL_ALIGN_IMAGE_BACKDROP, mrb_fltk_module );         // If the label contains an image, draw the image or deimage in the background.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP_LEFT, FL_ALIGN_TOP_LEFT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP_RIGHT, FL_ALIGN_TOP_RIGHT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM_LEFT, FL_ALIGN_BOTTOM_LEFT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM_RIGHT, FL_ALIGN_BOTTOM_RIGHT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT_TOP, FL_ALIGN_LEFT_TOP, mrb_fltk_module );           // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT_TOP, FL_ALIGN_RIGHT_TOP, mrb_fltk_module );         // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT_BOTTOM, FL_ALIGN_LEFT_BOTTOM, mrb_fltk_module );     // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT_BOTTOM, FL_ALIGN_RIGHT_BOTTOM, mrb_fltk_module );   // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_NOWRAP, FL_ALIGN_NOWRAP, mrb_fltk_module );               // for back compatibility
  DEFINE_FIXNUM_CONSTANT( ALIGN_POSITION_MASK, FL_ALIGN_POSITION_MASK, mrb_fltk_module ); // left, right, top, bottom
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_MASK, FL_ALIGN_IMAGE_MASK, mrb_fltk_module );       // l/r, t/b, backdrop

  // Fl_Font
  DEFINE_FIXNUM_CONSTANT( HELVETICA, FL_HELVETICA, mrb_fltk_module );                         // Helvetica (or Arial) normal (0)
  DEFINE_FIXNUM_CONSTANT( HELVETICA_BOLD, FL_HELVETICA_BOLD, mrb_fltk_module );               // Helvetica (or Arial) bold
  DEFINE_FIXNUM_CONSTANT( HELVETICA_ITALIC, FL_HELVETICA_ITALIC, mrb_fltk_module );           // Helvetica (or Arial) oblique
  DEFINE_FIXNUM_CONSTANT( HELVETICA_BOLD_ITALIC, FL_HELVETICA_BOLD_ITALIC, mrb_fltk_module ); // Helvetica (or Arial) bold-oblique
  DEFINE_FIXNUM_CONSTANT( COURIER, FL_COURIER, mrb_fltk_module );                             // Courier normal
  DEFINE_FIXNUM_CONSTANT( COURIER_BOLD, FL_COURIER_BOLD, mrb_fltk_module );                   // Courier bold
  DEFINE_FIXNUM_CONSTANT( COURIER_ITALIC, FL_COURIER_ITALIC, mrb_fltk_module );               // Courier italic
  DEFINE_FIXNUM_CONSTANT( COURIER_BOLD_ITALIC, FL_COURIER_BOLD_ITALIC, mrb_fltk_module );     // Courier bold-italic
  DEFINE_FIXNUM_CONSTANT( TIMES, FL_TIMES, mrb_fltk_module );                                 // Times roman
  DEFINE_FIXNUM_CONSTANT( TIMES_BOLD, FL_TIMES_BOLD, mrb_fltk_module );                       // Times roman bold
  DEFINE_FIXNUM_CONSTANT( TIMES_ITALIC, FL_TIMES_ITALIC, mrb_fltk_module );                   // Times roman italic
  DEFINE_FIXNUM_CONSTANT( TIMES_BOLD_ITALIC, FL_TIMES_BOLD_ITALIC, mrb_fltk_module );         // Times roman bold-italic
  DEFINE_FIXNUM_CONSTANT( SYMBOL, FL_SYMBOL, mrb_fltk_module );                               // Standard symbol font
  DEFINE_FIXNUM_CONSTANT( SCREEN, FL_SCREEN, mrb_fltk_module );                               // Default monospaced screen font
  DEFINE_FIXNUM_CONSTANT( SCREEN_BOLD, FL_SCREEN_BOLD, mrb_fltk_module );                     // Default monospaced bold screen font
  DEFINE_FIXNUM_CONSTANT( ZAPF_DINGBATS, FL_ZAPF_DINGBATS, mrb_fltk_module );                 // Zapf-dingbats font
  DEFINE_FIXNUM_CONSTANT( FREE_FONT, FL_FREE_FONT, mrb_fltk_module );                         // first one to allocate
  DEFINE_FIXNUM_CONSTANT( BOLD, FL_BOLD, mrb_fltk_module );                                   // add this to helvetica, courier, or times
  DEFINE_FIXNUM_CONSTANT( ITALIC, FL_ITALIC, mrb_fltk_module );                               // add this to helvetica, courier, or times
  DEFINE_FIXNUM_CONSTANT( BOLD_ITALIC, FL_BOLD_ITALIC, mrb_fltk_module );                     // add this to helvetica, courier, or times

  // Fl_When
  DEFINE_FIXNUM_CONSTANT( WHEN_NEVER, FL_WHEN_NEVER, mrb_fltk_module );                         // Never call the callback.
  DEFINE_FIXNUM_CONSTANT( WHEN_CHANGED, FL_WHEN_CHANGED, mrb_fltk_module );                     // Do the callback only when the widget value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_NOT_CHANGED, FL_WHEN_NOT_CHANGED, mrb_fltk_module );             // Do the callback whenever the user interacts with the widget.
  DEFINE_FIXNUM_CONSTANT( WHEN_RELEASE, FL_WHEN_RELEASE, mrb_fltk_module );                     // Do the callback when the button or key is released and the value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_RELEASE_ALWAYS, FL_WHEN_RELEASE_ALWAYS, mrb_fltk_module );       // Do the callback when the button or key is released, even if the value doesn't change.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY, FL_WHEN_ENTER_KEY, mrb_fltk_module );                 // Do the callback when the user presses the ENTER key and the value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY_ALWAYS, FL_WHEN_ENTER_KEY_ALWAYS, mrb_fltk_module );   // Do the callback when the user presses the ENTER key, even if the value doesn't change.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY_CHANGED, FL_WHEN_ENTER_KEY_CHANGED, mrb_fltk_module ); // ?

  // Fl_Event
  DEFINE_FIXNUM_CONSTANT( NO_EVENT, FL_NO_EVENT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( PUSH, FL_PUSH, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( RELEASE, FL_RELEASE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ENTER, FL_ENTER, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( LEAVE, FL_LEAVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DRAG, FL_DRAG, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( FOCUS, FL_FOCUS, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( UNFOCUS, FL_UNFOCUS, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYDOWN, FL_KEYDOWN, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYBOARD, FL_KEYBOARD, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYUP, FL_KEYUP, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( CLOSE, FL_CLOSE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( MOVE, FL_MOVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SHORTCUT, FL_SHORTCUT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DEACTIVATE, FL_DEACTIVATE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ACTIVATE, FL_ACTIVATE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( HIDE, FL_HIDE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SHOW, FL_SHOW, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( PASTE, FL_PASTE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SELECTIONCLEAR, FL_SELECTIONCLEAR, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( MOUSEWHEEL, FL_MOUSEWHEEL, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_ENTER, FL_DND_ENTER, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_DRAG, FL_DND_DRAG, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_LEAVE, FL_DND_LEAVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_RELEASE, FL_DND_RELEASE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SCREEN_CONFIGURATION_CHANGED, FL_SCREEN_CONFIGURATION_CHANGED, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( FULLSCREEN, FL_FULLSCREEN, mrb_fltk_module );

  // DEFINE_MODULE_METHOD( root, font_name, MRB_ARGS_REQ( 1 ) );
  mrb_define_module_function( mrb, mrb_fltk_module, "run", mrb_fltk_run_module_method, MRB_ARGS_NONE() );
  // DEFINE_MODULE_METHOD( root, set_fonts, MRB_ARGS_REQ( 1 ) );

  ARENA_RESTORE;
}
<commit_msg>FLTK.focus=(widget) and comments on FLTK.focus getter problems<commit_after>#include <mruby.h>
#include <mruby/data.h>

#include <Fl/Fl.h>
#include <Fl/Fl_draw.h>

#include "macros.h"
#include "helpers.h"

// FLTK.event_key(key=nil)
// Gets which key on the keyboard was last pushed.
// If a key is given, returns true if the given key was held down (or pressed) during the last event.
mrb_value mrb_fltk_event_key_module_method( mrb_state *mrb, mrb_value self ) {
  mrb_value key;
  mrb_get_args( mrb, "i", &key );

  if( mrb_nil_p( key ) ) {
    return mrb_fixnum_value( Fl::event_key() );
  } else {
    if( Fl::event_key( mrb_fixnum( key ) ) ) {
      return mrb_true_value();
    } else {
      return mrb_false_value();
    }
  }
}

// FLTK.focus
// Gets the current focused widget.
mrb_value mrb_fltk_focus_getter_module_method( mrb_state *mrb, mrb_value self ) {
  // TODO: I dunno how to go about this.
  //  Find the MRB instance wrapping the pointer
  //    Problem is that this seems impossible
  // OR
  //  Get the MRB class based on the pointer, set the DATA_PTR, and initialize it
  //    Problem is this works unless you want to retrieve a MRB subclass of that object. For example, I have a `class Sidebar < FLTK::HoldBrowser`.
}

// FLTK.focus=(widget)
// Sets the current focused widget.
mrb_value mrb_fltk_focus_setter_module_method( mrb_state *mrb, mrb_value self ) {
  mrb_value mrb_widget;
  mrb_get_args( mrb, "o", &mrb_widget );
  // TODO: Raise error unless it is a FLTK::Widget

  GET_DATA( fl_widget, Fl_Widget, mrb_widget );

  Fl::focus( fl_widget );

  return mrb_widget;
}

// FLTK.run
mrb_value mrb_fltk_run_module_method( mrb_state *mrb, mrb_value self ) {
  return mrb_fixnum_value( Fl::run() );
}

void mrb_fltk_module_init( mrb_state *mrb ) {
  ARENA_SAVE;

  struct RClass *mrb_fltk_module = mrb_define_module( mrb, "FLTK" );

  // Fl_Align
  DEFINE_FIXNUM_CONSTANT( ALIGN_CENTER, FL_ALIGN_CENTER, mrb_fltk_module );                         // Align the label horizontally in the middle.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP, FL_ALIGN_TOP, mrb_fltk_module );                               // Align the label at the top of the widget. Inside labels appear below the top, outside labels are drawn on top of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM, FL_ALIGN_BOTTOM, mrb_fltk_module );                         // Align the label at the bottom of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT, FL_ALIGN_LEFT, mrb_fltk_module );                             // Align the label at the left of the widget. Inside labels appear left-justified starting at the left side of the widget, outside labels are right-justified and drawn to the left of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT, FL_ALIGN_RIGHT, mrb_fltk_module );                           // Align the label to the right of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_INSIDE, FL_ALIGN_INSIDE, mrb_fltk_module );                         // Draw the label inside of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TEXT_OVER_IMAGE, FL_ALIGN_TEXT_OVER_IMAGE, mrb_fltk_module );       // If the label contains an image, draw the text on top of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_OVER_TEXT, FL_ALIGN_IMAGE_OVER_TEXT, mrb_fltk_module );       // If the label contains an image, draw the text below the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_CLIP, FL_ALIGN_CLIP, mrb_fltk_module );                             // All parts of the label that are lager than the widget will not be drawn .
  DEFINE_FIXNUM_CONSTANT( ALIGN_WRAP, FL_ALIGN_WRAP, mrb_fltk_module );                             // Wrap text that does not fit the width of the widget.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_NEXT_TO_TEXT, FL_ALIGN_IMAGE_NEXT_TO_TEXT, mrb_fltk_module ); // If the label contains an image, draw the text to the right of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TEXT_NEXT_TO_IMAGE, FL_ALIGN_TEXT_NEXT_TO_IMAGE, mrb_fltk_module ); // If the label contains an image, draw the text to the left of the image.
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_BACKDROP, FL_ALIGN_IMAGE_BACKDROP, mrb_fltk_module );         // If the label contains an image, draw the image or deimage in the background.
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP_LEFT, FL_ALIGN_TOP_LEFT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_TOP_RIGHT, FL_ALIGN_TOP_RIGHT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM_LEFT, FL_ALIGN_BOTTOM_LEFT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_BOTTOM_RIGHT, FL_ALIGN_BOTTOM_RIGHT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT_TOP, FL_ALIGN_LEFT_TOP, mrb_fltk_module );           // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT_TOP, FL_ALIGN_RIGHT_TOP, mrb_fltk_module );         // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_LEFT_BOTTOM, FL_ALIGN_LEFT_BOTTOM, mrb_fltk_module );     // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_RIGHT_BOTTOM, FL_ALIGN_RIGHT_BOTTOM, mrb_fltk_module );   // magic value
  DEFINE_FIXNUM_CONSTANT( ALIGN_NOWRAP, FL_ALIGN_NOWRAP, mrb_fltk_module );               // for back compatibility
  DEFINE_FIXNUM_CONSTANT( ALIGN_POSITION_MASK, FL_ALIGN_POSITION_MASK, mrb_fltk_module ); // left, right, top, bottom
  DEFINE_FIXNUM_CONSTANT( ALIGN_IMAGE_MASK, FL_ALIGN_IMAGE_MASK, mrb_fltk_module );       // l/r, t/b, backdrop

  // Fl_Font
  DEFINE_FIXNUM_CONSTANT( HELVETICA, FL_HELVETICA, mrb_fltk_module );                         // Helvetica (or Arial) normal (0)
  DEFINE_FIXNUM_CONSTANT( HELVETICA_BOLD, FL_HELVETICA_BOLD, mrb_fltk_module );               // Helvetica (or Arial) bold
  DEFINE_FIXNUM_CONSTANT( HELVETICA_ITALIC, FL_HELVETICA_ITALIC, mrb_fltk_module );           // Helvetica (or Arial) oblique
  DEFINE_FIXNUM_CONSTANT( HELVETICA_BOLD_ITALIC, FL_HELVETICA_BOLD_ITALIC, mrb_fltk_module ); // Helvetica (or Arial) bold-oblique
  DEFINE_FIXNUM_CONSTANT( COURIER, FL_COURIER, mrb_fltk_module );                             // Courier normal
  DEFINE_FIXNUM_CONSTANT( COURIER_BOLD, FL_COURIER_BOLD, mrb_fltk_module );                   // Courier bold
  DEFINE_FIXNUM_CONSTANT( COURIER_ITALIC, FL_COURIER_ITALIC, mrb_fltk_module );               // Courier italic
  DEFINE_FIXNUM_CONSTANT( COURIER_BOLD_ITALIC, FL_COURIER_BOLD_ITALIC, mrb_fltk_module );     // Courier bold-italic
  DEFINE_FIXNUM_CONSTANT( TIMES, FL_TIMES, mrb_fltk_module );                                 // Times roman
  DEFINE_FIXNUM_CONSTANT( TIMES_BOLD, FL_TIMES_BOLD, mrb_fltk_module );                       // Times roman bold
  DEFINE_FIXNUM_CONSTANT( TIMES_ITALIC, FL_TIMES_ITALIC, mrb_fltk_module );                   // Times roman italic
  DEFINE_FIXNUM_CONSTANT( TIMES_BOLD_ITALIC, FL_TIMES_BOLD_ITALIC, mrb_fltk_module );         // Times roman bold-italic
  DEFINE_FIXNUM_CONSTANT( SYMBOL, FL_SYMBOL, mrb_fltk_module );                               // Standard symbol font
  DEFINE_FIXNUM_CONSTANT( SCREEN, FL_SCREEN, mrb_fltk_module );                               // Default monospaced screen font
  DEFINE_FIXNUM_CONSTANT( SCREEN_BOLD, FL_SCREEN_BOLD, mrb_fltk_module );                     // Default monospaced bold screen font
  DEFINE_FIXNUM_CONSTANT( ZAPF_DINGBATS, FL_ZAPF_DINGBATS, mrb_fltk_module );                 // Zapf-dingbats font
  DEFINE_FIXNUM_CONSTANT( FREE_FONT, FL_FREE_FONT, mrb_fltk_module );                         // first one to allocate
  DEFINE_FIXNUM_CONSTANT( BOLD, FL_BOLD, mrb_fltk_module );                                   // add this to helvetica, courier, or times
  DEFINE_FIXNUM_CONSTANT( ITALIC, FL_ITALIC, mrb_fltk_module );                               // add this to helvetica, courier, or times
  DEFINE_FIXNUM_CONSTANT( BOLD_ITALIC, FL_BOLD_ITALIC, mrb_fltk_module );                     // add this to helvetica, courier, or times

  // Fl_When
  DEFINE_FIXNUM_CONSTANT( WHEN_NEVER, FL_WHEN_NEVER, mrb_fltk_module );                         // Never call the callback.
  DEFINE_FIXNUM_CONSTANT( WHEN_CHANGED, FL_WHEN_CHANGED, mrb_fltk_module );                     // Do the callback only when the widget value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_NOT_CHANGED, FL_WHEN_NOT_CHANGED, mrb_fltk_module );             // Do the callback whenever the user interacts with the widget.
  DEFINE_FIXNUM_CONSTANT( WHEN_RELEASE, FL_WHEN_RELEASE, mrb_fltk_module );                     // Do the callback when the button or key is released and the value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_RELEASE_ALWAYS, FL_WHEN_RELEASE_ALWAYS, mrb_fltk_module );       // Do the callback when the button or key is released, even if the value doesn't change.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY, FL_WHEN_ENTER_KEY, mrb_fltk_module );                 // Do the callback when the user presses the ENTER key and the value changes.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY_ALWAYS, FL_WHEN_ENTER_KEY_ALWAYS, mrb_fltk_module );   // Do the callback when the user presses the ENTER key, even if the value doesn't change.
  DEFINE_FIXNUM_CONSTANT( WHEN_ENTER_KEY_CHANGED, FL_WHEN_ENTER_KEY_CHANGED, mrb_fltk_module ); // ?

  // Fl_Event
  DEFINE_FIXNUM_CONSTANT( NO_EVENT, FL_NO_EVENT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( PUSH, FL_PUSH, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( RELEASE, FL_RELEASE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ENTER, FL_ENTER, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( LEAVE, FL_LEAVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DRAG, FL_DRAG, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( FOCUS, FL_FOCUS, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( UNFOCUS, FL_UNFOCUS, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYDOWN, FL_KEYDOWN, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYBOARD, FL_KEYBOARD, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( KEYUP, FL_KEYUP, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( CLOSE, FL_CLOSE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( MOVE, FL_MOVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SHORTCUT, FL_SHORTCUT, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DEACTIVATE, FL_DEACTIVATE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( ACTIVATE, FL_ACTIVATE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( HIDE, FL_HIDE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SHOW, FL_SHOW, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( PASTE, FL_PASTE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SELECTIONCLEAR, FL_SELECTIONCLEAR, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( MOUSEWHEEL, FL_MOUSEWHEEL, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_ENTER, FL_DND_ENTER, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_DRAG, FL_DND_DRAG, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_LEAVE, FL_DND_LEAVE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( DND_RELEASE, FL_DND_RELEASE, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( SCREEN_CONFIGURATION_CHANGED, FL_SCREEN_CONFIGURATION_CHANGED, mrb_fltk_module );
  DEFINE_FIXNUM_CONSTANT( FULLSCREEN, FL_FULLSCREEN, mrb_fltk_module );

  // DEFINE_MODULE_METHOD( root, font_name, MRB_ARGS_REQ( 1 ) );
  mrb_define_module_function( mrb, mrb_fltk_module, "run", mrb_fltk_run_module_method, MRB_ARGS_NONE() );
  mrb_define_module_function( mrb, mrb_fltk_module, "focus=", mrb_fltk_focus_setter_module_method, MRB_ARGS_REQ( 1 ) );
  // DEFINE_MODULE_METHOD( root, set_fonts, MRB_ARGS_REQ( 1 ) );

  ARENA_RESTORE;
}
<|endoftext|>


<commit_before>/*
 * Fork a process and connect its stdin and stdout to istreams.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "fork.hxx"
#include "fd_util.h"
#include "istream/istream_buffer.hxx"
#include "istream/istream_pointer.hxx"
#include "buffered_io.hxx"
#include "fd-util.h"
#include "direct.hxx"
#include "event/Event.hxx"
#include "gerrno.h"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/Cast.hxx"

#ifdef __linux
#include <fcntl.h>
#endif

#include <daemon/log.h>

#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <signal.h>
#include <limits.h>

struct Fork {
    struct istream output;
    int output_fd;
    Event output_event;

    SliceFifoBuffer buffer;

    IstreamPointer input;
    int input_fd;
    Event input_event;

    pid_t pid;

    child_callback_t callback;
    void *callback_ctx;

    Fork(struct pool &p, const char *name,
         struct istream *_input, int _input_fd,
         int _output_fd,
         pid_t _pid, child_callback_t _callback, void *_ctx);

    bool CheckDirect() const {
        return istream_check_direct(&output, FdType::FD_PIPE);
    }

    void Close();

    void FreeBuffer() {
        buffer.FreeIfDefined(fb_pool_get());
    }

    /**
     * Send data from the buffer.  Invokes the "eof" callback when the
     * buffer becomes empty and the pipe has been closed already.
     *
     * @return true if the caller shall read more data from the pipe
     */
    bool SendFromBuffer();

    void ReadFromOutput();
};

void
Fork::Close()
{
    assert(output_fd >= 0);

    if (input.IsDefined()) {
        assert(input_fd >= 0);

        input_event.Delete();
        close(input_fd);
        input.Close();
    }

    output_event.Delete();

    close(output_fd);
    output_fd = -1;

    if (pid >= 0)
        child_kill(pid);
}

inline bool
Fork::SendFromBuffer()
{
    assert(buffer.IsDefined());

    if (istream_buffer_send(&output, buffer) == 0)
        return false;

    if (output_fd < 0) {
        if (buffer.IsEmpty()) {
            FreeBuffer();
            istream_deinit_eof(&output);
        }

        return false;
    }

    return true;
}

/*
 * input handler
 *
 */

static size_t
fork_input_data(const void *data, size_t length, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input_fd >= 0);

    ssize_t nbytes = write(f->input_fd, data, length);
    if (nbytes > 0)
        f->input_event.Add();
    else if (nbytes < 0) {
        if (errno == EAGAIN) {
            f->input_event.Add();
            return 0;
        }

        daemon_log(1, "write() to subprocess failed: %s\n",
                   strerror(errno));
        f->input_event.Delete();
        close(f->input_fd);
        f->input.ClearAndClose();
        return 0;
    }

    return (size_t)nbytes;
}

#ifdef __linux
static ssize_t
fork_input_direct(FdType type,
                  int fd, size_t max_length, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input_fd >= 0);

    ssize_t nbytes = istream_direct_to_pipe(type, fd, f->input_fd, max_length);
    if (nbytes > 0)
        f->input_event.Add();
    else if (nbytes < 0) {
        if (errno == EAGAIN) {
            if (!fd_ready_for_writing(f->input_fd)) {
                f->input_event.Add();
                return ISTREAM_RESULT_BLOCKING;
            }

            /* try again, just in case connection->fd has become ready
               between the first splice() call and
               fd_ready_for_writing() */
            nbytes = istream_direct_to_pipe(type, fd, f->input_fd, max_length);
        }
    }

    return nbytes;
}
#endif

static void
fork_input_eof(void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input.IsDefined());
    assert(f->input_fd >= 0);

    f->input_event.Delete();
    close(f->input_fd);

    f->input.Clear();
}

static void
fork_input_abort(GError *error, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input.IsDefined());
    assert(f->input_fd >= 0);

    f->FreeBuffer();

    f->input_event.Delete();
    close(f->input_fd);
    f->input.Clear();

    f->Close();
    istream_deinit_abort(&f->output, error);
}

static const struct istream_handler fork_input_handler = {
    .data = fork_input_data,
#ifdef __linux
    .direct = fork_input_direct,
#endif
    .eof = fork_input_eof,
    .abort = fork_input_abort,
};

/*
 * event for fork.output_fd
 */

void
Fork::ReadFromOutput()
{
    assert(output_fd >= 0);

    if (!CheckDirect()) {
        buffer.AllocateIfNull(fb_pool_get());

        ssize_t nbytes = read_to_buffer(output_fd,
                                        (ForeignFifoBuffer<uint8_t> &)buffer,
                                        INT_MAX);
        if (nbytes == -2) {
            /* XXX should not happen */
        } else if (nbytes > 0) {
            if (istream_buffer_send(&output, buffer) > 0)
                output_event.Add();
        } else if (nbytes == 0) {
            Close();

            if (buffer.IsEmpty()) {
                FreeBuffer();
                istream_deinit_eof(&output);
            }
        } else if (errno == EAGAIN) {
            output_event.Add();

            if (input.IsDefined())
                /* the CGI may be waiting for more data from stdin */
                input.Read();
        } else {
            GError *error =
                new_error_errno_msg("failed to read from sub process");
            FreeBuffer();
            Close();
            istream_deinit_abort(&output, error);
        }
    } else {
        if (istream_buffer_consume(&output, buffer) > 0)
            /* there's data left in the buffer, which must be consumed
               before we can switch to "direct" transfer */
            return;

        /* at this point, the handler might have changed inside
           istream_buffer_consume(), and the new handler might not
           support "direct" transfer - check again */
        if (!CheckDirect()) {
            output_event.Add();
            return;
        }

        ssize_t nbytes = istream_invoke_direct(&output, FdType::FD_PIPE,
                                               output_fd, INT_MAX);
        if (nbytes == ISTREAM_RESULT_BLOCKING ||
            nbytes == ISTREAM_RESULT_CLOSED) {
            /* -2 means the callback wasn't able to consume any data right
               now */
        } else if (nbytes > 0) {
            output_event.Add();
        } else if (nbytes == ISTREAM_RESULT_EOF) {
            FreeBuffer();
            Close();
            istream_deinit_eof(&output);
        } else if (errno == EAGAIN) {
            output_event.Add();

            if (input.IsDefined())
                /* the CGI may be waiting for more data from stdin */
                input.Read();
        } else {
            GError *error =
                new_error_errno_msg("failed to read from sub process");
            FreeBuffer();
            Close();
            istream_deinit_abort(&output, error);
        }
    }
}

static void
fork_input_event_callback(int fd gcc_unused, short event gcc_unused,
                          void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input_fd == fd);
    assert(f->input.IsDefined());

    f->input.Read();
}

static void
fork_output_event_callback(int fd gcc_unused, short event gcc_unused,
                           void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->output_fd == fd);

    f->ReadFromOutput();
}

/*
 * istream implementation
 *
 */

static inline Fork *
istream_to_fork(struct istream *istream)
{
    return &ContainerCast2(*istream, &Fork::output);
}

static void
istream_fork_read(struct istream *istream)
{
    Fork *f = istream_to_fork(istream);

    if (f->buffer.IsEmpty() || f->SendFromBuffer())
        f->ReadFromOutput();
}

static void
istream_fork_close(struct istream *istream)
{
    Fork *f = istream_to_fork(istream);

    f->FreeBuffer();

    if (f->output_fd >= 0)
        f->Close();

    istream_deinit(&f->output);
}

static const struct istream_class istream_fork = {
    .read = istream_fork_read,
    .close = istream_fork_close,
};

/*
 * clone callback
 *
 */

struct clone_ctx {
    int stdin_pipe[2], stdin_fd, stdout_pipe[2];

    int (*fn)(void *ctx);
    void *ctx;
};

static int
beng_fork_fn(void *ctx)
{
    struct clone_ctx *c = (struct clone_ctx *)ctx;

    if (c->stdin_pipe[0] >= 0) {
        dup2(c->stdin_pipe[0], STDIN_FILENO);
        close(c->stdin_pipe[0]);
        close(c->stdin_pipe[1]);
    } else if (c->stdin_fd >= 0) {
        dup2(c->stdin_fd, STDIN_FILENO);
        close(c->stdin_fd);
    }

    dup2(c->stdout_pipe[1], STDOUT_FILENO);
    close(c->stdout_pipe[0]);
    close(c->stdout_pipe[1]);

    return c->fn(c->ctx);
}

/*
 * child callback
 *
 */

static void
fork_child_callback(int status, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->pid >= 0);

    f->pid = -1;

    if (f->callback)
        f->callback(status, f->callback_ctx);
}

/*
 * constructor
 *
 */

inline
Fork::Fork(struct pool &p, const char *name,
           struct istream *_input, int _input_fd,
           int _output_fd,
           pid_t _pid, child_callback_t _callback, void *_ctx)
    :output_fd(_output_fd),
     input(_input, fork_input_handler, this, ISTREAM_TO_PIPE),
     input_fd(_input_fd),
     pid(_pid),
     callback(_callback), callback_ctx(_ctx)
{
    istream_init(&output, &istream_fork, &p);

    output_event.Set(output_fd, EV_READ,
                     fork_output_event_callback, this);

    if (_input != nullptr) {
        input_event.Set(input_fd, EV_WRITE,
                        fork_input_event_callback, this);
        input_event.Add();
    }

    child_register(pid, name, fork_child_callback, this);
}

pid_t
beng_fork(struct pool *pool, const char *name,
          struct istream *input, struct istream **output_r,
          int clone_flags,
          int (*fn)(void *ctx), void *fn_ctx,
          child_callback_t callback, void *ctx,
          GError **error_r)
{
    assert(clone_flags & SIGCHLD);

    struct clone_ctx c = {
        .stdin_pipe = { [0] = -1 },
        .stdin_fd = -1,
        .fn = fn,
        .ctx = fn_ctx,
    };

    if (input != nullptr) {
        c.stdin_fd = istream_as_fd(input);
        if (c.stdin_fd >= 0)
            input = nullptr;
    }

    if (input != nullptr) {
        if (pipe_cloexec(c.stdin_pipe) < 0) {
            set_error_errno_msg(error_r, "pipe_cloexec() failed");
            istream_close_unused(input);
            return -1;
        }

        if (fd_set_nonblock(c.stdin_pipe[1], 1) < 0) {
            set_error_errno_msg(error_r, "fcntl(O_NONBLOCK) failed");
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
            return -1;
        }
    }

    if (pipe_cloexec(c.stdout_pipe) < 0) {
        set_error_errno_msg(error_r, "pipe() failed");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);
        return -1;
    }

    if (fd_set_nonblock(c.stdout_pipe[0], 1) < 0) {
        set_error_errno_msg(error_r, "fcntl(O_NONBLOCK) failed");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[0]);
        close(c.stdout_pipe[1]);
        return -1;
    }

    char stack[8192];
    const pid_t pid = clone(beng_fork_fn, stack + sizeof(stack),
                            clone_flags, &c);
    if (pid < 0) {
        set_error_errno_msg(error_r, "fork() failed: %s");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[0]);
        close(c.stdout_pipe[1]);
    } else {
        auto f = NewFromPool<Fork>(*pool, *pool, name,
                                   input, c.stdin_pipe[1],
                                   c.stdout_pipe[0],
                                   pid, callback, ctx);

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[1]);

        /* XXX CLOEXEC */

        *output_r = &f->output;
    }

    return pid;
}
<commit_msg>fork: use MakeSimpleEventCallback()<commit_after>/*
 * Fork a process and connect its stdin and stdout to istreams.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "fork.hxx"
#include "fd_util.h"
#include "istream/istream_buffer.hxx"
#include "istream/istream_pointer.hxx"
#include "buffered_io.hxx"
#include "fd-util.h"
#include "direct.hxx"
#include "event/Event.hxx"
#include "gerrno.h"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "event/Callback.hxx"
#include "util/Cast.hxx"

#ifdef __linux
#include <fcntl.h>
#endif

#include <daemon/log.h>

#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <signal.h>
#include <limits.h>

struct Fork {
    struct istream output;
    int output_fd;
    Event output_event;

    SliceFifoBuffer buffer;

    IstreamPointer input;
    int input_fd;
    Event input_event;

    pid_t pid;

    child_callback_t callback;
    void *callback_ctx;

    Fork(struct pool &p, const char *name,
         struct istream *_input, int _input_fd,
         int _output_fd,
         pid_t _pid, child_callback_t _callback, void *_ctx);

    bool CheckDirect() const {
        return istream_check_direct(&output, FdType::FD_PIPE);
    }

    void Close();

    void FreeBuffer() {
        buffer.FreeIfDefined(fb_pool_get());
    }

    /**
     * Send data from the buffer.  Invokes the "eof" callback when the
     * buffer becomes empty and the pipe has been closed already.
     *
     * @return true if the caller shall read more data from the pipe
     */
    bool SendFromBuffer();

    void ReadFromOutput();

    void InputEventCallback() {
        input.Read();
    }

    void OutputEventCallback() {
        ReadFromOutput();
    }
};

void
Fork::Close()
{
    assert(output_fd >= 0);

    if (input.IsDefined()) {
        assert(input_fd >= 0);

        input_event.Delete();
        close(input_fd);
        input.Close();
    }

    output_event.Delete();

    close(output_fd);
    output_fd = -1;

    if (pid >= 0)
        child_kill(pid);
}

inline bool
Fork::SendFromBuffer()
{
    assert(buffer.IsDefined());

    if (istream_buffer_send(&output, buffer) == 0)
        return false;

    if (output_fd < 0) {
        if (buffer.IsEmpty()) {
            FreeBuffer();
            istream_deinit_eof(&output);
        }

        return false;
    }

    return true;
}

/*
 * input handler
 *
 */

static size_t
fork_input_data(const void *data, size_t length, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input_fd >= 0);

    ssize_t nbytes = write(f->input_fd, data, length);
    if (nbytes > 0)
        f->input_event.Add();
    else if (nbytes < 0) {
        if (errno == EAGAIN) {
            f->input_event.Add();
            return 0;
        }

        daemon_log(1, "write() to subprocess failed: %s\n",
                   strerror(errno));
        f->input_event.Delete();
        close(f->input_fd);
        f->input.ClearAndClose();
        return 0;
    }

    return (size_t)nbytes;
}

#ifdef __linux
static ssize_t
fork_input_direct(FdType type,
                  int fd, size_t max_length, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input_fd >= 0);

    ssize_t nbytes = istream_direct_to_pipe(type, fd, f->input_fd, max_length);
    if (nbytes > 0)
        f->input_event.Add();
    else if (nbytes < 0) {
        if (errno == EAGAIN) {
            if (!fd_ready_for_writing(f->input_fd)) {
                f->input_event.Add();
                return ISTREAM_RESULT_BLOCKING;
            }

            /* try again, just in case connection->fd has become ready
               between the first splice() call and
               fd_ready_for_writing() */
            nbytes = istream_direct_to_pipe(type, fd, f->input_fd, max_length);
        }
    }

    return nbytes;
}
#endif

static void
fork_input_eof(void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input.IsDefined());
    assert(f->input_fd >= 0);

    f->input_event.Delete();
    close(f->input_fd);

    f->input.Clear();
}

static void
fork_input_abort(GError *error, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->input.IsDefined());
    assert(f->input_fd >= 0);

    f->FreeBuffer();

    f->input_event.Delete();
    close(f->input_fd);
    f->input.Clear();

    f->Close();
    istream_deinit_abort(&f->output, error);
}

static const struct istream_handler fork_input_handler = {
    .data = fork_input_data,
#ifdef __linux
    .direct = fork_input_direct,
#endif
    .eof = fork_input_eof,
    .abort = fork_input_abort,
};

/*
 * event for fork.output_fd
 */

void
Fork::ReadFromOutput()
{
    assert(output_fd >= 0);

    if (!CheckDirect()) {
        buffer.AllocateIfNull(fb_pool_get());

        ssize_t nbytes = read_to_buffer(output_fd,
                                        (ForeignFifoBuffer<uint8_t> &)buffer,
                                        INT_MAX);
        if (nbytes == -2) {
            /* XXX should not happen */
        } else if (nbytes > 0) {
            if (istream_buffer_send(&output, buffer) > 0)
                output_event.Add();
        } else if (nbytes == 0) {
            Close();

            if (buffer.IsEmpty()) {
                FreeBuffer();
                istream_deinit_eof(&output);
            }
        } else if (errno == EAGAIN) {
            output_event.Add();

            if (input.IsDefined())
                /* the CGI may be waiting for more data from stdin */
                input.Read();
        } else {
            GError *error =
                new_error_errno_msg("failed to read from sub process");
            FreeBuffer();
            Close();
            istream_deinit_abort(&output, error);
        }
    } else {
        if (istream_buffer_consume(&output, buffer) > 0)
            /* there's data left in the buffer, which must be consumed
               before we can switch to "direct" transfer */
            return;

        /* at this point, the handler might have changed inside
           istream_buffer_consume(), and the new handler might not
           support "direct" transfer - check again */
        if (!CheckDirect()) {
            output_event.Add();
            return;
        }

        ssize_t nbytes = istream_invoke_direct(&output, FdType::FD_PIPE,
                                               output_fd, INT_MAX);
        if (nbytes == ISTREAM_RESULT_BLOCKING ||
            nbytes == ISTREAM_RESULT_CLOSED) {
            /* -2 means the callback wasn't able to consume any data right
               now */
        } else if (nbytes > 0) {
            output_event.Add();
        } else if (nbytes == ISTREAM_RESULT_EOF) {
            FreeBuffer();
            Close();
            istream_deinit_eof(&output);
        } else if (errno == EAGAIN) {
            output_event.Add();

            if (input.IsDefined())
                /* the CGI may be waiting for more data from stdin */
                input.Read();
        } else {
            GError *error =
                new_error_errno_msg("failed to read from sub process");
            FreeBuffer();
            Close();
            istream_deinit_abort(&output, error);
        }
    }
}

/*
 * istream implementation
 *
 */

static inline Fork *
istream_to_fork(struct istream *istream)
{
    return &ContainerCast2(*istream, &Fork::output);
}

static void
istream_fork_read(struct istream *istream)
{
    Fork *f = istream_to_fork(istream);

    if (f->buffer.IsEmpty() || f->SendFromBuffer())
        f->ReadFromOutput();
}

static void
istream_fork_close(struct istream *istream)
{
    Fork *f = istream_to_fork(istream);

    f->FreeBuffer();

    if (f->output_fd >= 0)
        f->Close();

    istream_deinit(&f->output);
}

static const struct istream_class istream_fork = {
    .read = istream_fork_read,
    .close = istream_fork_close,
};

/*
 * clone callback
 *
 */

struct clone_ctx {
    int stdin_pipe[2], stdin_fd, stdout_pipe[2];

    int (*fn)(void *ctx);
    void *ctx;
};

static int
beng_fork_fn(void *ctx)
{
    struct clone_ctx *c = (struct clone_ctx *)ctx;

    if (c->stdin_pipe[0] >= 0) {
        dup2(c->stdin_pipe[0], STDIN_FILENO);
        close(c->stdin_pipe[0]);
        close(c->stdin_pipe[1]);
    } else if (c->stdin_fd >= 0) {
        dup2(c->stdin_fd, STDIN_FILENO);
        close(c->stdin_fd);
    }

    dup2(c->stdout_pipe[1], STDOUT_FILENO);
    close(c->stdout_pipe[0]);
    close(c->stdout_pipe[1]);

    return c->fn(c->ctx);
}

/*
 * child callback
 *
 */

static void
fork_child_callback(int status, void *ctx)
{
    const auto f = (Fork *)ctx;

    assert(f->pid >= 0);

    f->pid = -1;

    if (f->callback)
        f->callback(status, f->callback_ctx);
}

/*
 * constructor
 *
 */

inline
Fork::Fork(struct pool &p, const char *name,
           struct istream *_input, int _input_fd,
           int _output_fd,
           pid_t _pid, child_callback_t _callback, void *_ctx)
    :output_fd(_output_fd),
     input(_input, fork_input_handler, this, ISTREAM_TO_PIPE),
     input_fd(_input_fd),
     pid(_pid),
     callback(_callback), callback_ctx(_ctx)
{
    istream_init(&output, &istream_fork, &p);

    output_event.Set(output_fd, EV_READ,
                     MakeSimpleEventCallback(Fork, OutputEventCallback),
                     this);

    if (_input != nullptr) {
        input_event.Set(input_fd, EV_WRITE,
                        MakeSimpleEventCallback(Fork, InputEventCallback),
                        this);
        input_event.Add();
    }

    child_register(pid, name, fork_child_callback, this);
}

pid_t
beng_fork(struct pool *pool, const char *name,
          struct istream *input, struct istream **output_r,
          int clone_flags,
          int (*fn)(void *ctx), void *fn_ctx,
          child_callback_t callback, void *ctx,
          GError **error_r)
{
    assert(clone_flags & SIGCHLD);

    struct clone_ctx c = {
        .stdin_pipe = { [0] = -1 },
        .stdin_fd = -1,
        .fn = fn,
        .ctx = fn_ctx,
    };

    if (input != nullptr) {
        c.stdin_fd = istream_as_fd(input);
        if (c.stdin_fd >= 0)
            input = nullptr;
    }

    if (input != nullptr) {
        if (pipe_cloexec(c.stdin_pipe) < 0) {
            set_error_errno_msg(error_r, "pipe_cloexec() failed");
            istream_close_unused(input);
            return -1;
        }

        if (fd_set_nonblock(c.stdin_pipe[1], 1) < 0) {
            set_error_errno_msg(error_r, "fcntl(O_NONBLOCK) failed");
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
            return -1;
        }
    }

    if (pipe_cloexec(c.stdout_pipe) < 0) {
        set_error_errno_msg(error_r, "pipe() failed");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);
        return -1;
    }

    if (fd_set_nonblock(c.stdout_pipe[0], 1) < 0) {
        set_error_errno_msg(error_r, "fcntl(O_NONBLOCK) failed");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[0]);
        close(c.stdout_pipe[1]);
        return -1;
    }

    char stack[8192];
    const pid_t pid = clone(beng_fork_fn, stack + sizeof(stack),
                            clone_flags, &c);
    if (pid < 0) {
        set_error_errno_msg(error_r, "fork() failed: %s");

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
            close(c.stdin_pipe[1]);
            istream_close_unused(input);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[0]);
        close(c.stdout_pipe[1]);
    } else {
        auto f = NewFromPool<Fork>(*pool, *pool, name,
                                   input, c.stdin_pipe[1],
                                   c.stdout_pipe[0],
                                   pid, callback, ctx);

        if (input != nullptr) {
            close(c.stdin_pipe[0]);
        } else if (c.stdin_fd >= 0)
            close(c.stdin_fd);

        close(c.stdout_pipe[1]);

        /* XXX CLOEXEC */

        *output_r = &f->output;
    }

    return pid;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Tom van Dijk, Johannes Kepler University Linz
 *
 * 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.
 */

#ifndef GAME_HPP
#define GAME_HPP

#include <sstream>
#include <vector>
#include <map>

#include <boost/dynamic_bitset.hpp>

namespace pg {

typedef boost::dynamic_bitset<unsigned long long> bitset;

class Game
{
public:
    /**
     * Construct a new (uninitialized) parity game.
     */
    Game();

    /**
     * Construct a new parity game for <count> nodes.
     */
    Game(int count);

    /**
     * Construct a copy of an existing parity game.
     */
    Game(const Game& other);

    /**
     * Parse a pgsolver game.
     */
    Game(std::istream &inp);

    /**
     * Deconstructor.
     */
    ~Game();

    /**
     * Initialize the game with <count> uninitialized nodes.
     */
    void initGame(int count);

    /**
     * Initialize a node <node> with given <priority>, <owner> and <label>.
     */
    void initNode(int node, int priority, int owner, std::string label="");

    /**
     * Add an edge from <from> to <to>.
     * Returns true if the edge was added or false if it already existed.
     */
    bool addEdge(int from, int to);

    /**
     * Remove an edge from <from> to <to>.
     * Returns true if the edge was removed or false if it did not exist.
     */
    bool removeEdge(int from, int to);

    /**
     * Parse a pgsolver game.
     */
    void parse_pgsolver(std::istream &in);

    /**
     * Parse a [full or partial] pgsolver solution.
     */
    void parse_solution(std::istream &in);

    /**
     * Write the game in pgsolver format.
     */
    void write_pgsolver(std::ostream &out);

    /**
     * Write the game as a DOT graph.
     */
    void write_dot(std::ostream &out);

    /**
     * Write the solution in pgsolver format.
     */
    void write_sol(std::ostream &cout);

    /**
     * Sort the nodes in order of priority (low to high).
     * Afterwards, <mapping> is such that node <i> was originally at <mapping[i]>.
     */
    void reindex(int *mapping = NULL);

    /**
     * Reindex the game if it was not yet reindexed.
     */
    void reindex_once(void);

    /**
     * Apply a permutation, moving node <i> to position <mapping[i]>.
     * This reverses a reindex operation.
     */
    void permute(int *mapping); // undo reindex

    /**
     * Reassign priorities such that every node has a unique priority.
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int inflate(void);

    /**
     * Reassign priorities such that no priority is skipped. ("compression")
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int compress(void);

    /**
     * Reassign priorities in order, but do not inflate or compress.
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int renumber(void);

    /**
     * Swap players (priorities and ownership)
     * (Assumes reindex() has been called earlier.)
     */
    void evenodd(void);

    /**
     * Change a max game into a min game and vice versa.
     * (Assumes reindex() has been called earlier.)
     */
    void minmax(void);

    /**
     * Return the number of vertices.
     */
    inline size_t nodecount() { return n_nodes; }

    /**
     * Count and return the number of edges.
     */
    inline size_t edgecount() { edge_recount(); return n_edges; }

    /**
     * Returns whether every node has dominion 0 or 1.
     */
    inline bool gameSolved() { return solved.count() == nodecount(); }

    /**
     * Count and return how many nodes have dominion -1.
     */
    inline int countUnsolved() { return n_nodes - solved.count(); }

    inline void edge_recount()
    {
        n_edges = 0;
        for (int n=0; n<n_nodes; n++) n_edges += out[n].size();
    }

    /**
     * Create a new Game of the subgame of the nodes given in <selection>.
     * (We don't check if the relation is total.)
     * Afterwards, <mapping> contains for index i the corresponding index in the full game.
     * (mapping must be int[selection.size()])
     */
    Game *extract_subgame(std::vector<int> &selection, int *mapping=NULL);

    /**
     * Reset <solved>, <winner> and <strategy>.
     */
    void reset();

    /**
     * Copy the game.
     */
    Game &operator=(const Game &other);

    /**
     * Swap with other game.
     */
    void swap(Game& other);

    /**
     * Game fields
     */

    int n_nodes;           // number of nodes
    int n_edges;           // number of edges
    int *priority;         // priority of each node
    bitset owner;          // owner of each node (1 for odd, 0 for even)
    std::string *label;    // (optional) node labels
    std::vector<int> *out; // outgoing edges
    std::vector<int> *in;  // incoming edges

    bitset solved;         // set true if node solved
    bitset winner;         // for solved vertices, set 1 if won by 1, else 0
    int *strategy;         // strategy for winning vertices

    bool reindexed;        // records if the game was reindexed (before solving)

    class _label_vertex
    {
        public:
            _label_vertex(Game &g, int v) : g(g), v(v) { }
            friend std::ostream& operator<<(std::ostream& out, const _label_vertex &lv) {
                std::string& l = lv.g.label[lv.v];
                if (l.empty()) out << lv.v << "/" << lv.g.priority[lv.v];
                else out << l;
                return out;
            }
        protected:
            Game &g;
            int v;
    };

    _label_vertex label_vertex(int v)
    {
        return _label_vertex(*this, v);
    }
};

}

#endif
<commit_msg>Fix bug in label_vertex function in Game<commit_after>/*
 * Copyright 2017-2018 Tom van Dijk, Johannes Kepler University Linz
 *
 * 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.
 */

#ifndef GAME_HPP
#define GAME_HPP

#include <sstream>
#include <vector>
#include <map>

#include <boost/dynamic_bitset.hpp>

namespace pg {

typedef boost::dynamic_bitset<unsigned long long> bitset;

class Game
{
public:
    /**
     * Construct a new (uninitialized) parity game.
     */
    Game();

    /**
     * Construct a new parity game for <count> nodes.
     */
    Game(int count);

    /**
     * Construct a copy of an existing parity game.
     */
    Game(const Game& other);

    /**
     * Parse a pgsolver game.
     */
    Game(std::istream &inp);

    /**
     * Deconstructor.
     */
    ~Game();

    /**
     * Initialize the game with <count> uninitialized nodes.
     */
    void initGame(int count);

    /**
     * Initialize a node <node> with given <priority>, <owner> and <label>.
     */
    void initNode(int node, int priority, int owner, std::string label="");

    /**
     * Add an edge from <from> to <to>.
     * Returns true if the edge was added or false if it already existed.
     */
    bool addEdge(int from, int to);

    /**
     * Remove an edge from <from> to <to>.
     * Returns true if the edge was removed or false if it did not exist.
     */
    bool removeEdge(int from, int to);

    /**
     * Parse a pgsolver game.
     */
    void parse_pgsolver(std::istream &in);

    /**
     * Parse a [full or partial] pgsolver solution.
     */
    void parse_solution(std::istream &in);

    /**
     * Write the game in pgsolver format.
     */
    void write_pgsolver(std::ostream &out);

    /**
     * Write the game as a DOT graph.
     */
    void write_dot(std::ostream &out);

    /**
     * Write the solution in pgsolver format.
     */
    void write_sol(std::ostream &cout);

    /**
     * Sort the nodes in order of priority (low to high).
     * Afterwards, <mapping> is such that node <i> was originally at <mapping[i]>.
     */
    void reindex(int *mapping = NULL);

    /**
     * Reindex the game if it was not yet reindexed.
     */
    void reindex_once(void);

    /**
     * Apply a permutation, moving node <i> to position <mapping[i]>.
     * This reverses a reindex operation.
     */
    void permute(int *mapping); // undo reindex

    /**
     * Reassign priorities such that every node has a unique priority.
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int inflate(void);

    /**
     * Reassign priorities such that no priority is skipped. ("compression")
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int compress(void);

    /**
     * Reassign priorities in order, but do not inflate or compress.
     * (Assumes reindex() has been called earlier.)
     * Returns number of distinct priorities.
     */
    int renumber(void);

    /**
     * Swap players (priorities and ownership)
     * (Assumes reindex() has been called earlier.)
     */
    void evenodd(void);

    /**
     * Change a max game into a min game and vice versa.
     * (Assumes reindex() has been called earlier.)
     */
    void minmax(void);

    /**
     * Return the number of vertices.
     */
    inline size_t nodecount() { return n_nodes; }

    /**
     * Count and return the number of edges.
     */
    inline size_t edgecount() { edge_recount(); return n_edges; }

    /**
     * Returns whether every node has dominion 0 or 1.
     */
    inline bool gameSolved() { return solved.count() == nodecount(); }

    /**
     * Count and return how many nodes have dominion -1.
     */
    inline int countUnsolved() { return n_nodes - solved.count(); }

    inline void edge_recount()
    {
        n_edges = 0;
        for (int n=0; n<n_nodes; n++) n_edges += out[n].size();
    }

    /**
     * Create a new Game of the subgame of the nodes given in <selection>.
     * (We don't check if the relation is total.)
     * Afterwards, <mapping> contains for index i the corresponding index in the full game.
     * (mapping must be int[selection.size()])
     */
    Game *extract_subgame(std::vector<int> &selection, int *mapping=NULL);

    /**
     * Reset <solved>, <winner> and <strategy>.
     */
    void reset();

    /**
     * Copy the game.
     */
    Game &operator=(const Game &other);

    /**
     * Swap with other game.
     */
    void swap(Game& other);

    /**
     * Game fields
     */

    int n_nodes;           // number of nodes
    int n_edges;           // number of edges
    int *priority;         // priority of each node
    bitset owner;          // owner of each node (1 for odd, 0 for even)
    std::string *label;    // (optional) node labels
    std::vector<int> *out; // outgoing edges
    std::vector<int> *in;  // incoming edges

    bitset solved;         // set true if node solved
    bitset winner;         // for solved vertices, set 1 if won by 1, else 0
    int *strategy;         // strategy for winning vertices

    bool reindexed;        // records if the game was reindexed (before solving)

    class _label_vertex
    {
        public:
            _label_vertex(Game &g, int v) : g(g), v(v) { }
            friend std::ostream& operator<<(std::ostream& out, const _label_vertex &lv) {
                if (lv.v == -1) {
                    out << "-1";
                } else {
                    std::string& l = lv.g.label[lv.v];
                    if (l.empty()) out << lv.v << "/" << lv.g.priority[lv.v];
                    else out << l;
                }
                return out;
            }
        protected:
            Game &g;
            int v;
    };

    _label_vertex label_vertex(int v)
    {
        return _label_vertex(*this, v);
    }
};

}

#endif
<|endoftext|>


<commit_before>#ifndef _GAME_H_
#define _GAME_H_

#include <cmath>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <GL/glu.h>
#include <iostream>
#include "soko_board.hpp"
#include "helpers.hpp"
#include "SOIL.h"
#include "SDL.h"
#include "SDL_opengl.h"
using namespace Sokoban;

class Game {
  public:
    Game(SDL_Window*, SDL_GLContext*, int screenWidth, int screenHeight);
    ~Game();

    void loadLevel(const unsigned level);
    void setWindowSize(unsigned width, unsigned height);
    void setOldPosition(GLdouble x, GLdouble y);
    void setNewPosition(GLdouble xnew, GLdouble ynew);
    bool isLevelFinished() const;

    void moveDownAction();
    void moveUpAction();
    void moveLeftAction();
    void moveRightAction();
    void undoAction();
    void restartAction();

    /* Draws a cube of size edge centered at position (x, y, z). */
    void drawCube(GLdouble x, GLdouble y, GLdouble z, GLdouble edge);
    void sokoReshape();
    void renderScene();
    void renderGameFinished();

  private:
    SDL_Window* window;
    SDL_GLContext* glContext;
    int screenWidth, screenHeight;
    SokoBoard *board = NULL;
    GLdouble xold, yold;

    const char* GAME_WON_IMAGE="assets/theend.png";
};

#endif // _GAME_H_
<commit_msg>Supporting textures<commit_after>#ifndef _GAME_H_
#define _GAME_H_

#include <cmath>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <GL/glu.h>
#include <iostream>
#include "soko_board.hpp"
#include "helpers.hpp"
#include "<SOIL/SOIL.h>"
#include "SDL.h"
#include "SDL_opengl.h"
using namespace Sokoban;

class Game {
  public:
    Game(SDL_Window*, SDL_GLContext*, int screenWidth, int screenHeight);
    ~Game();

    void loadLevel(const unsigned level);
    void setWindowSize(unsigned width, unsigned height);
    void setOldPosition(GLdouble x, GLdouble y);
    void setNewPosition(GLdouble xnew, GLdouble ynew);
    bool isLevelFinished() const;

    void moveDownAction();
    void moveUpAction();
    void moveLeftAction();
    void moveRightAction();
    void undoAction();
    void restartAction();

    /* Draws a cube of size edge centered at position (x, y, z). */
    void drawCube(GLdouble x, GLdouble y, GLdouble z, GLdouble edge);
    void sokoReshape();
    void renderScene();
    void renderGameFinished();

  private:
    SDL_Window* window;
    SDL_GLContext* glContext;
    int screenWidth, screenHeight;
    SokoBoard *board = NULL;
    GLdouble xold, yold;

    const char* GAME_WON_IMAGE="assets/theend.png";
};

#endif // _GAME_H_
<|endoftext|>


<commit_before>// $Id$
// Main authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007

/**************************************************************************
 * Copyright(c) 1998-2008, ALICE Experiment at CERN, all rights reserved. *
 * See http://aliceinfo.cern.ch/Offline/AliRoot/License.html for          *
 * full copyright notice.                                                 *
 **************************************************************************/

#include "AliEveTRDLoaderImp.h"
#include "AliEveTRDModuleImp.h"
#include "EveBase/AliEveEventManager.h"

#include <TEveManager.h>

//#include "TFile.h"
#include "TTree.h"

#include <TGButton.h>

#include "AliLog.h"
#include "AliRun.h"
#include "AliRunLoader.h"
#include "AliTRDrawData.h"
#include "AliTRDrawStreamBase.h"
#include "AliTRDdigitsManager.h"
#include "AliRawReaderRoot.h"
#include "AliRawReaderDate.h"

ClassImp(AliEveTRDLoaderSim)
ClassImp(AliEveTRDLoaderRaw)
ClassImp(AliEveTRDLoaderSimEditor)
//ClassImp(TRDLoaderRawEditor)

///////////////////////////////////////////////////////////
/////////////    AliEveTRDLoaderSim  /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderSim::AliEveTRDLoaderSim(const Text_t* n, const Text_t* t) :
  AliEveTRDLoader(n, t)
  ,fRunLoader(0x0)
{
  // Constructor.
  if(gAlice && (fRunLoader = AliEveEventManager::AssertRunLoader())) SetDataLinked();
}

//______________________________________________________________________________
Bool_t	AliEveTRDLoaderSim::GoToEvent(int ev)
{
  // Go to given event.

  if(!fChildren.size()){
    AliWarning("Please select first the chamber that you want to monitor from \"Chamber(s) selector\".");
    return kFALSE;
  }
  if(!fDataType){
    AliWarning("Please select first the type of data that you want to monitor and then hit the \"Load\" button.");
    return kFALSE;
  }

  fEvent = ev;

  if(!fRunLoader){
    AliError("RunLoader not initialized.");
    return kFALSE;
  }
  fRunLoader->UnloadAll("TRD");
  Unload();

  if(fRunLoader->GetEvent(ev)) return kFALSE;
  TTree *t = 0;
  if(fDataType&kTRDHits){
    fRunLoader->LoadHits("TRD", "READ");
    t = fRunLoader->GetTreeH("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadHits(t)) return kFALSE;
  }
  if(fDataType&kTRDDigits){
    fRunLoader->LoadDigits("TRD", "READ");
    t = fRunLoader->GetTreeD("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadDigits(t)) return kFALSE;
  }
  if(fDataType&kTRDClusters){
    fRunLoader->LoadRecPoints("TRD", "READ");
    t = fRunLoader->GetTreeR("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadClusters(t)) return kFALSE;
  }
  if(fDataType&kTRDTracklets){
    fRunLoader->LoadTracks("TRD", "READ");
    t = fRunLoader->GetTreeT("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadTracklets(t)) return kFALSE;
  }

  gEve->Redraw3D();
  return kTRUE;
}

//______________________________________________________________________________
Bool_t	AliEveTRDLoaderSim::Open(const char *filename, const char *dir)
{
  // Open file in given dir.

  if(fRunLoader) return kTRUE;

  fRunLoader = AliRunLoader::Instance();
  if(!fRunLoader) fRunLoader = AliRunLoader::Open(filename,
         AliConfig::GetDefaultEventFolderName(),"read");
  if(!fRunLoader) return kFALSE;

  gAlice = fRunLoader->GetAliRun();
  if(!gAlice) fRunLoader->LoadgAlice();
  if(!gAlice) return kFALSE;

  fFilename = filename;
  fDir = dir;
  fDir += "/";
  fRunLoader->SetDirName(fDir);

  SetDataLinked();
  return kTRUE;
}

///////////////////////////////////////////////////////////
/////////////   AliEveTRDLoaderRaw    /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderRaw::AliEveTRDLoaderRaw(const Text_t* n, const Text_t* t) :
  AliEveTRDLoader(n, t)
  ,fRawDateReader (0x0)
  ,fRawRootReader (0x0)
  ,fRaw           (0x0)
  ,fEventCnt(-1)
{
  // Constructor.
}

//______________________________________________________________________________
Bool_t  AliEveTRDLoaderRaw::Open(const char *filename, const char *dir)
{
  // Open file in gvenn dir.

  fFilename = filename;
  fDir = dir;
  fDir += "/";

  if(fRaw) delete fRaw;
  fRaw = new AliTRDrawData();

  if(fDataType&kTRDRawRoot){
    if(fRawRootReader) delete fRawRootReader;
    fRawRootReader = new AliRawReaderRoot(filename);
  } else if(fDataType&kTRDRawDate){
    if(fRawDateReader) delete fRawDateReader;
    fRawDateReader = new AliRawReaderDate(fDir+fFilename);
  } else {
    AliError("No data type was set.");
    return kFALSE;
  }
  SetDataLinked();
  return kTRUE;
}

//______________________________________________________________________________
Bool_t AliEveTRDLoaderRaw::GoToEvent(int ev)
{
  // Go to given event.

  //AliInfo(Form("Event %d %d %d", ev, fEvent, fEventCnt));

  if(!fChildren.size()){
    AliWarning("Please select first the chamber that you want to monitor from \"Chamber(s) selector\".");
    return kFALSE;
  }

  static const TEveException kEH("AliEveTRDLoader::GotoEvent ");
  if(fRawRootReader == 0x0) throw(kEH + "data file not opened.");

  fEvent = ev;
  if(ev == fEventCnt) return kTRUE;
  if(ev < fEventCnt) {
    fRawRootReader->RewindEvents();
    fEventCnt = -1;
  }

  Bool_t FOUND = kFALSE;
  while(fRawRootReader->NextEvent()){
    fEventCnt++;
    if(fEventCnt == ev){
      FOUND = kTRUE;
      break;
    }
  }
  if(!FOUND) return kFALSE;

  LoadEvent();
  gEve->Redraw3D();

  return kTRUE;
}

//______________________________________________________________________________
Bool_t AliEveTRDLoaderRaw::LoadEvent()
{
  // Load event.
  AliInfo("Loading ...");

  static const TEveException kEH("AliEveTRDLoader::LoadEvent ");
  if(fRawRootReader == 0x0) throw(kEH + "data file not opened.");

  fRawRootReader->Reset();
  fRawRootReader->SelectEquipment(0, 1024, 1041);
  fRawRootReader->Select("TRD");

  AliTRDrawStreamBase::SetRawStreamVersion(AliTRDrawStreamBase::kTRDdefaultStream);
//   AliTRDrawStream::AllowCorruptedData();
//   AliTRDrawStream::DisableStackNumberChecker();
//   AliTRDrawStream::DisableStackLinkNumberChecker();

  AliTRDrawStreamBase *pinput =
  AliTRDrawStreamBase::GetRawStream(fRawRootReader);
  AliTRDrawStreamBase &input = *pinput;

 // AliInfo(Form("Stream version: %s", input.IsA()->GetName()));

  AliEveTRDChamber *chmb;
  AliTRDdigitsManager *dm = new AliTRDdigitsManager();
  dm->CreateArrays();

  Int_t det    = 0;
  while ((det = input.NextChamber(dm)) >= 0){
    if(!(chmb=GetChamber(det))) continue;
    chmb->LoadDigits(dm);

    dm->RemoveDigits(det);
    dm->RemoveDictionaries(det);
    dm->ClearIndexes(det);
  }

  delete pinput;
  pinput = NULL;

  return kTRUE;
}

///////////////////////////////////////////////////////////
//////////// AliEveTRDLoaderSimEditor /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderSimEditor::AliEveTRDLoaderSimEditor(const TGWindow* p, Int_t width, Int_t height,
                                                   UInt_t options, Pixel_t back) :
  TGedFrame(p, width, height, options | kVerticalFrame, back)
  ,fM(0x0)
  ,fCheckedHits(0x0)
  ,fCheckedDigits(0x0)
  ,fCheckedClusters(0x0)
  ,fCheckedTracklets(0x0)
{
  // Constructor.

  MakeTitle("AliEveTRDLoaderSim");

  // "Data selector" group frame
  TGGroupFrame *fGroupFrame = new TGGroupFrame(this,"Data selector");
  fCheckedHits = new TGCheckButton(fGroupFrame,"  Hits");
  fCheckedHits->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDHits));
  fGroupFrame->AddFrame(fCheckedHits, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedDigits = new TGCheckButton(fGroupFrame,"  Digits");
  fCheckedDigits->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDDigits));
  fGroupFrame->AddFrame(fCheckedDigits, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedClusters = new TGCheckButton(fGroupFrame,"  Clusters");
  fCheckedClusters->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDClusters));
  fGroupFrame->AddFrame(fCheckedClusters, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedTracklets = new TGCheckButton(fGroupFrame,"  Tracklets ");
  fCheckedTracklets->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDTracklets));
  fGroupFrame->AddFrame(fCheckedTracklets, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fGroupFrame->SetLayoutManager(new TGVerticalLayout(fGroupFrame));
  //	fGroupFrame->Resize(164,116);
  AddFrame(fGroupFrame, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));
}

//______________________________________________________________________________
void AliEveTRDLoaderSimEditor::SetModel(TObject* obj)
{
  // Set model object.

  if(!(fM = dynamic_cast<AliEveTRDLoaderSim*>(obj))) return;

  Bool_t kRL   = (fM->IsDataLinked()) ? kTRUE : kFALSE;

  fCheckedHits->SetEnabled(kRL);
  if(kRL) fCheckedHits->SetState(fM->fDataType&AliEveTRDLoader::kTRDHits ? kButtonDown : kButtonUp);
  fCheckedDigits->SetEnabled(kRL);
  if(kRL) fCheckedDigits->SetState(fM->fDataType&AliEveTRDLoader::kTRDDigits ? kButtonDown : kButtonUp);
  fCheckedClusters->SetEnabled(kRL);
  if(kRL) fCheckedClusters->SetState(fM->fDataType&AliEveTRDLoader::kTRDClusters ? kButtonDown : kButtonUp);
  fCheckedTracklets->SetEnabled(kRL);
  if(kRL) fCheckedTracklets->SetState(fM->fDataType&AliEveTRDLoader::kTRDTracklets ? kButtonDown : kButtonUp);
}

//______________________________________________________________________________
void AliEveTRDLoaderSimEditor::Toggle(Int_t id)
{
  // Toggle given button id.

  switch(id){
  case AliEveTRDLoader::kTRDHits:
    fM->fDataType |= fCheckedHits->IsDown() ? AliEveTRDLoader::kTRDHits : 0;
    break;
  case AliEveTRDLoader::kTRDDigits:
    fM->fDataType |= fCheckedDigits->IsDown() ? AliEveTRDLoader::kTRDDigits : 0;
    break;
  case AliEveTRDLoader::kTRDClusters:
    fM->fDataType |= fCheckedClusters->IsDown() ? AliEveTRDLoader::kTRDClusters : 0;
    break;
  case AliEveTRDLoader::kTRDTracklets:
    fM->fDataType |= fCheckedTracklets->IsDown() ? AliEveTRDLoader::kTRDTracklets : 0;
    break;
  }
}

<commit_msg>needed to get rid of AliTRDrawStreamerBase (Christoph)<commit_after>// $Id$
// Main authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007

/**************************************************************************
 * Copyright(c) 1998-2008, ALICE Experiment at CERN, all rights reserved. *
 * See http://aliceinfo.cern.ch/Offline/AliRoot/License.html for          *
 * full copyright notice.                                                 *
 **************************************************************************/

#include "AliEveTRDLoaderImp.h"
#include "AliEveTRDModuleImp.h"
#include "EveBase/AliEveEventManager.h"

#include <TEveManager.h>

//#include "TFile.h"
#include "TTree.h"

#include <TGButton.h>

#include "AliLog.h"
#include "AliRun.h"
#include "AliRunLoader.h"
#include "AliTRDrawData.h"
#include "AliTRDrawStream.h"
#include "AliTRDdigitsManager.h"
#include "AliRawReaderRoot.h"
#include "AliRawReaderDate.h"

ClassImp(AliEveTRDLoaderSim)
ClassImp(AliEveTRDLoaderRaw)
ClassImp(AliEveTRDLoaderSimEditor)
//ClassImp(TRDLoaderRawEditor)

///////////////////////////////////////////////////////////
/////////////    AliEveTRDLoaderSim  /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderSim::AliEveTRDLoaderSim(const Text_t* n, const Text_t* t) :
  AliEveTRDLoader(n, t)
  ,fRunLoader(0x0)
{
  // Constructor.
  if(gAlice && (fRunLoader = AliEveEventManager::AssertRunLoader())) SetDataLinked();
}

//______________________________________________________________________________
Bool_t	AliEveTRDLoaderSim::GoToEvent(int ev)
{
  // Go to given event.

  if(!fChildren.size()){
    AliWarning("Please select first the chamber that you want to monitor from \"Chamber(s) selector\".");
    return kFALSE;
  }
  if(!fDataType){
    AliWarning("Please select first the type of data that you want to monitor and then hit the \"Load\" button.");
    return kFALSE;
  }

  fEvent = ev;

  if(!fRunLoader){
    AliError("RunLoader not initialized.");
    return kFALSE;
  }
  fRunLoader->UnloadAll("TRD");
  Unload();

  if(fRunLoader->GetEvent(ev)) return kFALSE;
  TTree *t = 0;
  if(fDataType&kTRDHits){
    fRunLoader->LoadHits("TRD", "READ");
    t = fRunLoader->GetTreeH("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadHits(t)) return kFALSE;
  }
  if(fDataType&kTRDDigits){
    fRunLoader->LoadDigits("TRD", "READ");
    t = fRunLoader->GetTreeD("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadDigits(t)) return kFALSE;
  }
  if(fDataType&kTRDClusters){
    fRunLoader->LoadRecPoints("TRD", "READ");
    t = fRunLoader->GetTreeR("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadClusters(t)) return kFALSE;
  }
  if(fDataType&kTRDTracklets){
    fRunLoader->LoadTracks("TRD", "READ");
    t = fRunLoader->GetTreeT("TRD", kFALSE);
    if(!t) return kFALSE;
    if(!LoadTracklets(t)) return kFALSE;
  }

  gEve->Redraw3D();
  return kTRUE;
}

//______________________________________________________________________________
Bool_t	AliEveTRDLoaderSim::Open(const char *filename, const char *dir)
{
  // Open file in given dir.

  if(fRunLoader) return kTRUE;

  fRunLoader = AliRunLoader::Instance();
  if(!fRunLoader) fRunLoader = AliRunLoader::Open(filename,
         AliConfig::GetDefaultEventFolderName(),"read");
  if(!fRunLoader) return kFALSE;

  gAlice = fRunLoader->GetAliRun();
  if(!gAlice) fRunLoader->LoadgAlice();
  if(!gAlice) return kFALSE;

  fFilename = filename;
  fDir = dir;
  fDir += "/";
  fRunLoader->SetDirName(fDir);

  SetDataLinked();
  return kTRUE;
}

///////////////////////////////////////////////////////////
/////////////   AliEveTRDLoaderRaw    /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderRaw::AliEveTRDLoaderRaw(const Text_t* n, const Text_t* t) :
  AliEveTRDLoader(n, t)
  ,fRawDateReader (0x0)
  ,fRawRootReader (0x0)
  ,fRaw           (0x0)
  ,fEventCnt(-1)
{
  // Constructor.
}

//______________________________________________________________________________
Bool_t  AliEveTRDLoaderRaw::Open(const char *filename, const char *dir)
{
  // Open file in gvenn dir.

  fFilename = filename;
  fDir = dir;
  fDir += "/";

  if(fRaw) delete fRaw;
  fRaw = new AliTRDrawData();

  if(fDataType&kTRDRawRoot){
    if(fRawRootReader) delete fRawRootReader;
    fRawRootReader = new AliRawReaderRoot(filename);
  } else if(fDataType&kTRDRawDate){
    if(fRawDateReader) delete fRawDateReader;
    fRawDateReader = new AliRawReaderDate(fDir+fFilename);
  } else {
    AliError("No data type was set.");
    return kFALSE;
  }
  SetDataLinked();
  return kTRUE;
}

//______________________________________________________________________________
Bool_t AliEveTRDLoaderRaw::GoToEvent(int ev)
{
  // Go to given event.

  //AliInfo(Form("Event %d %d %d", ev, fEvent, fEventCnt));

  if(!fChildren.size()){
    AliWarning("Please select first the chamber that you want to monitor from \"Chamber(s) selector\".");
    return kFALSE;
  }

  static const TEveException kEH("AliEveTRDLoader::GotoEvent ");
  if(fRawRootReader == 0x0) throw(kEH + "data file not opened.");

  fEvent = ev;
  if(ev == fEventCnt) return kTRUE;
  if(ev < fEventCnt) {
    fRawRootReader->RewindEvents();
    fEventCnt = -1;
  }

  Bool_t FOUND = kFALSE;
  while(fRawRootReader->NextEvent()){
    fEventCnt++;
    if(fEventCnt == ev){
      FOUND = kTRUE;
      break;
    }
  }
  if(!FOUND) return kFALSE;

  LoadEvent();
  gEve->Redraw3D();

  return kTRUE;
}

//______________________________________________________________________________
Bool_t AliEveTRDLoaderRaw::LoadEvent()
{
  // Load event.
  AliInfo("Loading ...");

  static const TEveException kEH("AliEveTRDLoader::LoadEvent ");
  if(fRawRootReader == 0x0) throw(kEH + "data file not opened.");

  fRawRootReader->Reset();
  fRawRootReader->SelectEquipment(0, 1024, 1041);
  fRawRootReader->Select("TRD");

//   AliTRDrawStream::AllowCorruptedData();
//   AliTRDrawStream::DisableStackNumberChecker();
//   AliTRDrawStream::DisableStackLinkNumberChecker();

  AliTRDrawStream *pinput = new AliTRDrawStream(fRawRootReader);
  AliTRDrawStream &input = *pinput;

 // AliInfo(Form("Stream version: %s", input.IsA()->GetName()));

  AliEveTRDChamber *chmb;
  AliTRDdigitsManager *dm = new AliTRDdigitsManager();
  dm->CreateArrays();

  Int_t det    = 0;
  while ((det = input.NextChamber(dm)) >= 0){
    if(!(chmb=GetChamber(det))) continue;
    chmb->LoadDigits(dm);

    dm->RemoveDigits(det);
    dm->RemoveDictionaries(det);
    dm->ClearIndexes(det);
  }

  delete pinput;
  pinput = NULL;

  return kTRUE;
}

///////////////////////////////////////////////////////////
//////////// AliEveTRDLoaderSimEditor /////////////////////
///////////////////////////////////////////////////////////

//______________________________________________________________________________
AliEveTRDLoaderSimEditor::AliEveTRDLoaderSimEditor(const TGWindow* p, Int_t width, Int_t height,
                                                   UInt_t options, Pixel_t back) :
  TGedFrame(p, width, height, options | kVerticalFrame, back)
  ,fM(0x0)
  ,fCheckedHits(0x0)
  ,fCheckedDigits(0x0)
  ,fCheckedClusters(0x0)
  ,fCheckedTracklets(0x0)
{
  // Constructor.

  MakeTitle("AliEveTRDLoaderSim");

  // "Data selector" group frame
  TGGroupFrame *fGroupFrame = new TGGroupFrame(this,"Data selector");
  fCheckedHits = new TGCheckButton(fGroupFrame,"  Hits");
  fCheckedHits->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDHits));
  fGroupFrame->AddFrame(fCheckedHits, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedDigits = new TGCheckButton(fGroupFrame,"  Digits");
  fCheckedDigits->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDDigits));
  fGroupFrame->AddFrame(fCheckedDigits, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedClusters = new TGCheckButton(fGroupFrame,"  Clusters");
  fCheckedClusters->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDClusters));
  fGroupFrame->AddFrame(fCheckedClusters, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fCheckedTracklets = new TGCheckButton(fGroupFrame,"  Tracklets ");
  fCheckedTracklets->Connect("Clicked()", "AliEveTRDLoaderSimEditor", this, Form("Toggle(=%d)", (Int_t)AliEveTRDLoader::kTRDTracklets));
  fGroupFrame->AddFrame(fCheckedTracklets, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));

  fGroupFrame->SetLayoutManager(new TGVerticalLayout(fGroupFrame));
  //	fGroupFrame->Resize(164,116);
  AddFrame(fGroupFrame, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsCenterY | kLHintsExpandX,2,2,2,2));
}

//______________________________________________________________________________
void AliEveTRDLoaderSimEditor::SetModel(TObject* obj)
{
  // Set model object.

  if(!(fM = dynamic_cast<AliEveTRDLoaderSim*>(obj))) return;

  Bool_t kRL   = (fM->IsDataLinked()) ? kTRUE : kFALSE;

  fCheckedHits->SetEnabled(kRL);
  if(kRL) fCheckedHits->SetState(fM->fDataType&AliEveTRDLoader::kTRDHits ? kButtonDown : kButtonUp);
  fCheckedDigits->SetEnabled(kRL);
  if(kRL) fCheckedDigits->SetState(fM->fDataType&AliEveTRDLoader::kTRDDigits ? kButtonDown : kButtonUp);
  fCheckedClusters->SetEnabled(kRL);
  if(kRL) fCheckedClusters->SetState(fM->fDataType&AliEveTRDLoader::kTRDClusters ? kButtonDown : kButtonUp);
  fCheckedTracklets->SetEnabled(kRL);
  if(kRL) fCheckedTracklets->SetState(fM->fDataType&AliEveTRDLoader::kTRDTracklets ? kButtonDown : kButtonUp);
}

//______________________________________________________________________________
void AliEveTRDLoaderSimEditor::Toggle(Int_t id)
{
  // Toggle given button id.

  switch(id){
  case AliEveTRDLoader::kTRDHits:
    fM->fDataType |= fCheckedHits->IsDown() ? AliEveTRDLoader::kTRDHits : 0;
    break;
  case AliEveTRDLoader::kTRDDigits:
    fM->fDataType |= fCheckedDigits->IsDown() ? AliEveTRDLoader::kTRDDigits : 0;
    break;
  case AliEveTRDLoader::kTRDClusters:
    fM->fDataType |= fCheckedClusters->IsDown() ? AliEveTRDLoader::kTRDClusters : 0;
    break;
  case AliEveTRDLoader::kTRDTracklets:
    fM->fDataType |= fCheckedTracklets->IsDown() ? AliEveTRDLoader::kTRDTracklets : 0;
    break;
  }
}

<|endoftext|>